diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 9 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 23 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 7 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 52 | ||||
-rw-r--r-- | lib/AST/StmtProfile.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 1655 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.h | 69 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.cpp | 30 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.h | 14 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 7 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGExprScalar.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCGNU.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCMac.cpp | 92 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCRuntime.h | 6 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 90 | ||||
-rw-r--r-- | lib/Rewrite/RewriteObjC.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 210 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 4 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 21 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderStmt.cpp | 3 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 16 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterStmt.cpp | 1 |
24 files changed, 1279 insertions, 1060 deletions
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 *; }'. + CharUnits ptrSize, ptrAlign, intSize, intAlign; + llvm::tie(ptrSize, ptrAlign) = C.getTypeInfoInChars(C.VoidPtrTy); + llvm::tie(intSize, intAlign) = C.getTypeInfoInChars(C.IntTy); - { - llvm::Constant *BlockVarLayout; - // C = BuildBlockStructInitlist(); - unsigned int flags = BLOCK_HAS_SIGNATURE; + // Are there crazy embedded platforms where this isn't true? + assert(intSize <= ptrSize && "layout assumptions horribly violated"); - // We run this first so that we set BlockHasCopyDispose from the entire - // block literal. - // __invoke - llvm::Function *Fn - = CodeGenFunction(CGM).GenerateBlockFunction(CurGD, BE, Info, CurFuncDecl, - BlockVarLayout, - LocalDeclMap); - SynthesizeCopyDisposeHelpers |= 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 (Info.BlockHasCopyDispose) - flags |= BLOCK_HAS_COPY_DISPOSE; - // This block may import a c++ object. - if (Info.HasCXXObject) - flags |= BLOCK_HAS_CXX_OBJ; - - // __isa - C = CGM.getNSConcreteStackBlock(); - C = llvm::ConstantExpr::getBitCast(C, PtrToInt8Ty); - Elts[0] = C; - - // __flags - flags = computeBlockFlag(CGM, BE, flags); - const llvm::IntegerType *IntTy = cast<llvm::IntegerType>( - CGM.getTypes().ConvertType(CGM.getContext().IntTy)); - C = llvm::ConstantInt::get(IntTy, flags); - Elts[1] = C; - - // __reserved - C = llvm::ConstantInt::get(IntTy, 0); - Elts[2] = C; - - if (Info.BlockLayout.empty()) { - // __descriptor - C = llvm::Constant::getNullValue(PtrToInt8Ty); - Elts[4] = BuildDescriptorBlockDecl(BE, Info, 0, C, 0); - - // Optimize to being a global block. - Elts[0] = CGM.getNSConcreteGlobalBlock(); - - Elts[1] = llvm::ConstantInt::get(IntTy, flags|BLOCK_IS_GLOBAL); - - C = llvm::ConstantStruct::get(VMContext, Elts, false); - - C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true, - llvm::GlobalValue::InternalLinkage, C, - "__block_holder_tmp_" + - llvm::Twine(CGM.getGlobalUniqueCount())); - QualType BPT = BE->getType(); - C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT)); - return C; - } + CharUnits headerSize = ptrSize; + if (2 * intSize < ptrAlign) headerSize += ptrSize; + else headerSize += 2 * intSize; + headerSize += 2 * ptrSize; - 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 = 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()) { - if (BDRE->getDecl()->getType().isObjCGCWeak()) - hasWeakBlockVariable = true; - Types[i+BlockFields] = - llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0); - } else if (BDRE && BDRE->getDecl()->getType()->isReferenceType()) { - Types[i+BlockFields] = llvm::PointerType::get(ConvertType(Ty), 0); - } else - Types[i+BlockFields] = ConvertType(Ty); - } + info.BlockAlign = ptrAlign; + info.BlockSize = headerSize; - llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true); + assert(elementTypes.empty()); + const llvm::Type *i8p = CGM.getTypes().ConvertType(C.VoidPtrTy); + const llvm::Type *intTy = CGM.getTypes().ConvertType(C.IntTy); + elementTypes.push_back(i8p); + elementTypes.push_back(intTy); + elementTypes.push_back(intTy); + elementTypes.push_back(i8p); + elementTypes.push_back(CGM.getBlockDescriptorType()); - llvm::AllocaInst *A = CreateTempAlloca(Ty); - A->setAlignment(Info.BlockAlign.getQuantity()); - V = A; + assert(elementTypes.size() == BlockHeaderSize); +} - // Build layout / cleanup information for all the data entries in the - // layout, and write the enclosing fields into the type. - std::vector<HelperInfo> NoteForHelper(Info.BlockLayout.size()); - unsigned NumHelpers = 0; +/// Compute the layout of the given block. Attempts to lay the block +/// out with minimal space requirements. +static void computeBlockInfo(CodeGenModule &CGM, CGBlockInfo &info) { + ASTContext &C = CGM.getContext(); + const BlockDecl *block = info.getBlockDecl(); - for (unsigned i=0; i<4; ++i) - Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp")); + std::vector<const llvm::Type*> elementTypes; + initializeForBlockHeader(CGM, info, elementTypes); - for (unsigned i=0; i < Info.BlockLayout.size(); ++i) { - const Expr *E = Info.BlockLayout[i]; + if (!block->hasCaptures()) { + info.StructureType = + llvm::StructType::get(CGM.getLLVMContext(), elementTypes, true); + info.CanBeGlobal = true; + return; + } - // Skip padding. - if (isa<DeclRefExpr>(E)) continue; + // Collect the layout chunks. + llvm::SmallVector<BlockLayoutChunk, 16> layout; + layout.reserve(block->capturesCXXThis() + + (block->capture_end() - block->capture_begin())); - llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp"); - HelperInfo &Note = NoteForHelper[NumHelpers++]; + CharUnits maxFieldAlign; - Note.index = i+5; + // First, 'this'. + if (block->capturesCXXThis()) { + const DeclContext *DC = block->getDeclContext(); + for (; isa<BlockDecl>(DC); DC = cast<BlockDecl>(DC)->getDeclContext()) + ; + QualType thisType = cast<CXXMethodDecl>(DC)->getThisType(C); - if (isa<CXXThisExpr>(E)) { - Note.RequiresCopying = false; - Note.flag = BLOCK_FIELD_IS_OBJECT; + const llvm::Type *llvmType = CGM.getTypes().ConvertType(thisType); + std::pair<CharUnits,CharUnits> tinfo + = CGM.getContext().getTypeInfoInChars(thisType); + maxFieldAlign = std::max(maxFieldAlign, tinfo.second); - Builder.CreateStore(LoadCXXThis(), Addr); - continue; - } + layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first, 0, llvmType)); + } - const BlockDeclRefExpr *BDRE = cast<BlockDeclRefExpr>(E); - Note.RequiresCopying = BlockRequiresCopying(BDRE); - Note.cxxvar_import = - BDRE->getCopyConstructorExpr() ? BDRE : 0; - const ValueDecl *VD = BDRE->getDecl(); - QualType T = VD->getType(); - - if (BDRE->isByRef()) { - Note.flag = BLOCK_FIELD_IS_BYREF; - if (T.isObjCGCWeak()) - Note.flag |= BLOCK_FIELD_IS_WEAK; - } else if (T->isBlockPointerType()) { - Note.flag = BLOCK_FIELD_IS_BLOCK; - } else { - Note.flag = BLOCK_FIELD_IS_OBJECT; - } + // Next, all the block captures. + for (BlockDecl::capture_const_iterator ci = block->capture_begin(), + ce = block->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); - if (LocalDeclMap[VD]) { - if (BDRE->isByRef()) { - llvm::Value *Loc = LocalDeclMap[VD]; - Loc = Builder.CreateStructGEP(Loc, 1, "forwarding"); - Loc = Builder.CreateLoad(Loc); - Builder.CreateStore(Loc, Addr); - continue; - } else { - if (BDRE->getCopyConstructorExpr()) { - E = BDRE->getCopyConstructorExpr(); - PushDestructorCleanup(E->getType(), Addr); - } else { - E = new (getContext()) DeclRefExpr(const_cast<ValueDecl*>(VD), - VD->getType().getNonReferenceType(), - Expr::getValueKindForType(VD->getType()), - SourceLocation()); - if (VD->getType()->isReferenceType()) { - E = new (getContext()) - UnaryOperator(const_cast<Expr*>(E), UO_AddrOf, - getContext().getPointerType(E->getType()), - VK_RValue, OK_Ordinary, SourceLocation()); - } - } + if (ci->isByRef()) { + // We have to copy/dispose of the __block reference. + info.NeedsCopyDispose = true; + + // Also note that it's weak for GC purposes. + if (variable->getType().isObjCGCWeak()) + info.HasWeakBlockVariable = true; + + // Just use void* instead of a pointer to the byref type. + QualType byRefPtrTy = C.VoidPtrTy; + + const llvm::Type *llvmType = CGM.getTypes().ConvertType(byRefPtrTy); + std::pair<CharUnits,CharUnits> tinfo + = CGM.getContext().getTypeInfoInChars(byRefPtrTy); + maxFieldAlign = std::max(maxFieldAlign, tinfo.second); + + layout.push_back(BlockLayoutChunk(tinfo.second, tinfo.first, + &*ci, llvmType)); + continue; + } + + // Otherwise, build a layout chunk with the size and alignment of + // the declaration. + if (llvm::Constant *constant = tryCaptureAsConstant(CGM, variable)) { + info.Captures[variable] = CGBlockInfo::Capture::makeConstant(constant); + continue; + } + + // Block pointers require copy/dispose. + if (variable->getType()->isBlockPointerType()) { + info.NeedsCopyDispose = true; + + // So do Objective-C pointers. + } else if (variable->getType()->isObjCObjectPointerType() || + C.isObjCNSObjectType(variable->getType())) { + info.NeedsCopyDispose = true; + + // So do types that require non-trivial copy construction. + } else if (ci->hasCopyExpr()) { + info.NeedsCopyDispose = true; + info.HasCXXObject = true; + + // And so do types with destructors. + } else if (CGM.getLangOptions().CPlusPlus) { + if (const CXXRecordDecl *record = + variable->getType()->getAsCXXRecordDecl()) { + if (!record->hasTrivialDestructor()) { + info.HasCXXObject = true; + info.NeedsCopyDispose = true; } } + } + + CharUnits size = C.getTypeSizeInChars(variable->getType()); + CharUnits align = C.getDeclAlign(variable); + maxFieldAlign = std::max(maxFieldAlign, align); + + const llvm::Type *llvmType = + CGM.getTypes().ConvertTypeForMem(variable->getType()); + + layout.push_back(BlockLayoutChunk(align, size, &*ci, llvmType)); + } - if (BDRE->isByRef()) { - E = new (getContext()) - UnaryOperator(const_cast<Expr*>(E), UO_AddrOf, |