Switch field destruction over to use the new destroyer-based API

and kill a lot of redundant code.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@134988 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
John McCall 2011-07-12 16:41:08 +00:00
Родитель f1588660c1
Коммит 9928c4805a
8 изменённых файлов: 194 добавлений и 402 удалений

Просмотреть файл

@ -627,18 +627,21 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const BlockExpr *blockExpr) {
// Push a destructor if necessary. The semantics for when this
// actually gets run are really obscure.
if (!ci->isByRef()) {
switch (type.isDestructedType()) {
switch (QualType::DestructionKind dtorKind = type.isDestructedType()) {
case QualType::DK_none:
break;
case QualType::DK_cxx_destructor:
PushDestructorCleanup(type, blockField);
break;
// Block captures count as local values and have imprecise semantics.
// They also can't be arrays, so need to worry about that.
case QualType::DK_objc_strong_lifetime:
PushARCReleaseCleanup(getARCCleanupKind(), type, blockField, false);
pushDestroy(getCleanupKind(dtorKind), blockField, type,
destroyARCStrongImprecise,
/*useEHCleanupForArray*/ false);
break;
case QualType::DK_objc_weak_lifetime:
// __weak objects on the stack always get EH cleanups.
PushARCWeakReleaseCleanup(NormalAndEHCleanup, type, blockField);
case QualType::DK_cxx_destructor:
pushDestroy(dtorKind, blockField, type);
break;
}
}

Просмотреть файл

@ -929,47 +929,25 @@ namespace {
}
};
struct CallArrayFieldDtor : EHScopeStack::Cleanup {
const FieldDecl *Field;
CallArrayFieldDtor(const FieldDecl *Field) : Field(Field) {}
class DestroyField : public EHScopeStack::Cleanup {
const FieldDecl *field;
CodeGenFunction::Destroyer &destroyer;
bool useEHCleanupForArray;
void Emit(CodeGenFunction &CGF, bool IsForEH) {
QualType FieldType = Field->getType();
QualType BaseType = CGF.getContext().getBaseElementType(FieldType);
const CXXRecordDecl *FieldClassDecl = BaseType->getAsCXXRecordDecl();
public:
DestroyField(const FieldDecl *field, CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray)
: field(field), destroyer(*destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
llvm::Value *ThisPtr = CGF.LoadCXXThis();
LValue LHS = CGF.EmitLValueForField(ThisPtr, Field,
// FIXME: Qualifiers?
/*CVRQualifiers=*/0);
const llvm::Type *BasePtr
= CGF.ConvertType(BaseType)->getPointerTo();
llvm::Value *BaseAddrPtr
= CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
const ConstantArrayType *Array
= CGF.getContext().getAsConstantArrayType(FieldType);
CGF.EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(),
Array, BaseAddrPtr);
}
};
struct CallFieldDtor : EHScopeStack::Cleanup {
const FieldDecl *Field;
CallFieldDtor(const FieldDecl *Field) : Field(Field) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
const CXXRecordDecl *FieldClassDecl =
Field->getType()->getAsCXXRecordDecl();
llvm::Value *ThisPtr = CGF.LoadCXXThis();
LValue LHS = CGF.EmitLValueForField(ThisPtr, Field,
// FIXME: Qualifiers?
/*CVRQualifiers=*/0);
CGF.EmitCXXDestructorCall(FieldClassDecl->getDestructor(),
Dtor_Complete, /*ForVirtualBase=*/false,
LHS.getAddress());
void Emit(CodeGenFunction &CGF, bool isForEH) {
// Find the address of the field.
llvm::Value *thisValue = CGF.LoadCXXThis();
LValue LV = CGF.EmitLValueForField(thisValue, field, /*CVRQualifiers=*/0);
assert(LV.isSimple());
CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer,
!isForEH && useEHCleanupForArray);
}
};
}
@ -1043,33 +1021,15 @@ void CodeGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
E = ClassDecl->field_end(); I != E; ++I) {
const FieldDecl *Field = *I;
QualType FieldType = getContext().getCanonicalType(Field->getType());
const ConstantArrayType *Array =
getContext().getAsConstantArrayType(FieldType);
if (Array)
FieldType = getContext().getBaseElementType(Array->getElementType());
const FieldDecl *field = *I;
QualType type = field->getType();
QualType::DestructionKind dtorKind = type.isDestructedType();
if (!dtorKind) continue;
switch (FieldType.isDestructedType()) {
case QualType::DK_none:
continue;
case QualType::DK_cxx_destructor:
if (Array)
EHStack.pushCleanup<CallArrayFieldDtor>(NormalAndEHCleanup, Field);
else
EHStack.pushCleanup<CallFieldDtor>(NormalAndEHCleanup, Field);
break;
case QualType::DK_objc_strong_lifetime:
PushARCFieldReleaseCleanup(getARCCleanupKind(), Field);
break;
case QualType::DK_objc_weak_lifetime:
PushARCFieldWeakReleaseCleanup(getARCCleanupKind(), Field);
break;
}
CleanupKind cleanupKind = getCleanupKind(dtorKind);
EHStack.pushCleanup<DestroyField>(cleanupKind, field,
getDestroyer(dtorKind),
cleanupKind & EHCleanup);
}
}

