diff options
author | John McCall <rjmccall@apple.com> | 2011-07-12 16:41:08 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-07-12 16:41:08 +0000 |
commit | 9928c4805aa8d5fabd488d0d0c5aeb64fd50f0e3 (patch) | |
tree | b3860a47a6a5f606e5057653deddc0dd84d70635 | |
parent | f1588660c109610e6a79c786b83b7c9bbd6ed31e (diff) |
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
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 17 | ||||
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 96 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 39 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 42 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 317 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 73 | ||||
-rw-r--r-- | test/CodeGenObjC/arc.m | 9 | ||||
-rw-r--r-- | test/CodeGenObjCXX/arc-special-member-functions.mm | 15 |
8 files changed, 200 insertions, 408 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index f529b583af..7c35091a2c 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -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; } } diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 911dbf782f..e0b2b9f81e 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -929,47 +929,25 @@ namespace { } }; - struct CallArrayFieldDtor : EHScopeStack::Cleanup { - const FieldDecl *Field; - CallArrayFieldDtor(const FieldDecl *Field) : Field(Field) {} - - void Emit(CodeGenFunction &CGF, bool IsForEH) { - QualType FieldType = Field->getType(); - QualType BaseType = CGF.getContext().getBaseElementType(FieldType); - const CXXRecordDecl *FieldClassDecl = BaseType->getAsCXXRecordDecl(); - - 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()); + class DestroyField : public EHScopeStack::Cleanup { + const FieldDecl *field; + CodeGenFunction::Destroyer &destroyer; + bool useEHCleanupForArray; + + public: + DestroyField(const FieldDecl *field, CodeGenFunction::Destroyer *destroyer, + bool useEHCleanupForArray) + : field(field), destroyer(*destroyer), + useEHCleanupForArray(useEHCleanupForArray) {} + + 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()); - - 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; - } + const FieldDecl *field = *I; + QualType type = field->getType(); + QualType::DestructionKind dtorKind = type.isDestructedType(); + if (!dtorKind) continue; + + CleanupKind cleanupKind = getCleanupKind(dtorKind); + EHStack.pushCleanup<DestroyField>(cleanupKind, field, + getDestroyer(dtorKind), + cleanupKind & EHCleanup); } } diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 6eaaca0b72..0a580573b5 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -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); } diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index dd238c1715..90bdd5caf6 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -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; } } diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 8ea481f23a..05f5f4caa7 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -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 { - const ObjCIvarDecl *ivar; - llvm::Value *self; - CallArrayIvarDtor(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 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 { + struct DestroyIvar : EHScopeStack::Cleanup { + private: + llvm::Value *addr; 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(); + 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) {} - 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()); - - switch (destructKind) { - case QualType::DK_none: - continue; - - case QualType::DK_cxx_destructor: - if (arrayType) - CGF.EHStack.pushCleanup<CallArrayIvarDtor>(NormalAndEHCleanup, - ivar, self); - else - CGF.EHStack.pushCleanup<CallIvarDtor>(NormalAndEHCleanup, - ivar, self); - break; - - case QualType::DK_objc_strong_lifetime: - pushReleaseForIvar(CGF, ivar, self); - break; - - case QualType::DK_objc_weak_lifetime: - pushWeakReleaseForIvar(CGF, ivar, self); - break; + QualType::DestructionKind dtorKind = type.isDestructedType(); + if (!dtorKind) continue; + + CodeGenFunction::Destroyer *destroyer = 0; + + // 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; + + // 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) { diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 67e63cd346..f1a7187013 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -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(); diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m index 6beac19632..df3968722e 100644 --- a/test/CodeGenObjC/arc.m +++ b/test/CodeGenObjC/arc.m @@ -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. diff --git a/test/CodeGenObjCXX/arc-special-member-functions.mm b/test/CodeGenObjCXX/arc-special-member-functions.mm index 14e0899cd4..d88a2bd62f 100644 --- a/test/CodeGenObjCXX/arc-special-member-functions.mm +++ b/test/CodeGenObjCXX/arc-special-member-functions.mm @@ -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 |