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.cpp1419
1 files changed, 807 insertions, 612 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
index a45446a..5f3ebbd 100644
--- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp
@@ -659,9 +659,6 @@ public:
// MessageRefCPtrTy - clang type for struct _message_ref_t*
QualType MessageRefCPtrTy;
- // MessengerTy - Type of the messenger (shown as IMP above)
- llvm::FunctionType *MessengerTy;
-
// SuperMessageRefTy - LLVM for:
// struct _super_message_ref_t {
// SUPER_IMP messenger;
@@ -735,20 +732,6 @@ public:
class CGObjCCommonMac : public CodeGen::CGObjCRuntime {
public:
- // FIXME - accessibility
- class GC_IVAR {
- public:
- unsigned ivar_bytepos;
- unsigned ivar_size;
- GC_IVAR(unsigned bytepos = 0, unsigned size = 0)
- : ivar_bytepos(bytepos), ivar_size(size) {}
-
- // Allow sorting based on byte pos.
- bool operator<(const GC_IVAR &b) const {
- return ivar_bytepos < b.ivar_bytepos;
- }
- };
-
class SKIP_SCAN {
public:
unsigned skip;
@@ -830,10 +813,6 @@ protected:
// FIXME! May not be needing this after all.
unsigned ObjCABI;
- // 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;
@@ -854,7 +833,7 @@ protected:
llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames;
/// DefinedCategoryNames - list of category names in form Class_Category.
- llvm::SetVector<std::string> DefinedCategoryNames;
+ llvm::SmallSetVector<std::string, 16> DefinedCategoryNames;
/// MethodVarTypes - uniqued method type signatures. We have to use
/// a StringMap here because have no other unique reference.
@@ -934,20 +913,28 @@ protected:
/// BuildIvarLayout - Builds ivar layout bitmap for the class
/// implementation for the __strong or __weak case.
///
+ /// \param hasMRCWeakIvars - Whether we are compiling in MRC and there
+ /// are any weak ivars defined directly in the class. Meaningless unless
+ /// building a weak layout. Does not guarantee that the layout will
+ /// actually have any entries, because the ivar might be under-aligned.
llvm::Constant *BuildIvarLayout(const ObjCImplementationDecl *OI,
- bool ForStrongLayout);
-
- llvm::Constant *BuildIvarLayoutBitmap(std::string &BitMap);
+ CharUnits beginOffset,
+ CharUnits endOffset,
+ bool forStrongLayout,
+ bool hasMRCWeakIvars);
- void BuildAggrIvarRecordLayout(const RecordType *RT,
- unsigned int BytePos, bool ForStrongLayout,
- bool &HasUnion);
- void BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
- const llvm::StructLayout *Layout,
- const RecordDecl *RD,
- ArrayRef<const FieldDecl*> RecFields,
- unsigned int BytePos, bool ForStrongLayout,
- bool &HasUnion);
+ llvm::Constant *BuildStrongIvarLayout(const ObjCImplementationDecl *OI,
+ CharUnits beginOffset,
+ CharUnits endOffset) {
+ return BuildIvarLayout(OI, beginOffset, endOffset, true, false);
+ }
+
+ llvm::Constant *BuildWeakIvarLayout(const ObjCImplementationDecl *OI,
+ CharUnits beginOffset,
+ CharUnits endOffset,
+ bool hasMRCWeakIvars) {
+ return BuildIvarLayout(OI, beginOffset, endOffset, false, hasMRCWeakIvars);
+ }
Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT, bool ByrefLayout);
@@ -970,7 +957,6 @@ protected:
llvm::Constant *getBitmapBlockLayout(bool ComputeByrefLayout);
-
/// GetIvarLayoutName - Returns a unique constant for the given
/// ivar layout bitmap.
llvm::Constant *GetIvarLayoutName(IdentifierInfo *Ident,
@@ -1002,6 +988,7 @@ protected:
/// defined. The return value has type ProtocolPtrTy.
llvm::Constant *GetProtocolRef(const ObjCProtocolDecl *PD);
+public:
/// CreateMetadataVar - Create a global variable with internal
/// linkage for use by the Objective-C runtime.
///
@@ -1017,9 +1004,10 @@ protected:
/// \param AddToUsed - Whether the variable should be added to
/// "llvm.used".
llvm::GlobalVariable *CreateMetadataVar(Twine Name, llvm::Constant *Init,
- StringRef Section, unsigned Align,
+ StringRef Section, CharUnits Align,
bool AddToUsed);
+protected:
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
ReturnValueSlot Return,
QualType ResultType,
@@ -1029,6 +1017,7 @@ protected:
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *OMD,
+ const ObjCInterfaceDecl *ClassReceiver,
const ObjCCommonTypesHelper &ObjCTypes);
/// EmitImageInfo - Emit the image info marker used to encode some module
@@ -1039,7 +1028,11 @@ public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGObjCRuntime(cgm), VMContext(cgm.getLLVMContext()) { }
- llvm::Constant *GenerateConstantString(const StringLiteral *SL) override;
+ bool isNonFragileABI() const {
+ return ObjCABI == 2;
+ }
+
+ ConstantAddress GenerateConstantString(const StringLiteral *SL) override;
llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD=nullptr) override;
@@ -1084,7 +1077,9 @@ private:
/// EmitClassExtension - Generate the class extension structure used
/// to store the weak ivar layout and properties. The return value
/// has type ClassExtensionPtrTy.
- llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID);
+ llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID,
+ CharUnits instanceSize,
+ bool hasMRCWeakIvars);
/// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
/// for the given class.
@@ -1172,8 +1167,8 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
- llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel,
- bool lval=false);
+ llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
+ Address EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel);
public:
CGObjCMac(CodeGen::CodeGenModule &cgm);
@@ -1199,8 +1194,8 @@ public:
llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) override;
- llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
- bool lval = false) override;
+ llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override;
+ Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override;
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
@@ -1236,19 +1231,19 @@ public:
void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
bool ClearInsertionPoint=true) override;
llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj) override;
+ Address AddrWeakObj) override;
void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst) override;
+ llvm::Value *src, Address dst) override;
void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
+ llvm::Value *src, Address dest,
bool threadlocal = false) override;
void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
+ llvm::Value *src, Address dest,
llvm::Value *ivarOffset) override;
void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest) override;
+ llvm::Value *src, Address dest) override;
void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *dest, llvm::Value *src,
+ Address dest, Address src,
llvm::Value *size) override;
LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
@@ -1395,8 +1390,8 @@ private:
/// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy,
/// for the given selector.
- llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel,
- bool lval=false);
+ llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel);
+ Address EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel);
/// GetInterfaceEHType - Get the cached ehtype for the given Objective-C
/// interface. The return value has type EHTypePtrTy.
@@ -1474,9 +1469,10 @@ public:
llvm::Value *GetClass(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) override;
- llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
- bool lvalue = false) override
- { return EmitSelector(CGF, Sel, lvalue); }
+ llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override
+ { return EmitSelector(CGF, Sel); }
+ Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override
+ { return EmitSelectorAddr(CGF, Sel); }
/// The NeXT/Apple runtimes do not support typed selectors; just emit an
/// untyped one.
@@ -1531,19 +1527,19 @@ public:
void EmitThrowStmt(CodeGen::CodeGenFunction &CGF, const ObjCAtThrowStmt &S,
bool ClearInsertionPoint=true) override;
llvm::Value * EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj) override;
+ Address AddrWeakObj) override;
void EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst) override;
+ llvm::Value *src, Address edst) override;
void EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
+ llvm::Value *src, Address dest,
bool threadlocal = false) override;
void EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest,
+ llvm::Value *src, Address dest,
llvm::Value *ivarOffset) override;
void EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dest) override;
+ llvm::Value *src, Address dest) override;
void EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *dest, llvm::Value *src,
+ Address dest, Address src,
llvm::Value *size) override;
LValue EmitObjCValueForIvar(CodeGen::CodeGenFunction &CGF, QualType ObjectTy,
llvm::Value *BaseValue, const ObjCIvarDecl *Ivar,
@@ -1645,7 +1641,7 @@ struct NullReturnState {
// memory or (2) agg values in registers.
if (result.isAggregate()) {
assert(result.isAggregate() && "null init of non-aggregate result?");
- CGF.EmitNullInitialization(result.getAggregateAddr(), resultType);
+ CGF.EmitNullInitialization(result.getAggregateAddress(), resultType);
if (contBB) CGF.EmitBlock(contBB);
return result;
}
@@ -1711,9 +1707,11 @@ llvm::Value *CGObjCMac::GetClass(CodeGenFunction &CGF,
}
/// GetSelector - Return the pointer to the unique'd string for this selector.
-llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel,
- bool lval) {
- return EmitSelector(CGF, Sel, lval);
+llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel) {
+ return EmitSelector(CGF, Sel);
+}
+Address CGObjCMac::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) {
+ return EmitSelectorAddr(CGF, Sel);
}
llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl
*Method) {
@@ -1756,7 +1754,7 @@ llvm::Constant *CGObjCMac::GetEHType(QualType T) {
};
*/
-llvm::Constant *CGObjCCommonMac::GenerateConstantString(
+ConstantAddress CGObjCCommonMac::GenerateConstantString(
const StringLiteral *SL) {
return (CGM.getLangOpts().NoConstantCFStrings == 0 ?
CGM.GetAddrOfConstantCFString(SL) :
@@ -1783,13 +1781,14 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
const ObjCMethodDecl *Method) {
// Create and init a super structure; this is a (receiver, class)
// pair we will pass to objc_msgSendSuper.
- llvm::Value *ObjCSuper =
- CGF.CreateTempAlloca(ObjCTypes.SuperTy, "objc_super");
+ Address ObjCSuper =
+ CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(),
+ "objc_super");
llvm::Value *ReceiverAsObject =
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
CGF.Builder.CreateStore(
ReceiverAsObject,
- CGF.Builder.CreateStructGEP(ObjCTypes.SuperTy, ObjCSuper, 0));
+ CGF.Builder.CreateStructGEP(ObjCSuper, 0, CharUnits::Zero()));
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
@@ -1803,12 +1802,13 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// isa" is the first ivar in a class (which it must be).
Target = EmitClassRef(CGF, Class->getSuperClass());
Target = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, Target, 0);
- Target = CGF.Builder.CreateLoad(Target);
+ Target = CGF.Builder.CreateAlignedLoad(Target, CGF.getPointerAlign());
} else {
llvm::Constant *MetaClassPtr = EmitMetaClassRef(Class);
llvm::Value *SuperPtr =
CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, MetaClassPtr, 1);
- llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr);
+ llvm::Value *Super =
+ CGF.Builder.CreateAlignedLoad(SuperPtr, CGF.getPointerAlign());
Target = Super;
}
} else if (isCategoryImpl)
@@ -1816,19 +1816,19 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
else {
llvm::Value *ClassPtr = EmitSuperClassRef(Class);
ClassPtr = CGF.Builder.CreateStructGEP(ObjCTypes.ClassTy, ClassPtr, 1);
- Target = CGF.Builder.CreateLoad(ClassPtr);
+ Target = CGF.Builder.CreateAlignedLoad(ClassPtr, CGF.getPointerAlign());
}
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
llvm::Type *ClassTy =
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
- CGF.Builder.CreateStore(
- Target, CGF.Builder.CreateStructGEP(ObjCTypes.SuperTy, ObjCSuper, 1));
+ CGF.Builder.CreateStore(Target,
+ CGF.Builder.CreateStructGEP(ObjCSuper, 1, CGF.getPointerSize()));
return EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF, Sel),
- ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, ObjCTypes);
+ ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
+ true, CallArgs, Method, Class, ObjCTypes);
}
/// Generate code for a message send expression.
@@ -1843,7 +1843,16 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
return EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF, Sel),
Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, ObjCTypes);
+ false, CallArgs, Method, Class, ObjCTypes);
+}
+
+static bool isWeakLinkedClass(const ObjCInterfaceDecl *ID) {
+ do {
+ if (ID->isWeakImported())
+ return true;
+ } while ((ID = ID->getSuperClass()));
+
+ return false;
}
CodeGen::RValue
@@ -1856,6 +1865,7 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
bool IsSuper,
const CallArgList &CallArgs,
const ObjCMethodDecl *Method,
+ const ObjCInterfaceDecl *ClassReceiver,
const ObjCCommonTypesHelper &ObjCTypes) {
CallArgList ActualArgs;
if (!IsSuper)
@@ -1872,11 +1882,38 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
CGM.getContext().getCanonicalType(ResultType) &&
"Result type mismatch!");
+ bool ReceiverCanBeNull = true;
+
+ // Super dispatch assumes that self is non-null; even the messenger
+ // doesn't have a null check internally.
+ if (IsSuper) {
+ ReceiverCanBeNull = false;
+
+ // If this is a direct dispatch of a class method, check whether the class,
+ // or anything in its hierarchy, was weak-linked.
+ } else if (ClassReceiver && Method && Method->isClassMethod()) {
+ ReceiverCanBeNull = isWeakLinkedClass(ClassReceiver);
+
+ // If we're emitting a method, and self is const (meaning just ARC, for now),
+ // and the receiver is a load of self, then self is a valid object.
+ } else if (auto CurMethod =
+ dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl)) {
+ auto Self = CurMethod->getSelfDecl();
+ if (Self->getType().isConstQualified()) {
+ if (auto LI = dyn_cast<llvm::LoadInst>(Arg0->stripPointerCasts())) {
+ llvm::Value *SelfAddr = CGF.GetAddrOfLocalVar(Self).getPointer();
+ if (SelfAddr == LI->getPointerOperand()) {
+ ReceiverCanBeNull = false;
+ }
+ }
+ }
+ }
+
NullReturnState nullReturn;
llvm::Constant *Fn = nullptr;
if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) {
- if (!IsSuper) nullReturn.init(CGF, Arg0);
+ if (ReceiverCanBeNull) nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
: ObjCTypes.getSendStretFn(IsSuper);
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
@@ -1888,76 +1925,182 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF,
} else {
// arm64 uses objc_msgSend for stret methods and yet null receiver check
// must be made for it.
- if (!IsSuper && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
+ if (ReceiverCanBeNull && CGM.ReturnTypeUsesSRet(MSI.CallInfo))
nullReturn.init(CGF, Arg0);
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
: ObjCTypes.getSendFn(IsSuper);
}
-
- bool requiresnullCheck = false;
- if (CGM.getLangOpts().ObjCAutoRefCount && Method)
+
+ // Emit a null-check if there's a consumed argument other than the receiver.
+ bool RequiresNullCheck = false;
+ if (ReceiverCanBeNull && CGM.getLangOpts().ObjCAutoRefCount && Method) {
for (const auto *ParamDecl : Method->params()) {
if (ParamDecl->hasAttr<NSConsumedAttr>()) {
if (!nullReturn.NullBB)
nullReturn.init(CGF, Arg0);
- requiresnullCheck = true;
+ RequiresNullCheck = true;
break;
}
}
+ }
+ llvm::Instruction *CallSite;
Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType);
- RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs);
+ RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs,
+ CGCalleeInfo(), &CallSite);
+
+ // Mark the call as noreturn if the method is marked noreturn and the
+ // receiver cannot be null.
+ if (Method && Method->hasAttr<NoReturnAttr>() && !ReceiverCanBeNull) {
+ llvm::CallSite(CallSite).setDoesNotReturn();
+ }
+
return nullReturn.complete(CGF, rvalue, ResultType, CallArgs,
- requiresnullCheck ? Method : nullptr);
+ RequiresNullCheck ? Method : nullptr);
}
-static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) {
+static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT,
+ bool pointee = false) {
+ // Note that GC qualification applies recursively to C pointer types
+ // that aren't otherwise decorated. This is weird, but it's probably
+ // an intentional workaround to the unreliable placement of GC qualifiers.
if (FQT.isObjCGCStrong())
return Qualifiers::Strong;
-
- if (FQT.isObjCGCWeak() || FQT.getObjCLifetime() == Qualifiers::OCL_Weak)
+
+ if (FQT.isObjCGCWeak())
return Qualifiers::Weak;
+
+ if (auto ownership = FQT.getObjCLifetime()) {
+ // Ownership does not apply recursively to C pointer types.
+ if (pointee) return Qualifiers::GCNone;
+ switch (ownership) {
+ case Qualifiers::OCL_Weak: return Qualifiers::Weak;
+ case Qualifiers::OCL_Strong: return Qualifiers::Strong;
+ case Qualifiers::OCL_ExplicitNone: return Qualifiers::GCNone;
+ case Qualifiers::OCL_Autoreleasing: llvm_unreachable("autoreleasing ivar?");
+ case Qualifiers::OCL_None: llvm_unreachable("known nonzero");
+ }
+ llvm_unreachable("bad objc ownership");
+ }
- // check for __unsafe_unretained
- if (FQT.getObjCLifetime() == Qualifiers::OCL_ExplicitNone)
- return Qualifiers::GCNone;
-
+ // Treat unqualified retainable pointers as strong.
if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
return Qualifiers::Strong;
- if (const PointerType *PT = FQT->getAs<PointerType>())
- return GetGCAttrTypeForType(Ctx, PT->getPointeeType());
+ // Walk into C pointer types, but only in GC.
+ if (Ctx.getLangOpts().getGC() != LangOptions::NonGC) {
+ if (const PointerType *PT = FQT->getAs<PointerType>())
+ return GetGCAttrTypeForType(Ctx, PT->getPointeeType(), /*pointee*/ true);
+ }
return Qualifiers::GCNone;
}
+namespace {
+ struct IvarInfo {
+ CharUnits Offset;
+ uint64_t SizeInWords;
+ IvarInfo(CharUnits offset, uint64_t sizeInWords)
+ : Offset(offset), SizeInWords(sizeInWords) {}
+
+ // Allow sorting based on byte pos.
+ bool operator<(const IvarInfo &other) const {
+ return Offset < other.Offset;
+ }
+ };
+
+ /// A helper class for building GC layout strings.
+ class IvarLayoutBuilder {
+ CodeGenModule &CGM;
+
+ /// The start of the layout. Offsets will be relative to this value,
+ /// and entries less than this value will be silently discarded.
+ CharUnits InstanceBegin;
+
+ /// The end of the layout. Offsets will never exceed this value.
+ CharUnits InstanceEnd;
+
+ /// Whether we're generating the strong layout or the weak layout.
+ bool ForStrongLayout;
+
+ /// Whether the offsets in IvarsInfo might be out-of-order.
+ bool IsDisordered = false;
+
+ llvm::SmallVector<IvarInfo, 8> IvarsInfo;
+ public:
+ IvarLayoutBuilder(CodeGenModule &CGM, CharUnits instanceBegin,
+ CharUnits instanceEnd, bool forStrongLayout)
+ : CGM(CGM), InstanceBegin(instanceBegin), InstanceEnd(instanceEnd),
+ ForStrongLayout(forStrongLayout) {
+ }
+
+ void visitRecord(const RecordType *RT, CharUnits offset);
+
+ template <class Iterator, class GetOffsetFn>
+ void visitAggregate(Iterator begin, Iterator end,
+ CharUnits aggrOffset,
+ const GetOffsetFn &getOffset);
+
+ void visitField(const FieldDecl *field, CharUnits offset);
+
+ /// Add the layout of a block implementation.
+ void visitBlock(const CGBlockInfo &blockInfo);
+
+ /// Is there any information for an interesting bitmap?
+ bool hasBitmapData() const { return !IvarsInfo.empty(); }
+
+ llvm::Constant *buildBitmap(CGObjCCommonMac &CGObjC,
+ llvm::SmallVectorImpl<unsigned char> &buffer);
+
+ static void dump(ArrayRef<unsigned char> buffer) {
+ const unsigned char *s = buffer.data();
+ for (unsigned i = 0, e = buffer.size(); i < e; i++)
+ if (!(s[i] & 0xf0))
+ printf("0x0%x%s", s[i], s[i] != 0 ? ", " : "");
+ else
+ printf("0x%x%s", s[i], s[i] != 0 ? ", " : "");
+ printf("\n");
+ }
+ };
+}
+
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)
+ if (CGM.getLangOpts().getGC() == LangOptions::NonGC)
return nullPtr;
- bool hasUnion = false;
- SkipIvars.clear();
- IvarsInfo.clear();
- unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
+ IvarLayoutBuilder builder(CGM, CharUnits::Zero(), blockInfo.BlockSize,
+ /*for strong layout*/ true);
+
+ builder.visitBlock(blockInfo);
+
+ if (!builder.hasBitmapData())
+ return nullPtr;
+
+ llvm::SmallVector<unsigned char, 32> buffer;
+ llvm::Constant *C = builder.buildBitmap(*this, buffer);
+ if (CGM.getLangOpts().ObjCGCBitmapPrint && !buffer.empty()) {
+ printf("\n block variable layout for block: ");
+ builder.dump(buffer);
+ }
+ return C;
+}
+
+void IvarLayoutBuilder::visitBlock(const CGBlockInfo &blockInfo) {
// __isa is the first field in block descriptor and must assume by runtime's
// convention that it is GC'able.
- IvarsInfo.push_back(GC_IVAR(0, 1));
+ IvarsInfo.push_back(IvarInfo(CharUnits::Zero(), 1));
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.
+ CharUnits lastFieldOffset;
+
// Walk the captured variables.
for (const auto &CI : blockDecl->captures()) {
const VarDecl *variable = CI.getVariable();
@@ -1968,64 +2111,51 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
// Ignore constant captures.
if (capture.isConstant()) continue;
- uint64_t fieldOffset = layout->getElementOffset(capture.getIndex());
+ CharUnits fieldOffset = capture.getOffset();
+
+ // Block fields are not necessarily ordered; if we detect that we're
+ // adding them out-of-order, make sure we sort later.
+ if (fieldOffset < lastFieldOffset)
+ IsDisordered = true;
+ lastFieldOffset = fieldOffset;
// __block variables are passed by their descriptor address.
if (CI.isByRef()) {
- IvarsInfo.push_back(GC_IVAR(fieldOffset, /*size in words*/ 1));
+ IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
continue;
}
assert(!type->isArrayType() && "array variable should not be caught");
if (const RecordType *record = type->getAs<RecordType>()) {
- BuildAggrIvarRecordLayout(record, fieldOffset, true, hasUnion);
+ visitRecord(record, fieldOffset);
continue;
}
Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), type);
- unsigned fieldSize = CGM.getContext().getTypeSize(type);
-
- if (GCAttr == Qualifiers::Strong)
- IvarsInfo.push_back(GC_IVAR(fieldOffset,
- fieldSize / WordSizeInBits));
- else if (GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak)
- SkipIvars.push_back(GC_IVAR(fieldOffset,
- fieldSize / ByteSizeInBits));
- }
-
- if (IvarsInfo.empty())
- return nullPtr;
- // Sort on byte position; captures might not be allocated in order,
- // and unions can do funny things.
- llvm::array_pod_sort(IvarsInfo.begin(), IvarsInfo.end());
- llvm::array_pod_sort(SkipIvars.begin(), SkipIvars.end());
-
- std::string BitMap;
- llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
- if (CGM.getLangOpts().ObjCGCBitmapPrint) {
- printf("\n block variable layout for block: ");
- 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 ? ", " : "");
- else
- printf("0x%x%s", s[i], s[i] != 0 ? ", " : "");
- printf("\n");
+ if (GCAttr == Qualifiers::Strong) {
+ assert(CGM.getContext().getTypeSize(type)
+ == CGM.getTarget().getPointerWidth(0));
+ IvarsInfo.push_back(IvarInfo(fieldOffset, /*size in words*/ 1));
+ }
}
-
- 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,
bool ByrefLayout) {
+ // If it has an ownership qualifier, we're done.
+ if (auto lifetime = FQT.getObjCLifetime())
+ return lifetime;
+
+ // If it doesn't, and this is ARC, it has no ownership.
if (CGM.getLangOpts().ObjCAutoRefCount)
- return FQT.getObjCLifetime();
+ return Qualifiers::OCL_None;
- // MRR.
+ // In MRC, retainable pointers are owned by non-__block variables.
if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType())
return ByrefLayout ? Qualifiers::OCL_ExplicitNone : Qualifiers::OCL_Strong;
@@ -2361,9 +2491,8 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
}
}
- int e = Layout.size()-1;
- while (e >= 0) {
- unsigned char inst = Layout[e--];
+ while (!Layout.empty()) {
+ unsigned char inst = Layout.back();
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();
@@ -2376,19 +2505,19 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
// Block variable layout instruction has been inlined.
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
if (ComputeByrefLayout)
- printf("\n Inline instruction for BYREF variable layout: ");
+ printf("\n Inline BYREF variable layout: ");
else
- printf("\n Inline instruction for block variable layout: ");
- printf("0x0%" PRIx64 "\n", 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);
+ printf("\n Inline block variable layout: ");
+ printf("0x0%" PRIx64 "", Result);
+ if (auto numStrong = (Result & 0xF00) >> 8)
+ printf(", BL_STRONG:%d", (int) numStrong);
+ if (auto numByref = (Result & 0x0F0) >> 4)
+ printf(", BL_BYREF:%d", (int) numByref);
+ if (auto numWeak = (Result & 0x00F) >> 0)
+ printf(", BL_WEAK:%d", (int) numWeak);
+ printf(", BL_OPERATOR:0\n");
}
+ return llvm::ConstantInt::get(CGM.IntPtrTy, Result);
}
unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0;
@@ -2399,9 +2528,9 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
if (CGM.getLangOpts().ObjCGCBitmapPrint) {
if (ComputeByrefLayout)
- printf("\n BYREF variable layout: ");
+ printf("\n Byref variable layout: ");
else
- printf("\n block variable layout: ");
+ 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);
@@ -2443,7 +2572,7 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
llvm::GlobalVariable *Entry = CreateMetadataVar(
"OBJC_CLASS_NAME_",
llvm::ConstantDataArray::getString(VMContext, BitMap, false),
- "__TEXT,__objc_classname,cstring_literals", 1, true);
+ "__TEXT,__objc_classname,cstring_literals", CharUnits::One(), true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -2511,6 +2640,8 @@ llvm::Constant *CGObjCCommonMac::BuildByrefLayout(CodeGen::CodeGenModule &CGM,
if (const RecordType *record = T->getAs<RecordType>()) {
BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion, true /*ByrefLayout */);
llvm::Constant *Result = getBitmapBlockLayout(true);
+ if (isa<llvm::ConstantInt>(Result))
+ Result = llvm::ConstantExpr::getIntToPtr(Result, CGM.Int8PtrTy);
return Result;
}
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
@@ -2699,7 +2830,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD,
// No special section, but goes in llvm.used
return CreateMetadataVar("\01l_OBJC_PROTOCOLEXT_" + PD->getName(), Init,
- StringRef(), 0, true);
+ StringRef(), CGM.getPointerAlign(), true);
}
/*
@@ -2738,7 +2869,7 @@ CGObjCMac::EmitProtocolList(Twine Name,
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV =
CreateMetadataVar(Name, Init, "__OBJC,__cat_cls_meth,regular,no_dead_strip",
- 4, false);
+ CGM.getPointerAlign(), false);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy);
}
@@ -2779,15 +2910,26 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
const ObjCCommonTypesHelper &ObjCTypes) {
SmallVector<llvm::Constant *, 16> Properties;
llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet;
+
+ auto AddProperty = [&](const ObjCPropertyDecl *PD) {
+ llvm::Constant *Prop[] = {GetPropertyName(PD->getIdentifier()),
+ GetPropertyTypeString(PD, Container)};
+ Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop));
+ };
+ if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD))
+ for (const ObjCCategoryDecl *ClassExt : OID->known_extensions())
+ for (auto *PD : ClassExt->properties()) {
+ PropertySet.insert(PD->getIdentifier());
+ AddProperty(PD);
+ }
for (const auto *PD : OCD->properties()) {
- PropertySet.insert(PD->getIdentifier());
- llvm::Constant *Prop[] = {
- GetPropertyName(PD->getIdentifier()),
- GetPropertyTypeString(PD, Container)
- };
- Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy,
- Prop));
+ // Don't emit duplicate metadata for properties that were already in a
+ // class extension.
+ if (!PropertySet.insert(PD->getIdentifier()).second)
+ continue;
+ AddProperty(PD);
}
+
if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) {
for (const auto *P : OID->all_referenced_protocols())
PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes);
@@ -2815,7 +2957,7 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name,
CreateMetadataVar(Name, Init,
(ObjCABI == 2) ? "__DATA, __objc_const" :
"__OBJC,__property,regular,no_dead_strip",
- (ObjCABI == 2) ? 8 : 4,
+ CGM.getPointerAlign(),
true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy);
}
@@ -2834,7 +2976,7 @@ CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name,
llvm::GlobalVariable *GV = CreateMetadataVar(
Name, Init, (ObjCABI == 2) ? "__DATA, __objc_const" : StringRef(),
- (ObjCABI == 2) ? 8 : 4, true);
+ CGM.getPointerAlign(), true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy);
}
@@ -2872,7 +3014,8 @@ CGObjCMac::EmitMethodDescList(Twine Name, const char *Section,
Values[1] = llvm::ConstantArray::get(AT, Methods);
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
- llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true);
return llvm::ConstantExpr::getBitCast(GV,
ObjCTypes.MethodDescriptionListPtrTy);
}
@@ -2944,7 +3087,8 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
llvm::GlobalVariable *GV =
CreateMetadataVar("OBJC_CATEGORY_" + ExtName.str(), Init,
- "__OBJC,__category,regular,no_dead_strip", 4, true);
+ "__OBJC,__category,regular,no_dead_strip",
+ CGM.getPointerAlign(), true);
DefinedCategories.push_back(GV);
DefinedCategoryNames.insert(ExtName.str());
// method definition entries must be clear for next implementation.
@@ -2952,10 +3096,24 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
}
enum FragileClassFlags {
+ /// Apparently: is not a meta-class.
FragileABI_Class_Factory = 0x00001,
+
+ /// Is a meta-class.
FragileABI_Class_Meta = 0x00002,
+
+ /// Has a non-trivial constructor or destructor.
FragileABI_Class_HasCXXStructors = 0x02000,
- FragileABI_Class_Hidden = 0x20000
+
+ /// Has hidden visibility.
+ FragileABI_Class_Hidden = 0x20000,
+
+ /// Class implementation was compiled under ARC.
+ FragileABI_Class_CompiledByARC = 0x04000000,
+
+ /// Class implementation was compiled under MRC and has MRC weak ivars.
+ /// Exclusive with CompiledByARC.
+ FragileABI_Class_HasMRCWeakIvars = 0x08000000,
};
enum NonFragileClassFlags {
@@ -2965,7 +3123,7 @@ enum NonFragileClassFlags {
/// Is a root class.
NonFragileABI_Class_Root = 0x00002,
- /// Has a C++ constructor and destructor.
+ /// Has a non-trivial constructor or destructor.
NonFragileABI_Class_HasCXXStructors = 0x00004,
/// Has hidden visibility.
@@ -2981,9 +3139,46 @@ enum NonFragileClassFlags {
NonFragileABI_Class_CompiledByARC = 0x00080,
/// Class has non-trivial destructors, but zero-initialization is okay.
- NonFragileABI_Class_HasCXXDestructorOnly = 0x00100
+ NonFragileABI_Class_HasCXXDestructorOnly = 0x00100,
+
+ /// Class implementation was compiled under MRC and has MRC weak ivars.
+ /// Exclusive with CompiledByARC.
+ NonFragileABI_Class_HasMRCWeakIvars = 0x00200,
};
+static bool hasWeakMember(QualType type) {
+ if (type.getObjCLifetime() == Qualifiers::OCL_Weak) {
+ return true;
+ }
+
+ if (auto recType = type->getAs<RecordType>()) {
+ for (auto field : recType->getDecl()->fields()) {
+ if (hasWeakMember(field->getType()))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/// For compatibility, we only want to set the "HasMRCWeakIvars" flag
+/// (and actually fill in a layout string) if we really do have any
+/// __weak ivars.
+static bool hasMRCWeakIvars(CodeGenModule &CGM,
+ const ObjCImplementationDecl *ID) {
+ if (!CGM.getLangOpts().ObjCWeak) return false;
+ assert(CGM.getLangOpts().getGC() == LangOptions::NonGC);
+
+ for (const ObjCIvarDecl *ivar =
+ ID->getClassInterface()->all_declared_ivar_begin();
+ ivar; ivar = ivar->getNextIvar()) {
+ if (hasWeakMember(ivar->getType()))
+ return true;
+ }
+
+ return false;
+}
+
/*
struct _objc_class {
Class isa;
@@ -3017,8 +3212,16 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
unsigned Flags = FragileABI_Class_Factory;
if (ID->hasNonZeroConstructors() || ID->hasDestructors())
Flags |= FragileABI_Class_HasCXXStructors;
- unsigned Size =
- CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity();
+
+ bool hasMRCWeak = false;
+
+ if (CGM.getLangOpts().ObjCAutoRefCount)
+ Flags |= FragileABI_Class_CompiledByARC;
+ else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID)))
+ Flags |= FragileABI_Class_HasMRCWeakIvars;
+
+ CharUnits Size =
+ CGM.getContext().getASTObjCImplementationLayout(ID).getSize();
// FIXME: Set CXX-structors flag.
if (ID->getClassInterface()->getVisibility() == HiddenVisibility)
@@ -3062,7 +3265,7 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
// Version is always 0.
Values[ 3] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0);
Values[ 4] = llvm::ConstantInt::get(ObjCTypes.LongTy, Flags);
- Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size);
+ Values[ 5] = llvm::ConstantInt::get(ObjCTypes.LongTy, Size.getQuantity());
Values[ 6] = EmitIvarList(ID, false);
Values[7] = EmitMethodList("OBJC_INSTANCE_METHODS_" + ID->getName(),
"__OBJC,__inst_meth,regular,no_dead_strip",
@@ -3070,8 +3273,8 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
// cache is always NULL.
Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy);
Values[ 9] = Protocols;
- Values[10] = BuildIvarLayout(ID, true);
- Values[11] = EmitClassExtension(ID);
+ Values[10] = BuildStrongIvarLayout(ID, CharUnits::Zero(), Size);
+ Values[11] = EmitClassExtension(ID, Size, hasMRCWeak);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
std::string Name("OBJC_CLASS_");
@@ -3084,10 +3287,10 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
"Forward metaclass reference has incorrect type.");
GV->setInitializer(Init);
GV->setSection(Section);
- GV->setAlignment(4);
+ GV->setAlignment(CGM.getPointerAlign().getQuantity());
CGM.addCompilerUsedGlobal(GV);
} else
- GV = CreateMetadataVar(Name, Init, Section, 4, true);
+ GV = CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true);
DefinedClasses.push_back(GV);
ImplementedClasses.push_back(Interface);
// method definition entries must be clear for next implementation.
@@ -3198,6 +3401,10 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
}
/*
+ Emit a "class extension", which in this specific context means extra
+ data that doesn't fit in the normal fragile-ABI class structure, and
+ has nothing to do with the language concept of a class extension.
+
struct objc_class_ext {
uint32_t size;
const char *weak_ivar_layout;
@@ -3205,13 +3412,15 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
};
*/
llvm::Constant *
-CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
+CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID,
+ CharUnits InstanceSize, bool hasMRCWeakIvars) {
uint64_t Size =
CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy);
llvm::Constant *Values[3];
Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size);
- Values[1] = BuildIvarLayout(ID, false);
+ Values[1] = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize,
+ hasMRCWeakIvars);
Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(),
ID, ID->getClassInterface(), ObjCTypes);
@@ -3222,7 +3431,8 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) {
llvm::Constant *Init =
llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values);
return CreateMetadataVar("OBJC_CLASSEXT_" + ID->getName(), Init,
- "__OBJC,__class_ext,regular,no_dead_strip", 4, true);
+ "__OBJC,__class_ext,regular,no_dead_strip",
+ CGM.getPointerAlign(), true);
}
/*
@@ -3280,11 +3490,12 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID,
if (ForClass)
GV =
CreateMetadataVar("OBJC_CLASS_VARIABLES_" + ID->getName(), Init,
- "__OBJC,__class_vars,regular,no_dead_strip", 4, true);
+ "__OBJC,__class_vars,regular,no_dead_strip",
+ CGM.getPointerAlign(), true);
else
GV = CreateMetadataVar("OBJC_INSTANCE_VARIABLES_" + ID->getName(), Init,
- "__OBJC,__instance_vars,regular,no_dead_strip", 4,
- true);
+ "__OBJC,__instance_vars,regular,no_dead_strip",
+ CGM.getPointerAlign(), true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy);
}
@@ -3334,7 +3545,8 @@ llvm::Constant *CGObjCMac::EmitMethodList(Twine Name,
Values[2] = llvm::ConstantArray::get(AT, Methods);
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
- llvm::GlobalVariable *GV = CreateMetadataVar(Name, Init, Section, 4, true);
+ llvm::GlobalVariable *GV =
+ CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListPtrTy);
}
@@ -3359,7 +3571,7 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD,
llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
llvm::Constant *Init,
StringRef Section,
- unsigned Align,
+ CharUnits Align,
bool AddToUsed) {
llvm::Type *Ty = Init->getType();
llvm::GlobalVariable *GV =
@@ -3367,8 +3579,7 @@ llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name,
llvm::GlobalValue::PrivateLinkage, Init, Name);
if (!Section.empty())
GV->setSection(Section);
- if (Align)
- GV->setAlignment(Align);
+ GV->setAlignment(Align.getQuantity());
if (AddToUsed)
CGM.addCompilerUsedGlobal(GV);
return GV;
@@ -3421,16 +3632,16 @@ void CGObjCMac::EmitSynchronizedStmt(CodeGenFunction &CGF,
}
namespace {
- struct PerformFragileFinally : EHScopeStack::Cleanup {
+ struct PerformFragileFinally final : EHScopeStack::Cleanup {
const Stmt &S;
- llvm::Value *SyncArgSlot;
- llvm::Value *CallTryExitVar;
- llvm::Value *ExceptionData;
+ Address SyncArgSlot;
+ Address CallTryExitVar;
+ Address ExceptionData;
ObjCTypesHelper &ObjCTypes;
PerformFragileFinally(const Stmt *S,
- llvm::Value *SyncArgSlot,
- llvm::Value *CallTryExitVar,
- llvm::Value *ExceptionData,
+ Address SyncArgSlot,
+ Address CallTryExitVar,
+ Address ExceptionData,
ObjCTypesHelper *ObjCTypes)
: S(*S), SyncArgSlot(SyncArgSlot), CallTryExitVar(CallTryExitVar),
ExceptionData(ExceptionData), ObjCTypes(*ObjCTypes) {}
@@ -3447,7 +3658,7 @@ namespace {
CGF.EmitBlock(FinallyCallExit);
CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(),
- ExceptionData);
+ ExceptionData.getPointer());
CGF.EmitBlock(FinallyNoCallExit);
@@ -3568,7 +3779,7 @@ void FragileHazards::emitReadHazard(CGBuilderTy &Builder) {
void FragileHazards::emitHazardsInNewBlocks() {
if (Locals.empty()) return;
- CGBuilderTy Builder(CGF.getLLVMContext());
+ CGBuilderTy Builder(CGF, CGF.getLLVMContext());
// Iterate through all blocks, skipping those prior to the try.
for (llvm::Function::iterator
@@ -3607,6 +3818,10 @@ static void addIfPresent(llvm::DenseSet<llvm::Value*> &S, llvm::Value *V) {
if (V) S.insert(V);
}
+static void addIfPresent(llvm::DenseSet<llvm::Value*> &S, Address V) {
+ if (V.isValid()) S.insert(V.getPointer());
+}
+
void FragileHazards::collectLocals() {
// Compute a set of allocas to ignore.
llvm::DenseSet<llvm::Value*> AllocasToIgnore;
@@ -3760,21 +3975,23 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// @synchronized. We can't avoid a temp here because we need the
// value to be preserved. If the backend ever does liveness
// correctly after setjmp, this will be unnecessary.
- llvm::Value *SyncArgSlot = nullptr;
+ Address SyncArgSlot = Address::invalid();
if (!isTry) {
llvm::Value *SyncArg =
CGF.EmitScalarExpr(cast<ObjCAtSynchronizedStmt>(S).getSynchExpr());
SyncArg = CGF.Builder.CreateBitCast(SyncArg, ObjCTypes.ObjectPtrTy);
CGF.EmitNounwindRuntimeCall(ObjCTypes.getSyncEnterFn(), SyncArg);
- SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(), "sync.arg");
+ SyncArgSlot = CGF.CreateTempAlloca(SyncArg->getType(),
+ CGF.getPointerAlign(), "sync.arg");
CGF.Builder.CreateStore(SyncArg, SyncArgSlot);
}
// Allocate memory for the setjmp buffer. This needs to be kept
// live throughout the try and catch blocks.
- llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
- "exceptiondata.ptr");
+ Address ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
+ CGF.getPointerAlign(),
+ "exceptiondata.ptr");
// Create the fragile hazards. Note that this will not capture any
// of the allocas required for exception processing, but will
@@ -3790,12 +4007,13 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// The setjmp-safety rule here is that we should always store to this
// variable in a place that dominates the branch through the cleanup
// without passing through any setjmps.
- llvm::Value *CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(),
- "_call_try_exit");
+ Address CallTryExitVar = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(),
+ CharUnits::One(),
+ "_call_try_exit");
// A slot containing the exception to rethrow. Only needed when we
// have both a @catch and a @finally.
- llvm::Value *PropagatingExnVar = nullptr;
+ Address PropagatingExnVar = Address::invalid();
// Push a normal cleanup to leave the try scope.
CGF.EHStack.pushCleanup<PerformFragileFinally>(NormalAndEHCleanup, &S,
@@ -3808,13 +4026,14 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// - Call objc_exception_try_enter to push ExceptionData on top of
// the EH stack.
CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
- ExceptionData);
+ ExceptionData.getPointer());
// - Call setjmp on the exception data buffer.
llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
llvm::Value *GEPIndexes[] = { Zero, Zero, Zero };
llvm::Value *SetJmpBuffer = CGF.Builder.CreateGEP(
- ObjCTypes.ExceptionDataTy, ExceptionData, GEPIndexes, "setjmp_buffer");
+ ObjCTypes.ExceptionDataTy, ExceptionData.getPointer(), GEPIndexes,
+ "setjmp_buffer");
llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall(
ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result");
SetJmpResult->setCanReturnTwice();
@@ -3854,7 +4073,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// nothing can cross this so the value is already in SSA form.
llvm::CallInst *Caught =
CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData, "caught");
+ ExceptionData.getPointer(), "caught");
// Push the exception to rethrow onto the EH value stack for the
// benefit of any @throws in the handlers.
@@ -3870,13 +4089,14 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Save the currently-propagating exception before
// objc_exception_try_enter clears the exception slot.
PropagatingExnVar = CGF.CreateTempAlloca(Caught->getType(),
+ CGF.getPointerAlign(),
"propagating_exception");
CGF.Builder.CreateStore(Caught, PropagatingExnVar);
// Enter a new exception try block (in case a @catch block
// throws an exception).
CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(),
- ExceptionData);
+ ExceptionData.getPointer());
llvm::CallInst *SetJmpResult =
CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(),
@@ -3928,7 +4148,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
assert(CGF.HaveInsertPoint() && "DeclStmt destroyed insert point?");
// These types work out because ConvertType(id) == i8*.
- CGF.Builder.CreateStore(Caught, CGF.GetAddrOfLocalVar(CatchParam));
+ EmitInitOfCatchParam(CGF, Caught, CatchParam);
}
CGF.EmitStmt(CatchStmt->getCatchBody());
@@ -3975,7 +4195,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
llvm::Value *Tmp =
CGF.Builder.CreateBitCast(Caught,
CGF.ConvertType(CatchParam->getType()));
- CGF.Builder.CreateStore(Tmp, CGF.GetAddrOfLocalVar(CatchParam));
+ EmitInitOfCatchParam(CGF, Tmp, CatchParam);
CGF.EmitStmt(CatchStmt->getCatchBody());
@@ -4008,10 +4228,10 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Extract the new exception and save it to the
// propagating-exception slot.
- assert(PropagatingExnVar);
+ assert(PropagatingExnVar.isValid());
llvm::CallInst *NewCaught =
CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData, "caught");
+ ExceptionData.getPointer(), "caught");
CGF.Builder.CreateStore(NewCaught, PropagatingExnVar);
// Don't pop the catch handler; the throw already did.
@@ -4036,14 +4256,14 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
if (CGF.HaveInsertPoint()) {
// If we have a propagating-exception variable, check it.
llvm::Value *PropagatingExn;
- if (PropagatingExnVar) {
+ if (PropagatingExnVar.isValid()) {
PropagatingExn = CGF.Builder.CreateLoad(PropagatingExnVar);
// Otherwise, just look in the buffer for the exception to throw.
} else {
llvm::CallInst *Caught =
CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(),
- ExceptionData);
+ ExceptionData.getPointer());
PropagatingExn = Caught;
}
@@ -4083,14 +4303,13 @@ void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
/// object: objc_read_weak (id *src)
///
llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj) {
- llvm::Type* DestTy =
- cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
+ Address AddrWeakObj) {
+ llvm::Type* DestTy = AddrWeakObj.getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj,
ObjCTypes.PtrObjectPtrTy);
llvm::Value *read_weak =
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj, "weakread");
+ AddrWeakObj.getPointer(), "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
@@ -4099,7 +4318,7 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF,
/// objc_assign_weak (id src, id *dst)
///
void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst) {
+ llvm::Value *src, Address dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
@@ -4110,7 +4329,7 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst };
+ llvm::Value *args[] = { src, dst.getPointer() };
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
args, "weakassign");
return;
@@ -4120,7 +4339,7 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_global (id src, id *dst)
///
void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst,
+ llvm::Value *src, Address dst,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
@@ -4132,7 +4351,7 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst };
+ llvm::Value *args[] = { src, dst.getPointer() };
if (!threadlocal)
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
args, "globalassign");
@@ -4146,7 +4365,7 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_ivar (id src, id *dst, ptrdiff_t ivaroffset)
///
void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst,
+ llvm::Value *src, Address dst,
llvm::Value *ivarOffset) {
assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL");
llvm::Type * SrcTy = src->getType();
@@ -4159,7 +4378,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst, ivarOffset };
+ llvm::Value *args[] = { src, dst.getPointer(), ivarOffset };
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
return;
}
@@ -4168,7 +4387,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_strongCast (id src, id *dst)
///
void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst) {
+ llvm::Value *src, Address dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
@@ -4179,19 +4398,19 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst };
+ llvm::Value *args[] = { src, dst.getPointer() };
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
- args, "weakassign");
+ args, "strongassign");
return;
}
void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF,
- llvm::Value *DestPtr,
- llvm::Value *SrcPtr,
+ Address DestPtr,
+ Address SrcPtr,
llvm::Value *size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- llvm::Value *args[] = { DestPtr, SrcPtr, size };
+ llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), size };
CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
}
@@ -4283,7 +4502,7 @@ void CGObjCCommonMac::EmitImageInfo() {
// Indicate whether we're compiling this to run on a simulator.
const llvm::Triple &Triple = CGM.getTarget().getTriple();
- if (Triple.isiOS() &&
+ if ((Triple.isiOS() || Triple.isWatchOS()) &&
(Triple.getArch() == llvm::Triple::x86 ||
Triple.getArch() == llvm::Triple::x86_64))
Mod.addModuleFlag(llvm::Module::Error, "Objective-C Is Simulated",
@@ -4312,7 +4531,8 @@ void CGObjCMac::EmitModuleInfo() {
};
CreateMetadataVar("OBJC_MODULES",
llvm::ConstantStruct::get(ObjCTypes.ModuleTy, Values),
- "__OBJC,__module_info,regular,no_dead_strip", 4, true);
+ "__OBJC,__module_info,regular,no_dead_strip",
+ CGM.getPointerAlign(), true);
}
llvm::Constant *CGObjCMac::EmitModuleSymbols() {
@@ -4356,7 +4576,8 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() {
llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values);
llvm::GlobalVariable *GV = CreateMetadataVar(
- "OBJC_SYMBOLS", Init, "__OBJC,__symbols,regular,no_dead_strip", 4, true);
+ "OBJC_SYMBOLS", Init, "__OBJC,__symbols,regular,no_dead_strip",
+ CGM.getPointerAlign(), true);
return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy);
}
@@ -4372,10 +4593,11 @@ llvm::Value *CGObjCMac::EmitClassRefFromId(CodeGenFunction &CGF,
ObjCTypes.ClassPtrTy);
Entry = CreateMetadataVar(
"OBJC_CLASS_REFERENCES_", Casted,
- "__OBJC,__cls_refs,literal_pointers,no_dead_strip", 4, true);
+ "__OBJC,__cls_refs,literal_pointers,no_dead_strip",
+ CGM.getPointerAlign(), true);
}
- return CGF.Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateAlignedLoad(Entry, CGF.getPointerAlign());
}
llvm::Value *CGObjCMac::EmitClassRef(CodeGenFunction &CGF,
@@ -4388,23 +4610,25 @@ llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
return EmitClassRefFromId(CGF, II);
}
-llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel,
- bool lvalue) {
- llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
+llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) {
+ return CGF.Builder.CreateLoad(EmitSelectorAddr(CGF, Sel));
+}
+
+Address CGObjCMac::EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel) {
+ CharUnits Align = CGF.getPointerAlign();
+ llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
if (!Entry) {
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
ObjCTypes.SelectorPtrTy);
Entry = CreateMetadataVar(
"OBJC_SELECTOR_REFERENCES_", Casted,
- "__OBJC,__message_refs,literal_pointers,no_dead_strip", 4, true);
+ "__OBJC,__message_refs,literal_pointers,no_dead_strip", Align, true);
Entry->setExternallyInitialized(true);
}
- if (lvalue)
- return Entry;
- return CGF.Builder.CreateLoad(Entry);
+ return Address(Entry, Align);
}
llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) {
@@ -4415,7 +4639,7 @@ llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) {
llvm::ConstantDataArray::getString(VMContext, RuntimeName),
((ObjCABI == 2) ? "__TEXT,__objc_classname,cstring_literals"
: "__TEXT,__cstring,cstring_literals"),
- 1, true);
+ CharUnits::One(), true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4435,308 +4659,247 @@ llvm::Constant *CGObjCCommonMac::GetIvarLayoutName(IdentifierInfo *Ident,
return llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy);
}
-void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT,
- unsigned int BytePos,
- bool ForStrongLayout,
- bool &HasUnion) {
+void IvarLayoutBuilder::visitRecord(const RecordType *RT,
+ CharUnits offset) {
const RecordDecl *RD = RT->getDecl();
- // FIXME - Use iterator.
- SmallVector<const FieldDecl*, 16> Fields(RD->fields());
- llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0));
- const llvm::StructLayout *RecLayout =
- CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty));
- BuildAggrIvarLayout(nullptr, RecLayout, RD, Fields, BytePos, ForStrongLayout,
- HasUnion);
-}
+ // If this is a union, remember that we had one, because it might mess
+ // up the ordering of layout entries.
+ if (RD->isUnion())
+ IsDisordered = true;
+
+ const ASTRecordLayout *recLayout = nullptr;
+ visitAggregate(RD->field_begin(), RD->field_end(), offset,
+ [&](const FieldDecl *field) -> CharUnits {
+ if (!recLayout)
+ recLayout = &CGM.getContext().getASTRecordLayout(RD);
+ auto offsetInBits = recLayout->getFieldOffset(field->getFieldIndex());
+ return CGM.getContext().toCharUnitsFromBits(offsetInBits);
+ });
+}
+
+template <class Iterator, class GetOffsetFn>
+void IvarLayoutBuilder::visitAggregate(Iterator begin, Iterator end,
+ CharUnits aggregateOffset,
+ const GetOffsetFn &getOffset) {
+ for (; begin != end; ++begin) {
+ auto field = *begin;
+
+ // Skip over bitfields.
+ if (field->isBitField()) {
+ continue;
+ }
-void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
- const llvm::StructLayout *Layout,
- const RecordDecl *RD,
- ArrayRef<const FieldDecl*> RecFields,
- unsigned int BytePos, bool ForStrongLayout,
- bool &HasUnion) {
- bool IsUnion = (RD && RD->isUnion());
- uint64_t MaxUnionIvarSize = 0;
- uint64_t MaxSkippedUnionIvarSize = 0;
- const FieldDecl *MaxField = nullptr;
- const FieldDecl *MaxSkippedField = nullptr;
- const FieldDecl *LastFieldBitfieldOrUnnamed = nullptr;
- uint64_t MaxFieldOffset = 0;
- uint64_t MaxSkippedFieldOffset = 0;
- uint64_t LastBitfieldOrUnnamedOffset = 0;
- uint64_t FirstFieldDelta = 0;
+ // Compute the offset of the field within the aggregate.
+ CharUnits fieldOffset = aggregateOffset + getOffset(field);
- if (RecFields.empty())
- return;
- unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
- if (!RD && CGM.getLangOpts().ObjCAutoRefCount) {
- const FieldDecl *FirstField = RecFields[0];
- FirstFieldDelta =
- ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(FirstField));
+ visitField(field, fieldOffset);
}
-
- for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
- const FieldDecl *Field = RecFields[i];
- uint64_t FieldOffset;
- if (RD) {
- // 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);
- FieldOffset = (RL.getFieldOffset(i) / ByteSizeInBits) - FirstFieldDelta;
- } else
- FieldOffset =
- ComputeIvarBaseOffset(CGM, OI, cast<ObjCIvarDecl>(Field)) - FirstFieldDelta;
+}
- // Skip over unnamed or bitfields
- if (!Field->getIdentifier() || Field->isBitField()) {
- LastFieldBitfieldOrUnnamed = Field;
- LastBitfieldOrUnnamedOffset = FieldOffset;
- continue;
- }
+/// Collect layout information for the given fields into IvarsInfo.
+void IvarLayoutBuilder::visitField(const FieldDecl *field,
+ CharUnits fieldOffset) {
+ QualType fieldType = field->getType();
- LastFieldBitfieldOrUnnamed = nullptr;
- QualType FQT = Field->getType();
- if (FQT->isRecordType() || FQT->isUnionType()) {
- if (FQT->isUnionType())
- HasUnion = true;
+ // Drill down into arrays.
+ uint64_t numElts = 1;
+ while (auto arrayType = CGM.getContext().getAsConstantArrayType(fieldType)) {
+ numElts *= arrayType->getSize().getZExtValue();
+ fieldType = arrayType->getElementType();
+ }
- BuildAggrIvarRecordLayout(FQT->getAs<RecordType>(),
- BytePos + FieldOffset,
- ForStrongLayout, HasUnion);
- continue;
- }
+ assert(!fieldType->isArrayType() && "ivar of non-constant array type?");
- 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();
- }
- if (FQT->isRecordType() && ElCount) {
- int OldIndex = IvarsInfo.size() - 1;
- int OldSkIndex = SkipIvars.size() -1;
+ // If we ended up with a zero-sized array, we've done what we can do within
+ // the limits of this layout encoding.
+ if (numElts == 0) return;
- const RecordType *RT = FQT->getAs<RecordType>();
- BuildAggrIvarRecordLayout(RT, BytePos + FieldOffset,
- ForStrongLayout, HasUnion);
+ // Recurse if the base element type is a record type.
+ if (auto recType = fieldType->getAs<RecordType>()) {
+ size_t oldEnd = IvarsInfo.size();
- // Replicate layout information for each array element. Note that
- // one element is already done.
- uint64_t ElIx = 1;
- for (int FirstIndex = IvarsInfo.size() - 1,
- FirstSkIndex = SkipIvars.size() - 1 ;ElIx < ElCount; ElIx++) {
- uint64_t Size = CGM.getContext().getTypeSize(RT)/ByteSizeInBits;
- for (int i = OldIndex+1; i <= FirstIndex; ++i)
- IvarsInfo.push_back(GC_IVAR(IvarsInfo[i].ivar_bytepos + Size*ElIx,
- IvarsInfo[i].ivar_size));
- for (int i = OldSkIndex+1; i <= FirstSkIndex; ++i)
- SkipIvars.push_back(GC_IVAR(SkipIvars[i].ivar_bytepos + Size*ElIx,
- SkipIvars[i].ivar_size));
- }
- continue;
- }
- }
- // At this point, we are done with Record/Union and array there of.
- // For other arrays we are down to its element type.
- Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), FQT);
-
- unsigned FieldSize = CGM.getContext().getTypeSize(Field->getType());
- if ((ForStrongLayout && GCAttr == Qualifiers::Strong)
- || (!ForStrongLayout && GCAttr == Qualifiers::Weak)) {
- if (IsUnion) {
- uint64_t UnionIvarSize = FieldSize / WordSizeInBits;
- if (UnionIvarSize > MaxUnionIvarSize) {
- MaxUnionIvarSize = UnionIvarSize;
- MaxField = Field;
- MaxFieldOffset = FieldOffset;
- }
- } else {
- IvarsInfo.push_back(GC_IVAR(BytePos + FieldOffset,
- FieldSize / WordSizeInBits));
- }
- } else if ((ForStrongLayout &&
- (GCAttr == Qualifiers::GCNone || GCAttr == Qualifiers::Weak))
- || (!ForStrongLayout && GCAttr != Qualifiers::Weak)) {
- if (IsUnion) {
- // FIXME: Why the asymmetry? We divide by word size in bits on other
- // side.
- uint64_t UnionIvarSize = FieldSize / ByteSizeInBits;
- if (UnionIvarSize > MaxSkippedUnionIvarSize) {
- MaxSkippedUnionIvarSize = UnionIvarSize;
- MaxSkippedField = Field;
- MaxSkippedFieldOffset = FieldOffset;
+ visitRecord(recType, fieldOffset);
+
+ // If we have an array, replicate the first entry's layout information.
+ auto numEltEntries = IvarsInfo.size() - oldEnd;
+ if (numElts != 1 && numEltEntries != 0) {
+ CharUnits eltSize = CGM.getContext().getTypeSizeInChars(recType);
+ for (uint64_t eltIndex = 1; eltIndex != numElts; ++eltIndex) {
+ // Copy the last numEltEntries onto the end of the array, adjusting
+ // each for the element size.
+ for (size_t i = 0; i != numEltEntries; ++i) {
+ auto firstEntry = IvarsInfo[oldEnd + i];
+ IvarsInfo.push_back(IvarInfo(firstEntry.Offset + eltIndex * eltSize,
+ firstEntry.SizeInWords));
}
- } else {
- // FIXME: Why the asymmetry, we divide by byte size in bits here?
- SkipIvars.push_back(GC_IVAR(BytePos + FieldOffset,
- FieldSize / ByteSizeInBits));
}
}
+
+ return;
}
- if (LastFieldBitfieldOrUnnamed) {
- if (LastFieldBitfieldOrUnnamed->isBitField()) {
- // Last field was a bitfield. Must update skip info.
- uint64_t BitFieldSize
- = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext());
- GC_IVAR skivar;
- skivar.ivar_bytepos = BytePos + LastBitfieldOrUnnamedOffset;
- skivar.ivar_size = (BitFieldSize / ByteSizeInBits)
- + ((BitFieldSize % ByteSizeInBits) != 0);
- SkipIvars.push_back(skivar);
- } else {
- assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed");
- // Last field was unnamed. Must update skip info.
- unsigned FieldSize
- = CGM.getContext().getTypeSize(LastFieldBitfieldOrUnnamed->getType());
- SkipIvars.push_back(GC_IVAR(BytePos + LastBitfieldOrUnnamedOffset,
- FieldSize / ByteSizeInBits));
- }
+ // Classify the element type.
+ Qualifiers::GC GCAttr = GetGCAttrTypeForType(CGM.getContext(), fieldType);
+
+ // If it matches what we're looking for, add an entry.
+ if ((ForStrongLayout && GCAttr == Qualifiers::Strong)
+ || (!ForStrongLayout && GCAttr == Qualifiers::Weak)) {
+ assert(CGM.getContext().getTypeSizeInChars(fieldType)
+ == CGM.getPointerSize());
+ IvarsInfo.push_back(IvarInfo(fieldOffset, numElts));
}
+}
- if (MaxField)
- IvarsInfo.push_back(GC_IVAR(BytePos + MaxFieldOffset,
- MaxUnionIvarSize));
- if (MaxSkippedField)
- SkipIvars.push_back(GC_IVAR(BytePos + MaxSkippedFieldOffset,
- MaxSkippedUnionIvarSize));
-}
-
-/// BuildIvarLayoutBitmap - This routine is the horsework for doing all
-/// the computations and returning the layout bitmap (for ivar or blocks) in
-/// the given argument BitMap string container. Routine reads
-/// two containers, IvarsInfo and SkipIvars which are assumed to be
-/// filled already by the caller.
-llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) {
- unsigned int WordsToScan, WordsToSkip;
- llvm::Type *PtrTy = CGM.Int8PtrTy;
-
- // Build the string of skip/scan nibbles
- SmallVector<SKIP_SCAN, 32> SkipScanIvars;
- unsigned int WordSize =
- CGM.getTypes().getDataLayout().getTypeAllocSize(PtrTy);
- if (IvarsInfo[0].ivar_bytepos == 0) {
- WordsToSkip = 0;
- WordsToScan = IvarsInfo[0].ivar_size;
+/// buildBitmap - This routine does the horsework of taking the offsets of
+/// strong/weak references and creating a bitmap. The bitmap is also
+/// returned in the given buffer, suitable for being passed to \c dump().
+llvm::Constant *IvarLayoutBuilder::buildBitmap(CGObjCCommonMac &CGObjC,
+ llvm::SmallVectorImpl<unsigned char> &buffer) {
+ // The bitmap is a series of skip/scan instructions, aligned to word
+ // boundaries. The skip is performed first.
+ const unsigned char MaxNibble = 0xF;
+ const unsigned char SkipMask = 0xF0, SkipShift = 4;
+ const unsigned char ScanMask = 0x0F, ScanShift = 0;
+
+ assert(!IvarsInfo.empty() && "generating bitmap for no data");
+
+ // Sort the ivar info on byte position in case we encounterred a
+ // union nested in the ivar list.
+ if (IsDisordered) {
+ // This isn't a stable sort, but our algorithm should handle it fine.
+ llvm::array_pod_sort(IvarsInfo.begin(), IvarsInfo.end());
} else {
- WordsToSkip = IvarsInfo[0].ivar_bytepos/WordSize;
- WordsToScan = IvarsInfo[0].ivar_size;
- }
- for (unsigned int i=1, Last=IvarsInfo.size(); i != Last; i++) {
- unsigned int TailPrevGCObjC =
- IvarsInfo[i-1].ivar_bytepos + IvarsInfo[i-1].ivar_size * WordSize;
- if (IvarsInfo[i].ivar_bytepos == TailPrevGCObjC) {
- // consecutive 'scanned' object pointers.
- WordsToScan += IvarsInfo[i].ivar_size;
- } else {
- // Skip over 'gc'able object pointer which lay over each other.
- if (TailPrevGCObjC > IvarsInfo[i].ivar_bytepos)
- continue;
- // Must skip over 1 or more words. We save current skip/scan values
- // and start a new pair.
- SKIP_SCAN SkScan;
- SkScan.skip = WordsToSkip;
- SkScan.scan = WordsToScan;
- SkipScanIvars.push_back(SkScan);
-
- // Skip the hole.
- SkScan.skip = (IvarsInfo[i].ivar_bytepos - TailPrevGCObjC) / WordSize;
- SkScan.scan = 0;
- SkipScanIvars.push_back(SkScan);
- WordsToSkip = 0;
- WordsToScan = IvarsInfo[i].ivar_size;
+#ifndef NDEBUG
+ for (unsigned i = 1; i != IvarsInfo.size(); ++i) {
+ assert(IvarsInfo[i - 1].Offset <= IvarsInfo[i].Offset);
}
+#endif
}
- if (WordsToScan > 0) {
- SKIP_SCAN SkScan;
- SkScan.skip = WordsToSkip;
- SkScan.scan = WordsToScan;
- SkipScanIvars.push_back(SkScan);
- }
-
- if (!SkipIvars.empty()) {
- unsigned int LastIndex = SkipIvars.size()-1;
- int LastByteSkipped =
- SkipIvars[LastIndex].ivar_bytepos + SkipIvars[LastIndex].ivar_size;
- LastIndex = IvarsInfo.size()-1;
- int LastByteScanned =
- IvarsInfo[LastIndex].ivar_bytepos +
- IvarsInfo[LastIndex].ivar_size * WordSize;
- // Compute number of bytes to skip at the tail end of the last ivar scanned.
- if (LastByteSkipped > LastByteScanned) {
- unsigned int TotalWords = (LastByteSkipped + (WordSize -1)) / WordSize;
- SKIP_SCAN SkScan;
- SkScan.skip = TotalWords - (LastByteScanned/WordSize);
- SkScan.scan = 0;
- SkipScanIvars.push_back(SkScan);
+ assert(IvarsInfo.back().Offset < InstanceEnd);
+
+ assert(buffer.empty());
+
+ // Skip the next N words.
+ auto skip = [&](unsigned numWords) {
+ assert(numWords > 0);
+
+ // Try to merge into the previous byte. Since scans happen second, we
+ // can't do this if it includes a scan.
+ if (!buffer.empty() && !(buffer.back() & ScanMask)) {
+ unsigned lastSkip = buffer.back() >> SkipShift;
+ if (lastSkip < MaxNibble) {
+ unsigned claimed = std::min(MaxNibble - lastSkip, numWords);
+ numWords -= claimed;
+ lastSkip += claimed;
+ buffer.back() = (lastSkip << SkipShift);
+ }
}
- }
- // Mini optimization of nibbles such that an 0xM0 followed by 0x0N is produced
- // as 0xMN.
- int SkipScan = SkipScanIvars.size()-1;
- for (int i = 0; i <= SkipScan; i++) {
- if ((i < SkipScan) && SkipScanIvars[i].skip && SkipScanIvars[i].scan == 0
- && SkipScanIvars[i+1].skip == 0 && SkipScanIvars[i+1].scan) {
- // 0xM0 followed by 0x0N detected.
- SkipScanIvars[i].scan = SkipScanIvars[i+1].scan;
- for (int j = i+1; j < SkipScan; j++)
- SkipScanIvars[j] = SkipScanIvars[j+1];
- --SkipScan;
+
+ while (numWords >= MaxNibble) {
+ buffer.push_back(MaxNibble << SkipShift);
+ numWords -= MaxNibble;
}
- }
-
- // Generate the string.
- for (int i = 0; i <= SkipScan; i++) {
- unsigned char byte;
- unsigned int skip_small = SkipScanIvars[i].skip % 0xf;
- unsigned int scan_small = SkipScanIvars[i].scan % 0xf;
- unsigned int skip_big = SkipScanIvars[i].skip / 0xf;
- unsigned int scan_big = SkipScanIvars[i].scan / 0xf;
-
- // first skip big.
- for (unsigned int ix = 0; ix < skip_big; ix++)
- BitMap += (unsigned char)(0xf0);
-
- // next (skip small, scan)
- if (skip_small) {
- byte = skip_small << 4;
- if (scan_big > 0) {
- byte |= 0xf;
- --scan_big;
- } else if (scan_small) {
- byte |= scan_small;
- scan_small = 0;
+ if (numWords) {
+ buffer.push_back(numWords << SkipShift);
+ }
+ };
+
+ // Scan the next N words.
+ auto scan = [&](unsigned numWords) {
+ assert(numWords > 0);
+
+ // Try to merge into the previous byte. Since scans happen second, we can
+ // do this even if it includes a skip.
+ if (!buffer.empty()) {
+ unsigned lastScan = (buffer.back() & ScanMask) >> ScanShift;
+ if (lastScan < MaxNibble) {
+ unsigned claimed = std::min(MaxNibble - lastScan, numWords);
+ numWords -= claimed;
+ lastScan += claimed;
+ buffer.back() = (buffer.back() & SkipMask) | (lastScan << ScanShift);
}
- BitMap += byte;
}
- // next scan big
- for (unsigned int ix = 0; ix < scan_big; ix++)
- BitMap += (unsigned char)(0x0f);
- // last scan small
- if (scan_small) {
- byte = scan_small;
- BitMap += byte;
+
+ while (numWords >= MaxNibble) {
+ buffer.push_back(MaxNibble << ScanShift);
+ numWords -= MaxNibble;
+ }
+ if (numWords) {
+ buffer.push_back(numWords << ScanShift);
+ }
+ };
+
+ // One past the end of the last scan.
+ unsigned endOfLastScanInWords = 0;
+ const CharUnits WordSize = CGM.getPointerSize();
+
+ // Consider all the scan requests.
+ for (auto &request : IvarsInfo) {
+ CharUnits beginOfScan = request.Offset - InstanceBegin;
+
+ // Ignore scan requests that don't start at an even multiple of the
+ // word size. We can't encode them.
+ if ((beginOfScan % WordSize) != 0) continue;
+
+ // Ignore scan requests that start before the instance start.
+ // This assumes that scans never span that boundary. The boundary
+ // isn't the true start of the ivars, because in the fragile-ARC case
+ // it's rounded up to word alignment, but the test above should leave
+ // us ignoring that possibility.
+ if (beginOfScan.isNegative()) {
+ assert(request.Offset + request.SizeInWords * WordSize <= InstanceBegin);
+ continue;
}
+
+ unsigned beginOfScanInWords = beginOfScan / WordSize;
+ unsigned endOfScanInWords = beginOfScanInWords + request.SizeInWords;
+
+ // If the scan starts some number of words after the last one ended,
+ // skip forward.
+ if (beginOfScanInWords > endOfLastScanInWords) {
+ skip(beginOfScanInWords - endOfLastScanInWords);
+
+ // Otherwise, start scanning where the last left off.
+ } else {
+ beginOfScanInWords = endOfLastScanInWords;
+
+ // If that leaves us with nothing to scan, ignore this request.
+ if (beginOfScanInWords >= endOfScanInWords) continue;
+ }
+
+ // Scan to the end of the request.
+ assert(beginOfScanInWords < endOfScanInWords);
+ scan(endOfScanInWords - beginOfScanInWords);
+ endOfLastScanInWords = endOfScanInWords;
}
- // null terminate string.
- unsigned char zero = 0;
- BitMap += zero;
- llvm::GlobalVariable *Entry = CreateMetadataVar(
+ if (buffer.empty())
+ return llvm::ConstantPointerNull::get(CGM.Int8PtrTy);
+
+ // For GC layouts, emit a skip to the end of the allocation so that we
+ // have precise information about the entire thing. This isn't useful
+ // or necessary for the ARC-style layout strings.
+ if (CGM.getLangOpts().getGC() != LangOptions::NonGC) {
+ unsigned lastOffsetInWords =
+ (InstanceEnd - InstanceBegin + WordSize - CharUnits::One()) / WordSize;
+ if (lastOffsetInWords > endOfLastScanInWords) {
+ skip(lastOffsetInWords - endOfLastScanInWords);
+ }
+ }
+
+ // Null terminate the string.
+ buffer.push_back(0);
+
+ bool isNonFragileABI = CGObjC.isNonFragileABI();
+
+ llvm::GlobalVariable *Entry = CGObjC.CreateMetadataVar(
"OBJC_CLASS_NAME_",
- llvm::ConstantDataArray::getString(VMContext, BitMap, false),
- ((ObjCABI == 2) ? "__TEXT,__objc_classname,cstring_literals"
- : "__TEXT,__cstring,cstring_literals"),
- 1, true);
- return getConstantGEP(VMContext, Entry, 0, 0);
+ llvm::ConstantDataArray::get(CGM.getLLVMContext(), buffer),
+ (isNonFragileABI ? "__TEXT,__objc_classname,cstring_literals"
+ : "__TEXT,__cstring,cstring_literals"),
+ CharUnits::One(), true);
+ return getConstantGEP(CGM.getLLVMContext(), Entry, 0, 0);
}
/// BuildIvarLayout - Builds ivar layout bitmap for the class
@@ -4755,62 +4918,75 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) {
/// 2. When ForStrongLayout is false, following ivars are scanned:
/// - __weak anything
///
-llvm::Constant *CGObjCCommonMac::BuildIvarLayout(
- const ObjCImplementationDecl *OMD,
- bool ForStrongLayout) {
- bool hasUnion = false;
-
+llvm::Constant *
+CGObjCCommonMac::BuildIvarLayout(const ObjCImplementationDecl *OMD,
+ CharUnits beginOffset, CharUnits endOffset,
+ bool ForStrongLayout, bool HasMRCWeakIvars) {
+ // If this is MRC, and we're either building a strong layout or there
+ // are no weak ivars, bail out early.
llvm::Type *PtrTy = CGM.Int8PtrTy;
if (CGM.getLangOpts().getGC() == LangOptions::NonGC &&
- !CGM.getLangOpts().ObjCAutoRefCount)
+ !CGM.getLangOpts().ObjCAutoRefCount &&
+ (ForStrongLayout || !HasMRCWeakIvars))
return llvm::Constant::getNullValue(PtrTy);
const ObjCInterfaceDecl *OI = OMD->getClassInterface();
- SmallVector<const FieldDecl*, 32> RecFields;
- if (CGM.getLangOpts().ObjCAutoRefCount) {
+ SmallVector<const ObjCIvarDecl*, 32> ivars;
+
+ // GC layout strings include the complete object layout, possibly
+ // inaccurately in the non-fragile ABI; the runtime knows how to fix this
+ // up.
+ //
+ // ARC layout strings only include the class's ivars. In non-fragile
+ // runtimes, that means starting at InstanceStart, rounded up to word
+ // alignment. In fragile runtimes, there's no InstanceStart, so it means
+ // starting at the offset of the first ivar, rounded up to word alignment.
+ //
+ // MRC weak layout strings follow the ARC style.
+ CharUnits baseOffset;
+ if (CGM.getLangOpts().getGC() == LangOptions::NonGC) {
for (const ObjCIvarDecl *IVD = OI->all_declared_ivar_begin();
IVD; IVD = IVD->getNextIvar())
- RecFields.push_back(cast<FieldDecl>(IVD));
+ ivars.push_back(IVD);
+
+ if (isNonFragileABI()) {
+ baseOffset = beginOffset; // InstanceStart
+ } else if (!ivars.empty()) {
+ baseOffset =
+ CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivars[0]));
+ } else {
+ baseOffset = CharUnits::Zero();
+ }
+
+ baseOffset = baseOffset.RoundUpToAlignment(CGM.getPointerAlign());
}
else {
- SmallVector<const ObjCIvarDecl*, 32> Ivars;
- CGM.getContext().DeepCollectObjCIvars(OI, true, Ivars);
+ CGM.getContext().DeepCollectObjCIvars(OI, true, ivars);
- // FIXME: This is not ideal; we shouldn't have to do this copy.
- RecFields.append(Ivars.begin(), Ivars.end());
+ baseOffset = CharUnits::Zero();
}
- if (RecFields.empty())
+ if (ivars.empty())
return llvm::Constant::getNullValue(PtrTy);
- SkipIvars.clear();
- IvarsInfo.clear();
+ IvarLayoutBuilder builder(CGM, baseOffset, endOffset, ForStrongLayout);
+
+ builder.visitAggregate(ivars.begin(), ivars.end(), CharUnits::Zero(),
+ [&](const ObjCIvarDecl *ivar) -> CharUnits {
+ return CharUnits::fromQuantity(ComputeIvarBaseOffset(CGM, OMD, ivar));
+ });
- BuildAggrIvarLayout(OMD, nullptr, nullptr, RecFields, 0, ForStrongLayout,
- hasUnion);
- if (IvarsInfo.empty())
+ if (!builder.hasBitmapData())
return llvm::Constant::getNullValue(PtrTy);
- // Sort on byte position in case we encounterred a union nested in
- // the ivar list.
- if (hasUnion && !IvarsInfo.empty())
- std::sort(IvarsInfo.begin(), IvarsInfo.end());
- if (hasUnion && !SkipIvars.empty())
- std::sort(SkipIvars.begin(), SkipIvars.end());
-
- std::string BitMap;
- llvm::Constant *C = BuildIvarLayoutBitmap(BitMap);
+
+ llvm::SmallVector<unsigned char, 4> buffer;
+ llvm::Constant *C = builder.buildBitmap(*this, buffer);
- if (CGM.getLangOpts().ObjCGCBitmapPrint) {
+ if (CGM.getLangOpts().ObjCGCBitmapPrint && !buffer.empty()) {
printf("\n%s ivar layout for class '%s': ",
ForStrongLayout ? "strong" : "weak",
OMD->getClassInterface()->getName().str().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 ? ", " : "");
- else
- printf("0x%x%s", s[i], s[i] != 0 ? ", " : "");
- printf("\n");
+ builder.dump(buffer);
}
return C;
}
@@ -4825,7 +5001,7 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) {
llvm::ConstantDataArray::getString(VMContext, Sel.getAsString()),
((ObjCABI == 2) ? "__TEXT,__objc_methname,cstring_literals"
: "__TEXT,__cstring,cstring_literals"),
- 1, true);
+ CharUnits::One(), true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4847,7 +5023,7 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) {
llvm::ConstantDataArray::getString(VMContext, TypeStr),
((ObjCABI == 2) ? "__TEXT,__objc_methtype,cstring_literals"
: "__TEXT,__cstring,cstring_literals"),
- 1, true);
+ CharUnits::One(), true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4866,7 +5042,7 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D,
llvm::ConstantDataArray::getString(VMContext, TypeStr),
((ObjCABI == 2) ? "__TEXT,__objc_methtype,cstring_literals"
: "__TEXT,__cstring,cstring_literals"),
- 1, true);
+ CharUnits::One(), true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -4879,7 +5055,7 @@ llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) {
Entry = CreateMetadataVar(
"OBJC_PROP_NAME_ATTR_",
llvm::ConstantDataArray::getString(VMContext, Ident->getName()),
- "__TEXT,__cstring,cstring_literals", 1, true);
+ "__TEXT,__cstring,cstring_literals", CharUnits::One(), true);
return getConstantGEP(VMContext, Entry, 0, 0);
}
@@ -5583,8 +5759,14 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
std::string ClassName = ID->getObjCRuntimeNameAsString();
llvm::Constant *Values[10]; // 11 for 64bit targets!
+ CharUnits beginInstance = CharUnits::fromQuantity(InstanceStart);
+ CharUnits endInstance = CharUnits::fromQuantity(InstanceSize);
+
+ bool hasMRCWeak = false;
if (CGM.getLangOpts().ObjCAutoRefCount)
flags |= NonFragileABI_Class_CompiledByARC;
+ else if ((hasMRCWeak = hasMRCWeakIvars(CGM, ID)))
+ flags |= NonFragileABI_Class_HasMRCWeakIvars;
Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags);
Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart);
@@ -5592,7 +5774,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
// FIXME. For 64bit targets add 0 here.
Values[ 3] = (flags & NonFragileABI_Class_Meta)
? GetIvarLayoutName(nullptr, ObjCTypes)
- : BuildIvarLayout(ID, true);
+ : BuildStrongIvarLayout(ID, beginInstance, endInstance);
Values[ 4] = GetClassName(ID->getObjCRuntimeNameAsString());
// const struct _method_list_t * const baseMethods;
std::vector<llvm::Constant*> Methods;
@@ -5639,7 +5821,8 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer(
Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy);
} else {
Values[ 7] = EmitIvarList(ID);
- Values[ 8] = BuildIvarLayout(ID, false);
+ Values[ 8] = BuildWeakIvarLayout(ID, beginInstance, endInstance,
+ hasMRCWeak);
Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(),
ID, ID->getClassInterface(), ObjCTypes);
}
@@ -5731,7 +5914,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
// Make this entry NULL for any iOS device target, any iOS simulator target,
// OS X with deployment target 10.9 or later.
const llvm::Triple &Triple = CGM.getTarget().getTriple();
- if (Triple.isiOS() || (Triple.isMacOSX() && !Triple.isMacOSXVersionLT(10, 9)))
+ if (Triple.isiOS() || Triple.isWatchOS() ||
+ (Triple.isMacOSX() && !Triple.isMacOSXVersionLT(10, 9)))
// This entry will be null.
ObjCEmptyVtableVar = nullptr;
else
@@ -5887,9 +6071,11 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
std::string ProtocolName("\01l_OBJC_PROTOCOL_REFERENCE_$_");
ProtocolName += PD->getObjCRuntimeNameAsString();
+ CharUnits Align = CGF.getPointerAlign();
+
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
- return CGF.Builder.CreateLoad(PTGV);
+ return CGF.Builder.CreateAlignedLoad(PTGV, Align);
PTGV = new llvm::GlobalVariable(
CGM.getModule(),
Init->getType(), false,
@@ -5898,8 +6084,9 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CodeGenFunction &CGF,
ProtocolName);
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ PTGV->setAlignment(Align.getQuantity());
CGM.addCompilerUsedGlobal(PTGV);
- return CGF.Builder.CreateLoad(PTGV);
+ return CGF.Builder.CreateAlignedLoad(PTGV, Align);
}
/// GenerateCategory - Build metadata for a category implementation.
@@ -6428,7 +6615,8 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
llvm::Value *IvarOffsetValue = ObjCIvarOffsetVariable(Interface, Ivar);
- IvarOffsetValue = CGF.Builder.CreateLoad(IvarOffsetValue, "ivar");
+ IvarOffsetValue = CGF.Builder.CreateAlignedLoad(IvarOffsetValue,
+ CGF.getSizeAlign(), "ivar");
if (IsIvarOffsetKnownIdempotent(CGF, Ivar))
cast<llvm::LoadInst>(IvarOffsetValue)
->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
@@ -6559,16 +6747,17 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF,
}
}
- llvm::Value *mref =
- CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy);
+ Address mref =
+ Address(CGF.Builder.CreateBitCast(messageRef, ObjCTypes.MessageRefPtrTy),
+ CGF.getPointerAlign());
// Update the message ref argument.
- args[1].RV = RValue::get(mref);
+ args[1].RV = RValue::get(mref.getPointer());
// Load the function to call from the message ref table.
- llvm::Value *callee =
- CGF.Builder.CreateStructGEP(ObjCTypes.MessageRefTy, mref, 0);
- callee = CGF.Builder.CreateLoad(callee, "msgSend_fn");
+ Address calleeAddr =
+ CGF.Builder.CreateStructGEP(mref, 0, CharUnits::Zero());
+ llvm::Value *callee = CGF.Builder.CreateLoad(calleeAddr, "msgSend_fn");
callee = CGF.Builder.CreateBitCast(callee, MSI.MessengerType);
@@ -6594,7 +6783,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
: EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF, Sel),
Receiver, CGF.getContext().getObjCIdType(),
- false, CallArgs, Method, ObjCTypes);
+ false, CallArgs, Method, Class, ObjCTypes);
}
llvm::GlobalVariable *
@@ -6617,6 +6806,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
IdentifierInfo *II,
bool Weak,
const ObjCInterfaceDecl *ID) {
+ CharUnits Align = CGF.getPointerAlign();
llvm::GlobalVariable *&Entry = ClassReferences[II];
if (!Entry) {
@@ -6627,13 +6817,11 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF,
Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
false, llvm::GlobalValue::PrivateLinkage,
ClassGV, "OBJC_CLASSLIST_REFERENCES_$_");
- Entry->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(
- ObjCTypes.ClassnfABIPtrTy));
+ Entry->setAlignment(Align.getQuantity());
Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip");
CGM.addCompilerUsedGlobal(Entry);
}
- return CGF.Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateAlignedLoad(Entry, Align);
}
llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
@@ -6644,12 +6832,13 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF,
llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef(
CodeGenFunction &CGF) {
IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool");
- return EmitClassRefFromId(CGF, II, false, 0);
+ return EmitClassRefFromId(CGF, II, false, nullptr);
}
llvm::Value *
CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID) {
+ CharUnits Align = CGF.getPointerAlign();
llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()];
if (!Entry) {
@@ -6660,13 +6849,11 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
false, llvm::GlobalValue::PrivateLinkage,
ClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
- Entry->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(
- ObjCTypes.ClassnfABIPtrTy));
+ Entry->setAlignment(Align.getQuantity());
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.addCompilerUsedGlobal(Entry);
}
- return CGF.Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateAlignedLoad(Entry, Align);
}
/// EmitMetaClassRef - Return a Value * of the address of _class_t
@@ -6675,6 +6862,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF,
llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
const ObjCInterfaceDecl *ID,
bool Weak) {
+ CharUnits Align = CGF.getPointerAlign();
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
if (!Entry) {
llvm::SmallString<64> MetaClassName(getMetaclassSymbolPrefix());
@@ -6685,14 +6873,13 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF,
Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy,
false, llvm::GlobalValue::PrivateLinkage,
MetaClassGV, "OBJC_CLASSLIST_SUP_REFS_$_");
- Entry->setAlignment(
- CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABIPtrTy));
+ Entry->setAlignment(Align.getQuantity());
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.addCompilerUsedGlobal(Entry);
}
- return CGF.Builder.CreateLoad(Entry);
+ return CGF.Builder.CreateAlignedLoad(Entry, Align);
}
/// GetClass - Return a reference to the class for the given interface
@@ -6727,14 +6914,15 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
// ...
// Create and init a super structure; this is a (receiver, class)
// pair we will pass to objc_msgSendSuper.
- llvm::Value *ObjCSuper =
- CGF.CreateTempAlloca(ObjCTypes.SuperTy, "objc_super");
+ Address ObjCSuper =
+ CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(),
+ "objc_super");
llvm::Value *ReceiverAsObject =
CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy);
CGF.Builder.CreateStore(
ReceiverAsObject,
- CGF.Builder.CreateStructGEP(ObjCTypes.SuperTy, ObjCSuper, 0));
+ CGF.Builder.CreateStructGEP(ObjCSuper, 0, CharUnits::Zero()));
// If this is a class message the metaclass is passed as the target.
llvm::Value *Target;
@@ -6749,22 +6937,33 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType());
Target = CGF.Builder.CreateBitCast(Target, ClassTy);
CGF.Builder.CreateStore(
- Target, CGF.Builder.CreateStructGEP(ObjCTypes.SuperTy, ObjCSuper, 1));
+ Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1, CGF.getPointerSize()));
return (isVTableDispatchedSelector(Sel))
? EmitVTableMessageSend(CGF, Return, ResultType, Sel,
- ObjCSuper, ObjCTypes.SuperPtrCTy,
+ ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
true, CallArgs, Method)
: EmitMessageSend(CGF, Return, ResultType,
EmitSelector(CGF, Sel),
- ObjCSuper, ObjCTypes.SuperPtrCTy,
- true, CallArgs, Method, ObjCTypes);
+ ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy,
+ true, CallArgs, Method, Class, ObjCTypes);
}
llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
- Selector Sel, bool lval) {
+ Selector Sel) {
+ Address Addr = EmitSelectorAddr(CGF, Sel);
+
+ llvm::LoadInst* LI = CGF.Builder.CreateLoad(Addr);
+ LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
+ llvm::MDNode::get(VMContext, None));
+ return LI;
+}
+
+Address CGObjCNonFragileABIMac::EmitSelectorAddr(CodeGenFunction &CGF,
+ Selector Sel) {
llvm::GlobalVariable *&Entry = SelectorReferences[Sel];
+ CharUnits Align = CGF.getPointerAlign();
if (!Entry) {
llvm::Constant *Casted =
llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel),
@@ -6774,23 +6973,19 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF,
Casted, "OBJC_SELECTOR_REFERENCES_");
Entry->setExternallyInitialized(true);
Entry->setSection("__DATA, __objc_selrefs, literal_pointers, no_dead_strip");
+ Entry->setAlignment(Align.getQuantity());
CGM.addCompilerUsedGlobal(Entry);
}
- if (lval)
- return Entry;
- llvm::LoadInst* LI = CGF.Builder.CreateLoad(Entry);
-
- LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"),
- llvm::MDNode::get(VMContext, None));
- return LI;
+ return Address(Entry, Align);
}
+
/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
/// objc_assign_ivar (id src, id *dst, ptrdiff_t)
///
void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
llvm::Value *src,
- llvm::Value *dst,
+ Address dst,
llvm::Value *ivarOffset) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
@@ -6802,7 +6997,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst, ivarOffset };
+ llvm::Value *args[] = { src, dst.getPointer(), ivarOffset };
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args);
}
@@ -6811,7 +7006,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF,
///
void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst) {
+ llvm::Value *src, Address dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
@@ -6822,19 +7017,19 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign(
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst };
+ llvm::Value *args[] = { src, dst.getPointer() };
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(),
args, "weakassign");
}
void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
CodeGen::CodeGenFunction &CGF,
- llvm::Value *DestPtr,
- llvm::Value *SrcPtr,
+ Address DestPtr,
+ Address SrcPtr,
llvm::Value *Size) {
SrcPtr = CGF.Builder.CreateBitCast(SrcPtr, ObjCTypes.Int8PtrTy);
DestPtr = CGF.Builder.CreateBitCast(DestPtr, ObjCTypes.Int8PtrTy);
- llvm::Value *args[] = { DestPtr, SrcPtr, Size };
+ llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), Size };
CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args);
}
@@ -6843,13 +7038,12 @@ void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable(
///
llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
CodeGen::CodeGenFunction &CGF,
- llvm::Value *AddrWeakObj) {
- llvm::Type* DestTy =
- cast<llvm::PointerType>(AddrWeakObj->getType())->getElementType();
+ Address AddrWeakObj) {
+ llvm::Type *DestTy = AddrWeakObj.getElementType();
AddrWeakObj = CGF.Builder.CreateBitCast(AddrWeakObj, ObjCTypes.PtrObjectPtrTy);
llvm::Value *read_weak =
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(),
- AddrWeakObj, "weakread");
+ AddrWeakObj.getPointer(), "weakread");
read_weak = CGF.Builder.CreateBitCast(read_weak, DestTy);
return read_weak;
}
@@ -6858,7 +7052,7 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead(
/// objc_assign_weak (id src, id *dst)
///
void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst) {
+ llvm::Value *src, Address dst) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy);
@@ -6869,7 +7063,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst };
+ llvm::Value *args[] = { src, dst.getPointer() };
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(),
args, "weakassign");
}
@@ -6878,7 +7072,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF,
/// objc_assign_global (id src, id *dst)
///
void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
- llvm::Value *src, llvm::Value *dst,
+ llvm::Value *src, Address dst,
bool threadlocal) {
llvm::Type * SrcTy = src->getType();
if (!isa<llvm::PointerType>(SrcTy)) {
@@ -6890,7 +7084,7 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF,
}
src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy);
dst = CGF.Builder.CreateBitCast(dst, ObjCTypes.PtrObjectPtrTy);
- llvm::Value *args[] = { src, dst };
+ llvm::Value *args[] = { src, dst.getPointer() };
if (!threadlocal)
CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(),
args, "globalassign");
@@ -7043,6 +7237,7 @@ CodeGen::CreateMacObjCRuntime(CodeGen::CodeGenModule &CGM) {
case ObjCRuntime::MacOSX:
case ObjCRuntime::iOS:
+ case ObjCRuntime::WatchOS:
return new CGObjCNonFragileABIMac(CGM);
case ObjCRuntime::GNUstep:
OpenPOWER on IntegriCloud