summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp798
1 files changed, 691 insertions, 107 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
index ef802a3..2203f01 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
@@ -36,7 +36,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Target/TargetData.h"
+#include "llvm/DataLayout.h"
#include <cstdio>
using namespace clang;
@@ -66,7 +66,8 @@ private:
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy,
params, true),
"objc_msgSend",
- llvm::Attribute::NonLazyBind);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NonLazyBind));
}
/// void objc_msgSend_stret (id, SEL, ...)
@@ -433,19 +434,19 @@ public:
/// SyncEnterFn - LLVM object_sync_enter function.
llvm::Constant *getSyncEnterFn() {
- // void objc_sync_enter (id)
+ // int objc_sync_enter (id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, args, false);
+ llvm::FunctionType::get(CGM.IntTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter");
}
/// SyncExitFn - LLVM object_sync_exit function.
llvm::Constant *getSyncExitFn() {
- // void objc_sync_exit (id)
+ // int objc_sync_exit (id)
llvm::Type *args[] = { ObjectPtrTy };
llvm::FunctionType *FTy =
- llvm::FunctionType::get(CGM.VoidTy, args, false);
+ llvm::FunctionType::get(CGM.IntTy, args, false);
return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
}
@@ -583,7 +584,8 @@ public:
return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty,
params, false),
"_setjmp",
- llvm::Attribute::ReturnsTwice);
+ llvm::Attributes::get(CGM.getLLVMContext(),
+ llvm::Attributes::NonLazyBind));
}
public:
@@ -753,6 +755,74 @@ public:
: skip(_skip), scan(_scan) {}
};
+ /// opcode for captured block variables layout 'instructions'.
+ /// In the following descriptions, 'I' is the value of the immediate field.
+ /// (field following the opcode).
+ ///
+ enum BLOCK_LAYOUT_OPCODE {
+ /// An operator which affects how the following layout should be
+ /// interpreted.
+ /// I == 0: Halt interpretation and treat everything else as
+ /// a non-pointer. Note that this instruction is equal
+ /// to '\0'.
+ /// I != 0: Currently unused.
+ BLOCK_LAYOUT_OPERATOR = 0,
+
+ /// The next I+1 bytes do not contain a value of object pointer type.
+ /// Note that this can leave the stream unaligned, meaning that
+ /// subsequent word-size instructions do not begin at a multiple of
+ /// the pointer size.
+ BLOCK_LAYOUT_NON_OBJECT_BYTES = 1,
+
+ /// The next I+1 words do not contain a value of object pointer type.
+ /// This is simply an optimized version of BLOCK_LAYOUT_BYTES for
+ /// when the required skip quantity is a multiple of the pointer size.
+ BLOCK_LAYOUT_NON_OBJECT_WORDS = 2,
+
+ /// The next I+1 words are __strong pointers to Objective-C
+ /// objects or blocks.
+ BLOCK_LAYOUT_STRONG = 3,
+
+ /// The next I+1 words are pointers to __block variables.
+ BLOCK_LAYOUT_BYREF = 4,
+
+ /// The next I+1 words are __weak pointers to Objective-C
+ /// objects or blocks.
+ BLOCK_LAYOUT_WEAK = 5,
+
+ /// The next I+1 words are __unsafe_unretained pointers to
+ /// Objective-C objects or blocks.
+ BLOCK_LAYOUT_UNRETAINED = 6
+
+ /// The next I+1 words are block or object pointers with some
+ /// as-yet-unspecified ownership semantics. If we add more
+ /// flavors of ownership semantics, values will be taken from
+ /// this range.
+ ///
+ /// This is included so that older tools can at least continue
+ /// processing the layout past such things.
+ //BLOCK_LAYOUT_OWNERSHIP_UNKNOWN = 7..10,
+
+ /// All other opcodes are reserved. Halt interpretation and
+ /// treat everything else as opaque.
+ };
+
+ class RUN_SKIP {
+ public:
+ enum BLOCK_LAYOUT_OPCODE opcode;
+ CharUnits block_var_bytepos;
+ CharUnits block_var_size;
+ RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode = BLOCK_LAYOUT_OPERATOR,
+ CharUnits BytePos = CharUnits::Zero(),
+ CharUnits Size = CharUnits::Zero())
+ : opcode(Opcode), block_var_bytepos(BytePos), block_var_size(Size) {}
+
+ // Allow sorting based on byte pos.
+ bool operator<(const RUN_SKIP &b) const {
+ return block_var_bytepos < b.block_var_bytepos;
+ }
+ };
+
protected:
llvm::LLVMContext &VMContext;
// FIXME! May not be needing this after all.
@@ -761,6 +831,9 @@ protected:
// gc ivar layout bitmap calculation helper caches.
SmallVector<GC_IVAR, 16> SkipIvars;
SmallVector<GC_IVAR, 16> IvarsInfo;
+
+ // arc/mrr layout of captured block literal variables.
+ SmallVector<RUN_SKIP, 16> RunSkipBlockVars;
/// LazySymbols - Symbols to generate a lazy reference for. See
/// DefinedSymbols and FinishModule().
@@ -869,6 +942,24 @@ protected:
ArrayRef<const FieldDecl*> RecFields,
unsigned int BytePos, bool ForStrongLayout,
bool &HasUnion);
+
+ Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT);
+
+ void UpdateRunSkipBlockVars(bool IsByref,
+ Qualifiers::ObjCLifetime LifeTime,
+ CharUnits FieldOffset,
+ CharUnits FieldSize);
+
+ void BuildRCBlockVarRecordLayout(const RecordType *RT,
+ CharUnits BytePos, bool &HasUnion);
+
+ void BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
+ const RecordDecl *RD,
+ ArrayRef<const FieldDecl*> RecFields,
+ CharUnits BytePos, bool &HasUnion);
+
+ uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout);
+
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
@@ -959,6 +1050,8 @@ public:
virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0;
virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM,
const CGBlockInfo &blockInfo);
+ virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM,
+ const CGBlockInfo &blockInfo);
};
@@ -1787,8 +1880,8 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
const CGBlockInfo &blockInfo) {
+
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
-
if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
!CGM.getLangOpts().ObjCAutoRefCount)
return nullPtr;
@@ -1807,7 +1900,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
// Calculate the basic layout of the block structure.
const llvm::StructLayout *layout =
- CGM.getTargetData().getStructLayout(blockInfo.StructureType);
+ CGM.getDataLayout().getStructLayout(blockInfo.StructureType);
// Ignore the optional 'this' capture: C++ objects are not assumed
// to be GC'ed.
@@ -1860,7 +1953,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
printf("\n block variable layout for block: ");
- const unsigned char *s = (unsigned char*)BitMap.c_str();
+ const unsigned char *s = (const unsigned char*)BitMap.c_str();
for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
@@ -1872,6 +1965,476 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
return C;
}
+/// 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) {
+ if (CGM.getLangOpts().ObjCAutoRefCount)
+ return FQT.getObjCLifetime();
+
+ // MRR.
+ if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
+ return Qualifiers::OCL_ExplicitNone;
+
+ return Qualifiers::OCL_None;
+}
+
+void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref,
+ Qualifiers::ObjCLifetime LifeTime,
+ CharUnits FieldOffset,
+ CharUnits FieldSize) {
+ // __block variables are passed by their descriptor address.
+ if (IsByref)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_Strong)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_Weak)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, FieldOffset,
+ FieldSize));
+ else if (LifeTime == Qualifiers::OCL_ExplicitNone)
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, FieldOffset,
+ FieldSize));
+ else
+ RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES,
+ FieldOffset,
+ FieldSize));
+}
+
+void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
+ const RecordDecl *RD,
+ ArrayRef<const FieldDecl*> RecFields,
+ CharUnits BytePos, bool &HasUnion) {
+ bool IsUnion = (RD && RD->isUnion());
+ CharUnits MaxUnionSize = CharUnits::Zero();
+ const FieldDecl *MaxField = 0;
+ const FieldDecl *LastFieldBitfieldOrUnnamed = 0;
+ CharUnits MaxFieldOffset = CharUnits::Zero();
+ CharUnits LastBitfieldOrUnnamedOffset = CharUnits::Zero();
+
+ if (RecFields.empty())
+ return;
+ unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+
+ for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
+ const FieldDecl *Field = RecFields[i];
+ // Note that 'i' here is actually the field index inside RD of Field,
+ // although this dependency is hidden.
+ const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
+ CharUnits FieldOffset =
+ CGM.getContext().toCharUnitsFromBits(RL.getFieldOffset(i));
+
+ // Skip over unnamed or bitfields
+ if (!Field->getIdentifier() || Field->isBitField()) {
+ LastFieldBitfieldOrUnnamed = Field;
+ LastBitfieldOrUnnamedOffset = FieldOffset;
+ continue;
+ }
+
+ LastFieldBitfieldOrUnnamed = 0;
+ QualType FQT = Field->getType();
+ if (FQT->isRecordType() || FQT->isUnionType()) {
+ if (FQT->isUnionType())
+ HasUnion = true;
+
+ BuildRCBlockVarRecordLayout(FQT->getAs<RecordType>(),
+ BytePos + FieldOffset, HasUnion);
+ continue;
+ }
+
+ if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
+ const ConstantArrayType *CArray =
+ dyn_cast_or_null<ConstantArrayType>(Array);
+ uint64_t ElCount = CArray->getSize().getZExtValue();
+ assert(CArray && "only array with known element size is supported");
+ FQT = CArray->getElementType();
+ while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) {
+ const ConstantArrayType *CArray =
+ dyn_cast_or_null<ConstantArrayType>(Array);
+ ElCount *= CArray->getSize().getZExtValue();
+ FQT = CArray->getElementType();
+ }
+
+ assert(!FQT->isUnionType() &&
+ "layout for array of unions not supported");
+ if (FQT->isRecordType() && ElCount) {
+ int OldIndex = RunSkipBlockVars.size() - 1;
+ const RecordType *RT = FQT->getAs<RecordType>();
+ BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset,
+ HasUnion);
+
+ // Replicate layout information for each array element. Note that
+ // one element is already done.
+ uint64_t ElIx = 1;
+ for (int FirstIndex = RunSkipBlockVars.size() - 1 ;ElIx < ElCount; ElIx++) {
+ CharUnits Size = CGM.getContext().getTypeSizeInChars(RT);
+ for (int i = OldIndex+1; i <= FirstIndex; ++i)
+ RunSkipBlockVars.push_back(
+ RUN_SKIP(RunSkipBlockVars[i].opcode,
+ RunSkipBlockVars[i].block_var_bytepos + Size*ElIx,
+ RunSkipBlockVars[i].block_var_size));
+ }
+ continue;
+ }
+ }
+ CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(Field->getType());
+ if (IsUnion) {
+ CharUnits UnionIvarSize = FieldSize;
+ if (UnionIvarSize > MaxUnionSize) {
+ MaxUnionSize = UnionIvarSize;
+ MaxField = Field;
+ MaxFieldOffset = FieldOffset;
+ }
+ } else {
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(FQT),
+ BytePos + FieldOffset,
+ FieldSize);
+ }
+ }
+
+ if (LastFieldBitfieldOrUnnamed) {
+ if (LastFieldBitfieldOrUnnamed->isBitField()) {
+ // Last field was a bitfield. Must update the info.
+ uint64_t BitFieldSize
+ = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
+ unsigned UnsSize = (BitFieldSize / ByteSizeInBits) +
+ ((BitFieldSize % ByteSizeInBits) != 0);
+ CharUnits Size = CharUnits::fromQuantity(UnsSize);
+ Size += LastBitfieldOrUnnamedOffset;
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ BytePos + LastBitfieldOrUnnamedOffset,
+ Size);
+ } else {
+ assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed");
+ // Last field was unnamed. Must update skip info.
+ CharUnits FieldSize
+ = CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType());
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()),
+ BytePos + LastBitfieldOrUnnamedOffset,
+ FieldSize);
+ }
+ }
+
+ if (MaxField)
+ UpdateRunSkipBlockVars(false,
+ getBlockCaptureLifetime(MaxField->getType()),
+ BytePos + MaxFieldOffset,
+ MaxUnionSize);
+}
+
+void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT,
+ CharUnits BytePos,
+ bool &HasUnion) {
+ const RecordDecl *RD = RT->getDecl();
+ SmallVector<const FieldDecl*, 16> Fields;
+ for (RecordDecl::field_iterator i = RD->field_begin(),
+ e = RD->field_end(); i != e; ++i)
+ Fields.push_back(*i);
+ llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
+ const llvm::StructLayout *RecLayout =
+ CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
+
+ BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion);
+}
+
+/// InlineLayoutInstruction - This routine produce an inline instruction for the
+/// block variable layout if it can. If not, it returns 0. Rules are as follow:
+/// If ((uintptr_t) layout) < (1 << 12), the layout is inline. In the 64bit world,
+/// an inline layout of value 0x0000000000000xyz is interpreted as follows:
+/// x captured object pointers of BLOCK_LAYOUT_STRONG. Followed by
+/// y captured object of BLOCK_LAYOUT_BYREF. Followed by
+/// z captured object of BLOCK_LAYOUT_WEAK. If any of the above is missing, zero
+/// replaces it. For example, 0x00000x00 means x BLOCK_LAYOUT_STRONG and no
+/// BLOCK_LAYOUT_BYREF and no BLOCK_LAYOUT_WEAK objects are captured.
+uint64_t CGObjCCommonMac::InlineLayoutInstruction(
+ SmallVectorImpl<unsigned char> &Layout) {
+ uint64_t Result = 0;
+ if (Layout.size() <= 3) {
+ unsigned size = Layout.size();
+ unsigned strong_word_count = 0, byref_word_count=0, weak_word_count=0;
+ unsigned char inst;
+ enum BLOCK_LAYOUT_OPCODE opcode ;
+ switch (size) {
+ case 3:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG)
+ strong_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ inst = Layout[2];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ break;
+
+ case 2:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG) {
+ strong_word_count = (inst & 0xF)+1;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ }
+ else if (opcode == BLOCK_LAYOUT_BYREF) {
+ byref_word_count = (inst & 0xF)+1;
+ inst = Layout[1];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ break;
+
+ case 1:
+ inst = Layout[0];
+ opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4);
+ if (opcode == BLOCK_LAYOUT_STRONG)
+ strong_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_BYREF)
+ byref_word_count = (inst & 0xF)+1;
+ else if (opcode == BLOCK_LAYOUT_WEAK)
+ weak_word_count = (inst & 0xF)+1;
+ else
+ return 0;
+ break;
+
+ default:
+ return 0;
+ }
+
+ // Cannot inline when any of the word counts is 15. Because this is one less
+ // than the actual work count (so 15 means 16 actual word counts),
+ // and we can only display 0 thru 15 word counts.
+ if (strong_word_count == 16 || byref_word_count == 16 || weak_word_count == 16)
+ return 0;
+
+ unsigned count =
+ (strong_word_count != 0) + (byref_word_count != 0) + (weak_word_count != 0);
+
+ if (size == count) {
+ if (strong_word_count)
+ Result = strong_word_count;
+ Result <<= 4;
+ if (byref_word_count)
+ Result += byref_word_count;
+ Result <<= 4;
+ if (weak_word_count)
+ Result += weak_word_count;
+ }
+ }
+ return Result;
+}
+
+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;
+
+ 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;
+ 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) {
+ 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::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder,
const ObjCProtocolDecl *PD) {
// FIXME: I don't understand why gcc generates this, or where it is
@@ -2040,7 +2603,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
ArrayRef<llvm::Constant*> OptClassMethods,
ArrayRef<llvm::Constant*> MethodTypesExt) {
uint64_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy);
llvm::Constant *Values[] = {
llvm::ConstantInt::get(ObjCTypes.IntTy, Size),
EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"
@@ -2180,7 +2743,7 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
unsigned PropertySize =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.PropertyTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.PropertyTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size());
@@ -2269,7 +2832,7 @@ CGObjCMac::EmitMethodDescList(Twine Name, const char *Section,
};
*/
void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.CategoryTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategoryTy);
// FIXME: This is poor design, the OCD should have a pointer to the category
// decl. Additionally, note that Category can be null for the @implementation
@@ -2338,15 +2901,37 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
MethodDefinitions.clear();
}
-// FIXME: Get from somewhere?
-enum ClassFlags {
- eClassFlags_Factory = 0x00001,
- eClassFlags_Meta = 0x00002,
- // <rdr://5142207>
- eClassFlags_HasCXXStructors = 0x02000,
- eClassFlags_Hidden = 0x20000,
- eClassFlags_ABI2_Hidden = 0x00010,
- eClassFlags_ABI2_HasCXXStructors = 0x00004 // <rdr://4923634>
+enum FragileClassFlags {
+ FragileABI_Class_Factory = 0x00001,
+ FragileABI_Class_Meta = 0x00002,
+ FragileABI_Class_HasCXXStructors = 0x02000,
+ FragileABI_Class_Hidden = 0x20000
+};
+
+enum NonFragileClassFlags {
+ /// Is a meta-class.
+ NonFragileABI_Class_Meta = 0x00001,
+
+ /// Is a root class.
+ NonFragileABI_Class_Root = 0x00002,
+
+ /// Has a C++ constructor and destructor.
+ NonFragileABI_Class_HasCXXStructors = 0x00004,
+
+ /// Has hidden visibility.
+ NonFragileABI_Class_Hidden = 0x00010,
+
+ /// Has the exception attribute.
+ NonFragileABI_Class_Exception = 0x00020,
+
+ /// (Obsolete) ARC-specific: this class has a .release_ivars method
+ NonFragileABI_Class_HasIvarReleaser = 0x00040,
+
+ /// Class implementation was compiled under ARC.
+ NonFragileABI_Class_CompiledByARC = 0x00080,
+
+ /// Class has non-trivial destructors, but zero-initialization is okay.
+ NonFragileABI_Class_HasCXXDestructorOnly = 0x00100
};
/*
@@ -2379,15 +2964,15 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(),
Interface->all_referenced_protocol_begin(),
Interface->all_referenced_protocol_end());
- unsigned Flags = eClassFlags_Factory;
- if (ID->hasCXXStructors())
- Flags |= eClassFlags_HasCXXStructors;
+ unsigned Flags = FragileABI_Class_Factory;
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors())
+ Flags |= FragileABI_Class_HasCXXStructors;
unsigned Size =
CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
// FIXME: Set CXX-structors flag.
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
- Flags |= eClassFlags_Hidden;
+ Flags |= FragileABI_Class_Hidden;
llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods;
for (ObjCImplementationDecl::instmeth_iterator
@@ -2470,11 +3055,11 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID,
llvm::Constant *Protocols,
ArrayRef<llvm::Constant*> Methods) {
- unsigned Flags = eClassFlags_Meta;
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy);
+ unsigned Flags = FragileABI_Class_Meta;
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassTy);
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
- Flags |= eClassFlags_Hidden;
+ Flags |= FragileABI_Class_Hidden;
llvm::Constant *Values[12];
// The isa for the metaclass is the root of the hierarchy.
@@ -2588,7 +3173,7 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
llvm::Constant *
CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
uint64_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
@@ -3481,7 +4066,7 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3502,7 +4087,7 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3528,7 +4113,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3548,7 +4133,7 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy);
@@ -3679,7 +4264,7 @@ void CGObjCCommonMac::EmitImageInfo() {
static const int ModuleVersion = 7;
void CGObjCMac::EmitModuleInfo() {
- uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ModuleTy);
+ uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ModuleTy);
llvm::Constant *Values[] = {
llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion),
@@ -3824,7 +4409,7 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
Fields.push_back(*i);
llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
const llvm::StructLayout *RecLayout =
- CGM.getTargetData().getStructLayout(cast<llvm::StructType>(Ty));
+ CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
BuildAggrIvarLayout(0, RecLayout, RD, Fields, BytePos,
ForStrongLayout, HasUnion);
@@ -3951,7 +4536,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
if (IsUnion) {
// FIXME: Why the asymmetry? We divide by word size in bits on other
// side.
- uint64_t UnionIvarSize = FieldSize;
+ uint64_t UnionIvarSize = FieldSize / ByteSizeInBits;
if (UnionIvarSize > MaxSkippedUnionIvarSize) {
MaxSkippedUnionIvarSize = UnionIvarSize;
MaxSkippedField = Field;
@@ -4005,7 +4590,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) {
// Build the string of skip/scan nibbles
SmallVector<SKIP_SCAN, 32> SkipScanIvars;
unsigned int WordSize =
- CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy);
+ CGM.getTypes().getDataLayout().getTypeAllocSize(PtrTy);
if (IvarsInfo[0].ivar_bytepos == 0) {
WordsToSkip = 0;
WordsToScan = IvarsInfo[0].ivar_size;
@@ -4187,7 +4772,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
printf("\n%s ivar layout for class '%s': ",
ForStrongLayout ? "strong" : "weak",
OMD->getClassInterface()->getName().data());
- const unsigned char *s = (unsigned char*)BitMap.c_str();
+ const unsigned char *s = (const unsigned char*)BitMap.c_str();
for (unsigned i = 0, e = BitMap.size(); i < e; i++)
if (!(s[i] & 0xf0))
printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
@@ -4835,7 +5420,7 @@ AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container,
llvm::GlobalValue::InternalLinkage,
Init,
SymbolName);
- GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(SectionName);
CGM.AddUsedGlobal(GV);
}
@@ -4941,19 +5526,6 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) {
return VTableDispatchMethods.count(Sel);
}
-// Metadata flags
-enum MetaDataDlags {
- CLS = 0x0,
- CLS_META = 0x1,
- CLS_ROOT = 0x2,
- OBJC2_CLS_HIDDEN = 0x10,
- CLS_EXCEPTION = 0x20,
-
- /// (Obsolete) ARC-specific: this class has a .release_ivars method
- CLS_HAS_IVAR_RELEASER = 0x40,
- /// class was compiled with -fobjc-arr
- CLS_COMPILED_BY_ARC = 0x80 // (1<<7)
-};
/// BuildClassRoTInitializer - generate meta-data for:
/// struct _class_ro_t {
/// uint32_t const flags;
@@ -4978,19 +5550,20 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
llvm::Constant *Values[10]; // 11 for 64bit targets!
if (CGM.getLangOpts().ObjCAutoRefCount)
- flags |= CLS_COMPILED_BY_ARC;
+ flags |= NonFragileABI_Class_CompiledByARC;
Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize);
// FIXME. For 64bit targets add 0 here.
- Values[ 3] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
+ Values[ 3] = (flags & NonFragileABI_Class_Meta)
+ ? GetIvarLayoutName(0, ObjCTypes)
: BuildIvarLayout(ID, true);
Values[ 4] = GetClassName(ID->getIdentifier());
// const struct _method_list_t * const baseMethods;
std::vector<llvm::Constant*> Methods;
std::string MethodListName("\01l_OBJC_$_");
- if (flags & CLS_META) {
+ if (flags & NonFragileABI_Class_Meta) {
MethodListName += "CLASS_METHODS_" + ID->getNameAsString();
for (ObjCImplementationDecl::classmeth_iterator
i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) {
@@ -5030,28 +5603,27 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
OID->all_referenced_protocol_begin(),
OID->all_referenced_protocol_end());
- if (flags & CLS_META)
+ if (flags & NonFragileABI_Class_Meta) {
Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
- else
- Values[ 7] = EmitIvarList(ID);
- Values[ 8] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes)
- : BuildIvarLayout(ID, false);
- if (flags & CLS_META)
+ Values[ 8] = GetIvarLayoutName(0, ObjCTypes);
Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
- else
+ } else {
+ Values[ 7] = EmitIvarList(ID);
+ Values[ 8] = BuildIvarLayout(ID, false);
Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
ID, ID->getClassInterface(), ObjCTypes);
+ }
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy,
Values);
llvm::GlobalVariable *CLASS_RO_GV =
new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false,
llvm::GlobalValue::InternalLinkage,
Init,
- (flags & CLS_META) ?
+ (flags & NonFragileABI_Class_Meta) ?
std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName :
std::string("\01l_OBJC_CLASS_RO_$_")+ClassName);
CLASS_RO_GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassRonfABITy));
CLASS_RO_GV->setSection("__DATA, __objc_const");
return CLASS_RO_GV;
@@ -5088,7 +5660,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData(
GV->setInitializer(Init);
GV->setSection("__DATA, __objc_data");
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy));
if (HiddenVisibility)
GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
return GV;
@@ -5138,23 +5710,31 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
"CGObjCNonFragileABIMac::GenerateClass - class is 0");
// FIXME: Is this correct (that meta class size is never computed)?
uint32_t InstanceStart =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassnfABITy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassnfABITy);
uint32_t InstanceSize = InstanceStart;
- uint32_t flags = CLS_META;
+ uint32_t flags = NonFragileABI_Class_Meta;
std::string ObjCMetaClassName(getMetaclassSymbolPrefix());
std::string ObjCClassName(getClassSymbolPrefix());
llvm::GlobalVariable *SuperClassGV, *IsAGV;
+ // Build the flags for the metaclass.
bool classIsHidden =
ID->getClassInterface()->getVisibility() == HiddenVisibility;
if (classIsHidden)
- flags |= OBJC2_CLS_HIDDEN;
- if (ID->hasCXXStructors())
- flags |= eClassFlags_ABI2_HasCXXStructors;
+ flags |= NonFragileABI_Class_Hidden;
+
+ // FIXME: why is this flag set on the metaclass?
+ // ObjC metaclasses have no fields and don't really get constructed.
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
+ flags |= NonFragileABI_Class_HasCXXStructors;
+ if (!ID->hasNonZeroConstructors())
+ flags |= NonFragileABI_Class_HasCXXDestructorOnly;
+ }
+
if (!ID->getClassInterface()->getSuperClass()) {
// class is root
- flags |= CLS_ROOT;
+ flags |= NonFragileABI_Class_Root;
SuperClassGV = GetClassGlobal(ObjCClassName + ClassName);
IsAGV = GetClassGlobal(ObjCMetaClassName + ClassName);
} else {
@@ -5183,17 +5763,28 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
DefinedMetaClasses.push_back(MetaTClass);
// Metadata for the class
- flags = CLS;
+ flags = 0;
if (classIsHidden)
- flags |= OBJC2_CLS_HIDDEN;
- if (ID->hasCXXStructors())
- flags |= eClassFlags_ABI2_HasCXXStructors;
+ flags |= NonFragileABI_Class_Hidden;
+
+ if (ID->hasNonZeroConstructors() || ID->hasDestructors()) {
+ flags |= NonFragileABI_Class_HasCXXStructors;
+
+ // Set a flag to enable a runtime optimization when a class has
+ // fields that require destruction but which don't require
+ // anything except zero-initialization during construction. This
+ // is most notably true of __strong and __weak types, but you can
+ // also imagine there being C++ types with non-trivial default
+ // constructors that merely set all fields to null.
+ if (!ID->hasNonZeroConstructors())
+ flags |= NonFragileABI_Class_HasCXXDestructorOnly;
+ }
if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface()))
- flags |= CLS_EXCEPTION;
+ flags |= NonFragileABI_Class_Exception;
if (!ID->getClassInterface()->getSuperClass()) {
- flags |= CLS_ROOT;
+ flags |= NonFragileABI_Class_Root;
SuperClassGV = 0;
} else {
// Has a root. Current class is not a root.
@@ -5220,7 +5811,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
DefinedNonLazyClasses.push_back(ClassMD);
// Force the definition of the EHType if necessary.
- if (flags & CLS_EXCEPTION)
+ if (flags & NonFragileABI_Class_Exception)
GetInterfaceEHType(ID->getClassInterface(), true);
// Make sure method definition entries are all clear for next implementation.
MethodDefinitions.clear();
@@ -5344,7 +5935,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Init,
ExtCatName);
GCATV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.CategorynfABITy));
GCATV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GCATV);
DefinedCategories.push_back(GCATV);
@@ -5391,7 +5982,7 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::Constant *Values[3];
// sizeof(struct _objc_method)
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.MethodTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.MethodTy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
// method_count
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size());
@@ -5403,7 +5994,7 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name,
llvm::GlobalVariable *GV =
new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false,
llvm::GlobalValue::InternalLinkage, Init, Name);
- GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection(Section);
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy);
@@ -5437,7 +6028,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID,
IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy,
Offset));
IvarOffsetGV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.LongTy));
// FIXME: This matches gcc, but shouldn't the visibility be set on the use as
// well (i.e., in ObjCIvarOffsetVariable).
@@ -5490,7 +6081,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
Ivar[2] = GetMethodVarType(IVD);
llvm::Type *FieldTy =
CGM.getTypes().ConvertTypeForMem(IVD->getType());
- unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(FieldTy);
unsigned Align = CGM.getContext().getPreferredTypeAlign(
IVD->getType().getTypePtr()) >> 3;
Align = llvm::Log2_32(Align);
@@ -5508,7 +6099,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy);
llvm::Constant *Values[3];
- unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.IvarnfABITy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy);
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size());
llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy,
@@ -5522,7 +6113,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList(
Init,
Prefix + OID->getName());
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ CGM.getDataLayout().getABITypeAlignment(Init->getType()));
GV->setSection("__DATA, __objc_const");
CGM.AddUsedGlobal(GV);
@@ -5644,7 +6235,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getName(),
0, PD, ObjCTypes);
uint32_t Size =
- CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
+ CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy);
Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy);
Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_"
@@ -5663,7 +6254,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Init,
"\01l_OBJC_PROTOCOL_$_" + PD->getName());
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABITy));
Entry->setSection("__DATA,__datacoal_nt,coalesced");
Protocols[PD->getIdentifier()] = Entry;
@@ -5678,7 +6269,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol(
false, llvm::GlobalValue::WeakAnyLinkage, Entry,
"\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName());
PTGV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
+ CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy));
PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
@@ -5732,7 +6323,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name,
Init, Name);
GV->setSection("__DATA, __objc_const");
GV->setAlignment(
- CGM.getTargetData().getABITypeAlignment(Init->getType()));
+ CGM.getDataLayout().getABITypeAlignment(Init->getType()));
CGM.AddUsedGlobal(GV);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.ProtocolListnfABIPtrTy);
@@ -5970,7 +6561,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_REFERENCES_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -6004,7 +6595,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
ClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
@@ -6030,7 +6621,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
MetaClassGV,
"\01L_OBJC_CLASSLIST_SUP_REFS_$_");
Entry->setAlignment(
- CGM.getTargetData().getABITypeAlignment(
+ CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.ClassnfABIPtrTy));
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
@@ -6079,16 +6670,9 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
- if (IsClassMessage) {
- if (isCategoryImpl) {
- // Message sent to "super' in a class method defined in
- // a category implementation.
- Target = EmitClassRef(CGF.Builder, Class);
- Target = CGF.Builder.CreateStructGEP(Target, 0);
- Target = CGF.Builder.CreateLoad(Target);
- } else
+ if (IsClassMessage)
Target = EmitMetaClassRef(CGF.Builder, Class);
- } else
+ else
Target = EmitSuperClassRef(CGF.Builder, Class);
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
@@ -6143,7 +6727,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *ivarOffset) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6164,7 +6748,7 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6211,7 +6795,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src, llvm::Value *dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6232,7 +6816,7 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
- unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy);
+ unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
assert(Size <= 8 && "does not support size > 8");
src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy)
: CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy));
@@ -6364,7 +6948,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID,
if (CGM.getLangOpts().getVisibilityMode() == HiddenVisibility)
Entry->setVisibility(llvm::GlobalValue::HiddenVisibility);
- Entry->setAlignment(CGM.getTargetData().getABITypeAlignment(
+ Entry->setAlignment(CGM.getDataLayout().getABITypeAlignment(
ObjCTypes.EHTypeTy));
if (ForDefinition) {
OpenPOWER on IntegriCloud