diff options
Diffstat (limited to 'lib/CodeGen/CGObjCMac.cpp')
-rw-r--r-- | lib/CodeGen/CGObjCMac.cpp | 182 |
1 files changed, 111 insertions, 71 deletions
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 |