Просмотреть файл

@ -427,9 +427,14 @@ static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
break;
case Qualifiers::OCL_Strong: {
CGF.PushARCReleaseCleanup(CGF.getARCCleanupKind(),
var.getType(), addr,
var.hasAttr<ObjCPreciseLifetimeAttr>());
CodeGenFunction::Destroyer &destroyer =
(var.hasAttr<ObjCPreciseLifetimeAttr>()
? CodeGenFunction::destroyARCStrongPrecise
: CodeGenFunction::destroyARCStrongImprecise);
CleanupKind cleanupKind = CGF.getARCCleanupKind();
CGF.pushDestroy(cleanupKind, addr, var.getType(), destroyer,
cleanupKind & EHCleanup);
break;
}
case Qualifiers::OCL_Autoreleasing:
@ -439,7 +444,9 @@ static void EmitAutoVarWithLifetime(CodeGenFunction &CGF, const VarDecl &var,
case Qualifiers::OCL_Weak:
// __weak objects always get EH cleanups; otherwise, exceptions
// could cause really nasty crashes instead of mere leaks.
CGF.PushARCWeakReleaseCleanup(NormalAndEHCleanup, var.getType(), addr);
CGF.pushDestroy(NormalAndEHCleanup, addr, var.getType(),
CodeGenFunction::destroyARCWeak,
/*useEHCleanup*/ true);
break;
}
}
@ -1129,11 +1136,21 @@ CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
return *destroyer;
}
/// pushDestroy - Push the standard destructor for the given type.
void CodeGenFunction::pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type) {
assert(dtorKind && "cannot push destructor for trivial type");
CleanupKind cleanupKind = getCleanupKind(dtorKind);
pushDestroy(cleanupKind, addr, type, getDestroyer(dtorKind),
cleanupKind & EHCleanup);
}
void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
QualType type, Destroyer &destroyer,
bool useEHCleanupForArray) {
EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer,
useEHCleanupForArray);
pushFullExprCleanup<DestroyObject>(cleanupKind, addr, type,
destroyer, useEHCleanupForArray);
}
/// emitDestroy - Immediately perform the destruction of the given
@ -1324,13 +1341,12 @@ namespace {
/// \param destructionKind - the kind of destruction required
/// \param initializedElementCount - a value of type size_t* holding
/// the number of successfully-constructed elements
void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *array,
void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEndPointer,
QualType elementType,
Destroyer &destroyer) {
// FIXME: can this be in a conditional expression?
EHStack.pushCleanup<IrregularPartialArrayDestroy>(EHCleanup, array,
arrayEndPointer,
pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEndPointer,
elementType, &destroyer);
}
@ -1348,8 +1364,7 @@ void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
llvm::Value *arrayEnd,
QualType elementType,
Destroyer &destroyer) {
// FIXME: can this be in a conditional expression?
EHStack.pushCleanup<RegularPartialArrayDestroy>(EHCleanup,
pushFullExprCleanup<RegularPartialArrayDestroy>(EHCleanup,
arrayBegin, arrayEnd,
elementType, &destroyer);
}

Просмотреть файл

@ -283,19 +283,24 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
case Qualifiers::OCL_Autoreleasing:
break;
case Qualifiers::OCL_Strong:
CGF.PushARCReleaseCleanup(CGF.getARCCleanupKind(),
ObjCARCReferenceLifetimeType,
ReferenceTemporary,
/*Precise lifetime=*/false,
/*For full expression=*/true);
case Qualifiers::OCL_Strong: {
assert(!ObjCARCReferenceLifetimeType->isArrayType());
CleanupKind cleanupKind = CGF.getARCCleanupKind();
CGF.pushDestroy(cleanupKind,
ReferenceTemporary,
ObjCARCReferenceLifetimeType,
CodeGenFunction::destroyARCStrongImprecise,
cleanupKind & EHCleanup);
break;
}
case Qualifiers::OCL_Weak:
CGF.PushARCWeakReleaseCleanup(NormalAndEHCleanup,
ObjCARCReferenceLifetimeType,
ReferenceTemporary,
/*For full expression=*/true);
assert(!ObjCARCReferenceLifetimeType->isArrayType());
CGF.pushDestroy(NormalAndEHCleanup,
ReferenceTemporary,
ObjCARCReferenceLifetimeType,
CodeGenFunction::destroyARCWeak,
/*useEHCleanupForArray*/ true);
break;
}
@ -467,18 +472,21 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E,
// Nothing to do.
break;
case Qualifiers::OCL_Strong:
PushARCReleaseCleanup(getARCCleanupKind(), ObjCARCReferenceLifetimeType,
ReferenceTemporary,
VD && VD->hasAttr<ObjCPreciseLifetimeAttr>());
case Qualifiers::OCL_Strong: {
bool precise = VD && VD->hasAttr<ObjCPreciseLifetimeAttr>();
CleanupKind cleanupKind = getARCCleanupKind();
pushDestroy(cleanupKind, ReferenceTemporary,
ObjCARCReferenceLifetimeType,
precise ? destroyARCStrongPrecise : destroyARCStrongImprecise,
cleanupKind & EHCleanup);
break;
}
case Qualifiers::OCL_Weak:
// __weak objects always get EH cleanups; otherwise, exceptions
// could cause really nasty crashes instead of mere leaks.
PushARCWeakReleaseCleanup(NormalAndEHCleanup,
ObjCARCReferenceLifetimeType,
ReferenceTemporary);
pushDestroy(NormalAndEHCleanup, ReferenceTemporary,
ObjCARCReferenceLifetimeType, destroyARCWeak, true);
break;
}
}

