Added block type introspection support.
As per Fariborz's suggestion, committed now but can be reverted later if the used flag is problematic for Apple.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89134 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 1b3e092..c3dc8bc 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3071,6 +3071,54 @@
return sz / getTypeSize(CharTy);
}
+/// getObjCEncodingForBlockDecl - Return the encoded type for this method
+/// declaration.
+void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
+ std::string& S) {
+ const BlockDecl *Decl = Expr->getBlockDecl();
+ QualType BlockTy =
+ Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
+ // Encode result type.
+ getObjCEncodingForType(cast<FunctionType>(BlockTy)->getResultType(), S);
+ // Compute size of all parameters.
+ // Start with computing size of a pointer in number of bytes.
+ // FIXME: There might(should) be a better way of doing this computation!
+ SourceLocation Loc;
+ int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
+ int ParmOffset = PtrSize;
+ for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ E = Decl->param_end(); PI != E; ++PI) {
+ QualType PType = (*PI)->getType();
+ int sz = getObjCEncodingTypeSize(PType);
+ assert (sz > 0 && "BlockExpr - Incomplete param type");
+ ParmOffset += sz;
+ }
+ // Size of the argument frame
+ S += llvm::utostr(ParmOffset);
+ // Block pointer and offset.
+ S += "@?0";
+ ParmOffset = PtrSize;
+
+ // Argument types.
+ ParmOffset = PtrSize;
+ for (BlockDecl::param_const_iterator PI = Decl->param_begin(), E =
+ Decl->param_end(); PI != E; ++PI) {
+ ParmVarDecl *PVDecl = *PI;
+ QualType PType = PVDecl->getOriginalType();
+ if (const ArrayType *AT =
+ dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
+ // Use array's original type only if it has known number of
+ // elements.
+ if (!isa<ConstantArrayType>(AT))
+ PType = PVDecl->getType();
+ } else if (PType->isFunctionType())
+ PType = PVDecl->getType();
+ getObjCEncodingForType(PType, S);
+ S += llvm::utostr(ParmOffset);
+ ParmOffset += getObjCEncodingTypeSize(PType);
+ }
+}
+
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 682cf5d..bc9eb67 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -146,7 +146,23 @@
if (0 && CanBlockBeGlobal(Info))
return CGM.GetAddrOfGlobalBlock(BE, Name.c_str());
- std::vector<llvm::Constant*> Elts(5);
+ size_t BlockFields = 5;
+
+ bool hasIntrospection = CGM.getContext().getLangOptions().BlockIntrospection;
+
+ if (hasIntrospection) {
+ BlockFields++;
+ }
+ std::vector<llvm::Constant*> Elts(BlockFields);
+
+ if (hasIntrospection) {
+ std::string BlockTypeEncoding;
+ CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
+
+ Elts[5] = llvm::ConstantExpr::getBitCast(
+ CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty);
+ }
+
llvm::Constant *C;
llvm::Value *V;
@@ -154,6 +170,9 @@
// C = BuildBlockStructInitlist();
unsigned int flags = BLOCK_HAS_DESCRIPTOR;
+ if (hasIntrospection)
+ flags |= BLOCK_HAS_OBJC_TYPE;
+
// We run this first so that we set BlockHasCopyDispose from the entire
// block literal.
// __invoke
@@ -211,19 +230,21 @@
return C;
}
- std::vector<const llvm::Type *> Types(5+subBlockDeclRefDecls.size());
+ std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size());
for (int i=0; i<4; ++i)
Types[i] = Elts[i]->getType();
Types[4] = PtrToInt8Ty;
+ if (hasIntrospection)
+ Types[5] = PtrToInt8Ty;
for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) {
const Expr *E = subBlockDeclRefDecls[i];
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
QualType Ty = E->getType();
if (BDRE && BDRE->isByRef()) {
- Types[i+5] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
+ Types[i+BlockFields] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
} else
- Types[i+5] = ConvertType(Ty);
+ Types[i+BlockFields] = ConvertType(Ty);
}
llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
@@ -237,6 +258,8 @@
for (unsigned i=0; i<4; ++i)
Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp"));
+ if (hasIntrospection)
+ Builder.CreateStore(Elts[5], Builder.CreateStructGEP(V, 5, "block.tmp"));
for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i)
{
@@ -252,7 +275,7 @@
BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
VD = BDRE->getDecl();
- llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
+ llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp");
NoteForHelper[helpersize].index = i+5;
NoteForHelper[helpersize].RequiresCopying
= BlockRequiresCopying(VD->getType());
@@ -291,7 +314,7 @@
RValue r = EmitAnyExpr(E, Addr, false);
if (r.isScalar()) {
llvm::Value *Loc = r.getScalarVal();
- const llvm::Type *Ty = Types[i+5];
+ const llvm::Type *Ty = Types[i+BlockFields];
if (BDRE->isByRef()) {
// E is now the address of the value field, instead, we want the
// address of the actual ByRef struct. We optimize this slightly
@@ -375,8 +398,20 @@
// int __reserved;
// void (*__invoke)(void *);
// struct __block_descriptor *__descriptor;
+ // // GNU runtime only:
+ // const char *types;
// };
- GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
+ if (CGM.getContext().getLangOptions().BlockIntrospection)
+ GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
+ PtrToInt8Ty,
+ IntTy,
+ IntTy,
+ PtrToInt8Ty,
+ BlockDescPtrTy,
+ PtrToInt8Ty,
+ NULL);
+ else
+ GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
PtrToInt8Ty,
IntTy,
IntTy,
@@ -571,8 +606,12 @@
llvm::GlobalVariable::InternalLinkage,
DescriptorStruct, "__block_descriptor_global");
+ int FieldCount = 5;
// Generate the constants for the block literal.
- llvm::Constant *LiteralFields[5];
+ if (CGM.getContext().getLangOptions().BlockIntrospection)
+ FieldCount = 6;
+
+ std::vector<llvm::Constant*> LiteralFields(FieldCount);
CodeGenFunction::BlockInfo Info(0, n);
uint64_t subBlockSize, subBlockAlign;
@@ -592,7 +631,9 @@
LiteralFields[0] = getNSConcreteGlobalBlock();
// Flags
- LiteralFields[1] =
+ LiteralFields[1] = CGM.getContext().getLangOptions().BlockIntrospection ?
+ llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR |
+ BLOCK_HAS_OBJC_TYPE) :
llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR);
// Reserved
@@ -603,9 +644,17 @@
// Descriptor
LiteralFields[4] = Descriptor;
+
+ // Type encoding
+ if (CGM.getContext().getLangOptions().BlockIntrospection) {
+ std::string BlockTypeEncoding;
+ CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
+
+ LiteralFields[5] = CGM.GetAddrOfConstantCString(BlockTypeEncoding);
+ }
llvm::Constant *BlockLiteralStruct =
- llvm::ConstantStruct::get(VMContext, &LiteralFields[0], 5, false);
+ llvm::ConstantStruct::get(VMContext, LiteralFields, false);
llvm::GlobalVariable *BlockLiteral =
new llvm::GlobalVariable(getModule(), BlockLiteralStruct->getType(), true,
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 3ab4efb..38e02a7 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -55,7 +55,8 @@
BLOCK_HAS_CXX_OBJ = (1 << 26),
BLOCK_IS_GC = (1 << 27),
BLOCK_IS_GLOBAL = (1 << 28),
- BLOCK_HAS_DESCRIPTOR = (1 << 29)
+ BLOCK_HAS_DESCRIPTOR = (1 << 29),
+ BLOCK_HAS_OBJC_TYPE = (1 << 30)
};
};
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 9cfdfdc..34154f3 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -926,8 +926,10 @@
// -fblocks=0 is default.
if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
- getToolChain().IsBlocksDefault()))
+ getToolChain().IsBlocksDefault())) {
+ Args.AddLastArg(CmdArgs, options::OPT_fblock_introspection);
CmdArgs.push_back("-fblocks");
+ }
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions");