namespace clang {
class FileManager;
class ASTRecordLayout;
+ class BlockExpr;
class Expr;
class ExternalASTSource;
class IdentifierTable;
/// declaration.
void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S);
+ /// getObjCEncodingForBlockDecl - Return the encoded type for this block
+ /// declaration.
+ void getObjCEncodingForBlock(const BlockExpr *Expr, std::string& S);
+
/// getObjCEncodingForPropertyDecl - Return the encoded type for
/// this method declaration. If non-NULL, Container must be either
/// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should
unsigned POSIXThreads : 1; // Compiling with POSIX thread support
// (-pthread)
unsigned Blocks : 1; // block extension to C
+ unsigned BlockIntrospection: 1; // block have ObjC type encodings.
unsigned EmitAllDecls : 1; // Emit all declarations, even if
// they are unused.
unsigned MathErrno : 1; // Math functions must respect errno
ThreadsafeStatics = 0;
POSIXThreads = 0;
Blocks = 0;
+ BlockIntrospection = 0;
EmitAllDecls = 0;
MathErrno = 1;
OPTION("-fastf", fastf, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fast", fast, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fasynchronous-unwind-tables", fasynchronous_unwind_tables, Flag, f_Group, INVALID, "", 0, 0, 0)
+OPTION("-fblock-introspection", fblock_introspection, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fblocks", fblocks, Flag, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fbootclasspath=", fbootclasspath_EQ, Joined, f_Group, INVALID, "", 0, 0, 0)
OPTION("-fbuiltin-strcat", fbuiltin_strcat, Flag, f_Group, INVALID, "", 0, 0, 0)
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,
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;
// 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
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);
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)
{
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());
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
// 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,
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;
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
// 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,
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)
};
};
// -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");
// RUN: clang-cc -g %s -emit-llvm -o %t -fblocks
-// RUN: grep "func.start" %t | count 4
+// RUN: grep "func.start" %t | count 4 &&
+// RUN: clang-cc -g %s -triple i386-unknown-unknown -emit-llvm -o %t -fblocks -fblock-introspection &&
+// RUN: grep "v8@?0i4" %t | count 1 &&
+// RUN: clang-cc -g %s -triple i386-unknown-unknown -emit-llvm -o %t -fblocks &&
+// RUN: grep "v8@?0i4" %t | count 0 &&
// 1 declaration, 1 bar, 1 test_block_dbg and 1 for the block.
// XFAIL: *