Просмотреть файл

@ -677,56 +677,36 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP,
FinishFunction();
}
// FIXME: these are stolen from CGClass.cpp, which is lame.
namespace {
struct CallArrayIvarDtor : EHScopeStack::Cleanup {
struct DestroyIvar : EHScopeStack::Cleanup {
private:
llvm::Value *addr;
const ObjCIvarDecl *ivar;
llvm::Value *self;
CallArrayIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self)
: ivar(ivar), self(self) {}
CodeGenFunction::Destroyer &destroyer;
bool useEHCleanupForArray;
public:
DestroyIvar(llvm::Value *addr, const ObjCIvarDecl *ivar,
CodeGenFunction::Destroyer *destroyer,
bool useEHCleanupForArray)
: addr(addr), ivar(ivar), destroyer(*destroyer),
useEHCleanupForArray(useEHCleanupForArray) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
LValue lvalue =
CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0);
QualType type = ivar->getType();
const ConstantArrayType *arrayType
= CGF.getContext().getAsConstantArrayType(type);
QualType baseType = CGF.getContext().getBaseElementType(arrayType);
const CXXRecordDecl *classDecl = baseType->getAsCXXRecordDecl();
llvm::Value *base
= CGF.Builder.CreateBitCast(lvalue.getAddress(),
CGF.ConvertType(baseType)->getPointerTo());
CGF.EmitCXXAggrDestructorCall(classDecl->getDestructor(),
arrayType, base);
}
};
struct CallIvarDtor : EHScopeStack::Cleanup {
const ObjCIvarDecl *ivar;
llvm::Value *self;
CallIvarDtor(const ObjCIvarDecl *ivar, llvm::Value *self)
: ivar(ivar), self(self) {}
void Emit(CodeGenFunction &CGF, bool IsForEH) {
LValue lvalue =
CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), self, ivar, 0);
QualType type = ivar->getType();
const CXXRecordDecl *classDecl = type->getAsCXXRecordDecl();
CGF.EmitCXXDestructorCall(classDecl->getDestructor(),
Dtor_Complete, /*ForVirtualBase=*/false,
lvalue.getAddress());
void Emit(CodeGenFunction &CGF, bool isForEH) {
LValue lvalue
= CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
CGF.emitDestroy(lvalue.getAddress(), ivar->getType(), destroyer,
!isForEH && useEHCleanupForArray);
}
};
}
static void pushReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
llvm::Value *self);
static void pushWeakReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
llvm::Value *self);
/// Like CodeGenFunction::destroyARCStrong, but do it with a call.
static void destroyARCStrongWithStore(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
llvm::Value *null = getNullForVariable(addr);
CGF.EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
}
static void emitCXXDestructMethod(CodeGenFunction &CGF,
ObjCImplementationDecl *impl) {
@ -740,37 +720,26 @@ static void emitCXXDestructMethod(CodeGenFunction &CGF,
ivar; ivar = ivar->getNextIvar()) {
QualType type = ivar->getType();
// Drill down to the base element type.
QualType baseType = type;
const ConstantArrayType *arrayType =
CGF.getContext().getAsConstantArrayType(baseType);
if (arrayType) baseType = CGF.getContext().getBaseElementType(arrayType);
// Check whether the ivar is a destructible type.
QualType::DestructionKind destructKind = baseType.isDestructedType();
assert(destructKind == type.isDestructedType());
QualType::DestructionKind dtorKind = type.isDestructedType();
if (!dtorKind) continue;
switch (destructKind) {
case QualType::DK_none:
continue;
CodeGenFunction::Destroyer *destroyer = 0;
case QualType::DK_cxx_destructor:
if (arrayType)
CGF.EHStack.pushCleanup<CallArrayIvarDtor>(NormalAndEHCleanup,
ivar, self);
else
CGF.EHStack.pushCleanup<CallIvarDtor>(NormalAndEHCleanup,
ivar, self);
break;
// Use a call to objc_storeStrong to destroy strong ivars, for the
// general benefit of the tools.
if (dtorKind == QualType::DK_objc_strong_lifetime) {
destroyer = &destroyARCStrongWithStore;
case QualType::DK_objc_strong_lifetime:
pushReleaseForIvar(CGF, ivar, self);
break;
case QualType::DK_objc_weak_lifetime:
pushWeakReleaseForIvar(CGF, ivar, self);
break;
// Otherwise use the default for the destruction kind.
} else {
destroyer = &CGF.getDestroyer(dtorKind);
}
CleanupKind cleanupKind = CGF.getCleanupKind(dtorKind);
CGF.EHStack.pushCleanup<DestroyIvar>(cleanupKind, self, ivar, destroyer,
cleanupKind & EHCleanup);
}
assert(scope.requiresCleanups() && "nothing to do in .cxx_destruct?");
@ -1828,157 +1797,6 @@ void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
}
namespace {
struct ObjCReleasingCleanup : EHScopeStack::Cleanup {
private:
QualType type;
llvm::Value *addr;
CodeGenFunction::Destroyer &destroyer;
protected:
ObjCReleasingCleanup(QualType type, llvm::Value *addr,
CodeGenFunction::Destroyer *destroyer)
: type(type), addr(addr), destroyer(*destroyer) {}
virtual llvm::Value *getAddress(CodeGenFunction &CGF,
llvm::Value *addr) {
return addr;
}
public:
void Emit(CodeGenFunction &CGF, bool isForEH) {
const ArrayType *arrayType = CGF.getContext().getAsArrayType(type);
llvm::Value *addr = getAddress(CGF, this->addr);
// If we don't have an array type, this is easy.
if (!arrayType)
return destroyer(CGF, addr, type);
llvm::Value *begin = addr;
QualType baseType;
// Otherwise, this is more painful.
llvm::Value *count = CGF.emitArrayLength(arrayType, baseType, begin);
assert(baseType == CGF.getContext().getBaseElementType(arrayType));
llvm::BasicBlock *incomingBB = CGF.Builder.GetInsertBlock();
// id *cur = begin;
// id *end = begin + count;
llvm::Value *end =
CGF.Builder.CreateInBoundsGEP(begin, count, "array.end");
// loopBB:
llvm::BasicBlock *loopBB = CGF.createBasicBlock("release-loop");
CGF.EmitBlock(loopBB);
llvm::PHINode *cur = CGF.Builder.CreatePHI(begin->getType(), 2, "cur");
cur->addIncoming(begin, incomingBB);
// if (cur == end) goto endBB;
llvm::Value *eq = CGF.Builder.CreateICmpEQ(cur, end, "release-loop.done");
llvm::BasicBlock *bodyBB = CGF.createBasicBlock("release-loop.body");
llvm::BasicBlock *endBB = CGF.createBasicBlock("release-loop.cont");
CGF.Builder.CreateCondBr(eq, endBB, bodyBB);
CGF.EmitBlock(bodyBB);
// Release the value at 'cur'.
destroyer(CGF, cur, baseType);
// ++cur;
// goto loopBB;
llvm::Value *next = CGF.Builder.CreateConstInBoundsGEP1_32(cur, 1);
cur->addIncoming(next, CGF.Builder.GetInsertBlock());
CGF.Builder.CreateBr(loopBB);
// endBB:
CGF.EmitBlock(endBB);
}
};
/// A cleanup that calls @objc_release on all the objects to release.
struct CallReleaseForObject : ObjCReleasingCleanup {
CallReleaseForObject(QualType type, llvm::Value *addr,
CodeGenFunction::Destroyer *destroyer)
: ObjCReleasingCleanup(type, addr, destroyer) {}
};
/// A cleanup that calls @objc_storeStrong(nil) on all the objects to
/// release in an ivar.
struct CallReleaseForIvar : ObjCReleasingCleanup {
const ObjCIvarDecl *ivar;
CallReleaseForIvar(const ObjCIvarDecl *ivar, llvm::Value *self)
: ObjCReleasingCleanup(ivar->getType(), self,
destroyARCStrongIvar), ivar(ivar) {}
llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *addr) {
LValue lvalue
= CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
return lvalue.getAddress();
}
static void destroyARCStrongIvar(CodeGenFunction &CGF,
llvm::Value *addr,
QualType type) {
llvm::Value *null = getNullForVariable(addr);
CGF.EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
}
};
/// A cleanup that calls @objc_release on all of the objects to release in
/// a field.
struct CallReleaseForField : CallReleaseForObject {
const FieldDecl *Field;
explicit CallReleaseForField(const FieldDecl *Field)
: CallReleaseForObject(Field->getType(), 0,
CodeGenFunction::destroyARCStrongPrecise),
Field(Field) { }
llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *) {
llvm::Value *This = CGF.LoadCXXThis();
LValue LV = CGF.EmitLValueForField(This, Field, 0);
return LV.getAddress();
}
};
/// A cleanup that calls @objc_weak_release on all the objects to
/// release in an object.
struct CallWeakReleaseForObject : ObjCReleasingCleanup {
CallWeakReleaseForObject(QualType type, llvm::Value *addr)
: ObjCReleasingCleanup(type, addr, CodeGenFunction::destroyARCWeak) {}
};
/// A cleanup that calls @objc_weak_release on all the objects to
/// release in an ivar.
struct CallWeakReleaseForIvar : CallWeakReleaseForObject {
const ObjCIvarDecl *ivar;
CallWeakReleaseForIvar(const ObjCIvarDecl *ivar, llvm::Value *self)
: CallWeakReleaseForObject(ivar->getType(), self), ivar(ivar) {}
llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *addr) {
LValue lvalue
= CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0);
return lvalue.getAddress();
}
};
/// A cleanup that calls @objc_weak_release on all the objects to
/// release in a field;
struct CallWeakReleaseForField : CallWeakReleaseForObject {
const FieldDecl *Field;
CallWeakReleaseForField(const FieldDecl *Field)
: CallWeakReleaseForObject(Field->getType(), 0), Field(Field) {}
llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *) {
llvm::Value *This = CGF.LoadCXXThis();
LValue LV = CGF.EmitLValueForField(This, Field, 0);
return LV.getAddress();
}
};
struct CallObjCAutoreleasePoolObject : EHScopeStack::Cleanup {
llvm::Value *Token;
@ -2006,59 +1824,6 @@ void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) {
EHStack.pushCleanup<CallObjCMRRAutoreleasePoolObject>(NormalCleanup, Ptr);
}
/// PushARCReleaseCleanup - Enter a cleanup to perform a release on a
/// given object or array of objects.
void CodeGenFunction::PushARCReleaseCleanup(CleanupKind cleanupKind,
QualType type,
llvm::Value *addr,
bool precise,
bool forFullExpr) {
Destroyer *dtor =
(precise ? destroyARCStrongPrecise : destroyARCStrongImprecise);
if (forFullExpr)
pushFullExprCleanup<CallReleaseForObject>(cleanupKind, type, addr, dtor);
else
EHStack.pushCleanup<CallReleaseForObject>(cleanupKind, type, addr, dtor);
}
/// PushARCWeakReleaseCleanup - Enter a cleanup to perform a weak
/// release on the given object or array of objects.
void CodeGenFunction::PushARCWeakReleaseCleanup(CleanupKind cleanupKind,
QualType type,
llvm::Value *addr,
bool forFullExpr) {
if (forFullExpr)
pushFullExprCleanup<CallWeakReleaseForObject>(cleanupKind, type, addr);
else
EHStack.pushCleanup<CallWeakReleaseForObject>(cleanupKind, type, addr);
}
/// PushARCReleaseCleanup - Enter a cleanup to perform a release on a
/// given object or array of objects.
void CodeGenFunction::PushARCFieldReleaseCleanup(CleanupKind cleanupKind,
const FieldDecl *field) {
EHStack.pushCleanup<CallReleaseForField>(cleanupKind, field);
}
/// PushARCWeakReleaseCleanup - Enter a cleanup to perform a weak
/// release on the given object or array of objects.
void CodeGenFunction::PushARCFieldWeakReleaseCleanup(CleanupKind cleanupKind,
const FieldDecl *field) {
EHStack.pushCleanup<CallWeakReleaseForField>(cleanupKind, field);
}
static void pushReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
llvm::Value *self) {
CGF.EHStack.pushCleanup<CallReleaseForIvar>(CGF.getARCCleanupKind(),
ivar, self);
}
static void pushWeakReleaseForIvar(CodeGenFunction &CGF, ObjCIvarDecl *ivar,
llvm::Value *self) {
CGF.EHStack.pushCleanup<CallWeakReleaseForIvar>(CGF.getARCCleanupKind(),
ivar, self);
}
static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF,
LValue lvalue,
QualType type) {

Просмотреть файл

@ -255,6 +255,30 @@ public:
: a0_saved(a0), a1_saved(a1), a2_saved(a2) {}
};
template <class T, class A0, class A1, class A2, class A3>
class ConditionalCleanup4 : public Cleanup {
typedef typename DominatingValue<A0>::saved_type A0_saved;
typedef typename DominatingValue<A1>::saved_type A1_saved;
typedef typename DominatingValue<A2>::saved_type A2_saved;
typedef typename DominatingValue<A3>::saved_type A3_saved;
A0_saved a0_saved;
A1_saved a1_saved;
A2_saved a2_saved;
A3_saved a3_saved;
void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) {
A0 a0 = DominatingValue<A0>::restore(CGF, a0_saved);
A1 a1 = DominatingValue<A1>::restore(CGF, a1_saved);
A2 a2 = DominatingValue<A2>::restore(CGF, a2_saved);
A3 a3 = DominatingValue<A3>::restore(CGF, a3_saved);
T(a0, a1, a2, a3).Emit(CGF, IsForEHCleanup);
}
public:
ConditionalCleanup4(A0_saved a0, A1_saved a1, A2_saved a2, A3_saved a3)
: a0_saved(a0), a1_saved(a1), a2_saved(a2), a3_saved(a3) {}
};
private:
// The implementation for this class is in CGException.h and
// CGException.cpp; the definition is here because it's used as a
@ -710,6 +734,28 @@ public:
initFullExprCleanup();
}
/// pushFullExprCleanup - Push a cleanup to be run at the end of the
/// current full-expression. Safe against the possibility that
/// we're currently inside a conditionally-evaluated expression.
template <class T, class A0, class A1, class A2, class A3>
void pushFullExprCleanup(CleanupKind kind, A0 a0, A1 a1, A2 a2, A3 a3) {
// If we're not in a conditional branch, or if none of the
// arguments requires saving, then use the unconditional cleanup.
if (!isInConditionalBranch()) {
return EHStack.pushCleanup<T>(kind, a0, a1, a2, a3);
}
typename DominatingValue<A0>::saved_type a0_saved = saveValueInCond(a0);
typename DominatingValue<A1>::saved_type a1_saved = saveValueInCond(a1);
typename DominatingValue<A2>::saved_type a2_saved = saveValueInCond(a2);
typename DominatingValue<A3>::saved_type a3_saved = saveValueInCond(a3);
typedef EHScopeStack::ConditionalCleanup4<T, A0, A1, A2, A3> CleanupType;
EHStack.pushCleanup<CleanupType>(kind, a0_saved, a1_saved,
a2_saved, a3_saved);
initFullExprCleanup();
}
/// PushDestructorCleanup - Push a cleanup to call the
/// complete-object destructor of an object of the given type at the
/// given address. Does nothing if T is not a C++ class type with a
@ -1126,7 +1172,8 @@ public:
QualType elementType,
Destroyer &destroyer);
Destroyer &getDestroyer(QualType::DestructionKind destructionKind);
void pushDestroy(QualType::DestructionKind dtorKind,
llvm::Value *addr, QualType type);
void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
Destroyer &destroyer, bool useEHCleanupForArray);
void emitDestroy(llvm::Value *addr, QualType type, Destroyer &destroyer,
@ -1135,6 +1182,8 @@ public:
QualType type, Destroyer &destroyer,
bool useEHCleanup);
Destroyer &getDestroyer(QualType::DestructionKind destructionKind);
/// Determines whether an EH cleanup is required to destroy a type
/// with the given destruction kind.
bool needsEHCleanup(QualType::DestructionKind kind) {
@ -1151,6 +1200,10 @@ public:
llvm_unreachable("bad destruction kind");
}
CleanupKind getCleanupKind(QualType::DestructionKind kind) {
return (needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup);
}
//===--------------------------------------------------------------------===//
// Objective-C
//===--------------------------------------------------------------------===//
@ -2109,28 +2162,10 @@ public:
llvm::Value *EmitARCRetainScalarExpr(const Expr *expr);
llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr);
void PushARCReleaseCleanup(CleanupKind kind, QualType type,
llvm::Value *addr, bool precise,
bool forFullExpr = false);
void PushARCArrayReleaseCleanup(CleanupKind kind, QualType elementType,
llvm::Value *addr,
llvm::Value *countOrCountPtr,
bool precise, bool forFullExpr = false);
void PushARCWeakReleaseCleanup(CleanupKind kind, QualType type,
llvm::Value *addr, bool forFullExpr = false);
void PushARCArrayWeakReleaseCleanup(CleanupKind kind, QualType elementType,
llvm::Value *addr,
llvm::Value *countOrCountPtr,
bool forFullExpr = false);
static Destroyer destroyARCStrongImprecise;
static Destroyer destroyARCStrongPrecise;
static Destroyer destroyARCWeak;
void PushARCFieldReleaseCleanup(CleanupKind cleanupKind,
const FieldDecl *Field);
void PushARCFieldWeakReleaseCleanup(CleanupKind cleanupKind,
const FieldDecl *Field);
void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr);
llvm::Value *EmitObjCAutoreleasePoolPush();
llvm::Value *EmitObjCMRRAutoreleasePoolPush();

