From: David Chisnall Date: Tue, 17 Nov 2009 19:33:30 +0000 (+0000) Subject: Added block type introspection support. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e530af5d51572a0ed5dbe50da54bd333840c63d;p=clang 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/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 3cf6788b75..76834d77ec 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -37,6 +37,7 @@ namespace llvm { namespace clang { class FileManager; class ASTRecordLayout; + class BlockExpr; class Expr; class ExternalASTSource; class IdentifierTable; @@ -672,6 +673,10 @@ public: /// 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 diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h index 7fd57c0499..99c100d55e 100644 --- a/include/clang/Basic/LangOptions.h +++ b/include/clang/Basic/LangOptions.h @@ -55,6 +55,7 @@ public: 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 @@ -139,6 +140,7 @@ public: ThreadsafeStatics = 0; POSIXThreads = 0; Blocks = 0; + BlockIntrospection = 0; EmitAllDecls = 0; MathErrno = 1; diff --git a/include/clang/Driver/Options.def b/include/clang/Driver/Options.def index af943335eb..2b66b3506b 100644 --- a/include/clang/Driver/Options.def +++ b/include/clang/Driver/Options.def @@ -368,6 +368,7 @@ OPTION("-fastcp", fastcp, Flag, f_Group, INVALID, "", 0, 0, 0) 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) diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 1b3e09291d..c3dc8bc4da 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3071,6 +3071,54 @@ int ASTContext::getObjCEncodingTypeSize(QualType type) { 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()->getPointeeType(); + // Encode result type. + getObjCEncodingForType(cast(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(PType->getCanonicalTypeInternal())) { + // Use array's original type only if it has known number of + // elements. + if (!isa(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 682cf5da1e..bc9eb67674 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -146,7 +146,23 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { if (0 && CanBlockBeGlobal(Info)) return CGM.GetAddrOfGlobalBlock(BE, Name.c_str()); - std::vector Elts(5); + size_t BlockFields = 5; + + bool hasIntrospection = CGM.getContext().getLangOptions().BlockIntrospection; + + if (hasIntrospection) { + BlockFields++; + } + std::vector 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 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { // 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 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { return C; } - std::vector Types(5+subBlockDeclRefDecls.size()); + std::vector 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(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 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { 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 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { BlockDeclRefExpr *BDRE = dyn_cast(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 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) { 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 @@ const llvm::Type *BlockModule::getGenericBlockLiteralType() { // 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 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { 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 LiteralFields(FieldCount); CodeGenFunction::BlockInfo Info(0, n); uint64_t subBlockSize, subBlockAlign; @@ -592,7 +631,9 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { 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 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) { // 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 3ab4efb71b..38e02a70a4 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -55,7 +55,8 @@ public: 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 9cfdfdc67b..34154f3a3d 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -926,8 +926,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -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"); diff --git a/test/CodeGen/blocks-2.c b/test/CodeGen/blocks-2.c index fa4de3cf14..a88ce9de87 100644 --- a/test/CodeGen/blocks-2.c +++ b/test/CodeGen/blocks-2.c @@ -1,5 +1,9 @@ // 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: *