diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp | 2207 |
1 files changed, 1211 insertions, 996 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp index 5ab9fc4..7219592 100644 --- a/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp +++ b/contrib/llvm/tools/clang/lib/CodeGen/CGObjCMac.cpp @@ -11,12 +11,13 @@ // //===----------------------------------------------------------------------===// -#include "CGObjCRuntime.h" #include "CGBlocks.h" #include "CGCleanup.h" +#include "CGObjCRuntime.h" #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "ConstantBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -25,6 +26,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/Frontend/CodeGenOptions.h" +#include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -172,18 +174,18 @@ protected: CodeGen::CodeGenModule &CGM; public: - llvm::Type *ShortTy, *IntTy, *LongTy, *LongLongTy; - llvm::Type *Int8PtrTy, *Int8PtrPtrTy; + llvm::IntegerType *ShortTy, *IntTy, *LongTy; + llvm::PointerType *Int8PtrTy, *Int8PtrPtrTy; llvm::Type *IvarOffsetVarTy; /// ObjectPtrTy - LLVM type for object handles (typeof(id)) - llvm::Type *ObjectPtrTy; + llvm::PointerType *ObjectPtrTy; /// PtrObjectPtrTy - LLVM type for id * - llvm::Type *PtrObjectPtrTy; + llvm::PointerType *PtrObjectPtrTy; /// SelectorPtrTy - LLVM type for selector handles (typeof(SEL)) - llvm::Type *SelectorPtrTy; + llvm::PointerType *SelectorPtrTy; private: /// ProtocolPtrTy - LLVM type for external protocol handles @@ -212,7 +214,7 @@ public: /// SuperTy - LLVM type for struct objc_super. llvm::StructType *SuperTy; /// SuperPtrTy - LLVM type for struct objc_super *. - llvm::Type *SuperPtrTy; + llvm::PointerType *SuperPtrTy; /// PropertyTy - LLVM type for struct objc_property (struct _prop_t /// in GCC parlance). @@ -222,7 +224,7 @@ public: /// (_prop_list_t in GCC parlance). llvm::StructType *PropertyListTy; /// PropertyListPtrTy - LLVM type for struct objc_property_list*. - llvm::Type *PropertyListPtrTy; + llvm::PointerType *PropertyListPtrTy; // MethodTy - LLVM type for struct objc_method. llvm::StructType *MethodTy; @@ -230,7 +232,7 @@ public: /// CacheTy - LLVM type for struct objc_cache. llvm::Type *CacheTy; /// CachePtrTy - LLVM type for struct objc_cache *. - llvm::Type *CachePtrTy; + llvm::PointerType *CachePtrTy; llvm::Constant *getGetPropertyFn() { CodeGen::CodeGenTypes &Types = CGM.getTypes(); @@ -500,20 +502,20 @@ public: /// SymtabTy - LLVM type for struct objc_symtab. llvm::StructType *SymtabTy; /// SymtabPtrTy - LLVM type for struct objc_symtab *. - llvm::Type *SymtabPtrTy; + llvm::PointerType *SymtabPtrTy; /// ModuleTy - LLVM type for struct objc_module. llvm::StructType *ModuleTy; /// ProtocolTy - LLVM type for struct objc_protocol. llvm::StructType *ProtocolTy; /// ProtocolPtrTy - LLVM type for struct objc_protocol *. - llvm::Type *ProtocolPtrTy; + llvm::PointerType *ProtocolPtrTy; /// ProtocolExtensionTy - LLVM type for struct /// objc_protocol_extension. llvm::StructType *ProtocolExtensionTy; /// ProtocolExtensionTy - LLVM type for struct /// objc_protocol_extension *. - llvm::Type *ProtocolExtensionPtrTy; + llvm::PointerType *ProtocolExtensionPtrTy; /// MethodDescriptionTy - LLVM type for struct /// objc_method_description. llvm::StructType *MethodDescriptionTy; @@ -522,34 +524,34 @@ public: llvm::StructType *MethodDescriptionListTy; /// MethodDescriptionListPtrTy - LLVM type for struct /// objc_method_description_list *. - llvm::Type *MethodDescriptionListPtrTy; + llvm::PointerType *MethodDescriptionListPtrTy; /// ProtocolListTy - LLVM type for struct objc_property_list. llvm::StructType *ProtocolListTy; /// ProtocolListPtrTy - LLVM type for struct objc_property_list*. - llvm::Type *ProtocolListPtrTy; + llvm::PointerType *ProtocolListPtrTy; /// CategoryTy - LLVM type for struct objc_category. llvm::StructType *CategoryTy; /// ClassTy - LLVM type for struct objc_class. llvm::StructType *ClassTy; /// ClassPtrTy - LLVM type for struct objc_class *. - llvm::Type *ClassPtrTy; + llvm::PointerType *ClassPtrTy; /// ClassExtensionTy - LLVM type for struct objc_class_ext. llvm::StructType *ClassExtensionTy; /// ClassExtensionPtrTy - LLVM type for struct objc_class_ext *. - llvm::Type *ClassExtensionPtrTy; + llvm::PointerType *ClassExtensionPtrTy; // IvarTy - LLVM type for struct objc_ivar. llvm::StructType *IvarTy; /// IvarListTy - LLVM type for struct objc_ivar_list. - llvm::Type *IvarListTy; + llvm::StructType *IvarListTy; /// IvarListPtrTy - LLVM type for struct objc_ivar_list *. - llvm::Type *IvarListPtrTy; + llvm::PointerType *IvarListPtrTy; /// MethodListTy - LLVM type for struct objc_method_list. - llvm::Type *MethodListTy; + llvm::StructType *MethodListTy; /// MethodListPtrTy - LLVM type for struct objc_method_list *. - llvm::Type *MethodListPtrTy; + llvm::PointerType *MethodListPtrTy; /// ExceptionDataTy - LLVM type for struct _objc_exception_data. - llvm::Type *ExceptionDataTy; + llvm::StructType *ExceptionDataTy; /// ExceptionTryEnterFn - LLVM objc_exception_try_enter function. llvm::Constant *getExceptionTryEnterFn() { @@ -608,25 +610,25 @@ public: llvm::StructType *MethodListnfABITy; // MethodListnfABIPtrTy - LLVM for struct _method_list_t* - llvm::Type *MethodListnfABIPtrTy; + llvm::PointerType *MethodListnfABIPtrTy; // ProtocolnfABITy = LLVM for struct _protocol_t llvm::StructType *ProtocolnfABITy; // ProtocolnfABIPtrTy = LLVM for struct _protocol_t* - llvm::Type *ProtocolnfABIPtrTy; + llvm::PointerType *ProtocolnfABIPtrTy; // ProtocolListnfABITy - LLVM for struct _objc_protocol_list llvm::StructType *ProtocolListnfABITy; // ProtocolListnfABIPtrTy - LLVM for struct _objc_protocol_list* - llvm::Type *ProtocolListnfABIPtrTy; + llvm::PointerType *ProtocolListnfABIPtrTy; // ClassnfABITy - LLVM for struct _class_t llvm::StructType *ClassnfABITy; // ClassnfABIPtrTy - LLVM for struct _class_t* - llvm::Type *ClassnfABIPtrTy; + llvm::PointerType *ClassnfABIPtrTy; // IvarnfABITy - LLVM for struct _ivar_t llvm::StructType *IvarnfABITy; @@ -635,13 +637,13 @@ public: llvm::StructType *IvarListnfABITy; // IvarListnfABIPtrTy = LLVM for struct _ivar_list_t* - llvm::Type *IvarListnfABIPtrTy; + llvm::PointerType *IvarListnfABIPtrTy; // ClassRonfABITy - LLVM for struct _class_ro_t llvm::StructType *ClassRonfABITy; // ImpnfABITy - LLVM for id (*)(id, SEL, ...) - llvm::Type *ImpnfABITy; + llvm::PointerType *ImpnfABITy; // CategorynfABITy - LLVM for struct _category_t llvm::StructType *CategorynfABITy; @@ -670,7 +672,7 @@ public: llvm::StructType *SuperMessageRefTy; // SuperMessageRefPtrTy - LLVM for struct _super_message_ref_t* - llvm::Type *SuperMessageRefPtrTy; + llvm::PointerType *SuperMessageRefPtrTy; llvm::Constant *getMessageSendFixupFn() { // id objc_msgSend_fixup(id, struct message_ref_t*, ...) @@ -733,6 +735,13 @@ public: ObjCNonFragileABITypesHelper(CodeGen::CodeGenModule &cgm); }; +enum class ObjCLabelType { + ClassName, + MethodVarName, + MethodVarType, + PropertyName, +}; + class CGObjCCommonMac : public CodeGen::CGObjCRuntime { public: class SKIP_SCAN { @@ -836,7 +845,7 @@ protected: llvm::DenseMap<Selector, llvm::GlobalVariable*> MethodVarNames; /// DefinedCategoryNames - list of category names in form Class_Category. - llvm::SmallSetVector<std::string, 16> DefinedCategoryNames; + llvm::SmallSetVector<llvm::CachedHashString, 16> DefinedCategoryNames; /// MethodVarTypes - uniqued method type signatures. We have to use /// a StringMap here because have no other unique reference. @@ -879,6 +888,15 @@ protected: /// DefinedNonLazyCategories - List of defined "non-lazy" categories. SmallVector<llvm::GlobalValue*, 16> DefinedNonLazyCategories; + /// Cached reference to the class for constant strings. This value has type + /// int * but is actually an Obj-C class pointer. + llvm::WeakVH ConstantStringClassRef; + + /// \brief The LLVM type corresponding to NSConstantString. + llvm::StructType *NSConstantStringType = nullptr; + + llvm::StringMap<llvm::GlobalVariable *> NSConstantStringMap; + /// GetNameForMethod - Return a name for the given method. /// \param[out] NameOut - The return value. void GetNameForMethod(const ObjCMethodDecl *OMD, @@ -979,15 +997,6 @@ protected: ArrayRef<llvm::Constant*> MethodTypes, const ObjCCommonTypesHelper &ObjCTypes); - /// PushProtocolProperties - Push protocol's property on the input stack. - void PushProtocolProperties( - llvm::SmallPtrSet<const IdentifierInfo*, 16> &PropertySet, - SmallVectorImpl<llvm::Constant*> &Properties, - const Decl *Container, - const ObjCProtocolDecl *Proto, - const ObjCCommonTypesHelper &ObjCTypes, - bool IsClassProperty); - /// GetProtocolRef - Return a reference to the internal protocol /// description, creating an empty one if it has not been /// defined. The return value has type ProtocolPtrTy. @@ -1009,15 +1018,25 @@ public: /// /// \param Name - The variable name. /// \param Init - The variable initializer; this is also used to - /// define the type of the variable. + /// define the type of the variable. /// \param Section - The section the variable should go into, or empty. /// \param Align - The alignment for the variable, or 0. /// \param AddToUsed - Whether the variable should be added to - /// "llvm.used". - llvm::GlobalVariable *CreateMetadataVar(Twine Name, llvm::Constant *Init, + /// "llvm.used". + llvm::GlobalVariable *CreateMetadataVar(Twine Name, + ConstantStructBuilder &Init, + StringRef Section, CharUnits Align, + bool AddToUsed); + llvm::GlobalVariable *CreateMetadataVar(Twine Name, + llvm::Constant *Init, StringRef Section, CharUnits Align, bool AddToUsed); + llvm::GlobalVariable *CreateCStringLiteral(StringRef Name, + ObjCLabelType LabelType, + bool ForceNonFragileABI = false, + bool NullTerminate = true); + protected: CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, ReturnValueSlot Return, @@ -1044,6 +1063,7 @@ public: } ConstantAddress GenerateConstantString(const StringLiteral *SL) override; + ConstantAddress GenerateConstantNSString(const StringLiteral *SL); llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD=nullptr) override; @@ -1060,6 +1080,9 @@ public: /// forward references will be filled in with empty bodies if no /// definition is seen. The return value has type ProtocolPtrTy. virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0; + + virtual llvm::Constant *getNSConstantStringClassRef() = 0; + llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, const CGBlockInfo &blockInfo) override; llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, @@ -1069,8 +1092,95 @@ public: QualType T) override; }; +namespace { + +enum class MethodListType { + CategoryInstanceMethods, + CategoryClassMethods, + InstanceMethods, + ClassMethods, + ProtocolInstanceMethods, + ProtocolClassMethods, + OptionalProtocolInstanceMethods, + OptionalProtocolClassMethods, +}; + +/// A convenience class for splitting the methods of a protocol into +/// the four interesting groups. +class ProtocolMethodLists { +public: + enum Kind { + RequiredInstanceMethods, + RequiredClassMethods, + OptionalInstanceMethods, + OptionalClassMethods + }; + enum { + NumProtocolMethodLists = 4 + }; + + static MethodListType getMethodListKind(Kind kind) { + switch (kind) { + case RequiredInstanceMethods: + return MethodListType::ProtocolInstanceMethods; + case RequiredClassMethods: + return MethodListType::ProtocolClassMethods; + case OptionalInstanceMethods: + return MethodListType::OptionalProtocolInstanceMethods; + case OptionalClassMethods: + return MethodListType::OptionalProtocolClassMethods; + } + llvm_unreachable("bad kind"); + } + + SmallVector<const ObjCMethodDecl *, 4> Methods[NumProtocolMethodLists]; + + static ProtocolMethodLists get(const ObjCProtocolDecl *PD) { + ProtocolMethodLists result; + + for (auto MD : PD->methods()) { + size_t index = (2 * size_t(MD->isOptional())) + + (size_t(MD->isClassMethod())); + result.Methods[index].push_back(MD); + } + + return result; + } + + template <class Self> + SmallVector<llvm::Constant*, 8> emitExtendedTypesArray(Self *self) const { + // In both ABIs, the method types list is parallel with the + // concatenation of the methods arrays in the following order: + // instance methods + // class methods + // optional instance methods + // optional class methods + SmallVector<llvm::Constant*, 8> result; + + // Methods is already in the correct order for both ABIs. + for (auto &list : Methods) { + for (auto MD : list) { + result.push_back(self->GetMethodVarType(MD, true)); + } + } + + return result; + } + + template <class Self> + llvm::Constant *emitMethodList(Self *self, const ObjCProtocolDecl *PD, + Kind kind) const { + return self->emitMethodList(PD->getObjCRuntimeNameAsString(), + getMethodListKind(kind), Methods[kind]); + } +}; + +} // end anonymous namespace + class CGObjCMac : public CGObjCCommonMac { private: + friend ProtocolMethodLists; + ObjCTypesHelper ObjCTypes; /// EmitModuleInfo - Another marker encoding module level @@ -1091,7 +1201,7 @@ private: llvm::Constant *EmitClassExtension(const ObjCImplementationDecl *ID, CharUnits instanceSize, bool hasMRCWeakIvars, - bool isClassProperty); + bool isMetaclass); /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy, /// for the given class. @@ -1123,30 +1233,18 @@ private: /// given implementation. The return value has type ClassPtrTy. llvm::Constant *EmitMetaClass(const ObjCImplementationDecl *ID, llvm::Constant *Protocols, - ArrayRef<llvm::Constant*> Methods); + ArrayRef<const ObjCMethodDecl *> Methods); - llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD); + void emitMethodConstant(ConstantArrayBuilder &builder, + const ObjCMethodDecl *MD); - llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD); + void emitMethodDescriptionConstant(ConstantArrayBuilder &builder, + const ObjCMethodDecl *MD); /// EmitMethodList - Emit the method list for the given /// implementation. The return value has type MethodListPtrTy. - llvm::Constant *EmitMethodList(Twine Name, StringRef Section, - ArrayRef<llvm::Constant *> Methods); - - /// EmitMethodDescList - Emit a method description list for a list of - /// method declarations. - /// - TypeName: The name for the type containing the methods. - /// - IsProtocol: True iff these methods are for a protocol. - /// - ClassMethds: True iff these are class methods. - /// - Required: When true, only "required" methods are - /// listed. Similarly, when false only "optional" methods are - /// listed. For classes this should always be true. - /// - begin, end: The method list to output. - /// - /// The return value has type MethodDescriptionListPtrTy. - llvm::Constant *EmitMethodDescList(Twine Name, StringRef Section, - ArrayRef<llvm::Constant *> Methods); + llvm::Constant *emitMethodList(Twine Name, MethodListType MLT, + ArrayRef<const ObjCMethodDecl *> Methods); /// GetOrEmitProtocol - Get the protocol object for the given /// declaration, emitting it if necessary. The return value has type @@ -1165,9 +1263,7 @@ private: /// ProtocolExtensionPtrTy. llvm::Constant * EmitProtocolExtension(const ObjCProtocolDecl *PD, - ArrayRef<llvm::Constant*> OptInstanceMethods, - ArrayRef<llvm::Constant*> OptClassMethods, - ArrayRef<llvm::Constant*> MethodTypesExt); + const ProtocolMethodLists &methodLists); /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. @@ -1183,6 +1279,8 @@ private: public: CGObjCMac(CodeGen::CodeGenModule &cgm); + llvm::Constant *getNSConstantStringClassRef() override; + llvm::Function *ModuleInitFunction() override; CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, @@ -1262,20 +1360,14 @@ public: llvm::Value *EmitIvarOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar) override; - - /// GetClassGlobal - Return the global variable for the Objective-C - /// class of the given name. - llvm::GlobalVariable *GetClassGlobal(StringRef Name, - bool Weak = false) override { - llvm_unreachable("CGObjCMac::GetClassGlobal"); - } }; class CGObjCNonFragileABIMac : public CGObjCCommonMac { private: + friend ProtocolMethodLists; ObjCNonFragileABITypesHelper ObjCTypes; llvm::GlobalVariable* ObjCEmptyCacheVar; - llvm::GlobalVariable* ObjCEmptyVtableVar; + llvm::Constant* ObjCEmptyVtableVar; /// SuperClassReferences - uniqued super class references. llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> SuperClassReferences; @@ -1310,21 +1402,22 @@ private: unsigned InstanceStart, unsigned InstanceSize, const ObjCImplementationDecl *ID); - llvm::GlobalVariable * BuildClassMetaData(const std::string &ClassName, - llvm::Constant *IsAGV, - llvm::Constant *SuperClassGV, - llvm::Constant *ClassRoGV, - bool HiddenVisibility, - bool Weak); - - llvm::Constant *GetMethodConstant(const ObjCMethodDecl *MD); + llvm::GlobalVariable *BuildClassObject(const ObjCInterfaceDecl *CI, + bool isMetaclass, + llvm::Constant *IsAGV, + llvm::Constant *SuperClassGV, + llvm::Constant *ClassRoGV, + bool HiddenVisibility); + + void emitMethodConstant(ConstantArrayBuilder &builder, + const ObjCMethodDecl *MD, + bool forProtocol); + + /// Emit the method list for the given implementation. The return value + /// has type MethodListnfABITy. + llvm::Constant *emitMethodList(Twine Name, MethodListType MLT, + ArrayRef<const ObjCMethodDecl *> Methods); - llvm::Constant *GetMethodDescriptionConstant(const ObjCMethodDecl *MD); - - /// EmitMethodList - Emit the method list for the given - /// implementation. The return value has type MethodListnfABITy. - llvm::Constant *EmitMethodList(Twine Name, StringRef Section, - ArrayRef<llvm::Constant *> Methods); /// EmitIvarList - Emit the ivar list for the given /// implementation. If ForClass is true the list of class ivars /// (i.e. metaclass ivars) is emitted, otherwise the list of @@ -1365,8 +1458,12 @@ private: /// GetClassGlobal - Return the global variable for the Objective-C /// class of the given name. - llvm::GlobalVariable *GetClassGlobal(StringRef Name, - bool Weak = false) override; + llvm::Constant *GetClassGlobal(StringRef Name, + ForDefinition_t IsForDefinition, + bool Weak = false, bool DLLImport = false); + llvm::Constant *GetClassGlobal(const ObjCInterfaceDecl *ID, + bool isMetaclass, + ForDefinition_t isForDefinition); /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy, /// for the given class reference. @@ -1374,7 +1471,7 @@ private: const ObjCInterfaceDecl *ID); llvm::Value *EmitClassRefFromId(CodeGenFunction &CGF, - IdentifierInfo *II, bool Weak, + IdentifierInfo *II, const ObjCInterfaceDecl *ID); llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override; @@ -1404,7 +1501,7 @@ private: /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C /// interface. The return value has type EHTypePtrTy. llvm::Constant *GetInterfaceEHType(const ObjCInterfaceDecl *ID, - bool ForDefinition); + ForDefinition_t IsForDefinition); StringRef getMetaclassSymbolPrefix() const { return "OBJC_METACLASS_$_"; } @@ -1451,7 +1548,9 @@ private: public: CGObjCNonFragileABIMac(CodeGen::CodeGenModule &cgm); - // FIXME. All stubs for now! + + llvm::Constant *getNSConstantStringClassRef() override; + llvm::Function *ModuleInitFunction() override; CodeGen::RValue GenerateMessageSend(CodeGen::CodeGenFunction &CGF, @@ -1761,11 +1860,115 @@ llvm::Constant *CGObjCMac::GetEHType(QualType T) { }; */ -ConstantAddress CGObjCCommonMac::GenerateConstantString( - const StringLiteral *SL) { - return (CGM.getLangOpts().NoConstantCFStrings == 0 ? - CGM.GetAddrOfConstantCFString(SL) : - CGM.GetAddrOfConstantString(SL)); +ConstantAddress +CGObjCCommonMac::GenerateConstantString(const StringLiteral *SL) { + return (!CGM.getLangOpts().NoConstantCFStrings + ? CGM.GetAddrOfConstantCFString(SL) + : GenerateConstantNSString(SL)); +} + +static llvm::StringMapEntry<llvm::GlobalVariable *> & +GetConstantStringEntry(llvm::StringMap<llvm::GlobalVariable *> &Map, + const StringLiteral *Literal, unsigned &StringLength) { + StringRef String = Literal->getString(); + StringLength = String.size(); + return *Map.insert(std::make_pair(String, nullptr)).first; +} + +llvm::Constant *CGObjCMac::getNSConstantStringClassRef() { + if (llvm::Value *V = ConstantStringClassRef) + return cast<llvm::Constant>(V); + + auto &StringClass = CGM.getLangOpts().ObjCConstantStringClass; + std::string str = + StringClass.empty() ? "_NSConstantStringClassReference" + : "_" + StringClass + "ClassReference"; + + llvm::Type *PTy = llvm::ArrayType::get(CGM.IntTy, 0); + auto GV = CGM.CreateRuntimeVariable(PTy, str); + auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo()); + ConstantStringClassRef = V; + return V; +} + +llvm::Constant *CGObjCNonFragileABIMac::getNSConstantStringClassRef() { + if (llvm::Value *V = ConstantStringClassRef) + return cast<llvm::Constant>(V); + + auto &StringClass = CGM.getLangOpts().ObjCConstantStringClass; + std::string str = + StringClass.empty() ? "OBJC_CLASS_$_NSConstantString" + : "OBJC_CLASS_$_" + StringClass; + auto GV = GetClassGlobal(str, NotForDefinition); + + // Make sure the result is of the correct type. + auto V = llvm::ConstantExpr::getBitCast(GV, CGM.IntTy->getPointerTo()); + + ConstantStringClassRef = V; + return V; +} + +ConstantAddress +CGObjCCommonMac::GenerateConstantNSString(const StringLiteral *Literal) { + unsigned StringLength = 0; + llvm::StringMapEntry<llvm::GlobalVariable *> &Entry = + GetConstantStringEntry(NSConstantStringMap, Literal, StringLength); + + if (auto *C = Entry.second) + return ConstantAddress(C, CharUnits::fromQuantity(C->getAlignment())); + + // If we don't already have it, get _NSConstantStringClassReference. + llvm::Constant *Class = getNSConstantStringClassRef(); + + // If we don't already have it, construct the type for a constant NSString. + if (!NSConstantStringType) { + NSConstantStringType = + llvm::StructType::create({ + CGM.Int32Ty->getPointerTo(), + CGM.Int8PtrTy, + CGM.IntTy + }, "struct.__builtin_NSString"); + } + + ConstantInitBuilder Builder(CGM); + auto Fields = Builder.beginStruct(NSConstantStringType); + + // Class pointer. + Fields.add(Class); + + // String pointer. + llvm::Constant *C = + llvm::ConstantDataArray::getString(VMContext, Entry.first()); + + llvm::GlobalValue::LinkageTypes Linkage = llvm::GlobalValue::PrivateLinkage; + bool isConstant = !CGM.getLangOpts().WritableStrings; + + auto *GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), isConstant, + Linkage, C, ".str"); + GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + // Don't enforce the target's minimum global alignment, since the only use + // of the string is via this class initializer. + GV->setAlignment(1); + Fields.addBitCast(GV, CGM.Int8PtrTy); + + // String length. + Fields.addInt(CGM.IntTy, StringLength); + + // The struct. + CharUnits Alignment = CGM.getPointerAlign(); + GV = Fields.finishAndCreateGlobal("_unnamed_nsstring_", Alignment, + /*constant*/ true, + llvm::GlobalVariable::PrivateLinkage); + const char *NSStringSection = "__OBJC,__cstring_object,regular,no_dead_strip"; + const char *NSStringNonFragileABISection = + "__DATA,__objc_stringobj,regular,no_dead_strip"; + // FIXME. Fix section. + GV->setSection(CGM.getLangOpts().ObjCRuntime.isNonFragile() + ? NSStringNonFragileABISection + : NSStringSection); + Entry.second = GV; + + return ConstantAddress(GV, Alignment); } enum { @@ -1953,8 +2156,9 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, llvm::Instruction *CallSite; Fn = llvm::ConstantExpr::getBitCast(Fn, MSI.MessengerType); - RValue rvalue = CGF.EmitCall(MSI.CallInfo, Fn, Return, ActualArgs, - CGCalleeInfo(), &CallSite); + CGCallee Callee = CGCallee::forDirect(Fn); + RValue rvalue = CGF.EmitCall(MSI.CallInfo, Callee, Return, ActualArgs, + &CallSite); // Mark the call as noreturn if the method is marked noreturn and the // receiver cannot be null. @@ -2576,10 +2780,9 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) { } } - llvm::GlobalVariable *Entry = CreateMetadataVar( - "OBJC_CLASS_NAME_", - llvm::ConstantDataArray::getString(VMContext, BitMap, false), - "__TEXT,__objc_classname,cstring_literals", CharUnits::One(), true); + auto *Entry = CreateCStringLiteral(BitMap, ObjCLabelType::ClassName, + /*ForceNonFragileABI=*/true, + /*NullTerminate=*/false); return getConstantGEP(VMContext, Entry, 0, 0); } @@ -2730,66 +2933,29 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { LazySymbols.insert(&CGM.getContext().Idents.get("Protocol")); // Construct method lists. - std::vector<llvm::Constant*> InstanceMethods, ClassMethods; - std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods; - std::vector<llvm::Constant*> MethodTypesExt, OptMethodTypesExt; - for (const auto *MD : PD->instance_methods()) { - llvm::Constant *C = GetMethodDescriptionConstant(MD); - if (!C) - return GetOrEmitProtocolRef(PD); - - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptInstanceMethods.push_back(C); - OptMethodTypesExt.push_back(GetMethodVarType(MD, true)); - } else { - InstanceMethods.push_back(C); - MethodTypesExt.push_back(GetMethodVarType(MD, true)); - } - } - - for (const auto *MD : PD->class_methods()) { - llvm::Constant *C = GetMethodDescriptionConstant(MD); - if (!C) - return GetOrEmitProtocolRef(PD); - - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptClassMethods.push_back(C); - OptMethodTypesExt.push_back(GetMethodVarType(MD, true)); - } else { - ClassMethods.push_back(C); - MethodTypesExt.push_back(GetMethodVarType(MD, true)); - } - } - - MethodTypesExt.insert(MethodTypesExt.end(), - OptMethodTypesExt.begin(), OptMethodTypesExt.end()); - - llvm::Constant *Values[] = { - EmitProtocolExtension(PD, OptInstanceMethods, OptClassMethods, - MethodTypesExt), - GetClassName(PD->getObjCRuntimeNameAsString()), - EmitProtocolList("OBJC_PROTOCOL_REFS_" + PD->getName(), - PD->protocol_begin(), PD->protocol_end()), - EmitMethodDescList("OBJC_PROTOCOL_INSTANCE_METHODS_" + PD->getName(), - "__OBJC,__cat_inst_meth,regular,no_dead_strip", - InstanceMethods), - EmitMethodDescList("OBJC_PROTOCOL_CLASS_METHODS_" + PD->getName(), - "__OBJC,__cat_cls_meth,regular,no_dead_strip", - ClassMethods)}; - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolTy, - Values); + auto methodLists = ProtocolMethodLists::get(PD); + + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ProtocolTy); + values.add(EmitProtocolExtension(PD, methodLists)); + values.add(GetClassName(PD->getObjCRuntimeNameAsString())); + values.add(EmitProtocolList("OBJC_PROTOCOL_REFS_" + PD->getName(), + PD->protocol_begin(), PD->protocol_end())); + values.add(methodLists.emitMethodList(this, PD, + ProtocolMethodLists::RequiredInstanceMethods)); + values.add(methodLists.emitMethodList(this, PD, + ProtocolMethodLists::RequiredClassMethods)); if (Entry) { // Already created, update the initializer. assert(Entry->hasPrivateLinkage()); - Entry->setInitializer(Init); + values.finishAndSetAsInitializer(Entry); } else { - Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolTy, - false, llvm::GlobalValue::PrivateLinkage, - Init, "OBJC_PROTOCOL_" + PD->getName()); + Entry = values.finishAndCreateGlobal("OBJC_PROTOCOL_" + PD->getName(), + CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); Entry->setSection("__OBJC,__protocol,regular,no_dead_strip"); - // FIXME: Is this necessary? Why only for protocol? - Entry->setAlignment(4); Protocols[PD->getIdentifier()] = Entry; } @@ -2828,37 +2994,49 @@ llvm::Constant *CGObjCMac::GetOrEmitProtocolRef(const ObjCProtocolDecl *PD) { */ llvm::Constant * CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, - ArrayRef<llvm::Constant*> OptInstanceMethods, - ArrayRef<llvm::Constant*> OptClassMethods, - ArrayRef<llvm::Constant*> MethodTypesExt) { - uint64_t Size = - CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy); - llvm::Constant *Values[] = { - llvm::ConstantInt::get(ObjCTypes.IntTy, Size), - EmitMethodDescList("OBJC_PROTOCOL_INSTANCE_METHODS_OPT_" + PD->getName(), - "__OBJC,__cat_inst_meth,regular,no_dead_strip", - OptInstanceMethods), - EmitMethodDescList("OBJC_PROTOCOL_CLASS_METHODS_OPT_" + PD->getName(), - "__OBJC,__cat_cls_meth,regular,no_dead_strip", - OptClassMethods), - EmitPropertyList("OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr, PD, - ObjCTypes, false), - EmitProtocolMethodTypes("OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(), - MethodTypesExt, ObjCTypes), - EmitPropertyList("OBJC_$_CLASS_PROP_PROTO_LIST_" + PD->getName(), nullptr, - PD, ObjCTypes, true)}; + const ProtocolMethodLists &methodLists) { + auto optInstanceMethods = + methodLists.emitMethodList(this, PD, + ProtocolMethodLists::OptionalInstanceMethods); + auto optClassMethods = + methodLists.emitMethodList(this, PD, + ProtocolMethodLists::OptionalClassMethods); + + auto extendedMethodTypes = + EmitProtocolMethodTypes("OBJC_PROTOCOL_METHOD_TYPES_" + PD->getName(), + methodLists.emitExtendedTypesArray(this), + ObjCTypes); + + auto instanceProperties = + EmitPropertyList("OBJC_$_PROP_PROTO_LIST_" + PD->getName(), nullptr, PD, + ObjCTypes, false); + auto classProperties = + EmitPropertyList("OBJC_$_CLASS_PROP_PROTO_LIST_" + PD->getName(), nullptr, + PD, ObjCTypes, true); // Return null if no extension bits are used. - if (Values[1]->isNullValue() && Values[2]->isNullValue() && - Values[3]->isNullValue() && Values[4]->isNullValue() && - Values[5]->isNullValue()) + if (optInstanceMethods->isNullValue() && + optClassMethods->isNullValue() && + extendedMethodTypes->isNullValue() && + instanceProperties->isNullValue() && + classProperties->isNullValue()) { return llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy); + } - llvm::Constant *Init = - llvm::ConstantStruct::get(ObjCTypes.ProtocolExtensionTy, Values); + uint64_t size = + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy); + + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ProtocolExtensionTy); + values.addInt(ObjCTypes.IntTy, size); + values.add(optInstanceMethods); + values.add(optClassMethods); + values.add(instanceProperties); + values.add(extendedMethodTypes); + values.add(classProperties); // No special section, but goes in llvm.used - return CreateMetadataVar("\01l_OBJC_PROTOCOLEXT_" + PD->getName(), Init, + return CreateMetadataVar("\01l_OBJC_PROTOCOLEXT_" + PD->getName(), values, StringRef(), CGM.getPointerAlign(), true); } @@ -2870,59 +3048,57 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, }; */ llvm::Constant * -CGObjCMac::EmitProtocolList(Twine Name, +CGObjCMac::EmitProtocolList(Twine name, ObjCProtocolDecl::protocol_iterator begin, ObjCProtocolDecl::protocol_iterator end) { - SmallVector<llvm::Constant *, 16> ProtocolRefs; - - for (; begin != end; ++begin) - ProtocolRefs.push_back(GetProtocolRef(*begin)); - // Just return null for empty protocol lists - if (ProtocolRefs.empty()) + if (begin == end) return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); - // This list is null terminated. - ProtocolRefs.push_back(llvm::Constant::getNullValue(ObjCTypes.ProtocolPtrTy)); + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(); - llvm::Constant *Values[3]; // This field is only used by the runtime. - Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); - Values[1] = llvm::ConstantInt::get(ObjCTypes.LongTy, - ProtocolRefs.size() - 1); - Values[2] = - llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolPtrTy, - ProtocolRefs.size()), - ProtocolRefs); - - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); + values.addNullPointer(ObjCTypes.ProtocolListPtrTy); + + // Reserve a slot for the count. + auto countSlot = values.addPlaceholder(); + + auto refsArray = values.beginArray(ObjCTypes.ProtocolPtrTy); + for (; begin != end; ++begin) { + refsArray.add(GetProtocolRef(*begin)); + } + auto count = refsArray.size(); + + // This list is null terminated. + refsArray.addNullPointer(ObjCTypes.ProtocolPtrTy); + + refsArray.finishAndAddTo(values); + values.fillPlaceholderWithInt(countSlot, ObjCTypes.LongTy, count); + + StringRef section; + if (CGM.getTriple().isOSBinFormatMachO()) + section = "__OBJC,__cat_cls_meth,regular,no_dead_strip"; + llvm::GlobalVariable *GV = - CreateMetadataVar(Name, Init, "__OBJC,__cat_cls_meth,regular,no_dead_strip", - CGM.getPointerAlign(), false); + CreateMetadataVar(name, values, section, CGM.getPointerAlign(), false); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListPtrTy); } -void CGObjCCommonMac:: +static void PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet, - SmallVectorImpl<llvm::Constant *> &Properties, - const Decl *Container, + SmallVectorImpl<const ObjCPropertyDecl *> &Properties, const ObjCProtocolDecl *Proto, - const ObjCCommonTypesHelper &ObjCTypes, bool IsClassProperty) { for (const auto *P : Proto->protocols()) - PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes, - IsClassProperty); + PushProtocolProperties(PropertySet, Properties, P, IsClassProperty); for (const auto *PD : Proto->properties()) { if (IsClassProperty != PD->isClassProperty()) continue; if (!PropertySet.insert(PD->getIdentifier()).second) continue; - llvm::Constant *Prop[] = { - GetPropertyName(PD->getIdentifier()), - GetPropertyTypeString(PD, Container) - }; - Properties.push_back(llvm::ConstantStruct::get(ObjCTypes.PropertyTy, Prop)); + Properties.push_back(PD); } } @@ -2952,21 +3128,16 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); } - SmallVector<llvm::Constant *, 16> Properties; + SmallVector<const ObjCPropertyDecl *, 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()) { if (IsClassProperty != PD->isClassProperty()) continue; PropertySet.insert(PD->getIdentifier()); - AddProperty(PD); + Properties.push_back(PD); } for (const auto *PD : OCD->properties()) { @@ -2976,40 +3147,45 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, // class extension. if (!PropertySet.insert(PD->getIdentifier()).second) continue; - AddProperty(PD); + Properties.push_back(PD); } if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) { for (const auto *P : OID->all_referenced_protocols()) - PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes, - IsClassProperty); + PushProtocolProperties(PropertySet, Properties, P, IsClassProperty); } else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD)) { for (const auto *P : CD->protocols()) - PushProtocolProperties(PropertySet, Properties, Container, P, ObjCTypes, - IsClassProperty); + PushProtocolProperties(PropertySet, Properties, P, IsClassProperty); } // Return null for empty list. if (Properties.empty()) return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); - unsigned PropertySize = + unsigned propertySize = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.PropertyTy); - llvm::Constant *Values[3]; - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize); - Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size()); - llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.PropertyTy, - Properties.size()); - Values[2] = llvm::ConstantArray::get(AT, Properties); - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); + + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(); + values.addInt(ObjCTypes.IntTy, propertySize); + values.addInt(ObjCTypes.IntTy, Properties.size()); + auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy); + for (auto PD : Properties) { + auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy); + property.add(GetPropertyName(PD->getIdentifier())); + property.add(GetPropertyTypeString(PD, Container)); + property.finishAndAddTo(propertiesArray); + } + propertiesArray.finishAndAddTo(values); + + StringRef Section; + if (CGM.getTriple().isOSBinFormatMachO()) + Section = (ObjCABI == 2) ? "__DATA, __objc_const" + : "__OBJC,__property,regular,no_dead_strip"; llvm::GlobalVariable *GV = - CreateMetadataVar(Name, Init, - (ObjCABI == 2) ? "__DATA, __objc_const" : - "__OBJC,__property,regular,no_dead_strip", - CGM.getPointerAlign(), - true); + CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.PropertyListPtrTy); } @@ -3025,50 +3201,13 @@ CGObjCCommonMac::EmitProtocolMethodTypes(Twine Name, MethodTypes.size()); llvm::Constant *Init = llvm::ConstantArray::get(AT, MethodTypes); - llvm::GlobalVariable *GV = CreateMetadataVar( - Name, Init, (ObjCABI == 2) ? "__DATA, __objc_const" : StringRef(), - CGM.getPointerAlign(), true); - return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy); -} - -/* - struct objc_method_description_list { - int count; - struct objc_method_description list[]; - }; -*/ -llvm::Constant * -CGObjCMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { - llvm::Constant *Desc[] = { - llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), - ObjCTypes.SelectorPtrTy), - GetMethodVarType(MD) - }; - if (!Desc[1]) - return nullptr; - - return llvm::ConstantStruct::get(ObjCTypes.MethodDescriptionTy, - Desc); -} - -llvm::Constant * -CGObjCMac::EmitMethodDescList(Twine Name, StringRef Section, - ArrayRef<llvm::Constant *> Methods) { - // Return null for empty list. - if (Methods.empty()) - return llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy); - - llvm::Constant *Values[2]; - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size()); - llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodDescriptionTy, - Methods.size()); - Values[1] = llvm::ConstantArray::get(AT, Methods); - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); + StringRef Section; + if (CGM.getTriple().isOSBinFormatMachO() && ObjCABI == 2) + Section = "__DATA, __objc_const"; llvm::GlobalVariable *GV = - CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true); - return llvm::ConstantExpr::getBitCast(GV, - ObjCTypes.MethodDescriptionListPtrTy); + CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true); + return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.Int8PtrPtrTy); } /* @@ -3098,54 +3237,53 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { llvm::raw_svector_ostream(ExtName) << Interface->getName() << '_' << OCD->getName(); - SmallVector<llvm::Constant *, 16> InstanceMethods, ClassMethods; - for (const auto *I : OCD->instance_methods()) - // Instance methods should always be defined. - InstanceMethods.push_back(GetMethodConstant(I)); + ConstantInitBuilder Builder(CGM); + auto Values = Builder.beginStruct(ObjCTypes.CategoryTy); - for (const auto *I : OCD->class_methods()) - // Class methods should always be defined. - ClassMethods.push_back(GetMethodConstant(I)); + enum { + InstanceMethods, + ClassMethods, + NumMethodLists + }; + SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists]; + for (const auto *MD : OCD->methods()) { + Methods[unsigned(MD->isClassMethod())].push_back(MD); + } - llvm::Constant *Values[8]; - Values[0] = GetClassName(OCD->getName()); - Values[1] = GetClassName(Interface->getObjCRuntimeNameAsString()); + Values.add(GetClassName(OCD->getName())); + Values.add(GetClassName(Interface->getObjCRuntimeNameAsString())); LazySymbols.insert(Interface->getIdentifier()); - Values[2] = EmitMethodList("OBJC_CATEGORY_INSTANCE_METHODS_" + ExtName.str(), - "__OBJC,__cat_inst_meth,regular,no_dead_strip", - InstanceMethods); - Values[3] = EmitMethodList("OBJC_CATEGORY_CLASS_METHODS_" + ExtName.str(), - "__OBJC,__cat_cls_meth,regular,no_dead_strip", - ClassMethods); + + Values.add(emitMethodList(ExtName, MethodListType::CategoryInstanceMethods, + Methods[InstanceMethods])); + Values.add(emitMethodList(ExtName, MethodListType::CategoryClassMethods, + Methods[ClassMethods])); if (Category) { - Values[4] = + Values.add( EmitProtocolList("OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(), - Category->protocol_begin(), Category->protocol_end()); + Category->protocol_begin(), Category->protocol_end())); } else { - Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); + Values.addNullPointer(ObjCTypes.ProtocolListPtrTy); } - Values[5] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); + Values.addInt(ObjCTypes.IntTy, Size); // If there is no category @interface then there can be no properties. if (Category) { - Values[6] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(), - OCD, Category, ObjCTypes, false); - Values[7] = EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), - OCD, Category, ObjCTypes, true); + Values.add(EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(), + OCD, Category, ObjCTypes, false)); + Values.add(EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), + OCD, Category, ObjCTypes, true)); } else { - Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); - Values[7] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); + Values.addNullPointer(ObjCTypes.PropertyListPtrTy); + Values.addNullPointer(ObjCTypes.PropertyListPtrTy); } - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.CategoryTy, - Values); - llvm::GlobalVariable *GV = - CreateMetadataVar("OBJC_CATEGORY_" + ExtName.str(), Init, + CreateMetadataVar("OBJC_CATEGORY_" + ExtName.str(), Values, "__OBJC,__category,regular,no_dead_strip", CGM.getPointerAlign(), true); DefinedCategories.push_back(GV); - DefinedCategoryNames.insert(ExtName.str()); + DefinedCategoryNames.insert(llvm::CachedHashString(ExtName)); // method definition entries must be clear for next implementation. MethodDefinitions.clear(); } @@ -3282,57 +3420,56 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { if (ID->getClassInterface()->getVisibility() == HiddenVisibility) Flags |= FragileABI_Class_Hidden; - SmallVector<llvm::Constant *, 16> InstanceMethods, ClassMethods; - for (const auto *I : ID->instance_methods()) - // Instance methods should always be defined. - InstanceMethods.push_back(GetMethodConstant(I)); - - for (const auto *I : ID->class_methods()) - // Class methods should always be defined. - ClassMethods.push_back(GetMethodConstant(I)); + enum { + InstanceMethods, + ClassMethods, + NumMethodLists + }; + SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists]; + for (const auto *MD : ID->methods()) { + Methods[unsigned(MD->isClassMethod())].push_back(MD); + } for (const auto *PID : ID->property_impls()) { if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { ObjCPropertyDecl *PD = PID->getPropertyDecl(); if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) - if (llvm::Constant *C = GetMethodConstant(MD)) - InstanceMethods.push_back(C); + if (GetMethodDefinition(MD)) + Methods[InstanceMethods].push_back(MD); if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) - if (llvm::Constant *C = GetMethodConstant(MD)) - InstanceMethods.push_back(C); + if (GetMethodDefinition(MD)) + Methods[InstanceMethods].push_back(MD); } } - llvm::Constant *Values[12]; - Values[ 0] = EmitMetaClass(ID, Protocols, ClassMethods); + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ClassTy); + values.add(EmitMetaClass(ID, Protocols, Methods[ClassMethods])); if (ObjCInterfaceDecl *Super = Interface->getSuperClass()) { // Record a reference to the super class. LazySymbols.insert(Super->getIdentifier()); - Values[ 1] = - llvm::ConstantExpr::getBitCast(GetClassName(Super->getObjCRuntimeNameAsString()), - ObjCTypes.ClassPtrTy); + values.addBitCast(GetClassName(Super->getObjCRuntimeNameAsString()), + ObjCTypes.ClassPtrTy); } else { - Values[ 1] = llvm::Constant::getNullValue(ObjCTypes.ClassPtrTy); + values.addNullPointer(ObjCTypes.ClassPtrTy); } - Values[ 2] = GetClassName(ID->getObjCRuntimeNameAsString()); + values.add(GetClassName(ID->getObjCRuntimeNameAsString())); // 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.getQuantity()); - Values[ 6] = EmitIvarList(ID, false); - Values[7] = EmitMethodList("OBJC_INSTANCE_METHODS_" + ID->getName(), - "__OBJC,__inst_meth,regular,no_dead_strip", - InstanceMethods); + values.addInt(ObjCTypes.LongTy, 0); + values.addInt(ObjCTypes.LongTy, Flags); + values.addInt(ObjCTypes.LongTy, Size.getQuantity()); + values.add(EmitIvarList(ID, false)); + values.add(emitMethodList(ID->getName(), MethodListType::InstanceMethods, + Methods[InstanceMethods])); // cache is always NULL. - Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy); - Values[ 9] = Protocols; - Values[10] = BuildStrongIvarLayout(ID, CharUnits::Zero(), Size); - Values[11] = EmitClassExtension(ID, Size, hasMRCWeak, - false/*isClassProperty*/); - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy, - Values); + values.addNullPointer(ObjCTypes.CachePtrTy); + values.add(Protocols); + values.add(BuildStrongIvarLayout(ID, CharUnits::Zero(), Size)); + values.add(EmitClassExtension(ID, Size, hasMRCWeak, + /*isMetaclass*/ false)); + std::string Name("OBJC_CLASS_"); Name += ClassName; const char *Section = "__OBJC,__class,regular,no_dead_strip"; @@ -3341,12 +3478,12 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { if (GV) { assert(GV->getType()->getElementType() == ObjCTypes.ClassTy && "Forward metaclass reference has incorrect type."); - GV->setInitializer(Init); + values.finishAndSetAsInitializer(GV); GV->setSection(Section); GV->setAlignment(CGM.getPointerAlign().getQuantity()); CGM.addCompilerUsedGlobal(GV); } else - GV = CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true); + GV = CreateMetadataVar(Name, values, Section, CGM.getPointerAlign(), true); DefinedClasses.push_back(GV); ImplementedClasses.push_back(Interface); // method definition entries must be clear for next implementation. @@ -3355,50 +3492,46 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, llvm::Constant *Protocols, - ArrayRef<llvm::Constant*> Methods) { + ArrayRef<const ObjCMethodDecl*> Methods) { unsigned Flags = FragileABI_Class_Meta; unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassTy); if (ID->getClassInterface()->getVisibility() == HiddenVisibility) Flags |= FragileABI_Class_Hidden; - llvm::Constant *Values[12]; + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ClassTy); // The isa for the metaclass is the root of the hierarchy. const ObjCInterfaceDecl *Root = ID->getClassInterface(); while (const ObjCInterfaceDecl *Super = Root->getSuperClass()) Root = Super; - Values[ 0] = - llvm::ConstantExpr::getBitCast(GetClassName(Root->getObjCRuntimeNameAsString()), - ObjCTypes.ClassPtrTy); + values.addBitCast(GetClassName(Root->getObjCRuntimeNameAsString()), + ObjCTypes.ClassPtrTy); // The super class for the metaclass is emitted as the name of the // super class. The runtime fixes this up to point to the // *metaclass* for the super class. if (ObjCInterfaceDecl *Super = ID->getClassInterface()->getSuperClass()) { - Values[ 1] = - llvm::ConstantExpr::getBitCast(GetClassName(Super->getObjCRuntimeNameAsString()), - ObjCTypes.ClassPtrTy); + values.addBitCast(GetClassName(Super->getObjCRuntimeNameAsString()), + ObjCTypes.ClassPtrTy); } else { - Values[ 1] = llvm::Constant::getNullValue(ObjCTypes.ClassPtrTy); + values.addNullPointer(ObjCTypes.ClassPtrTy); } - Values[ 2] = GetClassName(ID->getObjCRuntimeNameAsString()); + values.add(GetClassName(ID->getObjCRuntimeNameAsString())); // 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[ 6] = EmitIvarList(ID, true); - Values[7] = - EmitMethodList("OBJC_CLASS_METHODS_" + ID->getNameAsString(), - "__OBJC,__cls_meth,regular,no_dead_strip", Methods); + values.addInt(ObjCTypes.LongTy, 0); + values.addInt(ObjCTypes.LongTy, Flags); + values.addInt(ObjCTypes.LongTy, Size); + values.add(EmitIvarList(ID, true)); + values.add(emitMethodList(ID->getName(), MethodListType::ClassMethods, + Methods)); // cache is always NULL. - Values[ 8] = llvm::Constant::getNullValue(ObjCTypes.CachePtrTy); - Values[ 9] = Protocols; + values.addNullPointer(ObjCTypes.CachePtrTy); + values.add(Protocols); // ivar_layout for metaclass is always NULL. - Values[10] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); + values.addNullPointer(ObjCTypes.Int8PtrTy); // The class extension is used to store class properties for metaclasses. - Values[11] = EmitClassExtension(ID, CharUnits::Zero(), false/*hasMRCWeak*/, - true/*isClassProperty*/); - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy, - Values); + values.add(EmitClassExtension(ID, CharUnits::Zero(), false/*hasMRCWeak*/, + /*isMetaclass*/true)); std::string Name("OBJC_METACLASS_"); Name += ID->getName(); @@ -3408,14 +3541,13 @@ llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, if (GV) { assert(GV->getType()->getElementType() == ObjCTypes.ClassTy && "Forward metaclass reference has incorrect type."); - GV->setInitializer(Init); + values.finishAndSetAsInitializer(GV); } else { - GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false, - llvm::GlobalValue::PrivateLinkage, - Init, Name); + GV = values.finishAndCreateGlobal(Name, CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); } GV->setSection("__OBJC,__meta_class,regular,no_dead_strip"); - GV->setAlignment(4); CGM.addCompilerUsedGlobal(GV); return GV; @@ -3471,32 +3603,38 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) { llvm::Constant * CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID, CharUnits InstanceSize, bool hasMRCWeakIvars, - bool isClassProperty) { - uint64_t Size = - CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy); + bool isMetaclass) { + // Weak ivar layout. + llvm::Constant *layout; + if (isMetaclass) { + layout = llvm::ConstantPointerNull::get(CGM.Int8PtrTy); + } else { + layout = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize, + hasMRCWeakIvars); + } - llvm::Constant *Values[3]; - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); - if (isClassProperty) { - llvm::Type *PtrTy = CGM.Int8PtrTy; - Values[1] = llvm::Constant::getNullValue(PtrTy); - } else - Values[1] = BuildWeakIvarLayout(ID, CharUnits::Zero(), InstanceSize, - hasMRCWeakIvars); - if (isClassProperty) - Values[2] = EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ID->getName(), - ID, ID->getClassInterface(), ObjCTypes, true); - else - Values[2] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(), - ID, ID->getClassInterface(), ObjCTypes, false); + // Properties. + llvm::Constant *propertyList = + EmitPropertyList((isMetaclass ? Twine("\01l_OBJC_$_CLASS_PROP_LIST_") + : Twine("\01l_OBJC_$_PROP_LIST_")) + + ID->getName(), + ID, ID->getClassInterface(), ObjCTypes, isMetaclass); // Return null if no extension bits are used. - if ((!Values[1] || Values[1]->isNullValue()) && Values[2]->isNullValue()) + if (layout->isNullValue() && propertyList->isNullValue()) { return llvm::Constant::getNullValue(ObjCTypes.ClassExtensionPtrTy); + } - llvm::Constant *Init = - llvm::ConstantStruct::get(ObjCTypes.ClassExtensionTy, Values); - return CreateMetadataVar("OBJC_CLASSEXT_" + ID->getName(), Init, + uint64_t size = + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy); + + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ClassExtensionTy); + values.addInt(ObjCTypes.IntTy, size); + values.add(layout); + values.add(propertyList); + + return CreateMetadataVar("OBJC_CLASSEXT_" + ID->getName(), values, "__OBJC,__class_ext,regular,no_dead_strip", CGM.getPointerAlign(), true); } @@ -3515,8 +3653,6 @@ CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID, */ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, bool ForClass) { - std::vector<llvm::Constant*> Ivars; - // When emitting the root class GCC emits ivar entries for the // actual class structure. It is not clear if we need to follow this // behavior; for now lets try and get away with not doing it. If so, @@ -3527,91 +3663,181 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, const ObjCInterfaceDecl *OID = ID->getClassInterface(); + ConstantInitBuilder builder(CGM); + auto ivarList = builder.beginStruct(); + auto countSlot = ivarList.addPlaceholder(); + auto ivars = ivarList.beginArray(ObjCTypes.IvarTy); + for (const ObjCIvarDecl *IVD = OID->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) { // Ignore unnamed bit-fields. if (!IVD->getDeclName()) continue; - llvm::Constant *Ivar[] = { - GetMethodVarName(IVD->getIdentifier()), - GetMethodVarType(IVD), - llvm::ConstantInt::get(ObjCTypes.IntTy, - ComputeIvarBaseOffset(CGM, OID, IVD)) - }; - Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy, Ivar)); + + auto ivar = ivars.beginStruct(ObjCTypes.IvarTy); + ivar.add(GetMethodVarName(IVD->getIdentifier())); + ivar.add(GetMethodVarType(IVD)); + ivar.addInt(ObjCTypes.IntTy, ComputeIvarBaseOffset(CGM, OID, IVD)); + ivar.finishAndAddTo(ivars); } // Return null for empty list. - if (Ivars.empty()) + auto count = ivars.size(); + if (count == 0) { + ivars.abandon(); + ivarList.abandon(); return llvm::Constant::getNullValue(ObjCTypes.IvarListPtrTy); + } - llvm::Constant *Values[2]; - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size()); - llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarTy, - Ivars.size()); - Values[1] = llvm::ConstantArray::get(AT, Ivars); - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); + ivars.finishAndAddTo(ivarList); + ivarList.fillPlaceholderWithInt(countSlot, ObjCTypes.IntTy, count); llvm::GlobalVariable *GV; if (ForClass) GV = - CreateMetadataVar("OBJC_CLASS_VARIABLES_" + ID->getName(), Init, + CreateMetadataVar("OBJC_CLASS_VARIABLES_" + ID->getName(), ivarList, "__OBJC,__class_vars,regular,no_dead_strip", CGM.getPointerAlign(), true); else - GV = CreateMetadataVar("OBJC_INSTANCE_VARIABLES_" + ID->getName(), Init, + GV = CreateMetadataVar("OBJC_INSTANCE_VARIABLES_" + ID->getName(), ivarList, "__OBJC,__instance_vars,regular,no_dead_strip", CGM.getPointerAlign(), true); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListPtrTy); } -/* - struct objc_method { - SEL method_name; - char *method_types; - void *method; - }; +/// Build a struct objc_method_description constant for the given method. +/// +/// struct objc_method_description { +/// SEL method_name; +/// char *method_types; +/// }; +void CGObjCMac::emitMethodDescriptionConstant(ConstantArrayBuilder &builder, + const ObjCMethodDecl *MD) { + auto description = builder.beginStruct(ObjCTypes.MethodDescriptionTy); + description.addBitCast(GetMethodVarName(MD->getSelector()), + ObjCTypes.SelectorPtrTy); + description.add(GetMethodVarType(MD)); + description.finishAndAddTo(builder); +} - struct objc_method_list { - struct objc_method_list *obsolete; - int count; - struct objc_method methods_list[count]; - }; -*/ +/// Build a struct objc_method constant for the given method. +/// +/// struct objc_method { +/// SEL method_name; +/// char *method_types; +/// void *method; +/// }; +void CGObjCMac::emitMethodConstant(ConstantArrayBuilder &builder, + const ObjCMethodDecl *MD) { + llvm::Function *fn = GetMethodDefinition(MD); + assert(fn && "no definition registered for method"); -/// GetMethodConstant - Return a struct objc_method constant for the -/// given method if it has been defined. The result is null if the -/// method has not been defined. The return value has type MethodPtrTy. -llvm::Constant *CGObjCMac::GetMethodConstant(const ObjCMethodDecl *MD) { - llvm::Function *Fn = GetMethodDefinition(MD); - if (!Fn) - return nullptr; - - llvm::Constant *Method[] = { - llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), - ObjCTypes.SelectorPtrTy), - GetMethodVarType(MD), - llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy) - }; - return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method); + auto method = builder.beginStruct(ObjCTypes.MethodTy); + method.addBitCast(GetMethodVarName(MD->getSelector()), + ObjCTypes.SelectorPtrTy); + method.add(GetMethodVarType(MD)); + method.addBitCast(fn, ObjCTypes.Int8PtrTy); + method.finishAndAddTo(builder); } -llvm::Constant *CGObjCMac::EmitMethodList(Twine Name, StringRef Section, - ArrayRef<llvm::Constant *> Methods) { +/// Build a struct objc_method_list or struct objc_method_description_list, +/// as appropriate. +/// +/// struct objc_method_list { +/// struct objc_method_list *obsolete; +/// int count; +/// struct objc_method methods_list[count]; +/// }; +/// +/// struct objc_method_description_list { +/// int count; +/// struct objc_method_description list[count]; +/// }; +llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT, + ArrayRef<const ObjCMethodDecl *> methods) { + StringRef prefix; + StringRef section; + bool forProtocol = false; + switch (MLT) { + case MethodListType::CategoryInstanceMethods: + prefix = "OBJC_CATEGORY_INSTANCE_METHODS_"; + section = "__OBJC,__cat_inst_meth,regular,no_dead_strip"; + forProtocol = false; + break; + case MethodListType::CategoryClassMethods: + prefix = "OBJC_CATEGORY_CLASS_METHODS_"; + section = "__OBJC,__cat_cls_meth,regular,no_dead_strip"; + forProtocol = false; + break; + case MethodListType::InstanceMethods: + prefix = "OBJC_INSTANCE_METHODS_"; + section = "__OBJC,__inst_meth,regular,no_dead_strip"; + forProtocol = false; + break; + case MethodListType::ClassMethods: + prefix = "OBJC_CLASS_METHODS_"; + section = "__OBJC,__cls_meth,regular,no_dead_strip"; + forProtocol = false; + break; + case MethodListType::ProtocolInstanceMethods: + prefix = "OBJC_PROTOCOL_INSTANCE_METHODS_"; + section = "__OBJC,__cat_inst_meth,regular,no_dead_strip"; + forProtocol = true; + break; + case MethodListType::ProtocolClassMethods: + prefix = "OBJC_PROTOCOL_CLASS_METHODS_"; + section = "__OBJC,__cat_cls_meth,regular,no_dead_strip"; + forProtocol = true; + break; + case MethodListType::OptionalProtocolInstanceMethods: + prefix = "OBJC_PROTOCOL_INSTANCE_METHODS_OPT_"; + section = "__OBJC,__cat_inst_meth,regular,no_dead_strip"; + forProtocol = true; + break; + case MethodListType::OptionalProtocolClassMethods: + prefix = "OBJC_PROTOCOL_CLASS_METHODS_OPT_"; + section = "__OBJC,__cat_cls_meth,regular,no_dead_strip"; + forProtocol = true; + break; + } + // Return null for empty list. - if (Methods.empty()) - return llvm::Constant::getNullValue(ObjCTypes.MethodListPtrTy); + if (methods.empty()) + return llvm::Constant::getNullValue(forProtocol + ? ObjCTypes.MethodDescriptionListPtrTy + : ObjCTypes.MethodListPtrTy); + + // For protocols, this is an objc_method_description_list, which has + // a slightly different structure. + if (forProtocol) { + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(); + values.addInt(ObjCTypes.IntTy, methods.size()); + auto methodArray = values.beginArray(ObjCTypes.MethodDescriptionTy); + for (auto MD : methods) { + emitMethodDescriptionConstant(methodArray, MD); + } + methodArray.finishAndAddTo(values); + + llvm::GlobalVariable *GV = CreateMetadataVar(prefix + name, values, section, + CGM.getPointerAlign(), true); + return llvm::ConstantExpr::getBitCast(GV, + ObjCTypes.MethodDescriptionListPtrTy); + } - llvm::Constant *Values[3]; - Values[0] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); - Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size()); - llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy, - Methods.size()); - Values[2] = llvm::ConstantArray::get(AT, Methods); - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); + // Otherwise, it's an objc_method_list. + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(); + values.addNullPointer(ObjCTypes.Int8PtrTy); + values.addInt(ObjCTypes.IntTy, methods.size()); + auto methodArray = values.beginArray(ObjCTypes.MethodTy); + for (auto MD : methods) { + emitMethodConstant(methodArray, MD); + } + methodArray.finishAndAddTo(values); - llvm::GlobalVariable *GV = - CreateMetadataVar(Name, Init, Section, CGM.getPointerAlign(), true); + llvm::GlobalVariable *GV = CreateMetadataVar(prefix + name, values, section, + CGM.getPointerAlign(), true); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListPtrTy); } @@ -3634,6 +3860,21 @@ llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, } llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name, + ConstantStructBuilder &Init, + StringRef Section, + CharUnits Align, + bool AddToUsed) { + llvm::GlobalVariable *GV = + Init.finishAndCreateGlobal(Name, Align, /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); + if (!Section.empty()) + GV->setSection(Section); + if (AddToUsed) + CGM.addCompilerUsedGlobal(GV); + return GV; +} + +llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name, llvm::Constant *Init, StringRef Section, CharUnits Align, @@ -3650,6 +3891,54 @@ llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name, return GV; } +llvm::GlobalVariable * +CGObjCCommonMac::CreateCStringLiteral(StringRef Name, ObjCLabelType Type, + bool ForceNonFragileABI, + bool NullTerminate) { + StringRef Label; + switch (Type) { + case ObjCLabelType::ClassName: Label = "OBJC_CLASS_NAME_"; break; + case ObjCLabelType::MethodVarName: Label = "OBJC_METH_VAR_NAME_"; break; + case ObjCLabelType::MethodVarType: Label = "OBJC_METH_VAR_TYPE_"; break; + case ObjCLabelType::PropertyName: Label = "OBJC_PROP_NAME_ATTR_"; break; + } + + bool NonFragile = ForceNonFragileABI || isNonFragileABI(); + + StringRef Section; + switch (Type) { + case ObjCLabelType::ClassName: + Section = NonFragile ? "__TEXT,__objc_classname,cstring_literals" + : "__TEXT,__cstring,cstring_literals"; + break; + case ObjCLabelType::MethodVarName: + Section = NonFragile ? "__TEXT,__objc_methname,cstring_literals" + : "__TEXT,__cstring,cstring_literals"; + break; + case ObjCLabelType::MethodVarType: + Section = NonFragile ? "__TEXT,__objc_methtype,cstring_literals" + : "__TEXT,__cstring,cstring_literals"; + break; + case ObjCLabelType::PropertyName: + Section = "__TEXT,__cstring,cstring_literals"; + break; + } + + llvm::Constant *Value = + llvm::ConstantDataArray::getString(VMContext, Name, NullTerminate); + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Value->getType(), + /*isConstant=*/true, + llvm::GlobalValue::PrivateLinkage, Value, Label); + if (CGM.getTriple().isOSBinFormatMachO()) + GV->setSection(Section); + GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + GV->setAlignment(CharUnits::One().getQuantity()); + CGM.addCompilerUsedGlobal(GV); + + return GV; +} + llvm::Function *CGObjCMac::ModuleInitFunction() { // Abuse this interface function as a place to finalize. FinishModule(); @@ -4390,8 +4679,8 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); - src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); + src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty) + : CGF.Builder.CreateBitCast(src, CGM.Int64Ty); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); @@ -4411,8 +4700,8 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); - src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); + src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty) + : CGF.Builder.CreateBitCast(src, CGM.Int64Ty); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); @@ -4437,8 +4726,8 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); - src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); + src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty) + : CGF.Builder.CreateBitCast(src, CGM.Int64Ty); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); @@ -4456,8 +4745,8 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, if (!isa<llvm::PointerType>(SrcTy)) { unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); - src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) - : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); + src = (Size == 4) ? CGF.Builder.CreateBitCast(src, CGM.Int32Ty) + : CGF.Builder.CreateBitCast(src, CGM.Int64Ty); src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); @@ -4590,15 +4879,14 @@ static const int ModuleVersion = 7; void CGObjCMac::EmitModuleInfo() { uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ModuleTy); - llvm::Constant *Values[] = { - llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion), - llvm::ConstantInt::get(ObjCTypes.LongTy, Size), - // This used to be the filename, now it is unused. <rdr://4327263> - GetClassName(StringRef("")), - EmitModuleSymbols() - }; - CreateMetadataVar("OBJC_MODULES", - llvm::ConstantStruct::get(ObjCTypes.ModuleTy, Values), + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ModuleTy); + values.addInt(ObjCTypes.LongTy, ModuleVersion); + values.addInt(ObjCTypes.LongTy, Size); + // This used to be the filename, now it is unused. <rdr://4327263> + values.add(GetClassName(StringRef(""))); + values.add(EmitModuleSymbols()); + CreateMetadataVar("OBJC_MODULES", values, "__OBJC,__module_info,regular,no_dead_strip", CGM.getPointerAlign(), true); } @@ -4611,15 +4899,16 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() { if (!NumClasses && !NumCategories) return llvm::Constant::getNullValue(ObjCTypes.SymtabPtrTy); - llvm::Constant *Values[5]; - Values[0] = llvm::ConstantInt::get(ObjCTypes.LongTy, 0); - Values[1] = llvm::Constant::getNullValue(ObjCTypes.SelectorPtrTy); - Values[2] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumClasses); - Values[3] = llvm::ConstantInt::get(ObjCTypes.ShortTy, NumCategories); + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(); + values.addInt(ObjCTypes.LongTy, 0); + values.addNullPointer(ObjCTypes.SelectorPtrTy); + values.addInt(ObjCTypes.ShortTy, NumClasses); + values.addInt(ObjCTypes.ShortTy, NumCategories); // The runtime expects exactly the list of defined classes followed // by the list of defined categories, in a single array. - SmallVector<llvm::Constant*, 8> Symbols(NumClasses + NumCategories); + auto array = values.beginArray(ObjCTypes.Int8PtrTy); for (unsigned i=0; i<NumClasses; i++) { const ObjCInterfaceDecl *ID = ImplementedClasses[i]; assert(ID); @@ -4627,24 +4916,16 @@ llvm::Constant *CGObjCMac::EmitModuleSymbols() { // We are implementing a weak imported interface. Give it external linkage if (ID->isWeakImported() && !IMP->isWeakImported()) DefinedClasses[i]->setLinkage(llvm::GlobalVariable::ExternalLinkage); - - Symbols[i] = llvm::ConstantExpr::getBitCast(DefinedClasses[i], - ObjCTypes.Int8PtrTy); + + array.addBitCast(DefinedClasses[i], ObjCTypes.Int8PtrTy); } for (unsigned i=0; i<NumCategories; i++) - Symbols[NumClasses + i] = - llvm::ConstantExpr::getBitCast(DefinedCategories[i], - ObjCTypes.Int8PtrTy); + array.addBitCast(DefinedCategories[i], ObjCTypes.Int8PtrTy); - Values[4] = - llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.Int8PtrTy, - Symbols.size()), - Symbols); - - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); + array.finishAndAddTo(values); llvm::GlobalVariable *GV = CreateMetadataVar( - "OBJC_SYMBOLS", Init, "__OBJC,__symbols,regular,no_dead_strip", + "OBJC_SYMBOLS", values, "__OBJC,__symbols,regular,no_dead_strip", CGM.getPointerAlign(), true); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.SymtabPtrTy); } @@ -4707,12 +4988,7 @@ Address CGObjCMac::EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel) { llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) { llvm::GlobalVariable *&Entry = ClassNames[RuntimeName]; if (!Entry) - Entry = CreateMetadataVar( - "OBJC_CLASS_NAME_", - llvm::ConstantDataArray::getString(VMContext, RuntimeName), - ((ObjCABI == 2) ? "__TEXT,__objc_classname,cstring_literals" - : "__TEXT,__cstring,cstring_literals"), - CharUnits::One(), true); + Entry = CreateCStringLiteral(RuntimeName, ObjCLabelType::ClassName); return getConstantGEP(VMContext, Entry, 0, 0); } @@ -4960,14 +5236,8 @@ llvm::Constant *IvarLayoutBuilder::buildBitmap(CGObjCCommonMac &CGObjC, // Null terminate the string. buffer.push_back(0); - bool isNonFragileABI = CGObjC.isNonFragileABI(); - - llvm::GlobalVariable *Entry = CGObjC.CreateMetadataVar( - "OBJC_CLASS_NAME_", - llvm::ConstantDataArray::get(CGM.getLLVMContext(), buffer), - (isNonFragileABI ? "__TEXT,__objc_classname,cstring_literals" - : "__TEXT,__cstring,cstring_literals"), - CharUnits::One(), true); + auto *Entry = CGObjC.CreateCStringLiteral( + reinterpret_cast<char *>(buffer.data()), ObjCLabelType::ClassName); return getConstantGEP(CGM.getLLVMContext(), Entry, 0, 0); } @@ -5062,16 +5332,9 @@ CGObjCCommonMac::BuildIvarLayout(const ObjCImplementationDecl *OMD, llvm::Constant *CGObjCCommonMac::GetMethodVarName(Selector Sel) { llvm::GlobalVariable *&Entry = MethodVarNames[Sel]; - // FIXME: Avoid std::string in "Sel.getAsString()" if (!Entry) - Entry = CreateMetadataVar( - "OBJC_METH_VAR_NAME_", - llvm::ConstantDataArray::getString(VMContext, Sel.getAsString()), - ((ObjCABI == 2) ? "__TEXT,__objc_methname,cstring_literals" - : "__TEXT,__cstring,cstring_literals"), - CharUnits::One(), true); - + Entry = CreateCStringLiteral(Sel.getAsString(), ObjCLabelType::MethodVarName); return getConstantGEP(VMContext, Entry, 0, 0); } @@ -5085,47 +5348,27 @@ llvm::Constant *CGObjCCommonMac::GetMethodVarType(const FieldDecl *Field) { CGM.getContext().getObjCEncodingForType(Field->getType(), TypeStr, Field); llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr]; - if (!Entry) - Entry = CreateMetadataVar( - "OBJC_METH_VAR_TYPE_", - llvm::ConstantDataArray::getString(VMContext, TypeStr), - ((ObjCABI == 2) ? "__TEXT,__objc_methtype,cstring_literals" - : "__TEXT,__cstring,cstring_literals"), - CharUnits::One(), true); - + Entry = CreateCStringLiteral(TypeStr, ObjCLabelType::MethodVarType); return getConstantGEP(VMContext, Entry, 0, 0); } llvm::Constant *CGObjCCommonMac::GetMethodVarType(const ObjCMethodDecl *D, bool Extended) { - std::string TypeStr; - if (CGM.getContext().getObjCEncodingForMethodDecl(D, TypeStr, Extended)) - return nullptr; + std::string TypeStr = + CGM.getContext().getObjCEncodingForMethodDecl(D, Extended); llvm::GlobalVariable *&Entry = MethodVarTypes[TypeStr]; - if (!Entry) - Entry = CreateMetadataVar( - "OBJC_METH_VAR_TYPE_", - llvm::ConstantDataArray::getString(VMContext, TypeStr), - ((ObjCABI == 2) ? "__TEXT,__objc_methtype,cstring_literals" - : "__TEXT,__cstring,cstring_literals"), - CharUnits::One(), true); - + Entry = CreateCStringLiteral(TypeStr, ObjCLabelType::MethodVarType); return getConstantGEP(VMContext, Entry, 0, 0); } // FIXME: Merge into a single cstring creation function. llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) { llvm::GlobalVariable *&Entry = PropertyNames[Ident]; - if (!Entry) - Entry = CreateMetadataVar( - "OBJC_PROP_NAME_ATTR_", - llvm::ConstantDataArray::getString(VMContext, Ident->getName()), - "__TEXT,__cstring,cstring_literals", CharUnits::One(), true); - + Entry = CreateCStringLiteral(Ident->getName(), ObjCLabelType::PropertyName); return getConstantGEP(VMContext, Entry, 0, 0); } @@ -5134,8 +5377,8 @@ llvm::Constant *CGObjCCommonMac::GetPropertyName(IdentifierInfo *Ident) { llvm::Constant * CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD, const Decl *Container) { - std::string TypeStr; - CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container, TypeStr); + std::string TypeStr = + CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container); return GetPropertyName(&CGM.getContext().Idents.get(TypeStr)); } @@ -5157,20 +5400,20 @@ void CGObjCMac::FinishModule() { // Emit the dummy bodies for any protocols which were referenced but // never defined. - for (llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*>::iterator - I = Protocols.begin(), e = Protocols.end(); I != e; ++I) { - if (I->second->hasInitializer()) + for (auto &entry : Protocols) { + llvm::GlobalVariable *global = entry.second; + if (global->hasInitializer()) continue; - llvm::Constant *Values[5]; - Values[0] = llvm::Constant::getNullValue(ObjCTypes.ProtocolExtensionPtrTy); - Values[1] = GetClassName(I->first->getName()); - Values[2] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); - Values[3] = Values[4] = - llvm::Constant::getNullValue(ObjCTypes.MethodDescriptionListPtrTy); - I->second->setInitializer(llvm::ConstantStruct::get(ObjCTypes.ProtocolTy, - Values)); - CGM.addCompilerUsedGlobal(I->second); + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ProtocolTy); + values.addNullPointer(ObjCTypes.ProtocolExtensionPtrTy); + values.add(GetClassName(entry.first->getName())); + values.addNullPointer(ObjCTypes.ProtocolListPtrTy); + values.addNullPointer(ObjCTypes.MethodDescriptionListPtrTy); + values.addNullPointer(ObjCTypes.MethodDescriptionListPtrTy); + values.finishAndSetAsInitializer(global); + CGM.addCompilerUsedGlobal(global); } // Add assembler directives to add lazy undefined symbol references @@ -5178,27 +5421,23 @@ void CGObjCMac::FinishModule() { // important for correct linker interaction. // // FIXME: It would be nice if we had an LLVM construct for this. - if (!LazySymbols.empty() || !DefinedSymbols.empty()) { + if ((!LazySymbols.empty() || !DefinedSymbols.empty()) && + CGM.getTriple().isOSBinFormatMachO()) { SmallString<256> Asm; Asm += CGM.getModule().getModuleInlineAsm(); if (!Asm.empty() && Asm.back() != '\n') Asm += '\n'; llvm::raw_svector_ostream OS(Asm); - for (llvm::SetVector<IdentifierInfo*>::iterator I = DefinedSymbols.begin(), - e = DefinedSymbols.end(); I != e; ++I) - OS << "\t.objc_class_name_" << (*I)->getName() << "=0\n" - << "\t.globl .objc_class_name_" << (*I)->getName() << "\n"; - for (llvm::SetVector<IdentifierInfo*>::iterator I = LazySymbols.begin(), - e = LazySymbols.end(); I != e; ++I) { - OS << "\t.lazy_reference .objc_class_name_" << (*I)->getName() << "\n"; - } + for (const auto *Sym : DefinedSymbols) + OS << "\t.objc_class_name_" << Sym->getName() << "=0\n" + << "\t.globl .objc_class_name_" << Sym->getName() << "\n"; + for (const auto *Sym : LazySymbols) + OS << "\t.lazy_reference .objc_class_name_" << Sym->getName() << "\n"; + for (const auto &Category : DefinedCategoryNames) + OS << "\t.objc_category_name_" << Category << "=0\n" + << "\t.globl .objc_category_name_" << Category << "\n"; - for (size_t i = 0, e = DefinedCategoryNames.size(); i < e; ++i) { - OS << "\t.objc_category_name_" << DefinedCategoryNames[i] << "=0\n" - << "\t.globl .objc_category_name_" << DefinedCategoryNames[i] << "\n"; - } - CGM.getModule().setModuleInlineAsm(OS.str()); } } @@ -5217,10 +5456,9 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) CodeGen::CodeGenTypes &Types = CGM.getTypes(); ASTContext &Ctx = CGM.getContext(); - ShortTy = Types.ConvertType(Ctx.ShortTy); - IntTy = Types.ConvertType(Ctx.IntTy); - LongTy = Types.ConvertType(Ctx.LongTy); - LongLongTy = Types.ConvertType(Ctx.LongLongTy); + ShortTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.ShortTy)); + IntTy = CGM.IntTy; + LongTy = cast<llvm::IntegerType>(Types.ConvertType(Ctx.LongTy)); Int8PtrTy = CGM.Int8PtrTy; Int8PtrPtrTy = CGM.Int8PtrPtrTy; @@ -5231,9 +5469,12 @@ ObjCCommonTypesHelper::ObjCCommonTypesHelper(CodeGen::CodeGenModule &cgm) else IvarOffsetVarTy = LongTy; - ObjectPtrTy = Types.ConvertType(Ctx.getObjCIdType()); - PtrObjectPtrTy = llvm::PointerType::getUnqual(ObjectPtrTy); - SelectorPtrTy = Types.ConvertType(Ctx.getObjCSelType()); + ObjectPtrTy = + cast<llvm::PointerType>(Types.ConvertType(Ctx.getObjCIdType())); + PtrObjectPtrTy = + llvm::PointerType::getUnqual(ObjectPtrTy); + SelectorPtrTy = + cast<llvm::PointerType>(Types.ConvertType(Ctx.getObjCSelType())); // I'm not sure I like this. The implicit coordination is a bit // gross. We should solve this in a reasonable fashion because this @@ -5831,7 +6072,6 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( unsigned InstanceSize, const ObjCImplementationDecl *ID) { std::string ClassName = ID->getObjCRuntimeNameAsString(); - llvm::Constant *Values[10]; // 11 for 64bit targets! CharUnits beginInstance = CharUnits::fromQuantity(InstanceStart); CharUnits endInstance = CharUnits::fromQuantity(InstanceSize); @@ -5842,85 +6082,84 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( 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); - Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize); - // FIXME. For 64bit targets add 0 here. - Values[ 3] = (flags & NonFragileABI_Class_Meta) - ? GetIvarLayoutName(nullptr, ObjCTypes) - : BuildStrongIvarLayout(ID, beginInstance, endInstance); - Values[ 4] = GetClassName(ID->getObjCRuntimeNameAsString()); + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ClassRonfABITy); + + values.addInt(ObjCTypes.IntTy, flags); + values.addInt(ObjCTypes.IntTy, InstanceStart); + values.addInt(ObjCTypes.IntTy, InstanceSize); + values.add((flags & NonFragileABI_Class_Meta) + ? GetIvarLayoutName(nullptr, ObjCTypes) + : BuildStrongIvarLayout(ID, beginInstance, endInstance)); + values.add(GetClassName(ID->getObjCRuntimeNameAsString())); + // const struct _method_list_t * const baseMethods; - std::vector<llvm::Constant*> Methods; - std::string MethodListName("\01l_OBJC_$_"); + SmallVector<const ObjCMethodDecl*, 16> methods; if (flags & NonFragileABI_Class_Meta) { - MethodListName += "CLASS_METHODS_"; - MethodListName += ID->getObjCRuntimeNameAsString(); - for (const auto *I : ID->class_methods()) - // Class methods should always be defined. - Methods.push_back(GetMethodConstant(I)); + for (const auto *MD : ID->class_methods()) + methods.push_back(MD); } else { - MethodListName += "INSTANCE_METHODS_"; - MethodListName += ID->getObjCRuntimeNameAsString(); - for (const auto *I : ID->instance_methods()) - // Instance methods should always be defined. - Methods.push_back(GetMethodConstant(I)); + for (const auto *MD : ID->instance_methods()) + methods.push_back(MD); for (const auto *PID : ID->property_impls()) { if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){ ObjCPropertyDecl *PD = PID->getPropertyDecl(); - if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) - if (llvm::Constant *C = GetMethodConstant(MD)) - Methods.push_back(C); - if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) - if (llvm::Constant *C = GetMethodConstant(MD)) - Methods.push_back(C); + if (auto MD = PD->getGetterMethodDecl()) + if (GetMethodDefinition(MD)) + methods.push_back(MD); + if (auto MD = PD->getSetterMethodDecl()) + if (GetMethodDefinition(MD)) + methods.push_back(MD); } } } - Values[ 5] = EmitMethodList(MethodListName, - "__DATA, __objc_const", Methods); + + values.add(emitMethodList(ID->getObjCRuntimeNameAsString(), + (flags & NonFragileABI_Class_Meta) + ? MethodListType::ClassMethods + : MethodListType::InstanceMethods, + methods)); const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer"); - Values[ 6] = EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_" + values.add(EmitProtocolList("\01l_OBJC_CLASS_PROTOCOLS_$_" + OID->getObjCRuntimeNameAsString(), - OID->all_referenced_protocol_begin(), - OID->all_referenced_protocol_end()); + OID->all_referenced_protocol_begin(), + OID->all_referenced_protocol_end())); if (flags & NonFragileABI_Class_Meta) { - Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy); - Values[ 8] = GetIvarLayoutName(nullptr, ObjCTypes); - Values[ 9] = EmitPropertyList( + values.addNullPointer(ObjCTypes.IvarListnfABIPtrTy); + values.add(GetIvarLayoutName(nullptr, ObjCTypes)); + values.add(EmitPropertyList( "\01l_OBJC_$_CLASS_PROP_LIST_" + ID->getObjCRuntimeNameAsString(), - ID, ID->getClassInterface(), ObjCTypes, true); + ID, ID->getClassInterface(), ObjCTypes, true)); } else { - Values[ 7] = EmitIvarList(ID); - Values[ 8] = BuildWeakIvarLayout(ID, beginInstance, endInstance, - hasMRCWeak); - Values[ 9] = EmitPropertyList( + values.add(EmitIvarList(ID)); + values.add(BuildWeakIvarLayout(ID, beginInstance, endInstance, hasMRCWeak)); + values.add(EmitPropertyList( "\01l_OBJC_$_PROP_LIST_" + ID->getObjCRuntimeNameAsString(), - ID, ID->getClassInterface(), ObjCTypes, false); + ID, ID->getClassInterface(), ObjCTypes, false)); } - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy, - Values); + + llvm::SmallString<64> roLabel; + llvm::raw_svector_ostream(roLabel) + << ((flags & NonFragileABI_Class_Meta) ? "\01l_OBJC_METACLASS_RO_$_" + : "\01l_OBJC_CLASS_RO_$_") + << ClassName; + llvm::GlobalVariable *CLASS_RO_GV = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false, - llvm::GlobalValue::PrivateLinkage, - Init, - (flags & NonFragileABI_Class_Meta) ? - std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName : - std::string("\01l_OBJC_CLASS_RO_$_")+ClassName); - CLASS_RO_GV->setAlignment( - CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassRonfABITy)); - CLASS_RO_GV->setSection("__DATA, __objc_const"); + values.finishAndCreateGlobal(roLabel, CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); + if (CGM.getTriple().isOSBinFormatMachO()) + CLASS_RO_GV->setSection("__DATA, __objc_const"); return CLASS_RO_GV; - } -/// BuildClassMetaData - This routine defines that to-level meta-data -/// for the given ClassName for: +/// Build the metaclass object for a class. +/// /// struct _class_t { /// struct _class_t *isa; /// struct _class_t * const superclass; @@ -5929,28 +6168,33 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( /// struct class_ro_t *ro; /// } /// -llvm::GlobalVariable *CGObjCNonFragileABIMac::BuildClassMetaData( - const std::string &ClassName, llvm::Constant *IsAGV, llvm::Constant *SuperClassGV, - llvm::Constant *ClassRoGV, bool HiddenVisibility, bool Weak) { - llvm::Constant *Values[] = { - IsAGV, - SuperClassGV, - ObjCEmptyCacheVar, // &ObjCEmptyCacheVar - ObjCEmptyVtableVar, // &ObjCEmptyVtableVar - ClassRoGV // &CLASS_RO_GV - }; - if (!Values[1]) - Values[1] = llvm::Constant::getNullValue(ObjCTypes.ClassnfABIPtrTy); - if (!Values[3]) - Values[3] = llvm::Constant::getNullValue( - llvm::PointerType::getUnqual(ObjCTypes.ImpnfABITy)); - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy, - Values); - llvm::GlobalVariable *GV = GetClassGlobal(ClassName, Weak); - GV->setInitializer(Init); - GV->setSection("__DATA, __objc_data"); +llvm::GlobalVariable * +CGObjCNonFragileABIMac::BuildClassObject(const ObjCInterfaceDecl *CI, + bool isMetaclass, + llvm::Constant *IsAGV, + llvm::Constant *SuperClassGV, + llvm::Constant *ClassRoGV, + bool HiddenVisibility) { + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ClassnfABITy); + values.add(IsAGV); + if (SuperClassGV) { + values.add(SuperClassGV); + } else { + values.addNullPointer(ObjCTypes.ClassnfABIPtrTy); + } + values.add(ObjCEmptyCacheVar); + values.add(ObjCEmptyVtableVar); + values.add(ClassRoGV); + + llvm::GlobalVariable *GV = + cast<llvm::GlobalVariable>(GetClassGlobal(CI, isMetaclass, ForDefinition)); + values.finishAndSetAsInitializer(GV); + + if (CGM.getTriple().isOSBinFormatMachO()) + GV->setSection("__DATA, __objc_data"); GV->setAlignment( - CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy)); + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy)); if (!CGM.getTriple().isOSBinFormatCOFF()) if (HiddenVisibility) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -6014,6 +6258,9 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ImpnfABITy, false, llvm::GlobalValue::ExternalLinkage, nullptr, "_objc_empty_vtable"); + else + ObjCEmptyVtableVar = + llvm::ConstantPointerNull::get(ObjCTypes.ImpnfABITy->getPointerTo()); } // FIXME: Is this correct (that meta class size is never computed)? @@ -6022,9 +6269,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { uint32_t InstanceSize = InstanceStart; uint32_t flags = NonFragileABI_Class_Meta; - llvm::GlobalVariable *SuperClassGV, *IsAGV; + llvm::Constant *SuperClassGV, *IsAGV; - StringRef ClassName = ID->getObjCRuntimeNameAsString(); const auto *CI = ID->getClassInterface(); assert(CI && "CGObjCNonFragileABIMac::GenerateClass - class is 0"); @@ -6047,17 +6293,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { // class is root flags |= NonFragileABI_Class_Root; - SuperClassGV = GetClassGlobal((getClassSymbolPrefix() + ClassName).str(), - CI->isWeakImported()); - if (CGM.getTriple().isOSBinFormatCOFF()) - if (CI->hasAttr<DLLImportAttr>()) - SuperClassGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); - - IsAGV = GetClassGlobal((getMetaclassSymbolPrefix() + ClassName).str(), - CI->isWeakImported()); - if (CGM.getTriple().isOSBinFormatCOFF()) - if (CI->hasAttr<DLLImportAttr>()) - IsAGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + SuperClassGV = GetClassGlobal(CI, /*metaclass*/ false, NotForDefinition); + IsAGV = GetClassGlobal(CI, /*metaclass*/ true, NotForDefinition); } else { // Has a root. Current class is not a root. const ObjCInterfaceDecl *Root = ID->getClassInterface(); @@ -6065,31 +6302,16 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { Root = Super; const auto *Super = CI->getSuperClass(); - StringRef RootClassName = Root->getObjCRuntimeNameAsString(); - StringRef SuperClassName = Super->getObjCRuntimeNameAsString(); - - IsAGV = GetClassGlobal((getMetaclassSymbolPrefix() + RootClassName).str(), - Root->isWeakImported()); - if (CGM.getTriple().isOSBinFormatCOFF()) - if (Root->hasAttr<DLLImportAttr>()) - IsAGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); - - // work on super class metadata symbol. - SuperClassGV = - GetClassGlobal((getMetaclassSymbolPrefix() + SuperClassName).str(), - Super->isWeakImported()); - if (CGM.getTriple().isOSBinFormatCOFF()) - if (Super->hasAttr<DLLImportAttr>()) - SuperClassGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + IsAGV = GetClassGlobal(Root, /*metaclass*/ true, NotForDefinition); + SuperClassGV = GetClassGlobal(Super, /*metaclass*/ true, NotForDefinition); } llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags, InstanceStart, InstanceSize, ID); llvm::GlobalVariable *MetaTClass = - BuildClassMetaData((getMetaclassSymbolPrefix() + ClassName).str(), IsAGV, - SuperClassGV, CLASS_RO_GV, classIsHidden, - CI->isWeakImported()); + BuildClassObject(CI, /*metaclass*/ true, + IsAGV, SuperClassGV, CLASS_RO_GV, classIsHidden); if (CGM.getTriple().isOSBinFormatCOFF()) if (CI->hasAttr<DLLExportAttr>()) MetaTClass->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); @@ -6122,14 +6344,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { } else { // Has a root. Current class is not a root. const auto *Super = CI->getSuperClass(); - StringRef SuperClassName = Super->getObjCRuntimeNameAsString(); - - SuperClassGV = - GetClassGlobal((getClassSymbolPrefix() + SuperClassName).str(), - Super->isWeakImported()); - if (CGM.getTriple().isOSBinFormatCOFF()) - if (Super->hasAttr<DLLImportAttr>()) - SuperClassGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + SuperClassGV = GetClassGlobal(Super, /*metaclass*/ false, NotForDefinition); } GetClassSizeInfo(ID, InstanceStart, InstanceSize); @@ -6137,9 +6352,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { BuildClassRoTInitializer(flags, InstanceStart, InstanceSize, ID); llvm::GlobalVariable *ClassMD = - BuildClassMetaData((getClassSymbolPrefix() + ClassName).str(), MetaTClass, - SuperClassGV, CLASS_RO_GV, classIsHidden, - CI->isWeakImported()); + BuildClassObject(CI, /*metaclass*/ false, + MetaTClass, SuperClassGV, CLASS_RO_GV, classIsHidden); if (CGM.getTriple().isOSBinFormatCOFF()) if (CI->hasAttr<DLLExportAttr>()) ClassMD->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); @@ -6152,7 +6366,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { // Force the definition of the EHType if necessary. if (flags & NonFragileABI_Class_Exception) - GetInterfaceEHType(CI, true); + (void) GetInterfaceEHType(CI, ForDefinition); // Make sure method definition entries are all clear for next implementation. MethodDefinitions.clear(); } @@ -6217,82 +6431,59 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { ExtCatName += "_$_"; ExtCatName += OCD->getNameAsString(); - llvm::SmallString<64> ExtClassName(getClassSymbolPrefix()); - ExtClassName += Interface->getObjCRuntimeNameAsString(); - - llvm::Constant *Values[8]; - Values[0] = GetClassName(OCD->getIdentifier()->getName()); + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.CategorynfABITy); + values.add(GetClassName(OCD->getIdentifier()->getName())); // meta-class entry symbol - llvm::GlobalVariable *ClassGV = - GetClassGlobal(ExtClassName.str(), Interface->isWeakImported()); + values.add(GetClassGlobal(Interface, /*metaclass*/ false, NotForDefinition)); + std::string listName = + (Interface->getObjCRuntimeNameAsString() + "_$_" + OCD->getName()).str(); + + SmallVector<const ObjCMethodDecl *, 16> instanceMethods; + SmallVector<const ObjCMethodDecl *, 8> classMethods; + for (const auto *MD : OCD->methods()) { + if (MD->isInstanceMethod()) { + instanceMethods.push_back(MD); + } else { + classMethods.push_back(MD); + } + } + + values.add(emitMethodList(listName, MethodListType::CategoryInstanceMethods, + instanceMethods)); + values.add(emitMethodList(listName, MethodListType::CategoryClassMethods, + classMethods)); - Values[1] = ClassGV; - std::vector<llvm::Constant*> Methods; - llvm::SmallString<64> MethodListName(Prefix); - - MethodListName += "INSTANCE_METHODS_"; - MethodListName += Interface->getObjCRuntimeNameAsString(); - MethodListName += "_$_"; - MethodListName += OCD->getName(); - - for (const auto *I : OCD->instance_methods()) - // Instance methods should always be defined. - Methods.push_back(GetMethodConstant(I)); - - Values[2] = EmitMethodList(MethodListName.str(), - "__DATA, __objc_const", - Methods); - - MethodListName = Prefix; - MethodListName += "CLASS_METHODS_"; - MethodListName += Interface->getObjCRuntimeNameAsString(); - MethodListName += "_$_"; - MethodListName += OCD->getNameAsString(); - - Methods.clear(); - for (const auto *I : OCD->class_methods()) - // Class methods should always be defined. - Methods.push_back(GetMethodConstant(I)); - - Values[3] = EmitMethodList(MethodListName.str(), - "__DATA, __objc_const", - Methods); const ObjCCategoryDecl *Category = Interface->FindCategoryDeclaration(OCD->getIdentifier()); if (Category) { SmallString<256> ExtName; llvm::raw_svector_ostream(ExtName) << Interface->getObjCRuntimeNameAsString() << "_$_" << OCD->getName(); - Values[4] = EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_" + values.add(EmitProtocolList("\01l_OBJC_CATEGORY_PROTOCOLS_$_" + Interface->getObjCRuntimeNameAsString() + "_$_" + Category->getName(), - Category->protocol_begin(), - Category->protocol_end()); - Values[5] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(), - OCD, Category, ObjCTypes, false); - Values[6] = EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), - OCD, Category, ObjCTypes, true); + Category->protocol_begin(), + Category->protocol_end())); + values.add(EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ExtName.str(), + OCD, Category, ObjCTypes, false)); + values.add(EmitPropertyList("\01l_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), + OCD, Category, ObjCTypes, true)); } else { - Values[4] = llvm::Constant::getNullValue(ObjCTypes.ProtocolListnfABIPtrTy); - Values[5] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); - Values[6] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); + values.addNullPointer(ObjCTypes.ProtocolListnfABIPtrTy); + values.addNullPointer(ObjCTypes.PropertyListPtrTy); + values.addNullPointer(ObjCTypes.PropertyListPtrTy); } unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy); - Values[7] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); - - llvm::Constant *Init = - llvm::ConstantStruct::get(ObjCTypes.CategorynfABITy, - Values); - llvm::GlobalVariable *GCATV - = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.CategorynfABITy, - false, - llvm::GlobalValue::PrivateLinkage, - Init, - ExtCatName.str()); - GCATV->setAlignment( - CGM.getDataLayout().getABITypeAlignment(ObjCTypes.CategorynfABITy)); - GCATV->setSection("__DATA, __objc_const"); + values.addInt(ObjCTypes.IntTy, Size); + + llvm::GlobalVariable *GCATV = + values.finishAndCreateGlobal(ExtCatName.str(), CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); + if (CGM.getTriple().isOSBinFormatMachO()) + GCATV->setSection("__DATA, __objc_const"); CGM.addCompilerUsedGlobal(GCATV); DefinedCategories.push_back(GCATV); @@ -6303,25 +6494,37 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { MethodDefinitions.clear(); } -/// GetMethodConstant - Return a struct objc_method constant for the -/// given method if it has been defined. The result is null if the -/// method has not been defined. The return value has type MethodPtrTy. -llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant( - const ObjCMethodDecl *MD) { - llvm::Function *Fn = GetMethodDefinition(MD); - if (!Fn) - return nullptr; - - llvm::Constant *Method[] = { - llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), - ObjCTypes.SelectorPtrTy), - GetMethodVarType(MD), - llvm::ConstantExpr::getBitCast(Fn, ObjCTypes.Int8PtrTy) - }; - return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Method); +/// emitMethodConstant - Return a struct objc_method constant. If +/// forProtocol is true, the implementation will be null; otherwise, +/// the method must have a definition registered with the runtime. +/// +/// struct _objc_method { +/// SEL _cmd; +/// char *method_type; +/// char *_imp; +/// } +void CGObjCNonFragileABIMac::emitMethodConstant(ConstantArrayBuilder &builder, + const ObjCMethodDecl *MD, + bool forProtocol) { + auto method = builder.beginStruct(ObjCTypes.MethodTy); + method.addBitCast(GetMethodVarName(MD->getSelector()), + ObjCTypes.SelectorPtrTy); + method.add(GetMethodVarType(MD)); + + if (forProtocol) { + // Protocol methods have no implementation. So, this entry is always NULL. + method.addNullPointer(ObjCTypes.Int8PtrTy); + } else { + llvm::Function *fn = GetMethodDefinition(MD); + assert(fn && "no definition for method?"); + method.addBitCast(fn, ObjCTypes.Int8PtrTy); + } + + method.finishAndAddTo(builder); } -/// EmitMethodList - Build meta-data for method declarations +/// Build meta-data for method declarations. +/// /// struct _method_list_t { /// uint32_t entsize; // sizeof(struct _objc_method) /// uint32_t method_count; @@ -6329,28 +6532,69 @@ llvm::Constant *CGObjCNonFragileABIMac::GetMethodConstant( /// } /// llvm::Constant * -CGObjCNonFragileABIMac::EmitMethodList(Twine Name, StringRef Section, - ArrayRef<llvm::Constant *> Methods) { +CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind, + ArrayRef<const ObjCMethodDecl *> methods) { // Return null for empty list. - if (Methods.empty()) + if (methods.empty()) return llvm::Constant::getNullValue(ObjCTypes.MethodListnfABIPtrTy); - llvm::Constant *Values[3]; + StringRef prefix; + bool forProtocol; + switch (kind) { + case MethodListType::CategoryInstanceMethods: + prefix = "\01l_OBJC_$_CATEGORY_INSTANCE_METHODS_"; + forProtocol = false; + break; + case MethodListType::CategoryClassMethods: + prefix = "\01l_OBJC_$_CATEGORY_CLASS_METHODS_"; + forProtocol = false; + break; + case MethodListType::InstanceMethods: + prefix = "\01l_OBJC_$_INSTANCE_METHODS_"; + forProtocol = false; + break; + case MethodListType::ClassMethods: + prefix = "\01l_OBJC_$_CLASS_METHODS_"; + forProtocol = false; + break; + + case MethodListType::ProtocolInstanceMethods: + prefix = "\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_"; + forProtocol = true; + break; + case MethodListType::ProtocolClassMethods: + prefix = "\01l_OBJC_$_PROTOCOL_CLASS_METHODS_"; + forProtocol = true; + break; + case MethodListType::OptionalProtocolInstanceMethods: + prefix = "\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_"; + forProtocol = true; + break; + case MethodListType::OptionalProtocolClassMethods: + prefix = "\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_"; + forProtocol = true; + break; + } + + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(); + // sizeof(struct _objc_method) unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.MethodTy); - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); + values.addInt(ObjCTypes.IntTy, Size); // method_count - Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size()); - llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.MethodTy, - Methods.size()); - Values[2] = llvm::ConstantArray::get(AT, Methods); - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); + values.addInt(ObjCTypes.IntTy, methods.size()); + auto methodArray = values.beginArray(ObjCTypes.MethodTy); + for (auto MD : methods) { + emitMethodConstant(methodArray, MD, forProtocol); + } + methodArray.finishAndAddTo(values); - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, - llvm::GlobalValue::PrivateLinkage, Init, Name); - GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType())); - GV->setSection(Section); + auto *GV = values.finishAndCreateGlobal(prefix + name, CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); + if (CGM.getTriple().isOSBinFormatMachO()) + GV->setSection("__DATA, __objc_const"); CGM.addCompilerUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy); } @@ -6406,7 +6650,8 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, IvarOffsetGV->setVisibility(llvm::GlobalValue::DefaultVisibility); } - IvarOffsetGV->setSection("__DATA, __objc_ivar"); + if (CGM.getTriple().isOSBinFormatMachO()) + IvarOffsetGV->setSection("__DATA, __objc_ivar"); return IvarOffsetGV; } @@ -6430,7 +6675,12 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( const ObjCImplementationDecl *ID) { - std::vector<llvm::Constant*> Ivars; + ConstantInitBuilder builder(CGM); + auto ivarList = builder.beginStruct(); + ivarList.addInt(ObjCTypes.IntTy, + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy)); + auto ivarCountSlot = ivarList.addPlaceholder(); + auto ivars = ivarList.beginArray(ObjCTypes.IvarnfABITy); const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::EmitIvarList - null interface"); @@ -6442,48 +6692,45 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( // Ignore unnamed bit-fields. if (!IVD->getDeclName()) continue; - llvm::Constant *Ivar[5]; - Ivar[0] = EmitIvarOffsetVar(ID->getClassInterface(), IVD, - ComputeIvarBaseOffset(CGM, ID, IVD)); - Ivar[1] = GetMethodVarName(IVD->getIdentifier()); - Ivar[2] = GetMethodVarType(IVD); + + auto ivar = ivars.beginStruct(ObjCTypes.IvarnfABITy); + ivar.add(EmitIvarOffsetVar(ID->getClassInterface(), IVD, + ComputeIvarBaseOffset(CGM, ID, IVD))); + ivar.add(GetMethodVarName(IVD->getIdentifier())); + ivar.add(GetMethodVarType(IVD)); llvm::Type *FieldTy = CGM.getTypes().ConvertTypeForMem(IVD->getType()); unsigned Size = CGM.getDataLayout().getTypeAllocSize(FieldTy); unsigned Align = CGM.getContext().getPreferredTypeAlign( IVD->getType().getTypePtr()) >> 3; Align = llvm::Log2_32(Align); - Ivar[3] = llvm::ConstantInt::get(ObjCTypes.IntTy, Align); + ivar.addInt(ObjCTypes.IntTy, Align); // NOTE. Size of a bitfield does not match gcc's, because of the // way bitfields are treated special in each. But I am told that // 'size' for bitfield ivars is ignored by the runtime so it does // not matter. If it matters, there is enough info to get the // bitfield right! - Ivar[4] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); - Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarnfABITy, Ivar)); + ivar.addInt(ObjCTypes.IntTy, Size); + ivar.finishAndAddTo(ivars); } // Return null for empty list. - if (Ivars.empty()) + if (ivars.empty()) { + ivars.abandon(); + ivarList.abandon(); return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy); + } + + auto ivarCount = ivars.size(); + ivars.finishAndAddTo(ivarList); + ivarList.fillPlaceholderWithInt(ivarCountSlot, ObjCTypes.IntTy, ivarCount); - llvm::Constant *Values[3]; - unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy); - Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); - Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size()); - llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy, - Ivars.size()); - Values[2] = llvm::ConstantArray::get(AT, Ivars); - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); const char *Prefix = "\01l_OBJC_$_INSTANCE_VARIABLES_"; llvm::GlobalVariable *GV = - new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, - llvm::GlobalValue::PrivateLinkage, - Init, - Prefix + OID->getObjCRuntimeNameAsString()); - GV->setAlignment( - CGM.getDataLayout().getABITypeAlignment(Init->getType())); - GV->setSection("__DATA, __objc_const"); - + ivarList.finishAndCreateGlobal(Prefix + OID->getObjCRuntimeNameAsString(), + CGM.getPointerAlign(), /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); + if (CGM.getTriple().isOSBinFormatMachO()) + GV->setSection("__DATA, __objc_const"); CGM.addCompilerUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.IvarListnfABIPtrTy); } @@ -6492,15 +6739,20 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocolRef( const ObjCProtocolDecl *PD) { llvm::GlobalVariable *&Entry = Protocols[PD->getIdentifier()]; - if (!Entry) + if (!Entry) { // We use the initializer as a marker of whether this is a forward // reference or not. At module finalization we add the empty // contents for protocols which were referenced but never defined. - Entry = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, - false, llvm::GlobalValue::ExternalLinkage, - nullptr, - "\01l_OBJC_PROTOCOL_$_" + PD->getObjCRuntimeNameAsString()); + llvm::SmallString<64> Protocol; + llvm::raw_svector_ostream(Protocol) << "\01l_OBJC_PROTOCOL_$_" + << PD->getObjCRuntimeNameAsString(); + + Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, + false, llvm::GlobalValue::ExternalLinkage, + nullptr, Protocol); + if (!CGM.getTriple().isOSBinFormatMachO()) + Entry->setComdat(CGM.getModule().getOrInsertComdat(Protocol)); + } return Entry; } @@ -6537,96 +6789,59 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( if (const ObjCProtocolDecl *Def = PD->getDefinition()) PD = Def; - // Construct method lists. - std::vector<llvm::Constant*> InstanceMethods, ClassMethods; - std::vector<llvm::Constant*> OptInstanceMethods, OptClassMethods; - std::vector<llvm::Constant*> MethodTypesExt, OptMethodTypesExt; - for (const auto *MD : PD->instance_methods()) { - llvm::Constant *C = GetMethodDescriptionConstant(MD); - if (!C) - return GetOrEmitProtocolRef(PD); - - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptInstanceMethods.push_back(C); - OptMethodTypesExt.push_back(GetMethodVarType(MD, true)); - } else { - InstanceMethods.push_back(C); - MethodTypesExt.push_back(GetMethodVarType(MD, true)); - } - } - - for (const auto *MD : PD->class_methods()) { - llvm::Constant *C = GetMethodDescriptionConstant(MD); - if (!C) - return GetOrEmitProtocolRef(PD); - - if (MD->getImplementationControl() == ObjCMethodDecl::Optional) { - OptClassMethods.push_back(C); - OptMethodTypesExt.push_back(GetMethodVarType(MD, true)); - } else { - ClassMethods.push_back(C); - MethodTypesExt.push_back(GetMethodVarType(MD, true)); - } - } + auto methodLists = ProtocolMethodLists::get(PD); - MethodTypesExt.insert(MethodTypesExt.end(), - OptMethodTypesExt.begin(), OptMethodTypesExt.end()); + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.ProtocolnfABITy); - llvm::Constant *Values[13]; // isa is NULL - Values[0] = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy); - Values[1] = GetClassName(PD->getObjCRuntimeNameAsString()); - Values[2] = EmitProtocolList("\01l_OBJC_$_PROTOCOL_REFS_" + PD->getObjCRuntimeNameAsString(), + values.addNullPointer(ObjCTypes.ObjectPtrTy); + values.add(GetClassName(PD->getObjCRuntimeNameAsString())); + values.add(EmitProtocolList("\01l_OBJC_$_PROTOCOL_REFS_" + + PD->getObjCRuntimeNameAsString(), PD->protocol_begin(), - PD->protocol_end()); - - Values[3] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_" - + PD->getObjCRuntimeNameAsString(), - "__DATA, __objc_const", - InstanceMethods); - Values[4] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_" - + PD->getObjCRuntimeNameAsString(), - "__DATA, __objc_const", - ClassMethods); - Values[5] = EmitMethodList("\01l_OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_" - + PD->getObjCRuntimeNameAsString(), - "__DATA, __objc_const", - OptInstanceMethods); - Values[6] = EmitMethodList("\01l_OBJC_$_PROTOCOL_CLASS_METHODS_OPT_" - + PD->getObjCRuntimeNameAsString(), - "__DATA, __objc_const", - OptClassMethods); - Values[7] = EmitPropertyList( - "\01l_OBJC_$_PROP_LIST_" + PD->getObjCRuntimeNameAsString(), - nullptr, PD, ObjCTypes, false); + PD->protocol_end())); + values.add(methodLists.emitMethodList(this, PD, + ProtocolMethodLists::RequiredInstanceMethods)); + values.add(methodLists.emitMethodList(this, PD, + ProtocolMethodLists::RequiredClassMethods)); + values.add(methodLists.emitMethodList(this, PD, + ProtocolMethodLists::OptionalInstanceMethods)); + values.add(methodLists.emitMethodList(this, PD, + ProtocolMethodLists::OptionalClassMethods)); + values.add(EmitPropertyList( + "\01l_OBJC_$_PROP_LIST_" + PD->getObjCRuntimeNameAsString(), + nullptr, PD, ObjCTypes, false)); uint32_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy); - Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); - Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy); - Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_" + values.addInt(ObjCTypes.IntTy, Size); + values.addInt(ObjCTypes.IntTy, 0); + values.add(EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_" + PD->getObjCRuntimeNameAsString(), - MethodTypesExt, ObjCTypes); + methodLists.emitExtendedTypesArray(this), + ObjCTypes)); + // const char *demangledName; - Values[11] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); + values.addNullPointer(ObjCTypes.Int8PtrTy); - Values[12] = EmitPropertyList( + values.add(EmitPropertyList( "\01l_OBJC_$_CLASS_PROP_LIST_" + PD->getObjCRuntimeNameAsString(), - nullptr, PD, ObjCTypes, true); + nullptr, PD, ObjCTypes, true)); - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ProtocolnfABITy, - Values); - if (Entry) { // Already created, fix the linkage and update the initializer. Entry->setLinkage(llvm::GlobalValue::WeakAnyLinkage); - Entry->setInitializer(Init); + values.finishAndSetAsInitializer(Entry); } else { - Entry = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABITy, - false, llvm::GlobalValue::WeakAnyLinkage, Init, - "\01l_OBJC_PROTOCOL_$_" + PD->getObjCRuntimeNameAsString()); - Entry->setAlignment( - CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABITy)); + llvm::SmallString<64> symbolName; + llvm::raw_svector_ostream(symbolName) + << "\01l_OBJC_PROTOCOL_$_" << PD->getObjCRuntimeNameAsString(); + + Entry = values.finishAndCreateGlobal(symbolName, CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::WeakAnyLinkage); + if (!CGM.getTriple().isOSBinFormatMachO()) + Entry->setComdat(CGM.getModule().getOrInsertComdat(symbolName)); Protocols[PD->getIdentifier()] = Entry; } @@ -6635,13 +6850,20 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( // Use this protocol meta-data to build protocol list table in section // __DATA, __objc_protolist + llvm::SmallString<64> ProtocolRef; + llvm::raw_svector_ostream(ProtocolRef) << "\01l_OBJC_LABEL_PROTOCOL_$_" + << PD->getObjCRuntimeNameAsString(); + llvm::GlobalVariable *PTGV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ProtocolnfABIPtrTy, false, llvm::GlobalValue::WeakAnyLinkage, Entry, - "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getObjCRuntimeNameAsString()); + ProtocolRef); + if (!CGM.getTriple().isOSBinFormatMachO()) + PTGV->setComdat(CGM.getModule().getOrInsertComdat(ProtocolRef)); PTGV->setAlignment( CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); - PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); + if (CGM.getTriple().isOSBinFormatMachO()) + PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); CGM.addCompilerUsedGlobal(PTGV); return Entry; @@ -6673,55 +6895,30 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name, if (GV) return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); - for (; begin != end; ++begin) - ProtocolRefs.push_back(GetProtocolRef(*begin)); // Implemented??? + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(); + auto countSlot = values.addPlaceholder(); - // This list is null terminated. - ProtocolRefs.push_back(llvm::Constant::getNullValue( - ObjCTypes.ProtocolnfABIPtrTy)); - - llvm::Constant *Values[2]; - Values[0] = - llvm::ConstantInt::get(ObjCTypes.LongTy, ProtocolRefs.size() - 1); - Values[1] = - llvm::ConstantArray::get(llvm::ArrayType::get(ObjCTypes.ProtocolnfABIPtrTy, - ProtocolRefs.size()), - ProtocolRefs); - - llvm::Constant *Init = llvm::ConstantStruct::getAnon(Values); - GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, - llvm::GlobalValue::PrivateLinkage, - Init, Name); - GV->setSection("__DATA, __objc_const"); - GV->setAlignment( - CGM.getDataLayout().getABITypeAlignment(Init->getType())); + // A null-terminated array of protocols. + auto array = values.beginArray(ObjCTypes.ProtocolnfABIPtrTy); + for (; begin != end; ++begin) + array.add(GetProtocolRef(*begin)); // Implemented??? + auto count = array.size(); + array.addNullPointer(ObjCTypes.ProtocolnfABIPtrTy); + + array.finishAndAddTo(values); + values.fillPlaceholderWithInt(countSlot, ObjCTypes.LongTy, count); + + GV = values.finishAndCreateGlobal(Name, CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); + if (CGM.getTriple().isOSBinFormatMachO()) + GV->setSection("__DATA, __objc_const"); CGM.addCompilerUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); } -/// GetMethodDescriptionConstant - This routine build following meta-data: -/// struct _objc_method { -/// SEL _cmd; -/// char *method_type; -/// char *_imp; -/// } - -llvm::Constant * -CGObjCNonFragileABIMac::GetMethodDescriptionConstant(const ObjCMethodDecl *MD) { - llvm::Constant *Desc[3]; - Desc[0] = - llvm::ConstantExpr::getBitCast(GetMethodVarName(MD->getSelector()), - ObjCTypes.SelectorPtrTy); - Desc[1] = GetMethodVarType(MD); - if (!Desc[1]) - return nullptr; - - // Protocol methods have no implementation. So, this entry is always NULL. - Desc[2] = llvm::Constant::getNullValue(ObjCTypes.Int8PtrTy); - return llvm::ConstantStruct::get(ObjCTypes.MethodTy, Desc); -} - /// EmitObjCValueForIvar - Code Gen for nonfragile ivar reference. /// This code gen. amounts to generating code for: /// @code @@ -6853,16 +7050,15 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, = CGM.getModule().getGlobalVariable(messageRefName); if (!messageRef) { // Build the message ref structure. - llvm::Constant *values[] = { fn, GetMethodVarName(selector) }; - llvm::Constant *init = llvm::ConstantStruct::getAnon(values); - messageRef = new llvm::GlobalVariable(CGM.getModule(), - init->getType(), - /*constant*/ false, - llvm::GlobalValue::WeakAnyLinkage, - init, - messageRefName); + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(); + values.add(fn); + values.add(GetMethodVarName(selector)); + messageRef = values.finishAndCreateGlobal(messageRefName, + CharUnits::fromQuantity(16), + /*constant*/ false, + llvm::GlobalValue::WeakAnyLinkage); messageRef->setVisibility(llvm::GlobalValue::HiddenVisibility); - messageRef->setAlignment(16); messageRef->setSection("__DATA, __objc_msgrefs, coalesced"); } @@ -6887,9 +7083,10 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, // Load the function to call from the message ref table. Address calleeAddr = CGF.Builder.CreateStructGEP(mref, 0, CharUnits::Zero()); - llvm::Value *callee = CGF.Builder.CreateLoad(calleeAddr, "msgSend_fn"); + llvm::Value *calleePtr = CGF.Builder.CreateLoad(calleeAddr, "msgSend_fn"); - callee = CGF.Builder.CreateBitCast(callee, MSI.MessengerType); + calleePtr = CGF.Builder.CreateBitCast(calleePtr, MSI.MessengerType); + CGCallee callee(CGCalleeInfo(), calleePtr); RValue result = CGF.EmitCall(MSI.CallInfo, callee, returnSlot, args); return nullReturn.complete(CGF, result, resultType, formalArgs, @@ -6916,33 +7113,59 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, false, CallArgs, Method, Class, ObjCTypes); } -llvm::GlobalVariable * -CGObjCNonFragileABIMac::GetClassGlobal(StringRef Name, bool Weak) { +llvm::Constant * +CGObjCNonFragileABIMac::GetClassGlobal(const ObjCInterfaceDecl *ID, + bool metaclass, + ForDefinition_t isForDefinition) { + auto prefix = + (metaclass ? getMetaclassSymbolPrefix() : getClassSymbolPrefix()); + return GetClassGlobal((prefix + ID->getObjCRuntimeNameAsString()).str(), + isForDefinition, + ID->isWeakImported(), + !isForDefinition + && CGM.getTriple().isOSBinFormatCOFF() + && ID->hasAttr<DLLImportAttr>()); +} + +llvm::Constant * +CGObjCNonFragileABIMac::GetClassGlobal(StringRef Name, + ForDefinition_t IsForDefinition, + bool Weak, bool DLLImport) { llvm::GlobalValue::LinkageTypes L = Weak ? llvm::GlobalValue::ExternalWeakLinkage : llvm::GlobalValue::ExternalLinkage; - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (!GV) + + llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); + if (!GV) { GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy, false, L, nullptr, Name); + if (DLLImport) + GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + } + assert(GV->getLinkage() == L); return GV; } -llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF, - IdentifierInfo *II, - bool Weak, - const ObjCInterfaceDecl *ID) { +llvm::Value * +CGObjCNonFragileABIMac::EmitClassRefFromId(CodeGenFunction &CGF, + IdentifierInfo *II, + const ObjCInterfaceDecl *ID) { CharUnits Align = CGF.getPointerAlign(); llvm::GlobalVariable *&Entry = ClassReferences[II]; if (!Entry) { - StringRef Name = ID ? ID->getObjCRuntimeNameAsString() : II->getName(); - std::string ClassName = (getClassSymbolPrefix() + Name).str(); - llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName, Weak); + llvm::Constant *ClassGV; + if (ID) { + ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition); + } else { + ClassGV = GetClassGlobal((getClassSymbolPrefix() + II->getName()).str(), + NotForDefinition); + } + Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false, llvm::GlobalValue::PrivateLinkage, ClassGV, "OBJC_CLASSLIST_REFERENCES_$_"); @@ -6960,13 +7183,13 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CodeGenFunction &CGF, if (ID->hasAttr<ObjCRuntimeVisibleAttr>()) return EmitClassRefViaRuntime(CGF, ID, ObjCTypes); - return EmitClassRefFromId(CGF, ID->getIdentifier(), ID->isWeakImported(), ID); + return EmitClassRefFromId(CGF, ID->getIdentifier(), ID); } llvm::Value *CGObjCNonFragileABIMac::EmitNSAutoreleasePoolClassRef( CodeGenFunction &CGF) { IdentifierInfo *II = &CGM.getContext().Idents.get("NSAutoreleasePool"); - return EmitClassRefFromId(CGF, II, false, nullptr); + return EmitClassRefFromId(CGF, II, nullptr); } llvm::Value * @@ -6976,10 +7199,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CodeGenFunction &CGF, llvm::GlobalVariable *&Entry = SuperClassReferences[ID->getIdentifier()]; if (!Entry) { - llvm::SmallString<64> ClassName(getClassSymbolPrefix()); - ClassName += ID->getObjCRuntimeNameAsString(); - llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName.str(), - ID->isWeakImported()); + auto ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition); Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false, llvm::GlobalValue::PrivateLinkage, ClassGV, "OBJC_CLASSLIST_SUP_REFS_$_"); @@ -6999,10 +7219,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF, CharUnits Align = CGF.getPointerAlign(); llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()]; if (!Entry) { - llvm::SmallString<64> MetaClassName(getMetaclassSymbolPrefix()); - MetaClassName += ID->getObjCRuntimeNameAsString(); - llvm::GlobalVariable *MetaClassGV = - GetClassGlobal(MetaClassName.str(), Weak); + auto MetaClassGV = GetClassGlobal(ID, /*metaclass*/ true, NotForDefinition); Entry = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABIPtrTy, false, llvm::GlobalValue::PrivateLinkage, @@ -7021,11 +7238,10 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CodeGenFunction &CGF, llvm::Value *CGObjCNonFragileABIMac::GetClass(CodeGenFunction &CGF, const ObjCInterfaceDecl *ID) { if (ID->isWeakImported()) { - llvm::SmallString<64> ClassName(getClassSymbolPrefix()); - ClassName += ID->getObjCRuntimeNameAsString(); - llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName.str(), true); + auto ClassGV = GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition); (void)ClassGV; - assert(ClassGV->hasExternalWeakLinkage()); + assert(!isa<llvm::GlobalVariable>(ClassGV) || + cast<llvm::GlobalVariable>(ClassGV)->hasExternalWeakLinkage()); } return EmitClassRef(CGF, ID); @@ -7258,7 +7474,7 @@ CGObjCNonFragileABIMac::GetEHType(QualType T) { const ObjCInterfaceType *IT = PT->getInterfaceType(); assert(IT && "Invalid @catch type."); - return GetInterfaceEHType(IT->getDecl(), false); + return GetInterfaceEHType(IT->getDecl(), NotForDefinition); } void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF, @@ -7290,13 +7506,13 @@ void CGObjCNonFragileABIMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF, llvm::Constant * CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, - bool ForDefinition) { + ForDefinition_t IsForDefinition) { llvm::GlobalVariable * &Entry = EHTypeReferences[ID->getIdentifier()]; StringRef ClassName = ID->getObjCRuntimeNameAsString(); // If we don't need a definition, return the entry if found or check // if we use an external reference. - if (!ForDefinition) { + if (!IsForDefinition) { if (Entry) return Entry; @@ -7332,23 +7548,24 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, } llvm::Value *VTableIdx = llvm::ConstantInt::get(CGM.Int32Ty, 2); - llvm::Constant *Values[] = { - llvm::ConstantExpr::getGetElementPtr(VTableGV->getValueType(), VTableGV, - VTableIdx), - GetClassName(ID->getObjCRuntimeNameAsString()), - GetClassGlobal((getClassSymbolPrefix() + ClassName).str()), - }; - llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.EHTypeTy, Values); - - llvm::GlobalValue::LinkageTypes L = ForDefinition + ConstantInitBuilder builder(CGM); + auto values = builder.beginStruct(ObjCTypes.EHTypeTy); + values.add(llvm::ConstantExpr::getGetElementPtr(VTableGV->getValueType(), + VTableGV, VTableIdx)); + values.add(GetClassName(ClassName)); + values.add(GetClassGlobal(ID, /*metaclass*/ false, NotForDefinition)); + + llvm::GlobalValue::LinkageTypes L = IsForDefinition ? llvm::GlobalValue::ExternalLinkage : llvm::GlobalValue::WeakAnyLinkage; if (Entry) { - Entry->setInitializer(Init); + values.finishAndSetAsInitializer(Entry); + Entry->setAlignment(CGM.getPointerAlign().getQuantity()); } else { - Entry = - new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.EHTypeTy, false, L, - Init, ("OBJC_EHTYPE_$_" + ClassName).str()); + Entry = values.finishAndCreateGlobal("OBJC_EHTYPE_$_" + ClassName, + CGM.getPointerAlign(), + /*constant*/ false, + L); if (CGM.getTriple().isOSBinFormatCOFF()) if (hasObjCExceptionAttribute(CGM.getContext(), ID)) if (ID->hasAttr<DLLExportAttr>()) @@ -7360,11 +7577,9 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, if (ID->getVisibility() == HiddenVisibility) Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); - const auto &DL = CGM.getDataLayout(); - Entry->setAlignment(DL.getABITypeAlignment(ObjCTypes.EHTypeTy)); - - if (ForDefinition) - Entry->setSection("__DATA,__objc_const"); + if (IsForDefinition) + if (CGM.getTriple().isOSBinFormatMachO()) + Entry->setSection("__DATA,__objc_const"); return Entry; } |