Просмотреть файл

@ -641,12 +641,11 @@ int (^test25(int x))(void) {
// CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [4 x i8*]* [[X]], i32 0, i32 0
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 4
// CHECK-NEXT: br label
// CHECK: [[CUR:%.*]] = phi i8**
// CHECK-NEXT: [[ISDONE:%.*]] = icmp eq i8** [[CUR]], [[END]]
// CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
// CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
// CHECK-NEXT: call void @objc_storeStrong(i8** [[CUR]], i8* null)
// CHECK-NEXT: [[ISDONE:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
// CHECK-NEXT: br i1 [[ISDONE]],
// CHECK: call void @objc_storeStrong(i8** [[CUR]], i8* null)
// CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds i8** [[CUR]], i32 1
// CHECK-NEXT: br label
// CHECK: ret void
// Check that 'init' retains self.

Просмотреть файл

@ -124,10 +124,17 @@ void test_ObjCBlockMember_copy_assign(ObjCBlockMember m1, ObjCBlockMember m2) {
// CHECK: ret
// Implicitly-generated destructor for ObjCArrayMember
// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberD2Ev
// CHECK: call void @objc_release
// CHECK: br label
// CHECK: ret
// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberD2Ev
// CHECK: [[BEGIN:%.*]] = getelementptr inbounds [2 x [3 x i8*]]*
// CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 6
// CHECK-NEXT: br label
// CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
// CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
// CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: [[T1:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
// CHECK-NEXT: br i1 [[T1]],
// CHECK: ret void
// Implicitly-generated default constructor for ObjCArrayMember
// CHECK: define linkonce_odr void @_ZN15ObjCArrayMemberC2Ev