|
@@ -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
|