diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2012-11-14 17:15:51 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2012-11-14 17:15:51 +0000 |
commit | 3ca23d7dc6cb61e6f363a58d9256d548199d120c (patch) | |
tree | 00205162a72e02a72fb4ac29effdb1648560aeae /lib | |
parent | accaf19bc1129c0273ec50dba52318e60bc29103 (diff) |
objective-C blocks: Provide layout map for byref
variables captured in a block. // rdar://12184410
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167931 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 34 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 77 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.h | 8 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCGNU.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCMac.cpp | 182 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCRuntime.h | 2 |
7 files changed, 235 insertions, 80 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 80ce66a017..7b61c25b1d 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4368,6 +4368,29 @@ bool ASTContext::BlockRequiresCopying(QualType Ty) const { return false; } +bool ASTContext::getByrefLifetime(QualType Ty, + Qualifiers::ObjCLifetime &LifeTime, + bool &HasByrefExtendedLayout) const { + + if (!getLangOpts().ObjC1 || + getLangOpts().getGC() != LangOptions::NonGC) + return false; + + HasByrefExtendedLayout = false; + if (Ty->isAggregateType()) { + HasByrefExtendedLayout = true; + LifeTime = Qualifiers::OCL_None; + } + else if (getLangOpts().ObjCAutoRefCount) + LifeTime = Ty.getObjCLifetime(); + // MRR. + else if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) + LifeTime = Qualifiers::OCL_ExplicitNone; + else + LifeTime = Qualifiers::OCL_None; + return true; +} + QualType ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { // type = struct __Block_byref_1_X { @@ -4377,10 +4400,13 @@ ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { // unsigned int __size; // void *__copy_helper; // as needed // void *__destroy_help // as needed + // void *__byref_variable_layout; // Extended layout info. for byref variable as needed // int X; // } * bool HasCopyAndDispose = BlockRequiresCopying(Ty); + bool HasByrefExtendedLayout; + Qualifiers::ObjCLifetime Lifetime; // FIXME: Move up SmallString<36> Name; @@ -4398,6 +4424,7 @@ ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { Int32Ty, getPointerType(VoidPtrTy), getPointerType(VoidPtrTy), + getPointerType(VoidPtrTy), Ty }; @@ -4408,12 +4435,15 @@ ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { "__size", "__copy_helper", "__destroy_helper", + "__byref_variable_layout", DeclName, }; - - for (size_t i = 0; i < 7; ++i) { + bool ByrefKnownLifetime = getByrefLifetime(Ty, Lifetime, HasByrefExtendedLayout); + for (size_t i = 0; i < 8; ++i) { if (!HasCopyAndDispose && i >=4 && i <= 5) continue; + if ((!ByrefKnownLifetime || !HasByrefExtendedLayout) && i == 6) + continue; FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), SourceLocation(), &Idents.get(FieldNames[i]), diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 6742f36cf8..33f6eebd67 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -1892,6 +1892,7 @@ llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr, /// int32_t __size; /// void *__copy_helper; // only if needed /// void *__destroy_helper; // only if needed +/// void *__byref_variable_layout;// only if needed /// char padding[X]; // only if needed /// T x; /// } x @@ -1930,6 +1931,12 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { /// void *__destroy_helper; types.push_back(Int8PtrTy); } + bool HasByrefExtendedLayout = false; + Qualifiers::ObjCLifetime Lifetime; + if (getContext().getByrefLifetime(Ty, Lifetime, HasByrefExtendedLayout) && + HasByrefExtendedLayout) + /// void *__byref_variable_layout; + types.push_back(Int8PtrTy); bool Packed = false; CharUnits Align = getContext().getDeclAlign(D); @@ -1939,9 +1946,14 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { // The struct above has 2 32-bit integers. unsigned CurrentOffsetInBytes = 4 * 2; - // And either 2 or 4 pointers. - CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) * - CGM.getDataLayout().getTypeAllocSize(Int8PtrTy); + // And either 2, 3, 4 or 5 pointers. + unsigned noPointers = 2; + if (HasCopyAndDispose) + noPointers += 2; + if (HasByrefExtendedLayout) + noPointers += 1; + + CurrentOffsetInBytes += noPointers * CGM.getDataLayout().getTypeAllocSize(Int8PtrTy); // Align the offset. unsigned AlignedOffsetInBytes = @@ -1991,6 +2003,11 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { const VarDecl &D = *emission.Variable; QualType type = D.getType(); + bool HasByrefExtendedLayout; + Qualifiers::ObjCLifetime ByrefLifetime; + bool ByRefHasLifetime = + getContext().getByrefLifetime(type, ByrefLifetime, HasByrefExtendedLayout); + llvm::Value *V; // Initialize the 'isa', which is just 0 or 1. @@ -2006,9 +2023,49 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { // Blocks ABI: // c) the flags field is set to either 0 if no helper functions are - // needed or BLOCK_HAS_COPY_DISPOSE if they are, + // needed or BLOCK_BYREF_HAS_COPY_DISPOSE if they are, BlockFlags flags; - if (helpers) flags |= BLOCK_HAS_COPY_DISPOSE; + if (helpers) flags |= BLOCK_BYREF_HAS_COPY_DISPOSE; + if (ByRefHasLifetime) { + if (HasByrefExtendedLayout) flags |= BLOCK_BYREF_LAYOUT_EXTENDED; + else switch (ByrefLifetime) { + case Qualifiers::OCL_Strong: + flags |= BLOCK_BYREF_LAYOUT_STRONG; + break; + case Qualifiers::OCL_Weak: + flags |= BLOCK_BYREF_LAYOUT_WEAK; + break; + case Qualifiers::OCL_ExplicitNone: + flags |= BLOCK_BYREF_LAYOUT_UNRETAINED; + break; + case Qualifiers::OCL_None: + if (!type->isObjCObjectPointerType() && !type->isBlockPointerType()) + flags |= BLOCK_BYREF_LAYOUT_NON_OBJECT; + break; + default: + break; + } + if (CGM.getLangOpts().ObjCGCBitmapPrint) { + printf("\n Inline flag for BYREF variable layout (%d):", flags.getBitMask()); + if (flags & BLOCK_BYREF_HAS_COPY_DISPOSE) + printf(" BLOCK_BYREF_HAS_COPY_DISPOSE"); + if (flags & BLOCK_BYREF_LAYOUT_MASK) { + BlockFlags ThisFlag(flags.getBitMask() & BLOCK_BYREF_LAYOUT_MASK); + if (ThisFlag == BLOCK_BYREF_LAYOUT_EXTENDED) + printf(" BLOCK_BYREF_LAYOUT_EXTENDED"); + if (ThisFlag == BLOCK_BYREF_LAYOUT_STRONG) + printf(" BLOCK_BYREF_LAYOUT_STRONG"); + if (ThisFlag == BLOCK_BYREF_LAYOUT_WEAK) + printf(" BLOCK_BYREF_LAYOUT_WEAK"); + if (ThisFlag == BLOCK_BYREF_LAYOUT_UNRETAINED) + printf(" BLOCK_BYREF_LAYOUT_UNRETAINED"); + if (ThisFlag == BLOCK_BYREF_LAYOUT_NON_OBJECT) + printf(" BLOCK_BYREF_LAYOUT_NON_OBJECT"); + } + printf("\n"); + } + } + Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()), Builder.CreateStructGEP(addr, 2, "byref.flags")); @@ -2023,6 +2080,16 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5); Builder.CreateStore(helpers->DisposeHelper, destroy_helper); } + if (ByRefHasLifetime && HasByrefExtendedLayout) { + llvm::Constant* ByrefLayoutInfo = CGM.getObjCRuntime().BuildByrefLayout(CGM, type); + llvm::Value *ByrefInfoAddr = Builder.CreateStructGEP(addr, helpers ? 6 : 4, + "byref.layout"); + // cast destination to pointer to source type. + llvm::Type *DesTy = ByrefLayoutInfo->getType(); + DesTy = DesTy->getPointerTo(); + llvm::Value *BC = Builder.CreatePointerCast(ByrefInfoAddr, DesTy); + Builder.CreateStore(ByrefLayoutInfo, BC); + } } void CodeGenFunction::BuildBlockRelease(llvm::Value *V, BlockFieldFlags flags) { diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index f85701af78..d54ba27692 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -69,11 +69,12 @@ enum BlockLiteralFlags { class BlockFlags { uint32_t flags; - BlockFlags(uint32_t flags) : flags(flags) {} public: + BlockFlags(uint32_t flags) : flags(flags) {} BlockFlags() : flags(0) {} BlockFlags(BlockLiteralFlags flag) : flags(flag) {} - + BlockFlags(BlockByrefFlags flag) : flags(flag) {} + uint32_t getBitMask() const { return flags; } bool empty() const { return flags == 0; } @@ -87,6 +88,9 @@ public: friend bool operator&(BlockFlags l, BlockFlags r) { return (l.flags & r.flags); } + bool operator==(BlockFlags r) { + return (flags == r.flags); + } }; inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) { return BlockFlags(l) | BlockFlags(r); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 80fa09be74..1d9f8ed146 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -2256,6 +2256,12 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, EltTys.push_back(CreateMemberType(Unit, FType, "__destroy_helper", &FieldOffset)); } + bool HasByrefExtendedLayout; + Qualifiers::ObjCLifetime Lifetime; + if (CGM.getContext().getByrefLifetime(Type, Lifetime, HasByrefExtendedLayout) && + HasByrefExtendedLayout) + EltTys.push_back(CreateMemberType(Unit, FType, "__byref_variable_layout", + &FieldOffset)); CharUnits Align = CGM.getContext().getDeclAlign(VD); if (Align > CGM.getContext().toCharUnitsFromBits( diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 68d234dde6..df73abc060 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -537,6 +537,12 @@ public: const CGBlockInfo &blockInfo) { return NULLPtr; } + + virtual llvm::Constant *BuildByrefLayout(CodeGenModule &CGM, + QualType T) { + return NULLPtr; + } + virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) { return 0; } diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 2203f01828..611fb384bd 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -943,7 +943,7 @@ protected: unsigned int BytePos, bool ForStrongLayout, bool &HasUnion); - Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT); + Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT, bool ByrefLayout); void UpdateRunSkipBlockVars(bool IsByref, Qualifiers::ObjCLifetime LifeTime, @@ -951,15 +951,19 @@ protected: CharUnits FieldSize); void BuildRCBlockVarRecordLayout(const RecordType *RT, - CharUnits BytePos, bool &HasUnion); + CharUnits BytePos, bool &HasUnion, + bool ByrefLayout=false); void BuildRCRecordLayout(const llvm::StructLayout *RecLayout, const RecordDecl *RD, ArrayRef<const FieldDecl*> RecFields, - CharUnits BytePos, bool &HasUnion); + CharUnits BytePos, bool &HasUnion, + bool ByrefLayout); uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout); + llvm::Constant *getBitmapBlockLayout(bool ComputeByrefLayout); + /// GetIvarLayoutName - Returns a unique constant for the given /// ivar layout bitmap. @@ -1053,6 +1057,8 @@ public: virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, const CGBlockInfo &blockInfo); + virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM, + QualType T); }; class CGObjCMac : public CGObjCCommonMac { @@ -1968,13 +1974,14 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, /// getBlockCaptureLifetime - This routine returns life time of the captured /// block variable for the purpose of block layout meta-data generation. FQT is /// the type of the variable captured in the block. -Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT) { +Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT, + bool ByrefLayout) { if (CGM.getLangOpts().ObjCAutoRefCount) return FQT.getObjCLifetime(); // MRR. if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType()) - return Qualifiers::OCL_ExplicitNone; + return ByrefLayout ? Qualifiers::OCL_ExplicitNone : Qualifiers::OCL_Strong; return Qualifiers::OCL_None; } @@ -2005,7 +2012,8 @@ void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref, void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, const RecordDecl *RD, ArrayRef<const FieldDecl*> RecFields, - CharUnits BytePos, bool &HasUnion) { + CharUnits BytePos, bool &HasUnion, + bool ByrefLayout) { bool IsUnion = (RD && RD->isUnion()); CharUnits MaxUnionSize = CharUnits::Zero(); const FieldDecl *MaxField = 0; @@ -2088,7 +2096,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, } } else { UpdateRunSkipBlockVars(false, - getBlockCaptureLifetime(FQT), + getBlockCaptureLifetime(FQT, ByrefLayout), BytePos + FieldOffset, FieldSize); } @@ -2104,7 +2112,8 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, CharUnits Size = CharUnits::fromQuantity(UnsSize); Size += LastBitfieldOrUnnamedOffset; UpdateRunSkipBlockVars(false, - getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()), + getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(), + ByrefLayout), BytePos + LastBitfieldOrUnnamedOffset, Size); } else { @@ -2113,7 +2122,8 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType()); UpdateRunSkipBlockVars(false, - getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()), + getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(), + ByrefLayout), BytePos + LastBitfieldOrUnnamedOffset, FieldSize); } @@ -2121,14 +2131,15 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, if (MaxField) UpdateRunSkipBlockVars(false, - getBlockCaptureLifetime(MaxField->getType()), + getBlockCaptureLifetime(MaxField->getType(), ByrefLayout), BytePos + MaxFieldOffset, MaxUnionSize); } void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT, CharUnits BytePos, - bool &HasUnion) { + bool &HasUnion, + bool ByrefLayout) { const RecordDecl *RD = RT->getDecl(); SmallVector<const FieldDecl*, 16> Fields; for (RecordDecl::field_iterator i = RD->field_begin(), @@ -2138,7 +2149,7 @@ void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT, const llvm::StructLayout *RecLayout = CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty)); - BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion); + BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion, ByrefLayout); } /// InlineLayoutInstruction - This routine produce an inline instruction for the @@ -2247,64 +2258,19 @@ uint64_t CGObjCCommonMac::InlineLayoutInstruction( return Result; } -llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, - const CGBlockInfo &blockInfo) { - assert(CGM.getLangOpts().getGC() == LangOptions::NonGC); - +llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) { llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); - - RunSkipBlockVars.clear(); - bool hasUnion = false; - + if (RunSkipBlockVars.empty()) + return nullPtr; unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; - const BlockDecl *blockDecl = blockInfo.getBlockDecl(); - - // Calculate the basic layout of the block structure. - const llvm::StructLayout *layout = - CGM.getDataLayout().getStructLayout(blockInfo.StructureType); - - // Ignore the optional 'this' capture: C++ objects are not assumed - // to be GC'ed. - - // Walk the captured variables. - for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), - ce = blockDecl->capture_end(); ci != ce; ++ci) { - const VarDecl *variable = ci->getVariable(); - QualType type = variable->getType(); - - const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); - - // Ignore constant captures. - if (capture.isConstant()) continue; - - CharUnits fieldOffset = - CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex())); - - assert(!type->isArrayType() && "array variable should not be caught"); - if (const RecordType *record = type->getAs<RecordType>()) { - BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion); - continue; - } - CharUnits fieldSize; - if (ci->isByRef()) - fieldSize = CharUnits::fromQuantity(WordSizeInBytes); - else - fieldSize = CGM.getContext().getTypeSizeInChars(type); - UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type), - fieldOffset, fieldSize); - } - - if (RunSkipBlockVars.empty()) - return nullPtr; - // Sort on byte position; captures might not be allocated in order, // and unions can do funny things. llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end()); SmallVector<unsigned char, 16> Layout; - + unsigned size = RunSkipBlockVars.size(); for (unsigned i = 0; i < size; i++) { enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode; @@ -2320,11 +2286,11 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, break; } CharUnits size_in_bytes = - end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size; + end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size; if (j < size) { CharUnits gap = - RunSkipBlockVars[j].block_var_bytepos - - RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size; + RunSkipBlockVars[j].block_var_bytepos - + RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size; size_in_bytes += gap; } CharUnits residue_in_bytes = CharUnits::Zero(); @@ -2333,7 +2299,7 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, size_in_bytes -= residue_in_bytes; opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS; } - + unsigned size_in_words = size_in_bytes.getQuantity() / WordSizeInBytes; while (size_in_words >= 16) { // Note that value in imm. is one less that the actual @@ -2350,7 +2316,7 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, } if (residue_in_bytes > CharUnits::Zero()) { unsigned char inst = - (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1); + (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1); Layout.push_back(inst); } } @@ -2369,7 +2335,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, if (Result != 0) { // Block variable layout instruction has been inlined. if (CGM.getLangOpts().ObjCGCBitmapPrint) { - printf("\n Inline instruction for block variable layout: "); + if (ComputeByrefLayout) + printf("\n Inline instruction for BYREF variable layout: "); + else + printf("\n Inline instruction for block variable layout: "); printf("0x0%llx\n", (unsigned long long)Result); } if (WordSizeInBytes == 8) { @@ -2389,7 +2358,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, BitMap += Layout[i]; if (CGM.getLangOpts().ObjCGCBitmapPrint) { - printf("\n block variable layout: "); + if (ComputeByrefLayout) + printf("\n BYREF variable layout: "); + else + printf("\n block variable layout: "); for (unsigned i = 0, e = BitMap.size(); i != e; i++) { unsigned char inst = BitMap[i]; enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); @@ -2417,10 +2389,10 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, case BLOCK_LAYOUT_UNRETAINED: printf("BL_UNRETAINED:"); break; - } + } // Actual value of word count is one more that what is in the imm. // field of the instruction - printf("%d", (inst & 0xf) + delta); + printf("%d", (inst & 0xf) + delta); if (i < e-1) printf(", "); else @@ -2429,12 +2401,80 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, } llvm::GlobalVariable * Entry = - CreateMetadataVar("\01L_OBJC_CLASS_NAME_", + CreateMetadataVar("\01L_OBJC_CLASS_NAME_", llvm::ConstantDataArray::getString(VMContext, BitMap,false), "__TEXT,__objc_classname,cstring_literals", 1, true); return getConstantGEP(VMContext, Entry, 0, 0); } +llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + assert(CGM.getLangOpts().getGC() == LangOptions::NonGC); + + RunSkipBlockVars.clear(); + bool hasUnion = false; + + unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; + + const BlockDecl *blockDecl = blockInfo.getBlockDecl(); + + // Calculate the basic layout of the block structure. + const llvm::StructLayout *layout = + CGM.getDataLayout().getStructLayout(blockInfo.StructureType); + + // Ignore the optional 'this' capture: C++ objects are not assumed + // to be GC'ed. + + // Walk the captured variables. + for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), + ce = blockDecl->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); + QualType type = variable->getType(); + + const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); + + // Ignore constant captures. + if (capture.isConstant()) continue; + + CharUnits fieldOffset = + CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex())); + + assert(!type->isArrayType() && "array variable should not be caught"); + if (!ci->isByRef()) + if (const RecordType *record = type->getAs<RecordType>()) { + BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion); + continue; + } + CharUnits fieldSize; + if (ci->isByRef()) + fieldSize = CharUnits::fromQuantity(WordSizeInBytes); + else + fieldSize = CGM.getContext().getTypeSizeInChars(type); + UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type, false), + fieldOffset, fieldSize); + } + return getBitmapBlockLayout(false); +} + + +llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM, + QualType T) { + assert(CGM.getLangOpts().getGC() == LangOptions::NonGC); + assert(!T->isArrayType() && "__block array variable should not be caught"); + CharUnits fieldOffset; + RunSkipBlockVars.clear(); + bool hasUnion = false; + if (const RecordType *record = T->getAs<RecordType>()) { + BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */); + llvm::Constant *Result = getBitmapBlockLayout(true); + return Result; + } + llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); + return nullPtr; +} + llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD) { // FIXME: I don't understand why gcc generates this, or where it is diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 3e77875e6b..17e7a9d7eb 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -263,6 +263,8 @@ public: const CodeGen::CGBlockInfo &blockInfo) = 0; virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, const CodeGen::CGBlockInfo &blockInfo) = 0; + virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM, + QualType T) = 0; virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0; struct MessageSendInfo { |