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
This commit is contained in:
John McCall 2010-05-21 04:11:14 +00:00
Родитель a9976d3b19
Коммит ee5042903d
5 изменённых файлов: 131 добавлений и 115 удалений

Просмотреть файл

@ -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;
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -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");
}

Просмотреть файл

@ -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);

Просмотреть файл

@ -31,5 +31,11 @@ void foo(T *P) {
-(void) im1 {
^(void) { [self im0]; }();
}
-(void) im2 {
^{ [super im0]; }();
}
-(void) im3 {
^{ ^{[super im0];}(); }();
}
@end