diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp | 1419 |
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: |