diff options
34 files changed, 1467 insertions, 1187 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 6d3a9f0619..8a05730154 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -855,9 +855,9 @@ public: void getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S) const; - /// getObjCEncodingForBlockDecl - Return the encoded type for this block + /// getObjCEncodingForBlock - Return the encoded type for this block /// declaration. - void getObjCEncodingForBlock(const BlockExpr *Expr, std::string& S) const; + std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const; /// getObjCEncodingForPropertyDecl - Return the encoded type for /// this method declaration. If non-NULL, Container must be either diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 485883e18b..f81f9d0ca4 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2493,6 +2493,46 @@ public: /// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } /// class BlockDecl : public Decl, public DeclContext { +public: + /// A class which contains all the information about a particular + /// captured value. + class Capture { + enum { + flag_isByRef = 0x1, + flag_isNested = 0x2 + }; + + /// The variable being captured. + llvm::PointerIntPair<VarDecl*, 2> VariableAndFlags; + + /// The copy expression, expressed in terms of a DeclRef (or + /// BlockDeclRef) to the captured variable. Only required if the + /// variable has a C++ class type. + Expr *CopyExpr; + + public: + Capture(VarDecl *variable, bool byRef, bool nested, Expr *copy) + : VariableAndFlags(variable, + (byRef ? flag_isByRef : 0) | (nested ? flag_isNested : 0)), + CopyExpr(copy) {} + + /// The variable being captured. + VarDecl *getVariable() const { return VariableAndFlags.getPointer(); } + + /// Whether this is a "by ref" capture, i.e. a capture of a __block + /// variable. + bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; } + + /// Whether this is a nested capture, i.e. the variable captured + /// is not from outside the immediately enclosing function/block. + bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; } + + bool hasCopyExpr() const { return CopyExpr != 0; } + Expr *getCopyExpr() const { return CopyExpr; } + void setCopyExpr(Expr *e) { CopyExpr = e; } + }; + +private: // FIXME: This can be packed into the bitfields in Decl. bool IsVariadic : 1; bool CapturesCXXThis : 1; @@ -2505,15 +2545,15 @@ class BlockDecl : public Decl, public DeclContext { Stmt *Body; TypeSourceInfo *SignatureAsWritten; - VarDecl **CapturedDecls; - unsigned NumCapturedDecls; + Capture *Captures; + unsigned NumCaptures; protected: BlockDecl(DeclContext *DC, SourceLocation CaretLoc) : Decl(Block, DC, CaretLoc), DeclContext(Block), IsVariadic(false), CapturesCXXThis(false), ParamInfo(0), NumParams(0), Body(0), - SignatureAsWritten(0), CapturedDecls(0), NumCapturedDecls(0) {} + SignatureAsWritten(0), Captures(0), NumCaptures(0) {} public: static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); @@ -2555,25 +2595,25 @@ public: /// hasCaptures - True if this block (or its nested blocks) captures /// anything of local storage from its enclosing scopes. - bool hasCaptures() const { return NumCapturedDecls != 0 || CapturesCXXThis; } + bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; } - unsigned getNumCapturedDecls() const { return NumCapturedDecls; } + /// getNumCaptures - Returns the number of captured variables. + /// Does not include an entry for 'this'. + unsigned getNumCaptures() const { return NumCaptures; } - typedef VarDecl * const *capture_iterator; - typedef VarDecl const * const *capture_const_iterator; - capture_iterator capture_begin() { return CapturedDecls; } - capture_iterator capture_end() { return CapturedDecls + NumCapturedDecls; } - capture_const_iterator capture_begin() const { return CapturedDecls; } - capture_const_iterator capture_end() const { - return CapturedDecls + NumCapturedDecls; - } + typedef const Capture *capture_iterator; + typedef const Capture *capture_const_iterator; + capture_iterator capture_begin() { return Captures; } + capture_iterator capture_end() { return Captures + NumCaptures; } + capture_const_iterator capture_begin() const { return Captures; } + capture_const_iterator capture_end() const { return Captures + NumCaptures; } bool capturesCXXThis() const { return CapturesCXXThis; } - void setCapturedDecls(ASTContext &Context, - VarDecl * const *begin, - VarDecl * const *end, - bool capturesCXXThis); + void setCaptures(ASTContext &Context, + const Capture *begin, + const Capture *end, + bool capturesCXXThis); virtual SourceRange getSourceRange() const; diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index cf1faf1aff..247a4d10ba 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -3565,27 +3565,25 @@ public: virtual child_iterator child_end(); }; -/// BlockDeclRefExpr - A reference to a declared variable, function, -/// enum, etc. +/// BlockDeclRefExpr - A reference to a local variable declared in an +/// enclosing scope. class BlockDeclRefExpr : public Expr { - ValueDecl *D; + VarDecl *D; SourceLocation Loc; bool IsByRef : 1; bool ConstQualAdded : 1; - Stmt *CopyConstructorVal; public: - BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK, - SourceLocation l, bool ByRef, bool constAdded = false, - Stmt *copyConstructorVal = 0); + BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK, + SourceLocation l, bool ByRef, bool constAdded = false); // \brief Build an empty reference to a declared variable in a // block. explicit BlockDeclRefExpr(EmptyShell Empty) : Expr(BlockDeclRefExprClass, Empty) { } - ValueDecl *getDecl() { return D; } - const ValueDecl *getDecl() const { return D; } - void setDecl(ValueDecl *VD) { D = VD; } + VarDecl *getDecl() { return D; } + const VarDecl *getDecl() const { return D; } + void setDecl(VarDecl *VD) { D = VD; } SourceLocation getLocation() const { return Loc; } void setLocation(SourceLocation L) { Loc = L; } @@ -3598,12 +3596,6 @@ public: bool isConstQualAdded() const { return ConstQualAdded; } void setConstQualAdded(bool C) { ConstQualAdded = C; } - const Expr *getCopyConstructorExpr() const - { return cast_or_null<Expr>(CopyConstructorVal); } - Expr *getCopyConstructorExpr() - { return cast_or_null<Expr>(CopyConstructorVal); } - void setCopyConstructorExpr(Expr *E) { CopyConstructorVal = E; } - static bool classof(const Stmt *T) { return T->getStmtClass() == BlockDeclRefExprClass; } diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index 0ba61b34eb..edd1432d8e 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -116,8 +116,11 @@ public: /// Its return type may be BuiltinType::Dependent. QualType FunctionType; - /// Captures - The set of variables captured by this block. - llvm::SmallSetVector<VarDecl*, 4> Captures; + /// CaptureMap - A map of captured variables to (index+1) into Captures. + llvm::DenseMap<VarDecl*, unsigned> CaptureMap; + + /// Captures - The captured variables. + llvm::SmallVector<BlockDecl::Capture, 4> Captures; /// CapturesCXXThis - Whether this block captures 'this'. bool CapturesCXXThis; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index d96d079908..63e84d4131 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -3693,10 +3693,11 @@ std::string charUnitsToString(const CharUnits &CU) { return llvm::itostr(CU.getQuantity()); } -/// getObjCEncodingForBlockDecl - Return the encoded type for this block +/// getObjCEncodingForBlock - Return the encoded type for this block /// declaration. -void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, - std::string& S) const { +std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { + std::string S; + const BlockDecl *Decl = Expr->getBlockDecl(); QualType BlockTy = Expr->getType()->getAs<BlockPointerType>()->getPointeeType(); @@ -3739,6 +3740,8 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr, S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } + + return S; } void ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index db69e0878a..4fb47bfcdc 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -2104,21 +2104,26 @@ void BlockDecl::setParams(ParmVarDecl **NewParamInfo, } } -void BlockDecl::setCapturedDecls(ASTContext &Context, - VarDecl * const *begin, - VarDecl * const *end, - bool capturesCXXThis) { +void BlockDecl::setCaptures(ASTContext &Context, + const Capture *begin, + const Capture *end, + bool capturesCXXThis) { CapturesCXXThis = capturesCXXThis; if (begin == end) { - NumCapturedDecls = 0; - CapturedDecls = 0; + NumCaptures = 0; + Captures = 0; return; } - NumCapturedDecls = end - begin; - CapturedDecls = new (Context) VarDecl*[NumCapturedDecls]; - memcpy(CapturedDecls, begin, NumCapturedDecls * sizeof(VarDecl*)); + NumCaptures = end - begin; + + // Avoid new Capture[] because we don't want to provide a default + // constructor. + size_t allocationSize = NumCaptures * sizeof(Capture); + void *buffer = Context.Allocate(allocationSize, /*alignment*/sizeof(void*)); + memcpy(buffer, begin, allocationSize); + Captures = static_cast<Capture*>(buffer); } SourceRange BlockDecl::getSourceRange() const { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 04498f7b9a..b22d9d5452 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2961,13 +2961,12 @@ Stmt::child_iterator ObjCMessageExpr::child_end() { } // Blocks -BlockDeclRefExpr::BlockDeclRefExpr(ValueDecl *d, QualType t, ExprValueKind VK, +BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK, SourceLocation l, bool ByRef, - bool constAdded, Stmt *copyConstructorVal) + bool constAdded) : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false, d->isParameterPack()), - D(d), Loc(l), IsByRef(ByRef), - ConstQualAdded(constAdded), CopyConstructorVal(copyConstructorVal) + D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded) { bool TypeDependent = false; bool ValueDependent = false; diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 8b62dcc940..5def7d9a0b 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -100,6 +100,7 @@ namespace { OS << ":'" << QualType::getAsString(D_split) << "'"; } } + void DumpDeclRef(Decl *node); void DumpStmt(const Stmt *Node) { Indent(); OS << "(" << Node->getStmtClassName() @@ -153,6 +154,7 @@ namespace { void VisitBinaryOperator(BinaryOperator *Node); void VisitCompoundAssignOperator(CompoundAssignOperator *Node); void VisitAddrLabelExpr(AddrLabelExpr *Node); + void VisitBlockExpr(BlockExpr *Node); // C++ void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); @@ -362,21 +364,21 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { DumpExpr(Node); OS << " "; - switch (Node->getDecl()->getKind()) { - default: OS << "Decl"; break; - case Decl::Function: OS << "FunctionDecl"; break; - case Decl::Var: OS << "Var"; break; - case Decl::ParmVar: OS << "ParmVar"; break; - case Decl::EnumConstant: OS << "EnumConstant"; break; - case Decl::Typedef: OS << "Typedef"; break; - case Decl::Record: OS << "Record"; break; - case Decl::Enum: OS << "Enum"; break; - case Decl::CXXRecord: OS << "CXXRecord"; break; - case Decl::ObjCInterface: OS << "ObjCInterface"; break; - case Decl::ObjCClass: OS << "ObjCClass"; break; + DumpDeclRef(Node->getDecl()); +} + +void StmtDumper::DumpDeclRef(Decl *d) { + OS << d->getDeclKindName() << ' ' << (void*) d; + + if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) { + OS << " '"; + nd->getDeclName().printName(OS); + OS << "'"; } - OS << "='" << Node->getDecl() << "' " << (void*)Node->getDecl(); + if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) { + OS << ' '; DumpType(vd->getType()); + } } void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { @@ -474,6 +476,30 @@ void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { DumpType(Node->getComputationResultType()); } +void StmtDumper::VisitBlockExpr(BlockExpr *Node) { + DumpExpr(Node); + + IndentLevel++; + BlockDecl *block = Node->getBlockDecl(); + if (block->capturesCXXThis()) { + OS << '\n'; Indent(); OS << "(capture this)"; + } + for (BlockDecl::capture_iterator + i = block->capture_begin(), e = block->capture_end(); i != e; ++i) { + OS << '\n'; + Indent(); + OS << "(capture "; + if (i->isByRef()) OS << "byref "; + if (i->isNested()) OS << "nested "; + DumpDeclRef(i->getVariable()); + if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr()); + OS << ")"; + } + IndentLevel--; + + DumpSubTree(block->getBody()); +} + // GNU extensions. void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index e75c274015..842a2d92d8 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -425,8 +425,6 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) { VisitDecl(S->getDecl()); ID.AddBoolean(S->isByRef()); ID.AddBoolean(S->isConstQualAdded()); - if (S->getCopyConstructorExpr()) - Visit(S->getCopyConstructorExpr()); } static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S, diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index a594a0bb9e..bdbc9d3b55 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -24,141 +24,84 @@ using namespace clang; using namespace CodeGen; -CGBlockInfo::CGBlockInfo(const char *N) - : Name(N), CXXThisRef(0), NeedsObjCSelf(false), - HasCXXObject(false) { +CGBlockInfo::CGBlockInfo(const BlockExpr *blockExpr, const char *N) + : Name(N), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false), + HasCXXObject(false), HasWeakBlockVariable(false), + StructureType(0), Block(blockExpr) { // Skip asm prefix, if any. if (Name && Name[0] == '\01') ++Name; } +/// Build the given block as a global block. +static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, + const CGBlockInfo &blockInfo, + llvm::Constant *blockFn); -llvm::Constant *CodeGenFunction:: -BuildDescriptorBlockDecl(const BlockExpr *BE, const CGBlockInfo &Info, - const llvm::StructType* Ty, - llvm::Constant *BlockVarLayout, - std::vector<HelperInfo> *NoteForHelper) { - CharUnits Size = Info.BlockSize; - const llvm::Type *UnsignedLongTy - = CGM.getTypes().ConvertType(getContext().UnsignedLongTy); - llvm::Constant *C; - std::vector<llvm::Constant*> Elts; +/// Build the helper function to copy a block. +static llvm::Constant *buildCopyHelper(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + return CodeGenFunction(CGM).GenerateCopyHelperFunction(blockInfo); +} + +/// Build the helper function to dipose of a block. +static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo); +} + +/// Build the block descriptor constant for a block. +static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + ASTContext &C = CGM.getContext(); + + const llvm::Type *ulong = CGM.getTypes().ConvertType(C.UnsignedLongTy); + const llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy); + + llvm::SmallVector<llvm::Constant*, 6> elements; // reserved - C = llvm::ConstantInt::get(UnsignedLongTy, 0); - Elts.push_back(C); + elements.push_back(llvm::ConstantInt::get(ulong, 0)); // Size // FIXME: What is the right way to say this doesn't fit? We should give // a user diagnostic in that case. Better fix would be to change the // API to size_t. - C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity()); - Elts.push_back(C); + elements.push_back(llvm::ConstantInt::get(ulong, + blockInfo.BlockSize.getQuantity())); - // optional copy/dispose helpers - if (Info.BlockHasCopyDispose) { + // Optional copy/dispose helpers. + if (blockInfo.NeedsCopyDispose) { // copy_func_helper_decl - Elts.push_back(BuildCopyHelper(Ty, NoteForHelper)); + elements.push_back(buildCopyHelper(CGM, blockInfo)); // destroy_func_decl - Elts.push_back(BuildDestroyHelper(Ty, NoteForHelper)); + elements.push_back(buildDisposeHelper(CGM, blockInfo)); } - // Signature. non-optional ObjC-style method descriptor @encode sequence - std::string BlockTypeEncoding; - CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding); - - Elts.push_back(llvm::ConstantExpr::getBitCast( - CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty)); + // Signature. Mandatory ObjC-style method descriptor @encode sequence. + std::string typeAtEncoding = + CGM.getContext().getObjCEncodingForBlock(blockInfo.getBlockExpr()); + elements.push_back(llvm::ConstantExpr::getBitCast( + CGM.GetAddrOfConstantCString(typeAtEncoding), i8p)); - // Layout. - C = BlockVarLayout; - - Elts.push_back(C); - - C = llvm::ConstantStruct::get(VMContext, Elts, false); - - C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, - llvm::GlobalValue::InternalLinkage, - C, "__block_descriptor_tmp"); - return C; -} - -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); - - // 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)) { - Info.InnerBlocks.insert(BE->getBlockDecl()); - CollectBlockDeclRefInfo(BE->getBody(), Info); - } - - else if (const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(S)) { - const ValueDecl *D = BDRE->getDecl(); - // FIXME: Handle enums. - 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 (!Info.InnerBlocks.count(D->getDeclContext())) { - if (BDRE->getCopyConstructorExpr()) - Info.HasCXXObject = true; - Info.DeclRefs.push_back(BDRE); - } - } + // GC layout. + if (C.getLangOptions().ObjC1) + elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo)); + else + elements.push_back(llvm::Constant::getNullValue(i8p)); - // 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; - } - else if (const ObjCPropertyRefExpr *PE = dyn_cast<ObjCPropertyRefExpr>(S)) { - // Getter/setter uses may also cause implicit super references, - // which we can check for with: - if (PE->isSuperReceiver()) - Info.NeedsObjCSelf = true; - } - else if (isa<CXXThisExpr>(S)) - Info.CXXThisRef = cast<CXXThisExpr>(S); -} + llvm::Constant *init = + llvm::ConstantStruct::get(CGM.getLLVMContext(), elements.data(), + elements.size(), false); -/// 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 CGBlockInfo &Info) { - return Info.DeclRefs.empty(); -} + llvm::GlobalVariable *global = + new llvm::GlobalVariable(CGM.getModule(), init->getType(), true, + llvm::GlobalValue::InternalLinkage, + init, "__block_descriptor_tmp"); -/// AllocateAllBlockDeclRefs - Preallocate all nested BlockDeclRefExprs to -/// ensure we can generate the debug information for the parameter for the block -/// invoke function. -static void AllocateAllBlockDeclRefs(CodeGenFunction &CGF, CGBlockInfo &Info) { - if (Info.CXXThisRef) - CGF.AllocateBlockCXXThisPointer(Info.CXXThisRef); - - for (size_t i = 0; i < Info.DeclRefs.size(); ++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(), VK_RValue, - SourceLocation(), false); - Info.DeclRefs.push_back(BDRE); - CGF.AllocateBlockDecl(BDRE); - } + return llvm::ConstantExpr::getBitCast(global, CGM.getBlockDescriptorType()); } static unsigned computeBlockFlag(CodeGenModule &CGM, @@ -176,256 +119,506 @@ static unsigned computeBlockFlag(CodeGenModule &CGM, return flags; } -// 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(); - CGBlockInfo Info(Name.c_str()); - Info.InnerBlocks.insert(BE->getBlockDecl()); - CollectBlockDeclRefInfo(BE->getBody(), Info); +/* + Purely notional variadic template describing the layout of a block. + + template <class _ResultType, class... _ParamTypes, class... _CaptureTypes> + struct Block_literal { + /// Initialized to one of: + /// extern void *_NSConcreteStackBlock[]; + /// extern void *_NSConcreteGlobalBlock[]; + /// + /// In theory, we could start one off malloc'ed by setting + /// BLOCK_NEEDS_FREE, giving it a refcount of 1, and using + /// this isa: + /// extern void *_NSConcreteMallocBlock[]; + struct objc_class *isa; + + /// These are the flags (with corresponding bit number) that the + /// compiler is actually supposed to know about. + /// 25. BLOCK_HAS_COPY_DISPOSE - indicates that the block + /// descriptor provides copy and dispose helper functions + /// 26. BLOCK_HAS_CXX_OBJ - indicates that there's a captured + /// object with a nontrivial destructor or copy constructor + /// 28. BLOCK_IS_GLOBAL - indicates that the block is allocated + /// as global memory + /// 29. BLOCK_USE_STRET - indicates that the block function + /// uses stret, which objc_msgSend needs to know about + /// 30. BLOCK_HAS_SIGNATURE - indicates that the block has an + /// @encoded signature string + /// And we're not supposed to manipulate these: + /// 24. BLOCK_NEEDS_FREE - indicates that the block has been moved + /// to malloc'ed memory + /// 27. BLOCK_IS_GC - indicates that the block has been moved to + /// to GC-allocated memory + /// Additionally, the bottom 16 bits are a reference count which + /// should be zero on the stack. + int flags; + + /// Reserved; should be zero-initialized. + int reserved; + + /// Function pointer generated from block literal. + _ResultType (*invoke)(Block_literal *, _ParamTypes...); + + /// Block description metadata generated from block literal. + struct Block_descriptor *block_descriptor; + + /// Captured values follow. + _CapturesTypes captures...; + }; + */ + +/// The number of fields in a block header. +const unsigned BlockHeaderSize = 5; + +namespace { + /// A chunk of data that we actually have to capture in the block. + struct BlockLayoutChunk { + CharUnits Alignment; + CharUnits Size; + const BlockDecl::Capture *Capture; // null for 'this' + const llvm::Type *Type; + + BlockLayoutChunk(CharUnits align, CharUnits size, + const BlockDecl::Capture *capture, + const llvm::Type *type) + : Alignment(align), Size(size), Capture(capture), Type(type) {} + + /// Tell the block info that this chunk has the given field index. + void setIndex(CGBlockInfo &info, unsigned index) { + if (!Capture) + info.CXXThisIndex = index; + else + info.Captures[Capture->getVariable()] + = CGBlockInfo::Capture::makeIndex(index); + } + }; - // Check if the block can be global. - // FIXME: This test doesn't work for nested blocks yet. Longer term, I'd like - // to just have one code path. We should move this function into CGM and pass - // CGF, then we can just check to see if CGF is 0. - if (0 && CanBlockBeGlobal(Info)) - return CGM.GetAddrOfGlobalBlock(BE, Name.c_str()); + /// Order by descending alignment. + bool operator<(const BlockLayoutChunk &left, const BlockLayoutChunk &right) { + return left.Alignment > right.Alignment; + } +} - size_t BlockFields = 5; +/// It is illegal to modify a const object after initialization. +/// Therefore, if a const object has a constant initializer, we don't +/// actually need to keep storage for it in the block; we'll just +/// rematerialize it at the start of the block function. This is +/// acceptable because we make no promises about address stability of +/// captured variables. +static llvm::Constant *tryCaptureAsConstant(CodeGenModule &CGM, + const VarDecl *var) { + QualType type = var->getType(); + + // We can only do this if the variable is const. + if (!type.isConstQualified()) return 0; + + // Furthermore, in C++ we can't do this for classes. TODO: we might + // actually be able to get away with it for classes with a trivial + // destructor and a trivial copy constructor and no mutable fields. + if (CGM.getLangOptions().CPlusPlus && + type->getBaseElementTypeUnsafe()->isRecordType()) + return 0; + + // If the variable doesn't have any initializer (shouldn't this be + // invalid?), it's not clear what we should do. Maybe capture as + // zero? + const Expr *init = var->getInit(); + if (!init) return 0; + + return CGM.EmitConstantExpr(init, var->getType()); +} - std::vector<llvm::Constant*> Elts(BlockFields); +/// Get the low bit of a nonzero character count. This is the +/// alignment of the nth byte if the 0th byte is universally aligned. +static CharUnits getLowBit(CharUnits v) { + return CharUnits::fromQuantity(v.getQuantity() & (~v.getQuantity() + 1)); +} - llvm::Constant *C; - llvm::Value *V; +static void initializeForBlockHeader(CodeGenModule &CGM, CGBlockInfo &info, + std::vector<const llvm::Type*> &elementTypes) { + ASTContext &C = CGM.getContext(); - bool hasWeakBlockVariable = false; + // The header is basically a 'struct { void *; int; int; void *; void *; }'. + |