]> granicus.if.org Git - clang/commitdiff
Allocate space in a block record for implicit references to the Objective C
authorJohn McCall <rjmccall@apple.com>
Fri, 21 May 2010 04:11:14 +0000 (04:11 +0000)
committerJohn McCall <rjmccall@apple.com>
Fri, 21 May 2010 04:11:14 +0000 (04:11 +0000)
'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

lib/CodeGen/CGBlocks.cpp
lib/CodeGen/CGBlocks.h
lib/CodeGen/CGObjC.cpp
lib/CodeGen/CodeGenFunction.h
test/CodeGenObjC/blocks.m

index 7b4eb8f582dc93367a1686c1ab8037f5a5c645f0..d7e0d5fcbc147ead25a29552b4aa103d689e15c4 100644 (file)
 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;
 }
 
index 067dfc7fdfda8484243afc5cd8c61699e23ec760..e9b2bd549af542dcb3628a2f98b5b83389ccae6e 100644 (file)
@@ -148,30 +148,6 @@ public:
     BLOCK_BYREF_CURRENT_MAX = 256
   };
 
-  /// BlockInfo - Information to generate a block literal.
-  struct BlockInfo {
-    /// BlockLiteralTy - The type of the block literal.
-    const llvm::Type *BlockLiteralTy;
-
-    /// Name - the name of the function this block was created for, if any.
-    const char *Name;
-
-    /// ByCopyDeclRefs - Variables from parent scopes that have been imported
-    /// into this block.
-    llvm::SmallVector<const BlockDeclRefExpr *, 8> DeclRefs;
-
-    /// CXXThisRef - An expression referring to the required 'this'
-    /// expression.
-    const CXXThisExpr *CXXThisRef;
-
-    BlockInfo(const llvm::Type *blt, const char *n)
-      : BlockLiteralTy(blt), Name(n), CXXThisRef(0) {
-      // Skip asm prefix, if any.
-      if (Name && Name[0] == '\01')
-        ++Name;
-    }
-  };
-
   CGBuilderTy &Builder;
 
   BlockFunction(CodeGenModule &cgm, CodeGenFunction &cgf, CGBuilderTy &B);
index 9943a3b700756a2f25dccddccd551aa550a500e9..674f50234e550ea1464e14d3a5c5ade5bcbe7132 100644 (file)
@@ -494,8 +494,6 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
 
 llvm::Value *CodeGenFunction::LoadObjCSelf() {
   const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
-  // See if we need to lazily forward self inside a block literal.
-  BlockForwardSelf();
   return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self");
 }
 
index 048bd0918ad7c92bb0d4e4f75b586bad62a8299e..bac05ba70512d02f31648bd3686a5d3781ceb156 100644 (file)
@@ -67,6 +67,7 @@ namespace CodeGen {
   class CGDebugInfo;
   class CGFunctionInfo;
   class CGRecordLayout;
+  class CGBlockInfo;
 
 /// CodeGenFunction - This class organizes the per-function state that is used
 /// while generating LLVM code.
@@ -501,19 +502,18 @@ public:
                                            std::vector<HelperInfo> *);
 
   llvm::Function *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*> &subBlockDeclRefDecls,
-                                        bool &subBlockHasCopyDispose);
+                                  llvm::DenseMap<const Decl*, llvm::Value*> ldm);
 
-  void BlockForwardSelf();
   llvm::Value *LoadBlockStruct();
 
   void AllocateBlockCXXThisPointer(const CXXThisExpr *E);
   void AllocateBlockDecl(const BlockDeclRefExpr *E);
-  llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E);
+  llvm::Value *GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
+    return GetAddrOfBlockDecl(E->getDecl(), E->isByRef());
+  }
+  llvm::Value *GetAddrOfBlockDecl(const ValueDecl *D, bool ByRef);
   const llvm::Type *BuildByRefType(const ValueDecl *D);
 
   void GenerateCode(GlobalDecl GD, llvm::Function *Fn);
index 8ba319eefee14474b5efbe13401ec6fc81636dab..75b81062f0ef0258691575ad26a589d78e90ebec 100644 (file)
@@ -31,5 +31,11 @@ void foo(T *P) {
 -(void) im1 {
   ^(void) { [self im0]; }();
 }
+-(void) im2 {
+  ^{ [super im0]; }();
+}
+-(void) im3 {
+  ^{ ^{[super im0];}(); }();
+}
 @end