From: Fariborz Jahanian Date: Sat, 13 Nov 2010 21:53:34 +0000 (+0000) Subject: Block API patch to do copy ctor of copied-in cxx objects in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=34999876e215b22febc240b1a6dc054215d12f9c;p=clang Block API patch to do copy ctor of copied-in cxx objects in copy helper function and dtor of copied cxx objects in dispose helper functions. __block variables TBD next. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119011 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 33646871e0..b186c96325 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -112,8 +112,11 @@ static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) { } // Only Decls that escape are added. - if (!Info.InnerBlocks.count(D->getDeclContext())) + if (!Info.InnerBlocks.count(D->getDeclContext())) { + if (BDRE->getCopyConstructorExpr()) + Info.HasCXXObject = true; Info.DeclRefs.push_back(BDRE); + } } // Make sure to capture implicit 'self' references due to super calls. @@ -221,6 +224,9 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); } if (Info.BlockHasCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; + // This block may import a c++ object. + if (Info.HasCXXObject) + flags |= BLOCK_HAS_CXX_OBJ; // __isa C = CGM.getNSConcreteStackBlock(); @@ -312,9 +318,11 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { const BlockDeclRefExpr *BDRE = cast(E); Note.RequiresCopying = BlockRequiresCopying(BDRE); - + Note.cxxvar_import = + BDRE->getCopyConstructorExpr() ? BDRE : 0; const ValueDecl *VD = BDRE->getDecl(); QualType T = VD->getType(); + if (BDRE->isByRef()) { Note.flag = BLOCK_FIELD_IS_BYREF; if (T.isObjCGCWeak()) @@ -1000,14 +1008,18 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T, Srcv = Builder.CreateStructGEP(Srcv, index); Srcv = Builder.CreateBitCast(Srcv, llvm::PointerType::get(PtrToInt8Ty, 0)); - Srcv = Builder.CreateLoad(Srcv); - llvm::Value *Dstv = Builder.CreateStructGEP(DstObj, index); - Dstv = Builder.CreateBitCast(Dstv, PtrToInt8Ty); - - llvm::Value *N = llvm::ConstantInt::get(CGF.Int32Ty, flag); - llvm::Value *F = CGM.getBlockObjectAssign(); - Builder.CreateCall3(F, Dstv, Srcv, N); + if (NoteForHelper[i].cxxvar_import) { + CGF.EmitSynthesizedCXXCopyCtor(Dstv, Srcv, + NoteForHelper[i].cxxvar_import); + } + else { + Srcv = Builder.CreateLoad(Srcv); + Dstv = Builder.CreateBitCast(Dstv, PtrToInt8Ty); + llvm::Value *N = llvm::ConstantInt::get(CGF.Int32Ty, flag); + llvm::Value *F = CGM.getBlockObjectAssign(); + Builder.CreateCall3(F, Dstv, Srcv, N); + } } } } @@ -1063,7 +1075,7 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, PtrPtrT = llvm::PointerType::get(llvm::PointerType::get(T, 0), 0); SrcObj = Builder.CreateBitCast(SrcObj, PtrPtrT); SrcObj = Builder.CreateLoad(SrcObj); - + EHScopeStack::stable_iterator CleanupDepth = CGF.EHStack.stable_begin(); for (unsigned i=0; i < NoteForHelper.size(); ++i) { int flag = NoteForHelper[i].flag; int index = NoteForHelper[i].index; @@ -1074,11 +1086,22 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose, Srcv = Builder.CreateStructGEP(Srcv, index); Srcv = Builder.CreateBitCast(Srcv, llvm::PointerType::get(PtrToInt8Ty, 0)); - Srcv = Builder.CreateLoad(Srcv); - - BuildBlockRelease(Srcv, flag); + if (NoteForHelper[i].cxxvar_import) { + const BlockDeclRefExpr *BDRE = NoteForHelper[i].cxxvar_import; + const Expr *E = BDRE->getCopyConstructorExpr(); + QualType ClassTy = E->getType(); + QualType PtrClassTy = getContext().getPointerType(ClassTy); + const llvm::Type *t = CGM.getTypes().ConvertType(PtrClassTy); + Srcv = Builder.CreateBitCast(Srcv, t); + CGF.PushDestructorCleanup(ClassTy, Srcv); + } + else { + Srcv = Builder.CreateLoad(Srcv); + BuildBlockRelease(Srcv, flag); + } } } + CGF.PopCleanupBlocks(CleanupDepth); } CGF.FinishFunction(); diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index ce721a4640..a5f2aa9e69 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -122,6 +122,7 @@ public: struct HelperInfo { int index; int flag; + const BlockDeclRefExpr *cxxvar_import; bool RequiresCopying; }; diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index d5ecd9f97e..ae99e03c35 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -1150,6 +1150,64 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd); } +void +CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, + llvm::Value *This, llvm::Value *Src, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd) { + if (D->isTrivial()) { + assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor"); + assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor"); + EmitAggregateCopy(This, Src, (*ArgBeg)->getType()); + return; + } + llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, + clang::Ctor_Complete); + assert(D->isInstance() && + "Trying to emit a member call expr on a static method!"); + + const FunctionProtoType *FPT = D->getType()->getAs(); + + CallArgList Args; + + // Push the this ptr. + Args.push_back(std::make_pair(RValue::get(This), + D->getThisType(getContext()))); + + + // Push the src ptr. + QualType QT = *(FPT->arg_type_begin()); + const llvm::Type *t = CGM.getTypes().ConvertType(QT); + Src = Builder.CreateBitCast(Src, t); + Args.push_back(std::make_pair(RValue::get(Src), QT)); + + // Skip over first argument (Src). + ++ArgBeg; + CallExpr::const_arg_iterator Arg = ArgBeg; + for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin()+1, + E = FPT->arg_type_end(); I != E; ++I, ++Arg) { + assert(Arg != ArgEnd && "Running over edge of argument list!"); + QualType ArgType = *I; + Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType), + ArgType)); + } + // Either we've emitted all the call args, or we have a call to a + // variadic function. + assert((Arg == ArgEnd || FPT->isVariadic()) && + "Extra arguments in non-variadic function!"); + // If we still have any arguments, emit them using the type of the argument. + for (; Arg != ArgEnd; ++Arg) { + QualType ArgType = Arg->getType(); + Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType), + ArgType)); + } + + QualType ResultType = FPT->getResultType(); + EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args, + FPT->getExtInfo()), + Callee, ReturnValueSlot(), Args, D); +} + void CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index a03a1fe362..137c54ab1e 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -341,6 +341,33 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, } } +void +CodeGenFunction::EmitSynthesizedCXXCopyCtor(llvm::Value *Dest, + llvm::Value *Src, + const BlockDeclRefExpr *BDRE) { + const Expr *Exp = BDRE->getCopyConstructorExpr(); + if (const CXXExprWithTemporaries *E = dyn_cast(Exp)) + Exp = E->getSubExpr(); + assert(isa(Exp) && + "EmitSynthesizedCXXCopyCtor - unknown copy ctor expr"); + const CXXConstructExpr* E = cast(Exp); + const CXXConstructorDecl *CD = E->getConstructor(); + RunCleanupsScope Scope(*this); + + // If we require zero initialization before (or instead of) calling the + // constructor, as can be the case with a non-user-provided default + // constructor, emit the zero initialization now. + // FIXME. Do I still need this for a copy ctor synthesis? + if (E->requiresZeroInitialization()) + EmitNullInitialization(Dest, E->getType()); + + const ConstantArrayType *Array + = getContext().getAsConstantArrayType(E->getType()); + assert (!Array && "EmitSynthesizedCXXCopyCtor - Copied-in Array"); + EmitSynthesizedCXXCopyCtorCall(CD, Dest, Src, + E->arg_begin(), E->arg_end()); +} + /// Check whether the given operator new[] is the global placement /// operator new[]. static bool IsPlacementOperatorNewArray(ASTContext &Ctx, diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 1898c08719..2e9feefe0b 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1171,6 +1171,11 @@ public: bool ForVirtualBase, llvm::Value *This, CallExpr::const_arg_iterator ArgBeg, CallExpr::const_arg_iterator ArgEnd); + + void EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, + llvm::Value *This, llvm::Value *Src, + CallExpr::const_arg_iterator ArgBeg, + CallExpr::const_arg_iterator ArgEnd); void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, const ConstantArrayType *ArrayTy, @@ -1651,6 +1656,9 @@ public: llvm::GlobalVariable *Addr); void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest); + + void EmitSynthesizedCXXCopyCtor(llvm::Value *Dest, llvm::Value *Src, + const BlockDeclRefExpr *BDRE); RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E, AggValueSlot Slot @@ -1799,10 +1807,14 @@ public: /// NeedsObjCSelf - True if something in this block has an implicit /// reference to 'self'. - bool NeedsObjCSelf; - + bool NeedsObjCSelf : 1; + + /// HasCXXObject - True if block has imported c++ object requiring copy + /// construction in copy helper and destruction in copy dispose helpers. + bool HasCXXObject : 1; + /// These are initialized by GenerateBlockFunction. - bool BlockHasCopyDispose; + bool BlockHasCopyDispose : 1; CharUnits BlockSize; CharUnits BlockAlign; llvm::SmallVector BlockLayout; diff --git a/test/CodeGenCXX/cxx-block-objects.cpp b/test/CodeGenCXX/cxx-block-objects.cpp new file mode 100644 index 0000000000..b989065996 --- /dev/null +++ b/test/CodeGenCXX/cxx-block-objects.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s +// rdar://8594790 + +extern "C" { +extern "C" void *_Block_copy(const void *aBlock); +extern "C" void _Block_release(const void *aBlock); +} + +class A { +public: + int x; + A(const A &o); + A(); + virtual ~A(); + void hello() const; +}; + +int +main() +{ + A a; + void (^c)(void) = ((__typeof(^{ a.hello(); }))_Block_copy((const void *)(^{ a.hello(); }))); + c(); + _Block_release((const void *)(c)); + return 0; +} + +// CHECK: define internal void @__copy_helper_block_ +// CHECK: call void @_ZN1AC1ERKS_ + + +// CHECK:define internal void @__destroy_helper_block_ +// CHECK: call void @_ZN1AD1Ev