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
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 80ce66a..7b61c25 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -4368,6 +4368,29 @@
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 @@
// 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 @@
Int32Ty,
getPointerType(VoidPtrTy),
getPointerType(VoidPtrTy),
+ getPointerType(VoidPtrTy),
Ty
};
@@ -4408,12 +4435,15 @@
"__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 6742f36..33f6eeb 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -1892,6 +1892,7 @@
/// 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 @@
/// 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 @@
// 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 @@
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 @@
// 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 @@
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 f85701a..d54ba27 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -69,11 +69,12 @@
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 @@
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 80fa09b..1d9f8ed 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -2256,6 +2256,12 @@
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 68d234d..df73abc 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -537,6 +537,12 @@
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 2203f01..611fb38 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -943,7 +943,7 @@
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 @@
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 @@
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 @@
/// 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::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 @@
}
} else {
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(FQT),
+ getBlockCaptureLifetime(FQT, ByrefLayout),
BytePos + FieldOffset,
FieldSize);
}
@@ -2104,7 +2112,8 @@
CharUnits Size = CharUnits::fromQuantity(UnsSize);
Size += LastBitfieldOrUnnamedOffset;
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
+ ByrefLayout),
BytePos + LastBitfieldOrUnnamedOffset,
Size);
} else {
@@ -2113,7 +2122,8 @@
CharUnits FieldSize
= CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
UpdateRunSkipBlockVars(false,
- getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType(),
+ ByrefLayout),
BytePos + LastBitfieldOrUnnamedOffset,
FieldSize);
}
@@ -2121,14 +2131,15 @@
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 @@
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,12 +2258,159 @@
return Result;
}
+llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
+ llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+ if (RunSkipBlockVars.empty())
+ return nullPtr;
+ unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
+
+ // 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;
+ CharUnits start_byte_pos = RunSkipBlockVars[i].block_var_bytepos;
+ CharUnits end_byte_pos = start_byte_pos;
+ unsigned j = i+1;
+ while (j < size) {
+ if (opcode == RunSkipBlockVars[j].opcode) {
+ end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos;
+ i++;
+ }
+ else
+ break;
+ }
+ CharUnits size_in_bytes =
+ 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;
+ size_in_bytes += gap;
+ }
+ CharUnits residue_in_bytes = CharUnits::Zero();
+ if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) {
+ residue_in_bytes = size_in_bytes % WordSizeInBytes;
+ 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
+ // value. So, 0xf means 16 words follow!
+ unsigned char inst = (opcode << 4) | 0xf;
+ Layout.push_back(inst);
+ size_in_words -= 16;
+ }
+ if (size_in_words > 0) {
+ // Note that value in imm. is one less that the actual
+ // value. So, we subtract 1 away!
+ unsigned char inst = (opcode << 4) | (size_in_words-1);
+ Layout.push_back(inst);
+ }
+ if (residue_in_bytes > CharUnits::Zero()) {
+ unsigned char inst =
+ (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
+ Layout.push_back(inst);
+ }
+ }
+
+ int e = Layout.size()-1;
+ while (e >= 0) {
+ unsigned char inst = Layout[e--];
+ enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS)
+ Layout.pop_back();
+ else
+ break;
+ }
+
+ uint64_t Result = InlineLayoutInstruction(Layout);
+ if (Result != 0) {
+ // Block variable layout instruction has been inlined.
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ 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) {
+ const llvm::APInt Instruction(64, Result);
+ return llvm::Constant::getIntegerValue(CGM.Int64Ty, Instruction);
+ }
+ else {
+ const llvm::APInt Instruction(32, Result);
+ return llvm::Constant::getIntegerValue(CGM.Int32Ty, Instruction);
+ }
+ }
+
+ unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
+ Layout.push_back(inst);
+ std::string BitMap;
+ for (unsigned i = 0, e = Layout.size(); i != e; i++)
+ BitMap += Layout[i];
+
+ if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ 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);
+ unsigned delta = 1;
+ switch (opcode) {
+ case BLOCK_LAYOUT_OPERATOR:
+ printf("BL_OPERATOR:");
+ delta = 0;
+ break;
+ case BLOCK_LAYOUT_NON_OBJECT_BYTES:
+ printf("BL_NON_OBJECT_BYTES:");
+ break;
+ case BLOCK_LAYOUT_NON_OBJECT_WORDS:
+ printf("BL_NON_OBJECT_WORD:");
+ break;
+ case BLOCK_LAYOUT_STRONG:
+ printf("BL_STRONG:");
+ break;
+ case BLOCK_LAYOUT_BYREF:
+ printf("BL_BYREF:");
+ break;
+ case BLOCK_LAYOUT_WEAK:
+ printf("BL_WEAK:");
+ break;
+ 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);
+ if (i < e-1)
+ printf(", ");
+ else
+ printf("\n");
+ }
+ }
+
+ llvm::GlobalVariable * Entry =
+ 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);
- llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
-
RunSkipBlockVars.clear();
bool hasUnion = false;
@@ -2284,155 +2442,37 @@
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;
- }
+ 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),
+ UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type, false),
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;
+ return getBitmapBlockLayout(false);
+}
- unsigned size = RunSkipBlockVars.size();
- for (unsigned i = 0; i < size; i++) {
- enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode;
- CharUnits start_byte_pos = RunSkipBlockVars[i].block_var_bytepos;
- CharUnits end_byte_pos = start_byte_pos;
- unsigned j = i+1;
- while (j < size) {
- if (opcode == RunSkipBlockVars[j].opcode) {
- end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos;
- i++;
- }
- else
- break;
- }
- CharUnits size_in_bytes =
- 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;
- size_in_bytes += gap;
- }
- CharUnits residue_in_bytes = CharUnits::Zero();
- if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) {
- residue_in_bytes = size_in_bytes % WordSizeInBytes;
- 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
- // value. So, 0xf means 16 words follow!
- unsigned char inst = (opcode << 4) | 0xf;
- Layout.push_back(inst);
- size_in_words -= 16;
- }
- if (size_in_words > 0) {
- // Note that value in imm. is one less that the actual
- // value. So, we subtract 1 away!
- unsigned char inst = (opcode << 4) | (size_in_words-1);
- Layout.push_back(inst);
- }
- if (residue_in_bytes > CharUnits::Zero()) {
- unsigned char inst =
- (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1);
- Layout.push_back(inst);
- }
+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;
}
-
- int e = Layout.size()-1;
- while (e >= 0) {
- unsigned char inst = Layout[e--];
- enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
- if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS)
- Layout.pop_back();
- else
- break;
- }
-
- uint64_t Result = InlineLayoutInstruction(Layout);
- if (Result != 0) {
- // Block variable layout instruction has been inlined.
- if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- printf("\n Inline instruction for block variable layout: ");
- printf("0x0%llx\n", (unsigned long long)Result);
- }
- if (WordSizeInBytes == 8) {
- const llvm::APInt Instruction(64, Result);
- return llvm::Constant::getIntegerValue(CGM.Int64Ty, Instruction);
- }
- else {
- const llvm::APInt Instruction(32, Result);
- return llvm::Constant::getIntegerValue(CGM.Int32Ty, Instruction);
- }
- }
-
- unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
- Layout.push_back(inst);
- std::string BitMap;
- for (unsigned i = 0, e = Layout.size(); i != e; i++)
- BitMap += Layout[i];
-
- if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- 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);
- unsigned delta = 1;
- switch (opcode) {
- case BLOCK_LAYOUT_OPERATOR:
- printf("BL_OPERATOR:");
- delta = 0;
- break;
- case BLOCK_LAYOUT_NON_OBJECT_BYTES:
- printf("BL_NON_OBJECT_BYTES:");
- break;
- case BLOCK_LAYOUT_NON_OBJECT_WORDS:
- printf("BL_NON_OBJECT_WORD:");
- break;
- case BLOCK_LAYOUT_STRONG:
- printf("BL_STRONG:");
- break;
- case BLOCK_LAYOUT_BYREF:
- printf("BL_BYREF:");
- break;
- case BLOCK_LAYOUT_WEAK:
- printf("BL_WEAK:");
- break;
- 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);
- if (i < e-1)
- printf(", ");
- else
- printf("\n");
- }
- }
-
- llvm::GlobalVariable * Entry =
- 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 *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
+ return nullPtr;
}
llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 3e77875..17e7a9d 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -263,6 +263,8 @@
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 {