diff options
author | John McCall <rjmccall@apple.com> | 2010-05-21 04:11:14 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-05-21 04:11:14 +0000 |
commit | ee5042903d53fa7b0fbc1902d0ea07d57c7775b1 (patch) | |
tree | 9c6605cd9fe9de4d25a697455de501edfc7acc45 /lib/CodeGen/CGBlocks.cpp | |
parent | a9976d3b192690db20f59dc44099ac4ca939bdb7 (diff) |
Allocate space in a block record for implicit references to the Objective C
'self' variable arising from uses of the 'super' keyword. Also reorganize
some code so that BlockInfo (now CGBlockInfo) can be opaque outside of
CGBlocks.cpp.
Fixes rdar://problem/8010633.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104312 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGBlocks.cpp')
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 200 |
1 files changed, 118 insertions, 82 deletions
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 7b4eb8f582..d7e0d5fcbc 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -24,6 +24,45 @@ using namespace clang; using namespace CodeGen; +/// CGBlockInfo - Information to generate a block literal. +class clang::CodeGen::CGBlockInfo { +public: + /// Name - The name of the block, kindof. + const char *Name; + + /// DeclRefs - Variables from parent scopes that have been + /// imported into this block. + llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs; + + /// InnerBlocks - This block and the blocks it encloses. + llvm::SmallPtrSet<const DeclContext *, 4> InnerBlocks; + + /// CXXThisRef - Non-null if 'this' was required somewhere, in + /// which case this is that expression. + const CXXThisExpr *CXXThisRef; + + /// NeedsObjCSelf - True if something in this block has an implicit + /// reference to 'self'. + bool NeedsObjCSelf; + + /// These are initialized by GenerateBlockFunction. + bool BlockHasCopyDispose; + CharUnits BlockSize; + CharUnits BlockAlign; + llvm::SmallVector<const Expr*, 8> BlockLayout; + + CGBlockInfo(const char *Name); +}; + +CGBlockInfo::CGBlockInfo(const char *N) + : Name(N), CXXThisRef(0), NeedsObjCSelf(false) { + + // Skip asm prefix, if any. + if (Name && Name[0] == '\01') + ++Name; +} + + llvm::Constant *CodeGenFunction:: BuildDescriptorBlockDecl(const BlockExpr *BE, bool BlockHasCopyDispose, CharUnits Size, const llvm::StructType* Ty, @@ -86,62 +125,85 @@ llvm::Constant *BlockModule::getNSConcreteStackBlock() { return NSConcreteStackBlock; } -static void CollectBlockDeclRefInfo( - const Stmt *S, CodeGenFunction::BlockInfo &Info, - llvm::SmallSet<const DeclContext *, 16> &InnerContexts) { +static void CollectBlockDeclRefInfo(const Stmt *S, CGBlockInfo &Info) { for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); I != E; ++I) if (*I) - CollectBlockDeclRefInfo(*I, Info, InnerContexts); + CollectBlockDeclRefInfo(*I, Info); // We want to ensure we walk down into block literals so we can find // all nested BlockDeclRefExprs. if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) { - InnerContexts.insert(cast<DeclContext>(BE->getBlockDecl())); - CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); + Info.InnerBlocks.insert(BE->getBlockDecl()); + CollectBlockDeclRefInfo(BE->getBody(), Info); } - if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { + else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { + const ValueDecl *D = BDRE->getDecl(); // FIXME: Handle enums. - if (isa<FunctionDecl>(BDRE->getDecl())) + if (isa<FunctionDecl>(D)) return; + if (isa<ImplicitParamDecl>(D) && + isa<ObjCMethodDecl>(D->getDeclContext()) && + cast<ObjCMethodDecl>(D->getDeclContext())->getSelfDecl() == D) { + Info.NeedsObjCSelf = true; + return; + } + // Only Decls that escape are added. - if (!InnerContexts.count(BDRE->getDecl()->getDeclContext())) + if (!Info.InnerBlocks.count(D->getDeclContext())) Info.DeclRefs.push_back(BDRE); } - if (isa<CXXThisExpr>(S)) + // Make sure to capture implicit 'self' references due to super calls. + else if (const ObjCMessageExpr *E = dyn_cast<ObjCMessageExpr>(S)) + if (E->getReceiverKind() == ObjCMessageExpr::SuperClass || + E->getReceiverKind() == ObjCMessageExpr::SuperInstance) + Info.NeedsObjCSelf = true; + + // Getter/setter uses may also cause implicit super references, + // which we can check for with: + else if (isa<ObjCSuperExpr>(S)) + Info.NeedsObjCSelf = true; + + else if (isa<CXXThisExpr>(S)) Info.CXXThisRef = cast<CXXThisExpr>(S); } -/// CanBlockBeGlobal - Given a BlockInfo struct, determines if a block can be +/// CanBlockBeGlobal - Given a CGBlockInfo struct, determines if a block can be /// declared as a global variable instead of on the stack. -static bool CanBlockBeGlobal(const CodeGenFunction::BlockInfo &Info) { +static bool CanBlockBeGlobal(const CGBlockInfo &Info) { return Info.DeclRefs.empty(); } /// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to /// ensure we can generate the debug information for the parameter for the block /// invoke function. -static void AllocateAllBlockDeclRefs(const CodeGenFunction::BlockInfo &Info, - CodeGenFunction *CGF) { +static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) { if (Info.CXXThisRef) - CGF->AllocateBlockCXXThisPointer(Info.CXXThisRef); + CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef); for (size_t i = 0; i < Info.DeclRefs.size(); ++i) - CGF->AllocateBlockDecl(Info.DeclRefs[i]); + CGF.AllocateBlockDecl(Info.DeclRefs[i]); + + if (Info.NeedsObjCSelf) { + ValueDecl *Self = cast<ObjCMethodDecl>(CGF.CurFuncDecl)->getSelfDecl(); + BlockDeclRefExpr *BDRE = + new (CGF.getContext()) BlockDeclRefExpr(Self, Self->getType(), + SourceLocation(), false); + Info.DeclRefs.push_back(BDRE); + CGF.AllocateBlockDecl(BDRE); + } } // FIXME: Push most into CGM, passing down a few bits, like current function // name. llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { - std::string Name = CurFn->getName(); - CodeGenFunction::BlockInfo Info(0, Name.c_str()); - llvm::SmallSet<const DeclContext *, 16> InnerContexts; - InnerContexts.insert(BE->getBlockDecl()); - CollectBlockDeclRefInfo(BE->getBody(), Info, InnerContexts); + CGBlockInfo Info(Name.c_str()); + Info.InnerBlocks.insert(BE->getBlockDecl()); + CollectBlockDeclRefInfo(BE->getBody(), Info); // Check if the block can be global. // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like @@ -164,23 +226,15 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // We run this first so that we set BlockHasCopyDispose from the entire // block literal. // __invoke - CharUnits subBlockSize; - CharUnits subBlockAlign; - llvm::SmallVector<const Expr *, 8> subBlockLayout; - bool subBlockHasCopyDispose = false; llvm::Function *Fn = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, CurFuncDecl, - LocalDeclMap, - subBlockSize, - subBlockAlign, - subBlockLayout, - subBlockHasCopyDispose); - BlockHasCopyDispose |= subBlockHasCopyDispose; + LocalDeclMap); + BlockHasCopyDispose |= Info.BlockHasCopyDispose; Elts[3] = Fn; // FIXME: Don't use BlockHasCopyDispose, it is set more often then // necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); } - if (subBlockHasCopyDispose) + if (Info.BlockHasCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; // __isa @@ -210,10 +264,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { C = llvm::ConstantInt::get(IntTy, 0); Elts[2] = C; - if (subBlockLayout.empty()) { + if (Info.BlockLayout.empty()) { // __descriptor - Elts[4] = BuildDescriptorBlockDecl(BE, subBlockHasCopyDispose, subBlockSize, - 0, 0); + Elts[4] = BuildDescriptorBlockDecl(BE, Info.BlockHasCopyDispose, + Info.BlockSize, 0, 0); // Optimize to being a global block. Elts[0] = CGM.getNSConcreteGlobalBlock(); @@ -231,13 +285,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { return C; } - std::vector<const llvm::Type *> Types(BlockFields+subBlockLayout.size()); + std::vector<const llvm::Type *> Types(BlockFields+Info.BlockLayout.size()); for (int i=0; i<4; ++i) Types[i] = Elts[i]->getType(); Types[4] = PtrToInt8Ty; - for (unsigned i = 0, n = subBlockLayout.size(); i != n; ++i) { - const Expr *E = subBlockLayout[i]; + for (unsigned i = 0, n = Info.BlockLayout.size(); i != n; ++i) { + const Expr *E = Info.BlockLayout[i]; const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E); QualType Ty = E->getType(); if (BDRE && BDRE->isByRef()) { @@ -249,19 +303,19 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true); llvm::AllocaInst *A = CreateTempAlloca(Ty); - A->setAlignment(subBlockAlign.getQuantity()); + A->setAlignment(Info.BlockAlign.getQuantity()); V = A; // Build layout / cleanup information for all the data entries in the // layout, and write the enclosing fields into the type. - std::vector<HelperInfo> NoteForHelper(subBlockLayout.size()); + std::vector<HelperInfo> NoteForHelper(Info.BlockLayout.size()); unsigned NumHelpers = 0; for (unsigned i=0; i<4; ++i) Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); - for (unsigned i=0; i < subBlockLayout.size(); ++i) { - const Expr *E = subBlockLayout[i]; + for (unsigned i=0; i < Info.BlockLayout.size(); ++i) { + const Expr *E = Info.BlockLayout[i]; // Skip padding. if (isa<DeclRefExpr>(E)) continue; @@ -354,8 +408,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // __descriptor llvm::Value *Descriptor = BuildDescriptorBlockDecl(BE, - subBlockHasCopyDispose, - subBlockSize, Ty, + Info.BlockHasCopyDispose, + Info.BlockSize, Ty, &NoteForHelper); Descriptor = Builder.CreateBitCast(Descriptor, PtrToInt8Ty); Builder.CreateStore(Descriptor, Builder.CreateStructGEP(V, 4, "block.tmp")); @@ -542,8 +596,8 @@ void CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) { BlockLayout.push_back(E); } -llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { - const ValueDecl *VD = E->getDecl(); +llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const ValueDecl *VD, + bool IsByRef) { CharUnits offset = BlockDecls[VD]; assert(!offset.isZero() && "getting address of unallocated decl"); @@ -552,7 +606,7 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), offset.getQuantity()), "block.literal"); - if (E->isByRef()) { + if (IsByRef) { const llvm::Type *PtrStructTy = llvm::PointerType::get(BuildByRefType(VD), 0); // The block literal will need a copy/destroy helper. @@ -578,19 +632,6 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) { return V; } -void CodeGenFunction::BlockForwardSelf() { - const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl); - ImplicitParamDecl *SelfDecl = OMD->getSelfDecl(); - llvm::Value *&DMEntry = LocalDeclMap[SelfDecl]; - if (DMEntry) - return; - // FIXME - Eliminate BlockDeclRefExprs, clients don't need/want to care - BlockDeclRefExpr *BDRE = new (getContext()) - BlockDeclRefExpr(SelfDecl, - SelfDecl->getType(), SourceLocation(), false); - DMEntry = GetAddrOfBlockDecl(BDRE); -} - llvm::Constant * BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // Generate the block descriptor. @@ -635,19 +676,11 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { std::vector<llvm::Constant*> LiteralFields(FieldCount); - CodeGenFunction::BlockInfo Info(0, n); - CharUnits subBlockSize; - CharUnits subBlockAlign; - llvm::SmallVector<const Expr *, 8> subBlockLayout; - bool subBlockHasCopyDispose = false; + CGBlockInfo Info(n); llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap; llvm::Function *Fn - = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap, - subBlockSize, - subBlockAlign, - subBlockLayout, - subBlockHasCopyDispose); - assert(subBlockSize == BlockLiteralSize + = CodeGenFunction(CGM).GenerateBlockFunction(BE, Info, 0, LocalDeclMap); + assert(Info.BlockSize == BlockLiteralSize && "no imports allowed for global block"); // isa @@ -686,13 +719,9 @@ llvm::Value *CodeGenFunction::LoadBlockStruct() { llvm::Function * CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, - const BlockInfo& Info, + CGBlockInfo &Info, const Decl *OuterFuncDecl, - llvm::DenseMap<const Decl*, llvm::Value*> ldm, - CharUnits &Size, - CharUnits &Align, - llvm::SmallVectorImpl<const Expr *> &subBlockLayout, - bool &subBlockHasCopyDispose) { + llvm::DenseMap<const Decl*, llvm::Value*> ldm) { // Check if we should generate debug info for this block. if (CGM.getDebugInfo()) @@ -737,7 +766,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); // Build the block struct now. - AllocateAllBlockDeclRefs(Info, this); + AllocateAllBlockDeclRefs(*this, Info); QualType ParmTy = getContext().getBlockParmType(BlockHasCopyDispose, BlockLayout); @@ -795,6 +824,13 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, CXXThisValue = Builder.CreateLoad(ThisPtr, "this"); } + // If we have an Objective C 'self' reference, go ahead and force it + // into existence now. + if (Info.NeedsObjCSelf) { + ValueDecl *Self = cast<ObjCMethodDecl>(CurFuncDecl)->getSelfDecl(); + LocalDeclMap[Self] = GetAddrOfBlockDecl(Self, false); + } + // Save a spot to insert the debug information for all the BlockDeclRefDecls. llvm::BasicBlock *entry = Builder.GetInsertBlock(); llvm::BasicBlock::iterator entry_ptr = Builder.GetInsertPoint(); @@ -837,10 +873,10 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr, llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign.getQuantity())); - Size = BlockOffset; - Align = BlockAlign; - subBlockLayout = BlockLayout; - subBlockHasCopyDispose |= BlockHasCopyDispose; + Info.BlockSize = BlockOffset; + Info.BlockAlign = BlockAlign; + Info.BlockLayout = BlockLayout; + Info.BlockHasCopyDispose = BlockHasCopyDispose; return Fn; } |