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,
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
// 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
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();
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()) {
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;
// __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"));
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");
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.
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.
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
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())
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);
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();
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;
}