diff options
author | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 13:58:24 +0300 |
---|---|---|
committer | thegeorg <thegeorg@yandex-team.com> | 2024-03-13 14:11:53 +0300 |
commit | 11a895b7e15d1c5a1f52706396b82e3f9db953cb (patch) | |
tree | fabc6d883b0f946151f61ae7865cee9f529a1fdd /contrib/libs/clang16/lib/CodeGen/CGObjCGNU.cpp | |
parent | 9685917341315774aad5733b1793b1e533a88bbb (diff) | |
download | ydb-11a895b7e15d1c5a1f52706396b82e3f9db953cb.tar.gz |
Export clang-format16 via ydblib project
6e6be3a95868fde888d801b7590af4044049563f
Diffstat (limited to 'contrib/libs/clang16/lib/CodeGen/CGObjCGNU.cpp')
-rw-r--r-- | contrib/libs/clang16/lib/CodeGen/CGObjCGNU.cpp | 4224 |
1 files changed, 4224 insertions, 0 deletions
diff --git a/contrib/libs/clang16/lib/CodeGen/CGObjCGNU.cpp b/contrib/libs/clang16/lib/CodeGen/CGObjCGNU.cpp new file mode 100644 index 0000000000..c7b193e34e --- /dev/null +++ b/contrib/libs/clang16/lib/CodeGen/CGObjCGNU.cpp @@ -0,0 +1,4224 @@ +//===------- CGObjCGNU.cpp - Emit LLVM Code from ASTs for a Module --------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This provides Objective-C code generation targeting the GNU runtime. The +// class in this file generates structures used by the GNU Objective-C runtime +// library. These structures are defined in objc/objc.h and objc/objc-api.h in +// the GNU runtime distribution. +// +//===----------------------------------------------------------------------===// + +#include "CGCXXABI.h" +#include "CGCleanup.h" +#include "CGObjCRuntime.h" +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtObjC.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/CodeGen/ConstantInitBuilder.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ConvertUTF.h" +#include <cctype> + +using namespace clang; +using namespace CodeGen; + +namespace { + +/// Class that lazily initialises the runtime function. Avoids inserting the +/// types and the function declaration into a module if they're not used, and +/// avoids constructing the type more than once if it's used more than once. +class LazyRuntimeFunction { + CodeGenModule *CGM; + llvm::FunctionType *FTy; + const char *FunctionName; + llvm::FunctionCallee Function; + +public: + /// Constructor leaves this class uninitialized, because it is intended to + /// be used as a field in another class and not all of the types that are + /// used as arguments will necessarily be available at construction time. + LazyRuntimeFunction() + : CGM(nullptr), FunctionName(nullptr), Function(nullptr) {} + + /// Initialises the lazy function with the name, return type, and the types + /// of the arguments. + template <typename... Tys> + void init(CodeGenModule *Mod, const char *name, llvm::Type *RetTy, + Tys *... Types) { + CGM = Mod; + FunctionName = name; + Function = nullptr; + if(sizeof...(Tys)) { + SmallVector<llvm::Type *, 8> ArgTys({Types...}); + FTy = llvm::FunctionType::get(RetTy, ArgTys, false); + } + else { + FTy = llvm::FunctionType::get(RetTy, std::nullopt, false); + } + } + + llvm::FunctionType *getType() { return FTy; } + + /// Overloaded cast operator, allows the class to be implicitly cast to an + /// LLVM constant. + operator llvm::FunctionCallee() { + if (!Function) { + if (!FunctionName) + return nullptr; + Function = CGM->CreateRuntimeFunction(FTy, FunctionName); + } + return Function; + } +}; + + +/// GNU Objective-C runtime code generation. This class implements the parts of +/// Objective-C support that are specific to the GNU family of runtimes (GCC, +/// GNUstep and ObjFW). +class CGObjCGNU : public CGObjCRuntime { +protected: + /// The LLVM module into which output is inserted + llvm::Module &TheModule; + /// strut objc_super. Used for sending messages to super. This structure + /// contains the receiver (object) and the expected class. + llvm::StructType *ObjCSuperTy; + /// struct objc_super*. The type of the argument to the superclass message + /// lookup functions. + llvm::PointerType *PtrToObjCSuperTy; + /// LLVM type for selectors. Opaque pointer (i8*) unless a header declaring + /// SEL is included in a header somewhere, in which case it will be whatever + /// type is declared in that header, most likely {i8*, i8*}. + llvm::PointerType *SelectorTy; + /// Element type of SelectorTy. + llvm::Type *SelectorElemTy; + /// LLVM i8 type. Cached here to avoid repeatedly getting it in all of the + /// places where it's used + llvm::IntegerType *Int8Ty; + /// Pointer to i8 - LLVM type of char*, for all of the places where the + /// runtime needs to deal with C strings. + llvm::PointerType *PtrToInt8Ty; + /// struct objc_protocol type + llvm::StructType *ProtocolTy; + /// Protocol * type. + llvm::PointerType *ProtocolPtrTy; + /// Instance Method Pointer type. This is a pointer to a function that takes, + /// at a minimum, an object and a selector, and is the generic type for + /// Objective-C methods. Due to differences between variadic / non-variadic + /// calling conventions, it must always be cast to the correct type before + /// actually being used. + llvm::PointerType *IMPTy; + /// Type of an untyped Objective-C object. Clang treats id as a built-in type + /// when compiling Objective-C code, so this may be an opaque pointer (i8*), + /// but if the runtime header declaring it is included then it may be a + /// pointer to a structure. + llvm::PointerType *IdTy; + /// Element type of IdTy. + llvm::Type *IdElemTy; + /// Pointer to a pointer to an Objective-C object. Used in the new ABI + /// message lookup function and some GC-related functions. + llvm::PointerType *PtrToIdTy; + /// The clang type of id. Used when using the clang CGCall infrastructure to + /// call Objective-C methods. + CanQualType ASTIdTy; + /// LLVM type for C int type. + llvm::IntegerType *IntTy; + /// LLVM type for an opaque pointer. This is identical to PtrToInt8Ty, but is + /// used in the code to document the difference between i8* meaning a pointer + /// to a C string and i8* meaning a pointer to some opaque type. + llvm::PointerType *PtrTy; + /// LLVM type for C long type. The runtime uses this in a lot of places where + /// it should be using intptr_t, but we can't fix this without breaking + /// compatibility with GCC... + llvm::IntegerType *LongTy; + /// LLVM type for C size_t. Used in various runtime data structures. + llvm::IntegerType *SizeTy; + /// LLVM type for C intptr_t. + llvm::IntegerType *IntPtrTy; + /// LLVM type for C ptrdiff_t. Mainly used in property accessor functions. + llvm::IntegerType *PtrDiffTy; + /// LLVM type for C int*. Used for GCC-ABI-compatible non-fragile instance + /// variables. + llvm::PointerType *PtrToIntTy; + /// LLVM type for Objective-C BOOL type. + llvm::Type *BoolTy; + /// 32-bit integer type, to save us needing to look it up every time it's used. + llvm::IntegerType *Int32Ty; + /// 64-bit integer type, to save us needing to look it up every time it's used. + llvm::IntegerType *Int64Ty; + /// The type of struct objc_property. + llvm::StructType *PropertyMetadataTy; + /// Metadata kind used to tie method lookups to message sends. The GNUstep + /// runtime provides some LLVM passes that can use this to do things like + /// automatic IMP caching and speculative inlining. + unsigned msgSendMDKind; + /// Does the current target use SEH-based exceptions? False implies + /// Itanium-style DWARF unwinding. + bool usesSEHExceptions; + + /// Helper to check if we are targeting a specific runtime version or later. + bool isRuntime(ObjCRuntime::Kind kind, unsigned major, unsigned minor=0) { + const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime; + return (R.getKind() == kind) && + (R.getVersion() >= VersionTuple(major, minor)); + } + + std::string ManglePublicSymbol(StringRef Name) { + return (StringRef(CGM.getTriple().isOSBinFormatCOFF() ? "$_" : "._") + Name).str(); + } + + std::string SymbolForProtocol(Twine Name) { + return (ManglePublicSymbol("OBJC_PROTOCOL_") + Name).str(); + } + + std::string SymbolForProtocolRef(StringRef Name) { + return (ManglePublicSymbol("OBJC_REF_PROTOCOL_") + Name).str(); + } + + + /// Helper function that generates a constant string and returns a pointer to + /// the start of the string. The result of this function can be used anywhere + /// where the C code specifies const char*. + llvm::Constant *MakeConstantString(StringRef Str, const char *Name = "") { + ConstantAddress Array = + CGM.GetAddrOfConstantCString(std::string(Str), Name); + return llvm::ConstantExpr::getGetElementPtr(Array.getElementType(), + Array.getPointer(), Zeros); + } + + /// Emits a linkonce_odr string, whose name is the prefix followed by the + /// string value. This allows the linker to combine the strings between + /// different modules. Used for EH typeinfo names, selector strings, and a + /// few other things. + llvm::Constant *ExportUniqueString(const std::string &Str, + const std::string &prefix, + bool Private=false) { + std::string name = prefix + Str; + auto *ConstStr = TheModule.getGlobalVariable(name); + if (!ConstStr) { + llvm::Constant *value = llvm::ConstantDataArray::getString(VMContext,Str); + auto *GV = new llvm::GlobalVariable(TheModule, value->getType(), true, + llvm::GlobalValue::LinkOnceODRLinkage, value, name); + GV->setComdat(TheModule.getOrInsertComdat(name)); + if (Private) + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + ConstStr = GV; + } + return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(), + ConstStr, Zeros); + } + + /// Returns a property name and encoding string. + llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD, + const Decl *Container) { + assert(!isRuntime(ObjCRuntime::GNUstep, 2)); + if (isRuntime(ObjCRuntime::GNUstep, 1, 6)) { + std::string NameAndAttributes; + std::string TypeStr = + CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container); + NameAndAttributes += '\0'; + NameAndAttributes += TypeStr.length() + 3; + NameAndAttributes += TypeStr; + NameAndAttributes += '\0'; + NameAndAttributes += PD->getNameAsString(); + return MakeConstantString(NameAndAttributes); + } + return MakeConstantString(PD->getNameAsString()); + } + + /// Push the property attributes into two structure fields. + void PushPropertyAttributes(ConstantStructBuilder &Fields, + const ObjCPropertyDecl *property, bool isSynthesized=true, bool + isDynamic=true) { + int attrs = property->getPropertyAttributes(); + // For read-only properties, clear the copy and retain flags + if (attrs & ObjCPropertyAttribute::kind_readonly) { + attrs &= ~ObjCPropertyAttribute::kind_copy; + attrs &= ~ObjCPropertyAttribute::kind_retain; + attrs &= ~ObjCPropertyAttribute::kind_weak; + attrs &= ~ObjCPropertyAttribute::kind_strong; + } + // The first flags field has the same attribute values as clang uses internally + Fields.addInt(Int8Ty, attrs & 0xff); + attrs >>= 8; + attrs <<= 2; + // For protocol properties, synthesized and dynamic have no meaning, so we + // reuse these flags to indicate that this is a protocol property (both set + // has no meaning, as a property can't be both synthesized and dynamic) + attrs |= isSynthesized ? (1<<0) : 0; + attrs |= isDynamic ? (1<<1) : 0; + // The second field is the next four fields left shifted by two, with the + // low bit set to indicate whether the field is synthesized or dynamic. + Fields.addInt(Int8Ty, attrs & 0xff); + // Two padding fields + Fields.addInt(Int8Ty, 0); + Fields.addInt(Int8Ty, 0); + } + + virtual llvm::Constant *GenerateCategoryProtocolList(const + ObjCCategoryDecl *OCD); + virtual ConstantArrayBuilder PushPropertyListHeader(ConstantStructBuilder &Fields, + int count) { + // int count; + Fields.addInt(IntTy, count); + // int size; (only in GNUstep v2 ABI. + if (isRuntime(ObjCRuntime::GNUstep, 2)) { + llvm::DataLayout td(&TheModule); + Fields.addInt(IntTy, td.getTypeSizeInBits(PropertyMetadataTy) / + CGM.getContext().getCharWidth()); + } + // struct objc_property_list *next; + Fields.add(NULLPtr); + // struct objc_property properties[] + return Fields.beginArray(PropertyMetadataTy); + } + virtual void PushProperty(ConstantArrayBuilder &PropertiesArray, + const ObjCPropertyDecl *property, + const Decl *OCD, + bool isSynthesized=true, bool + isDynamic=true) { + auto Fields = PropertiesArray.beginStruct(PropertyMetadataTy); + ASTContext &Context = CGM.getContext(); + Fields.add(MakePropertyEncodingString(property, OCD)); + PushPropertyAttributes(Fields, property, isSynthesized, isDynamic); + auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { + if (accessor) { + std::string TypeStr = Context.getObjCEncodingForMethodDecl(accessor); + llvm::Constant *TypeEncoding = MakeConstantString(TypeStr); + Fields.add(MakeConstantString(accessor->getSelector().getAsString())); + Fields.add(TypeEncoding); + } else { + Fields.add(NULLPtr); + Fields.add(NULLPtr); + } + }; + addPropertyMethod(property->getGetterMethodDecl()); + addPropertyMethod(property->getSetterMethodDecl()); + Fields.finishAndAddTo(PropertiesArray); + } + + /// Ensures that the value has the required type, by inserting a bitcast if + /// required. This function lets us avoid inserting bitcasts that are + /// redundant. + llvm::Value *EnforceType(CGBuilderTy &B, llvm::Value *V, llvm::Type *Ty) { + if (V->getType() == Ty) + return V; + return B.CreateBitCast(V, Ty); + } + + // Some zeros used for GEPs in lots of places. + llvm::Constant *Zeros[2]; + /// Null pointer value. Mainly used as a terminator in various arrays. + llvm::Constant *NULLPtr; + /// LLVM context. + llvm::LLVMContext &VMContext; + +protected: + + /// Placeholder for the class. Lots of things refer to the class before we've + /// actually emitted it. We use this alias as a placeholder, and then replace + /// it with a pointer to the class structure before finally emitting the + /// module. + llvm::GlobalAlias *ClassPtrAlias; + /// Placeholder for the metaclass. Lots of things refer to the class before + /// we've / actually emitted it. We use this alias as a placeholder, and then + /// replace / it with a pointer to the metaclass structure before finally + /// emitting the / module. + llvm::GlobalAlias *MetaClassPtrAlias; + /// All of the classes that have been generated for this compilation units. + std::vector<llvm::Constant*> Classes; + /// All of the categories that have been generated for this compilation units. + std::vector<llvm::Constant*> Categories; + /// All of the Objective-C constant strings that have been generated for this + /// compilation units. + std::vector<llvm::Constant*> ConstantStrings; + /// Map from string values to Objective-C constant strings in the output. + /// Used to prevent emitting Objective-C strings more than once. This should + /// not be required at all - CodeGenModule should manage this list. + llvm::StringMap<llvm::Constant*> ObjCStrings; + /// All of the protocols that have been declared. + llvm::StringMap<llvm::Constant*> ExistingProtocols; + /// For each variant of a selector, we store the type encoding and a + /// placeholder value. For an untyped selector, the type will be the empty + /// string. Selector references are all done via the module's selector table, + /// so we create an alias as a placeholder and then replace it with the real + /// value later. + typedef std::pair<std::string, llvm::GlobalAlias*> TypedSelector; + /// Type of the selector map. This is roughly equivalent to the structure + /// used in the GNUstep runtime, which maintains a list of all of the valid + /// types for a selector in a table. + typedef llvm::DenseMap<Selector, SmallVector<TypedSelector, 2> > + SelectorMap; + /// A map from selectors to selector types. This allows us to emit all + /// selectors of the same name and type together. + SelectorMap SelectorTable; + + /// Selectors related to memory management. When compiling in GC mode, we + /// omit these. + Selector RetainSel, ReleaseSel, AutoreleaseSel; + /// Runtime functions used for memory management in GC mode. Note that clang + /// supports code generation for calling these functions, but neither GNU + /// runtime actually supports this API properly yet. + LazyRuntimeFunction IvarAssignFn, StrongCastAssignFn, MemMoveFn, WeakReadFn, + WeakAssignFn, GlobalAssignFn; + + typedef std::pair<std::string, std::string> ClassAliasPair; + /// All classes that have aliases set for them. + std::vector<ClassAliasPair> ClassAliases; + +protected: + /// Function used for throwing Objective-C exceptions. + LazyRuntimeFunction ExceptionThrowFn; + /// Function used for rethrowing exceptions, used at the end of \@finally or + /// \@synchronize blocks. + LazyRuntimeFunction ExceptionReThrowFn; + /// Function called when entering a catch function. This is required for + /// differentiating Objective-C exceptions and foreign exceptions. + LazyRuntimeFunction EnterCatchFn; + /// Function called when exiting from a catch block. Used to do exception + /// cleanup. + LazyRuntimeFunction ExitCatchFn; + /// Function called when entering an \@synchronize block. Acquires the lock. + LazyRuntimeFunction SyncEnterFn; + /// Function called when exiting an \@synchronize block. Releases the lock. + LazyRuntimeFunction SyncExitFn; + +private: + /// Function called if fast enumeration detects that the collection is + /// modified during the update. + LazyRuntimeFunction EnumerationMutationFn; + /// Function for implementing synthesized property getters that return an + /// object. + LazyRuntimeFunction GetPropertyFn; + /// Function for implementing synthesized property setters that return an + /// object. + LazyRuntimeFunction SetPropertyFn; + /// Function used for non-object declared property getters. + LazyRuntimeFunction GetStructPropertyFn; + /// Function used for non-object declared property setters. + LazyRuntimeFunction SetStructPropertyFn; + +protected: + /// The version of the runtime that this class targets. Must match the + /// version in the runtime. + int RuntimeVersion; + /// The version of the protocol class. Used to differentiate between ObjC1 + /// and ObjC2 protocols. Objective-C 1 protocols can not contain optional + /// components and can not contain declared properties. We always emit + /// Objective-C 2 property structures, but we have to pretend that they're + /// Objective-C 1 property structures when targeting the GCC runtime or it + /// will abort. + const int ProtocolVersion; + /// The version of the class ABI. This value is used in the class structure + /// and indicates how various fields should be interpreted. + const int ClassABIVersion; + /// Generates an instance variable list structure. This is a structure + /// containing a size and an array of structures containing instance variable + /// metadata. This is used purely for introspection in the fragile ABI. In + /// the non-fragile ABI, it's used for instance variable fixup. + virtual llvm::Constant *GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames, + ArrayRef<llvm::Constant *> IvarTypes, + ArrayRef<llvm::Constant *> IvarOffsets, + ArrayRef<llvm::Constant *> IvarAlign, + ArrayRef<Qualifiers::ObjCLifetime> IvarOwnership); + + /// Generates a method list structure. This is a structure containing a size + /// and an array of structures containing method metadata. + /// + /// This structure is used by both classes and categories, and contains a next + /// pointer allowing them to be chained together in a linked list. + llvm::Constant *GenerateMethodList(StringRef ClassName, + StringRef CategoryName, + ArrayRef<const ObjCMethodDecl*> Methods, + bool isClassMethodList); + + /// Emits an empty protocol. This is used for \@protocol() where no protocol + /// is found. The runtime will (hopefully) fix up the pointer to refer to the + /// real protocol. + virtual llvm::Constant *GenerateEmptyProtocol(StringRef ProtocolName); + + /// Generates a list of property metadata structures. This follows the same + /// pattern as method and instance variable metadata lists. + llvm::Constant *GeneratePropertyList(const Decl *Container, + const ObjCContainerDecl *OCD, + bool isClassProperty=false, + bool protocolOptionalProperties=false); + + /// Generates a list of referenced protocols. Classes, categories, and + /// protocols all use this structure. + llvm::Constant *GenerateProtocolList(ArrayRef<std::string> Protocols); + + /// To ensure that all protocols are seen by the runtime, we add a category on + /// a class defined in the runtime, declaring no methods, but adopting the + /// protocols. This is a horribly ugly hack, but it allows us to collect all + /// of the protocols without changing the ABI. + void GenerateProtocolHolderCategory(); + + /// Generates a class structure. + llvm::Constant *GenerateClassStructure( + llvm::Constant *MetaClass, + llvm::Constant *SuperClass, + unsigned info, + const char *Name, + llvm::Constant *Version, + llvm::Constant *InstanceSize, + llvm::Constant *IVars, + llvm::Constant *Methods, + llvm::Constant *Protocols, + llvm::Constant *IvarOffsets, + llvm::Constant *Properties, + llvm::Constant *StrongIvarBitmap, + llvm::Constant *WeakIvarBitmap, + bool isMeta=false); + + /// Generates a method list. This is used by protocols to define the required + /// and optional methods. + virtual llvm::Constant *GenerateProtocolMethodList( + ArrayRef<const ObjCMethodDecl*> Methods); + /// Emits optional and required method lists. + template<class T> + void EmitProtocolMethodList(T &&Methods, llvm::Constant *&Required, + llvm::Constant *&Optional) { + SmallVector<const ObjCMethodDecl*, 16> RequiredMethods; + SmallVector<const ObjCMethodDecl*, 16> OptionalMethods; + for (const auto *I : Methods) + if (I->isOptional()) + OptionalMethods.push_back(I); + else + RequiredMethods.push_back(I); + Required = GenerateProtocolMethodList(RequiredMethods); + Optional = GenerateProtocolMethodList(OptionalMethods); + } + + /// Returns a selector with the specified type encoding. An empty string is + /// used to return an untyped selector (with the types field set to NULL). + virtual llvm::Value *GetTypedSelector(CodeGenFunction &CGF, Selector Sel, + const std::string &TypeEncoding); + + /// Returns the name of ivar offset variables. In the GNUstep v1 ABI, this + /// contains the class and ivar names, in the v2 ABI this contains the type + /// encoding as well. + virtual std::string GetIVarOffsetVariableName(const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar) { + const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString() + + '.' + Ivar->getNameAsString(); + return Name; + } + /// Returns the variable used to store the offset of an instance variable. + llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar); + /// Emits a reference to a class. This allows the linker to object if there + /// is no class of the matching name. + void EmitClassRef(const std::string &className); + + /// Emits a pointer to the named class + virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF, + const std::string &Name, bool isWeak); + + /// Looks up the method for sending a message to the specified object. This + /// mechanism differs between the GCC and GNU runtimes, so this method must be + /// overridden in subclasses. + virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, + llvm::Value *&Receiver, + llvm::Value *cmd, + llvm::MDNode *node, + MessageSendInfo &MSI) = 0; + + /// Looks up the method for sending a message to a superclass. This + /// mechanism differs between the GCC and GNU runtimes, so this method must + /// be overridden in subclasses. + virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, + Address ObjCSuper, + llvm::Value *cmd, + MessageSendInfo &MSI) = 0; + + /// Libobjc2 uses a bitfield representation where small(ish) bitfields are + /// stored in a 64-bit value with the low bit set to 1 and the remaining 63 + /// bits set to their values, LSB first, while larger ones are stored in a + /// structure of this / form: + /// + /// struct { int32_t length; int32_t values[length]; }; + /// + /// The values in the array are stored in host-endian format, with the least + /// significant bit being assumed to come first in the bitfield. Therefore, + /// a bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, + /// while a bitfield / with the 63rd bit set will be 1<<64. + llvm::Constant *MakeBitField(ArrayRef<bool> bits); + +public: + CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, + unsigned protocolClassVersion, unsigned classABI=1); + + ConstantAddress GenerateConstantString(const StringLiteral *) override; + + RValue + GenerateMessageSend(CodeGenFunction &CGF, ReturnValueSlot Return, + QualType ResultType, Selector Sel, + llvm::Value *Receiver, const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, + const ObjCMethodDecl *Method) override; + RValue + GenerateMessageSendSuper(CodeGenFunction &CGF, ReturnValueSlot Return, + QualType ResultType, Selector Sel, + const ObjCInterfaceDecl *Class, + bool isCategoryImpl, llvm::Value *Receiver, + bool IsClassMessage, const CallArgList &CallArgs, + const ObjCMethodDecl *Method) override; + llvm::Value *GetClass(CodeGenFunction &CGF, + const ObjCInterfaceDecl *OID) override; + llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override; + Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override; + llvm::Value *GetSelector(CodeGenFunction &CGF, + const ObjCMethodDecl *Method) override; + virtual llvm::Constant *GetConstantSelector(Selector Sel, + const std::string &TypeEncoding) { + llvm_unreachable("Runtime unable to generate constant selector"); + } + llvm::Constant *GetConstantSelector(const ObjCMethodDecl *M) { + return GetConstantSelector(M->getSelector(), + CGM.getContext().getObjCEncodingForMethodDecl(M)); + } + llvm::Constant *GetEHType(QualType T) override; + + llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) override; + void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn, + const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) override; + void GenerateCategory(const ObjCCategoryImplDecl *CMD) override; + void GenerateClass(const ObjCImplementationDecl *ClassDecl) override; + void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override; + llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF, + const ObjCProtocolDecl *PD) override; + void GenerateProtocol(const ObjCProtocolDecl *PD) override; + + virtual llvm::Constant *GenerateProtocolRef(const ObjCProtocolDecl *PD); + + llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override { + return GenerateProtocolRef(PD); + } + + llvm::Function *ModuleInitFunction() override; + llvm::FunctionCallee GetPropertyGetFunction() override; + llvm::FunctionCallee GetPropertySetFunction() override; + llvm::FunctionCallee GetOptimizedPropertySetFunction(bool atomic, + bool copy) override; + llvm::FunctionCallee GetSetStructFunction() override; + llvm::FunctionCallee GetGetStructFunction() override; + llvm::FunctionCallee GetCppAtomicObjectGetFunction() override; + llvm::FunctionCallee GetCppAtomicObjectSetFunction() override; + llvm::FunctionCallee EnumerationMutationFunction() override; + + void EmitTryStmt(CodeGenFunction &CGF, + const ObjCAtTryStmt &S) override; + void EmitSynchronizedStmt(CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S) override; + void EmitThrowStmt(CodeGenFunction &CGF, + const ObjCAtThrowStmt &S, + bool ClearInsertionPoint=true) override; + llvm::Value * EmitObjCWeakRead(CodeGenFunction &CGF, + Address AddrWeakObj) override; + void EmitObjCWeakAssign(CodeGenFunction &CGF, + llvm::Value *src, Address dst) override; + void EmitObjCGlobalAssign(CodeGenFunction &CGF, + llvm::Value *src, Address dest, + bool threadlocal=false) override; + void EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *src, + Address dest, llvm::Value *ivarOffset) override; + void EmitObjCStrongCastAssign(CodeGenFunction &CGF, + llvm::Value *src, Address dest) override; + void EmitGCMemmoveCollectable(CodeGenFunction &CGF, Address DestPtr, + Address SrcPtr, + llvm::Value *Size) override; + LValue EmitObjCValueForIvar(CodeGenFunction &CGF, QualType ObjectTy, + llvm::Value *BaseValue, const ObjCIvarDecl *Ivar, + unsigned CVRQualifiers) override; + llvm::Value *EmitIvarOffset(CodeGenFunction &CGF, + const ObjCInterfaceDecl *Interface, + const ObjCIvarDecl *Ivar) override; + llvm::Value *EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) override; + llvm::Constant *BuildGCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) override { + return NULLPtr; + } + llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) override { + return NULLPtr; + } + + llvm::Constant *BuildByrefLayout(CodeGenModule &CGM, QualType T) override { + return NULLPtr; + } +}; + +/// Class representing the legacy GCC Objective-C ABI. This is the default when +/// -fobjc-nonfragile-abi is not specified. +/// +/// The GCC ABI target actually generates code that is approximately compatible +/// with the new GNUstep runtime ABI, but refrains from using any features that +/// would not work with the GCC runtime. For example, clang always generates +/// the extended form of the class structure, and the extra fields are simply +/// ignored by GCC libobjc. +class CGObjCGCC : public CGObjCGNU { + /// The GCC ABI message lookup function. Returns an IMP pointing to the + /// method implementation for this message. + LazyRuntimeFunction MsgLookupFn; + /// The GCC ABI superclass message lookup function. Takes a pointer to a + /// structure describing the receiver and the class, and a selector as + /// arguments. Returns the IMP for the corresponding method. + LazyRuntimeFunction MsgLookupSuperFn; + +protected: + llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, + llvm::Value *cmd, llvm::MDNode *node, + MessageSendInfo &MSI) override { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *args[] = { + EnforceType(Builder, Receiver, IdTy), + EnforceType(Builder, cmd, SelectorTy) }; + llvm::CallBase *imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args); + imp->setMetadata(msgSendMDKind, node); + return imp; + } + + llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, + llvm::Value *cmd, MessageSendInfo &MSI) override { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *lookupArgs[] = { + EnforceType(Builder, ObjCSuper.getPointer(), PtrToObjCSuperTy), cmd}; + return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); + } + +public: + CGObjCGCC(CodeGenModule &Mod) : CGObjCGNU(Mod, 8, 2) { + // IMP objc_msg_lookup(id, SEL); + MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy); + // IMP objc_msg_lookup_super(struct objc_super*, SEL); + MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, + PtrToObjCSuperTy, SelectorTy); + } +}; + +/// Class used when targeting the new GNUstep runtime ABI. +class CGObjCGNUstep : public CGObjCGNU { + /// The slot lookup function. Returns a pointer to a cacheable structure + /// that contains (among other things) the IMP. + LazyRuntimeFunction SlotLookupFn; + /// The GNUstep ABI superclass message lookup function. Takes a pointer to + /// a structure describing the receiver and the class, and a selector as + /// arguments. Returns the slot for the corresponding method. Superclass + /// message lookup rarely changes, so this is a good caching opportunity. + LazyRuntimeFunction SlotLookupSuperFn; + /// Specialised function for setting atomic retain properties + LazyRuntimeFunction SetPropertyAtomic; + /// Specialised function for setting atomic copy properties + LazyRuntimeFunction SetPropertyAtomicCopy; + /// Specialised function for setting nonatomic retain properties + LazyRuntimeFunction SetPropertyNonAtomic; + /// Specialised function for setting nonatomic copy properties + LazyRuntimeFunction SetPropertyNonAtomicCopy; + /// Function to perform atomic copies of C++ objects with nontrivial copy + /// constructors from Objective-C ivars. + LazyRuntimeFunction CxxAtomicObjectGetFn; + /// Function to perform atomic copies of C++ objects with nontrivial copy + /// constructors to Objective-C ivars. + LazyRuntimeFunction CxxAtomicObjectSetFn; + /// Type of a slot structure pointer. This is returned by the various + /// lookup functions. + llvm::Type *SlotTy; + /// Type of a slot structure. + llvm::Type *SlotStructTy; + + public: + llvm::Constant *GetEHType(QualType T) override; + + protected: + llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, + llvm::Value *cmd, llvm::MDNode *node, + MessageSendInfo &MSI) override { + CGBuilderTy &Builder = CGF.Builder; + llvm::FunctionCallee LookupFn = SlotLookupFn; + + // Store the receiver on the stack so that we can reload it later + Address ReceiverPtr = + CGF.CreateTempAlloca(Receiver->getType(), CGF.getPointerAlign()); + Builder.CreateStore(Receiver, ReceiverPtr); + + llvm::Value *self; + + if (isa<ObjCMethodDecl>(CGF.CurCodeDecl)) { + self = CGF.LoadObjCSelf(); + } else { + self = llvm::ConstantPointerNull::get(IdTy); + } + + // The lookup function is guaranteed not to capture the receiver pointer. + if (auto *LookupFn2 = dyn_cast<llvm::Function>(LookupFn.getCallee())) + LookupFn2->addParamAttr(0, llvm::Attribute::NoCapture); + + llvm::Value *args[] = { + EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy), + EnforceType(Builder, cmd, SelectorTy), + EnforceType(Builder, self, IdTy) }; + llvm::CallBase *slot = CGF.EmitRuntimeCallOrInvoke(LookupFn, args); + slot->setOnlyReadsMemory(); + slot->setMetadata(msgSendMDKind, node); + + // Load the imp from the slot + llvm::Value *imp = Builder.CreateAlignedLoad( + IMPTy, Builder.CreateStructGEP(SlotStructTy, slot, 4), + CGF.getPointerAlign()); + + // The lookup function may have changed the receiver, so make sure we use + // the new one. + Receiver = Builder.CreateLoad(ReceiverPtr, true); + return imp; + } + + llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, + llvm::Value *cmd, + MessageSendInfo &MSI) override { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *lookupArgs[] = {ObjCSuper.getPointer(), cmd}; + + llvm::CallInst *slot = + CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs); + slot->setOnlyReadsMemory(); + + return Builder.CreateAlignedLoad( + IMPTy, Builder.CreateStructGEP(SlotStructTy, slot, 4), + CGF.getPointerAlign()); + } + + public: + CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNUstep(Mod, 9, 3, 1) {} + CGObjCGNUstep(CodeGenModule &Mod, unsigned ABI, unsigned ProtocolABI, + unsigned ClassABI) : + CGObjCGNU(Mod, ABI, ProtocolABI, ClassABI) { + const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime; + + SlotStructTy = llvm::StructType::get(PtrTy, PtrTy, PtrTy, IntTy, IMPTy); + SlotTy = llvm::PointerType::getUnqual(SlotStructTy); + // Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender); + SlotLookupFn.init(&CGM, "objc_msg_lookup_sender", SlotTy, PtrToIdTy, + SelectorTy, IdTy); + // Slot_t objc_slot_lookup_super(struct objc_super*, SEL); + SlotLookupSuperFn.init(&CGM, "objc_slot_lookup_super", SlotTy, + PtrToObjCSuperTy, SelectorTy); + // If we're in ObjC++ mode, then we want to make + if (usesSEHExceptions) { + llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); + // void objc_exception_rethrow(void) + ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy); + } else if (CGM.getLangOpts().CPlusPlus) { + llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); + // void *__cxa_begin_catch(void *e) + EnterCatchFn.init(&CGM, "__cxa_begin_catch", PtrTy, PtrTy); + // void __cxa_end_catch(void) + ExitCatchFn.init(&CGM, "__cxa_end_catch", VoidTy); + // void _Unwind_Resume_or_Rethrow(void*) + ExceptionReThrowFn.init(&CGM, "_Unwind_Resume_or_Rethrow", VoidTy, + PtrTy); + } else if (R.getVersion() >= VersionTuple(1, 7)) { + llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); + // id objc_begin_catch(void *e) + EnterCatchFn.init(&CGM, "objc_begin_catch", IdTy, PtrTy); + // void objc_end_catch(void) + ExitCatchFn.init(&CGM, "objc_end_catch", VoidTy); + // void _Unwind_Resume_or_Rethrow(void*) + ExceptionReThrowFn.init(&CGM, "objc_exception_rethrow", VoidTy, PtrTy); + } + llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); + SetPropertyAtomic.init(&CGM, "objc_setProperty_atomic", VoidTy, IdTy, + SelectorTy, IdTy, PtrDiffTy); + SetPropertyAtomicCopy.init(&CGM, "objc_setProperty_atomic_copy", VoidTy, + IdTy, SelectorTy, IdTy, PtrDiffTy); + SetPropertyNonAtomic.init(&CGM, "objc_setProperty_nonatomic", VoidTy, + IdTy, SelectorTy, IdTy, PtrDiffTy); + SetPropertyNonAtomicCopy.init(&CGM, "objc_setProperty_nonatomic_copy", + VoidTy, IdTy, SelectorTy, IdTy, PtrDiffTy); + // void objc_setCppObjectAtomic(void *dest, const void *src, void + // *helper); + CxxAtomicObjectSetFn.init(&CGM, "objc_setCppObjectAtomic", VoidTy, PtrTy, + PtrTy, PtrTy); + // void objc_getCppObjectAtomic(void *dest, const void *src, void + // *helper); + CxxAtomicObjectGetFn.init(&CGM, "objc_getCppObjectAtomic", VoidTy, PtrTy, + PtrTy, PtrTy); + } + + llvm::FunctionCallee GetCppAtomicObjectGetFunction() override { + // The optimised functions were added in version 1.7 of the GNUstep + // runtime. + assert (CGM.getLangOpts().ObjCRuntime.getVersion() >= + VersionTuple(1, 7)); + return CxxAtomicObjectGetFn; + } + + llvm::FunctionCallee GetCppAtomicObjectSetFunction() override { + // The optimised functions were added in version 1.7 of the GNUstep + // runtime. + assert (CGM.getLangOpts().ObjCRuntime.getVersion() >= + VersionTuple(1, 7)); + return CxxAtomicObjectSetFn; + } + + llvm::FunctionCallee GetOptimizedPropertySetFunction(bool atomic, + bool copy) override { + // The optimised property functions omit the GC check, and so are not + // safe to use in GC mode. The standard functions are fast in GC mode, + // so there is less advantage in using them. + assert ((CGM.getLangOpts().getGC() == LangOptions::NonGC)); + // The optimised functions were added in version 1.7 of the GNUstep + // runtime. + assert (CGM.getLangOpts().ObjCRuntime.getVersion() >= + VersionTuple(1, 7)); + + if (atomic) { + if (copy) return SetPropertyAtomicCopy; + return SetPropertyAtomic; + } + + return copy ? SetPropertyNonAtomicCopy : SetPropertyNonAtomic; + } +}; + +/// GNUstep Objective-C ABI version 2 implementation. +/// This is the ABI that provides a clean break with the legacy GCC ABI and +/// cleans up a number of things that were added to work around 1980s linkers. +class CGObjCGNUstep2 : public CGObjCGNUstep { + enum SectionKind + { + SelectorSection = 0, + ClassSection, + ClassReferenceSection, + CategorySection, + ProtocolSection, + ProtocolReferenceSection, + ClassAliasSection, + ConstantStringSection + }; + static const char *const SectionsBaseNames[8]; + static const char *const PECOFFSectionsBaseNames[8]; + template<SectionKind K> + std::string sectionName() { + if (CGM.getTriple().isOSBinFormatCOFF()) { + std::string name(PECOFFSectionsBaseNames[K]); + name += "$m"; + return name; + } + return SectionsBaseNames[K]; + } + /// The GCC ABI superclass message lookup function. Takes a pointer to a + /// structure describing the receiver and the class, and a selector as + /// arguments. Returns the IMP for the corresponding method. + LazyRuntimeFunction MsgLookupSuperFn; + /// A flag indicating if we've emitted at least one protocol. + /// If we haven't, then we need to emit an empty protocol, to ensure that the + /// __start__objc_protocols and __stop__objc_protocols sections exist. + bool EmittedProtocol = false; + /// A flag indicating if we've emitted at least one protocol reference. + /// If we haven't, then we need to emit an empty protocol, to ensure that the + /// __start__objc_protocol_refs and __stop__objc_protocol_refs sections + /// exist. + bool EmittedProtocolRef = false; + /// A flag indicating if we've emitted at least one class. + /// If we haven't, then we need to emit an empty protocol, to ensure that the + /// __start__objc_classes and __stop__objc_classes sections / exist. + bool EmittedClass = false; + /// Generate the name of a symbol for a reference to a class. Accesses to + /// classes should be indirected via this. + + typedef std::pair<std::string, std::pair<llvm::GlobalVariable*, int>> + EarlyInitPair; + std::vector<EarlyInitPair> EarlyInitList; + + std::string SymbolForClassRef(StringRef Name, bool isWeak) { + if (isWeak) + return (ManglePublicSymbol("OBJC_WEAK_REF_CLASS_") + Name).str(); + else + return (ManglePublicSymbol("OBJC_REF_CLASS_") + Name).str(); + } + /// Generate the name of a class symbol. + std::string SymbolForClass(StringRef Name) { + return (ManglePublicSymbol("OBJC_CLASS_") + Name).str(); + } + void CallRuntimeFunction(CGBuilderTy &B, StringRef FunctionName, + ArrayRef<llvm::Value*> Args) { + SmallVector<llvm::Type *,8> Types; + for (auto *Arg : Args) + Types.push_back(Arg->getType()); + llvm::FunctionType *FT = llvm::FunctionType::get(B.getVoidTy(), Types, + false); + llvm::FunctionCallee Fn = CGM.CreateRuntimeFunction(FT, FunctionName); + B.CreateCall(Fn, Args); + } + + ConstantAddress GenerateConstantString(const StringLiteral *SL) override { + + auto Str = SL->getString(); + CharUnits Align = CGM.getPointerAlign(); + + // Look for an existing one + llvm::StringMap<llvm::Constant*>::iterator old = ObjCStrings.find(Str); + if (old != ObjCStrings.end()) + return ConstantAddress(old->getValue(), IdElemTy, Align); + + bool isNonASCII = SL->containsNonAscii(); + + auto LiteralLength = SL->getLength(); + + if ((CGM.getTarget().getPointerWidth(LangAS::Default) == 64) && + (LiteralLength < 9) && !isNonASCII) { + // Tiny strings are only used on 64-bit platforms. They store 8 7-bit + // ASCII characters in the high 56 bits, followed by a 4-bit length and a + // 3-bit tag (which is always 4). + uint64_t str = 0; + // Fill in the characters + for (unsigned i=0 ; i<LiteralLength ; i++) + str |= ((uint64_t)SL->getCodeUnit(i)) << ((64 - 4 - 3) - (i*7)); + // Fill in the length + str |= LiteralLength << 3; + // Set the tag + str |= 4; + auto *ObjCStr = llvm::ConstantExpr::getIntToPtr( + llvm::ConstantInt::get(Int64Ty, str), IdTy); + ObjCStrings[Str] = ObjCStr; + return ConstantAddress(ObjCStr, IdElemTy, Align); + } + + StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass; + + if (StringClass.empty()) StringClass = "NSConstantString"; + + std::string Sym = SymbolForClass(StringClass); + + llvm::Constant *isa = TheModule.getNamedGlobal(Sym); + + if (!isa) { + isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false, + llvm::GlobalValue::ExternalLinkage, nullptr, Sym); + if (CGM.getTriple().isOSBinFormatCOFF()) { + cast<llvm::GlobalValue>(isa)->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + } + } else if (isa->getType() != PtrToIdTy) + isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy); + + // struct + // { + // Class isa; + // uint32_t flags; + // uint32_t length; // Number of codepoints + // uint32_t size; // Number of bytes + // uint32_t hash; + // const char *data; + // }; + + ConstantInitBuilder Builder(CGM); + auto Fields = Builder.beginStruct(); + if (!CGM.getTriple().isOSBinFormatCOFF()) { + Fields.add(isa); + } else { + Fields.addNullPointer(PtrTy); + } + // For now, all non-ASCII strings are represented as UTF-16. As such, the + // number of bytes is simply double the number of UTF-16 codepoints. In + // ASCII strings, the number of bytes is equal to the number of non-ASCII + // codepoints. + if (isNonASCII) { + unsigned NumU8CodeUnits = Str.size(); + // A UTF-16 representation of a unicode string contains at most the same + // number of code units as a UTF-8 representation. Allocate that much + // space, plus one for the final null character. + SmallVector<llvm::UTF16, 128> ToBuf(NumU8CodeUnits + 1); + const llvm::UTF8 *FromPtr = (const llvm::UTF8 *)Str.data(); + llvm::UTF16 *ToPtr = &ToBuf[0]; + (void)llvm::ConvertUTF8toUTF16(&FromPtr, FromPtr + NumU8CodeUnits, + &ToPtr, ToPtr + NumU8CodeUnits, llvm::strictConversion); + uint32_t StringLength = ToPtr - &ToBuf[0]; + // Add null terminator + *ToPtr = 0; + // Flags: 2 indicates UTF-16 encoding + Fields.addInt(Int32Ty, 2); + // Number of UTF-16 codepoints + Fields.addInt(Int32Ty, StringLength); + // Number of bytes + Fields.addInt(Int32Ty, StringLength * 2); + // Hash. Not currently initialised by the compiler. + Fields.addInt(Int32Ty, 0); + // pointer to the data string. + auto Arr = llvm::ArrayRef(&ToBuf[0], ToPtr + 1); + auto *C = llvm::ConstantDataArray::get(VMContext, Arr); + auto *Buffer = new llvm::GlobalVariable(TheModule, C->getType(), + /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, C, ".str"); + Buffer->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); + Fields.add(Buffer); + } else { + // Flags: 0 indicates ASCII encoding + Fields.addInt(Int32Ty, 0); + // Number of UTF-16 codepoints, each ASCII byte is a UTF-16 codepoint + Fields.addInt(Int32Ty, Str.size()); + // Number of bytes + Fields.addInt(Int32Ty, Str.size()); + // Hash. Not currently initialised by the compiler. + Fields.addInt(Int32Ty, 0); + // Data pointer + Fields.add(MakeConstantString(Str)); + } + std::string StringName; + bool isNamed = !isNonASCII; + if (isNamed) { + StringName = ".objc_str_"; + for (int i=0,e=Str.size() ; i<e ; ++i) { + unsigned char c = Str[i]; + if (isalnum(c)) + StringName += c; + else if (c == ' ') + StringName += '_'; + else { + isNamed = false; + break; + } + } + } + llvm::GlobalVariable *ObjCStrGV = + Fields.finishAndCreateGlobal( + isNamed ? StringRef(StringName) : ".objc_string", + Align, false, isNamed ? llvm::GlobalValue::LinkOnceODRLinkage + : llvm::GlobalValue::PrivateLinkage); + ObjCStrGV->setSection(sectionName<ConstantStringSection>()); + if (isNamed) { + ObjCStrGV->setComdat(TheModule.getOrInsertComdat(StringName)); + ObjCStrGV->setVisibility(llvm::GlobalValue::HiddenVisibility); + } + if (CGM.getTriple().isOSBinFormatCOFF()) { + std::pair<llvm::GlobalVariable*, int> v{ObjCStrGV, 0}; + EarlyInitList.emplace_back(Sym, v); + } + llvm::Constant *ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStrGV, IdTy); + ObjCStrings[Str] = ObjCStr; + ConstantStrings.push_back(ObjCStr); + return ConstantAddress(ObjCStr, IdElemTy, Align); + } + + void PushProperty(ConstantArrayBuilder &PropertiesArray, + const ObjCPropertyDecl *property, + const Decl *OCD, + bool isSynthesized=true, bool + isDynamic=true) override { + // struct objc_property + // { + // const char *name; + // const char *attributes; + // const char *type; + // SEL getter; + // SEL setter; + // }; + auto Fields = PropertiesArray.beginStruct(PropertyMetadataTy); + ASTContext &Context = CGM.getContext(); + Fields.add(MakeConstantString(property->getNameAsString())); + std::string TypeStr = + CGM.getContext().getObjCEncodingForPropertyDecl(property, OCD); + Fields.add(MakeConstantString(TypeStr)); + std::string typeStr; + Context.getObjCEncodingForType(property->getType(), typeStr); + Fields.add(MakeConstantString(typeStr)); + auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { + if (accessor) { + std::string TypeStr = Context.getObjCEncodingForMethodDecl(accessor); + Fields.add(GetConstantSelector(accessor->getSelector(), TypeStr)); + } else { + Fields.add(NULLPtr); + } + }; + addPropertyMethod(property->getGetterMethodDecl()); + addPropertyMethod(property->getSetterMethodDecl()); + Fields.finishAndAddTo(PropertiesArray); + } + + llvm::Constant * + GenerateProtocolMethodList(ArrayRef<const ObjCMethodDecl*> Methods) override { + // struct objc_protocol_method_description + // { + // SEL selector; + // const char *types; + // }; + llvm::StructType *ObjCMethodDescTy = + llvm::StructType::get(CGM.getLLVMContext(), + { PtrToInt8Ty, PtrToInt8Ty }); + ASTContext &Context = CGM.getContext(); + ConstantInitBuilder Builder(CGM); + // struct objc_protocol_method_description_list + // { + // int count; + // int size; + // struct objc_protocol_method_description methods[]; + // }; + auto MethodList = Builder.beginStruct(); + // int count; + MethodList.addInt(IntTy, Methods.size()); + // int size; // sizeof(struct objc_method_description) + llvm::DataLayout td(&TheModule); + MethodList.addInt(IntTy, td.getTypeSizeInBits(ObjCMethodDescTy) / + CGM.getContext().getCharWidth()); + // struct objc_method_description[] + auto MethodArray = MethodList.beginArray(ObjCMethodDescTy); + for (auto *M : Methods) { + auto Method = MethodArray.beginStruct(ObjCMethodDescTy); + Method.add(CGObjCGNU::GetConstantSelector(M)); + Method.add(GetTypeString(Context.getObjCEncodingForMethodDecl(M, true))); + Method.finishAndAddTo(MethodArray); + } + MethodArray.finishAndAddTo(MethodList); + return MethodList.finishAndCreateGlobal(".objc_protocol_method_list", + CGM.getPointerAlign()); + } + llvm::Constant *GenerateCategoryProtocolList(const ObjCCategoryDecl *OCD) + override { + const auto &ReferencedProtocols = OCD->getReferencedProtocols(); + auto RuntimeProtocols = GetRuntimeProtocolList(ReferencedProtocols.begin(), + ReferencedProtocols.end()); + SmallVector<llvm::Constant *, 16> Protocols; + for (const auto *PI : RuntimeProtocols) + Protocols.push_back( + llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI), + ProtocolPtrTy)); + return GenerateProtocolList(Protocols); + } + + llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, + llvm::Value *cmd, MessageSendInfo &MSI) override { + // Don't access the slot unless we're trying to cache the result. + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *lookupArgs[] = {CGObjCGNU::EnforceType(Builder, + ObjCSuper.getPointer(), + PtrToObjCSuperTy), + cmd}; + return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); + } + + llvm::GlobalVariable *GetClassVar(StringRef Name, bool isWeak=false) { + std::string SymbolName = SymbolForClassRef(Name, isWeak); + auto *ClassSymbol = TheModule.getNamedGlobal(SymbolName); + if (ClassSymbol) + return ClassSymbol; + ClassSymbol = new llvm::GlobalVariable(TheModule, + IdTy, false, llvm::GlobalValue::ExternalLinkage, + nullptr, SymbolName); + // If this is a weak symbol, then we are creating a valid definition for + // the symbol, pointing to a weak definition of the real class pointer. If + // this is not a weak reference, then we are expecting another compilation + // unit to provide the real indirection symbol. + if (isWeak) + ClassSymbol->setInitializer(new llvm::GlobalVariable(TheModule, + Int8Ty, false, llvm::GlobalValue::ExternalWeakLinkage, + nullptr, SymbolForClass(Name))); + else { + if (CGM.getTriple().isOSBinFormatCOFF()) { + IdentifierInfo &II = CGM.getContext().Idents.get(Name); + TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl(); + DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl); + + const ObjCInterfaceDecl *OID = nullptr; + for (const auto *Result : DC->lookup(&II)) + if ((OID = dyn_cast<ObjCInterfaceDecl>(Result))) + break; + + // The first Interface we find may be a @class, + // which should only be treated as the source of + // truth in the absence of a true declaration. + assert(OID && "Failed to find ObjCInterfaceDecl"); + const ObjCInterfaceDecl *OIDDef = OID->getDefinition(); + if (OIDDef != nullptr) + OID = OIDDef; + + auto Storage = llvm::GlobalValue::DefaultStorageClass; + if (OID->hasAttr<DLLImportAttr>()) + Storage = llvm::GlobalValue::DLLImportStorageClass; + else if (OID->hasAttr<DLLExportAttr>()) + Storage = llvm::GlobalValue::DLLExportStorageClass; + + cast<llvm::GlobalValue>(ClassSymbol)->setDLLStorageClass(Storage); + } + } + assert(ClassSymbol->getName() == SymbolName); + return ClassSymbol; + } + llvm::Value *GetClassNamed(CodeGenFunction &CGF, + const std::string &Name, + bool isWeak) override { + return CGF.Builder.CreateLoad( + Address(GetClassVar(Name, isWeak), IdTy, CGM.getPointerAlign())); + } + int32_t FlagsForOwnership(Qualifiers::ObjCLifetime Ownership) { + // typedef enum { + // ownership_invalid = 0, + // ownership_strong = 1, + // ownership_weak = 2, + // ownership_unsafe = 3 + // } ivar_ownership; + int Flag; + switch (Ownership) { + case Qualifiers::OCL_Strong: + Flag = 1; + break; + case Qualifiers::OCL_Weak: + Flag = 2; + break; + case Qualifiers::OCL_ExplicitNone: + Flag = 3; + break; + case Qualifiers::OCL_None: + case Qualifiers::OCL_Autoreleasing: + assert(Ownership != Qualifiers::OCL_Autoreleasing); + Flag = 0; + } + return Flag; + } + llvm::Constant *GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames, + ArrayRef<llvm::Constant *> IvarTypes, + ArrayRef<llvm::Constant *> IvarOffsets, + ArrayRef<llvm::Constant *> IvarAlign, + ArrayRef<Qualifiers::ObjCLifetime> IvarOwnership) override { + llvm_unreachable("Method should not be called!"); + } + + llvm::Constant *GenerateEmptyProtocol(StringRef ProtocolName) override { + std::string Name = SymbolForProtocol(ProtocolName); + auto *GV = TheModule.getGlobalVariable(Name); + if (!GV) { + // Emit a placeholder symbol. + GV = new llvm::GlobalVariable(TheModule, ProtocolTy, false, + llvm::GlobalValue::ExternalLinkage, nullptr, Name); + GV->setAlignment(CGM.getPointerAlign().getAsAlign()); + } + return llvm::ConstantExpr::getBitCast(GV, ProtocolPtrTy); + } + + /// Existing protocol references. + llvm::StringMap<llvm::Constant*> ExistingProtocolRefs; + + llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF, + const ObjCProtocolDecl *PD) override { + auto Name = PD->getNameAsString(); + auto *&Ref = ExistingProtocolRefs[Name]; + if (!Ref) { + auto *&Protocol = ExistingProtocols[Name]; + if (!Protocol) + Protocol = GenerateProtocolRef(PD); + std::string RefName = SymbolForProtocolRef(Name); + assert(!TheModule.getGlobalVariable(RefName)); + // Emit a reference symbol. + auto GV = new llvm::GlobalVariable(TheModule, ProtocolPtrTy, + false, llvm::GlobalValue::LinkOnceODRLinkage, + llvm::ConstantExpr::getBitCast(Protocol, ProtocolPtrTy), RefName); + GV->setComdat(TheModule.getOrInsertComdat(RefName)); + GV->setSection(sectionName<ProtocolReferenceSection>()); + GV->setAlignment(CGM.getPointerAlign().getAsAlign()); + Ref = GV; + } + EmittedProtocolRef = true; + return CGF.Builder.CreateAlignedLoad(ProtocolPtrTy, Ref, + CGM.getPointerAlign()); + } + + llvm::Constant *GenerateProtocolList(ArrayRef<llvm::Constant*> Protocols) { + llvm::ArrayType *ProtocolArrayTy = llvm::ArrayType::get(ProtocolPtrTy, + Protocols.size()); + llvm::Constant * ProtocolArray = llvm::ConstantArray::get(ProtocolArrayTy, + Protocols); + ConstantInitBuilder builder(CGM); + auto ProtocolBuilder = builder.beginStruct(); + ProtocolBuilder.addNullPointer(PtrTy); + ProtocolBuilder.addInt(SizeTy, Protocols.size()); + ProtocolBuilder.add(ProtocolArray); + return ProtocolBuilder.finishAndCreateGlobal(".objc_protocol_list", + CGM.getPointerAlign(), false, llvm::GlobalValue::InternalLinkage); + } + + void GenerateProtocol(const ObjCProtocolDecl *PD) override { + // Do nothing - we only emit referenced protocols. + } + llvm::Constant *GenerateProtocolRef(const ObjCProtocolDecl *PD) override { + std::string ProtocolName = PD->getNameAsString(); + auto *&Protocol = ExistingProtocols[ProtocolName]; + if (Protocol) + return Protocol; + + EmittedProtocol = true; + + auto SymName = SymbolForProtocol(ProtocolName); + auto *OldGV = TheModule.getGlobalVariable(SymName); + + // Use the protocol definition, if there is one. + if (const ObjCProtocolDecl *Def = PD->getDefinition()) + PD = Def; + else { + // If there is no definition, then create an external linkage symbol and + // hope that someone else fills it in for us (and fail to link if they + // don't). + assert(!OldGV); + Protocol = new llvm::GlobalVariable(TheModule, ProtocolTy, + /*isConstant*/false, + llvm::GlobalValue::ExternalLinkage, nullptr, SymName); + return Protocol; + } + + SmallVector<llvm::Constant*, 16> Protocols; + auto RuntimeProtocols = + GetRuntimeProtocolList(PD->protocol_begin(), PD->protocol_end()); + for (const auto *PI : RuntimeProtocols) + Protocols.push_back( + llvm::ConstantExpr::getBitCast(GenerateProtocolRef(PI), + ProtocolPtrTy)); + llvm::Constant *ProtocolList = GenerateProtocolList(Protocols); + + // Collect information about methods + llvm::Constant *InstanceMethodList, *OptionalInstanceMethodList; + llvm::Constant *ClassMethodList, *OptionalClassMethodList; + EmitProtocolMethodList(PD->instance_methods(), InstanceMethodList, + OptionalInstanceMethodList); + EmitProtocolMethodList(PD->class_methods(), ClassMethodList, + OptionalClassMethodList); + + // The isa pointer must be set to a magic number so the runtime knows it's + // the correct layout. + ConstantInitBuilder builder(CGM); + auto ProtocolBuilder = builder.beginStruct(); + ProtocolBuilder.add(llvm::ConstantExpr::getIntToPtr( + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); + ProtocolBuilder.add(MakeConstantString(ProtocolName)); + ProtocolBuilder.add(ProtocolList); + ProtocolBuilder.add(InstanceMethodList); + ProtocolBuilder.add(ClassMethodList); + ProtocolBuilder.add(OptionalInstanceMethodList); + ProtocolBuilder.add(OptionalClassMethodList); + // Required instance properties + ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, false, false)); + // Optional instance properties + ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, false, true)); + // Required class properties + ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, true, false)); + // Optional class properties + ProtocolBuilder.add(GeneratePropertyList(nullptr, PD, true, true)); + + auto *GV = ProtocolBuilder.finishAndCreateGlobal(SymName, + CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage); + GV->setSection(sectionName<ProtocolSection>()); + GV->setComdat(TheModule.getOrInsertComdat(SymName)); + if (OldGV) { + OldGV->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GV, + OldGV->getType())); + OldGV->removeFromParent(); + GV->setName(SymName); + } + Protocol = GV; + return GV; + } + llvm::Constant *EnforceType(llvm::Constant *Val, llvm::Type *Ty) { + if (Val->getType() == Ty) + return Val; + return llvm::ConstantExpr::getBitCast(Val, Ty); + } + llvm::Value *GetTypedSelector(CodeGenFunction &CGF, Selector Sel, + const std::string &TypeEncoding) override { + return GetConstantSelector(Sel, TypeEncoding); + } + llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) { + if (TypeEncoding.empty()) + return NULLPtr; + std::string MangledTypes = std::string(TypeEncoding); + std::replace(MangledTypes.begin(), MangledTypes.end(), + '@', '\1'); + std::string TypesVarName = ".objc_sel_types_" + MangledTypes; + auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName); + if (!TypesGlobal) { + llvm::Constant *Init = llvm::ConstantDataArray::getString(VMContext, + TypeEncoding); + auto *GV = new llvm::GlobalVariable(TheModule, Init->getType(), + true, llvm::GlobalValue::LinkOnceODRLinkage, Init, TypesVarName); + GV->setComdat(TheModule.getOrInsertComdat(TypesVarName)); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + TypesGlobal = GV; + } + return llvm::ConstantExpr::getGetElementPtr(TypesGlobal->getValueType(), + TypesGlobal, Zeros); + } + llvm::Constant *GetConstantSelector(Selector Sel, + const std::string &TypeEncoding) override { + // @ is used as a special character in symbol names (used for symbol + // versioning), so mangle the name to not include it. Replace it with a + // character that is not a valid type encoding character (and, being + // non-printable, never will be!) + std::string MangledTypes = TypeEncoding; + std::replace(MangledTypes.begin(), MangledTypes.end(), + '@', '\1'); + auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" + + MangledTypes).str(); + if (auto *GV = TheModule.getNamedGlobal(SelVarName)) + return EnforceType(GV, SelectorTy); + ConstantInitBuilder builder(CGM); + auto SelBuilder = builder.beginStruct(); + SelBuilder.add(ExportUniqueString(Sel.getAsString(), ".objc_sel_name_", + true)); + SelBuilder.add(GetTypeString(TypeEncoding)); + auto *GV = SelBuilder.finishAndCreateGlobal(SelVarName, + CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage); + GV->setComdat(TheModule.getOrInsertComdat(SelVarName)); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + GV->setSection(sectionName<SelectorSection>()); + auto *SelVal = EnforceType(GV, SelectorTy); + return SelVal; + } + llvm::StructType *emptyStruct = nullptr; + + /// Return pointers to the start and end of a section. On ELF platforms, we + /// use the __start_ and __stop_ symbols that GNU-compatible linkers will set + /// to the start and end of section names, as long as those section names are + /// valid identifiers and the symbols are referenced but not defined. On + /// Windows, we use the fact that MSVC-compatible linkers will lexically sort + /// by subsections and place everything that we want to reference in a middle + /// subsection and then insert zero-sized symbols in subsections a and z. + std::pair<llvm::Constant*,llvm::Constant*> + GetSectionBounds(StringRef Section) { + if (CGM.getTriple().isOSBinFormatCOFF()) { + if (emptyStruct == nullptr) { + emptyStruct = llvm::StructType::create(VMContext, ".objc_section_sentinel"); + emptyStruct->setBody({}, /*isPacked*/true); + } + auto ZeroInit = llvm::Constant::getNullValue(emptyStruct); + auto Sym = [&](StringRef Prefix, StringRef SecSuffix) { + auto *Sym = new llvm::GlobalVariable(TheModule, emptyStruct, + /*isConstant*/false, + llvm::GlobalValue::LinkOnceODRLinkage, ZeroInit, Prefix + + Section); + Sym->setVisibility(llvm::GlobalValue::HiddenVisibility); + Sym->setSection((Section + SecSuffix).str()); + Sym->setComdat(TheModule.getOrInsertComdat((Prefix + + Section).str())); + Sym->setAlignment(CGM.getPointerAlign().getAsAlign()); + return Sym; + }; + return { Sym("__start_", "$a"), Sym("__stop", "$z") }; + } + auto *Start = new llvm::GlobalVariable(TheModule, PtrTy, + /*isConstant*/false, + llvm::GlobalValue::ExternalLinkage, nullptr, StringRef("__start_") + + Section); + Start->setVisibility(llvm::GlobalValue::HiddenVisibility); + auto *Stop = new llvm::GlobalVariable(TheModule, PtrTy, + /*isConstant*/false, + llvm::GlobalValue::ExternalLinkage, nullptr, StringRef("__stop_") + + Section); + Stop->setVisibility(llvm::GlobalValue::HiddenVisibility); + return { Start, Stop }; + } + CatchTypeInfo getCatchAllTypeInfo() override { + return CGM.getCXXABI().getCatchAllTypeInfo(); + } + llvm::Function *ModuleInitFunction() override { + llvm::Function *LoadFunction = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false), + llvm::GlobalValue::LinkOnceODRLinkage, ".objcv2_load_function", + &TheModule); + LoadFunction->setVisibility(llvm::GlobalValue::HiddenVisibility); + LoadFunction->setComdat(TheModule.getOrInsertComdat(".objcv2_load_function")); + + llvm::BasicBlock *EntryBB = + llvm::BasicBlock::Create(VMContext, "entry", LoadFunction); + CGBuilderTy B(CGM, VMContext); + B.SetInsertPoint(EntryBB); + ConstantInitBuilder builder(CGM); + auto InitStructBuilder = builder.beginStruct(); + InitStructBuilder.addInt(Int64Ty, 0); + auto §ionVec = CGM.getTriple().isOSBinFormatCOFF() ? PECOFFSectionsBaseNames : SectionsBaseNames; + for (auto *s : sectionVec) { + auto bounds = GetSectionBounds(s); + InitStructBuilder.add(bounds.first); + InitStructBuilder.add(bounds.second); + } + auto *InitStruct = InitStructBuilder.finishAndCreateGlobal(".objc_init", + CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage); + InitStruct->setVisibility(llvm::GlobalValue::HiddenVisibility); + InitStruct->setComdat(TheModule.getOrInsertComdat(".objc_init")); + + CallRuntimeFunction(B, "__objc_load", {InitStruct});; + B.CreateRetVoid(); + // Make sure that the optimisers don't delete this function. + CGM.addCompilerUsedGlobal(LoadFunction); + // FIXME: Currently ELF only! + // We have to do this by hand, rather than with @llvm.ctors, so that the + // linker can remove the duplicate invocations. + auto *InitVar = new llvm::GlobalVariable(TheModule, LoadFunction->getType(), + /*isConstant*/false, llvm::GlobalValue::LinkOnceAnyLinkage, + LoadFunction, ".objc_ctor"); + // Check that this hasn't been renamed. This shouldn't happen, because + // this function should be called precisely once. + assert(InitVar->getName() == ".objc_ctor"); + // In Windows, initialisers are sorted by the suffix. XCL is for library + // initialisers, which run before user initialisers. We are running + // Objective-C loads at the end of library load. This means +load methods + // will run before any other static constructors, but that static + // constructors can see a fully initialised Objective-C state. + if (CGM.getTriple().isOSBinFormatCOFF()) + InitVar->setSection(".CRT$XCLz"); + else + { + if (CGM.getCodeGenOpts().UseInitArray) + InitVar->setSection(".init_array"); + else + InitVar->setSection(".ctors"); + } + InitVar->setVisibility(llvm::GlobalValue::HiddenVisibility); + InitVar->setComdat(TheModule.getOrInsertComdat(".objc_ctor")); + CGM.addUsedGlobal(InitVar); + for (auto *C : Categories) { + auto *Cat = cast<llvm::GlobalVariable>(C->stripPointerCasts()); + Cat->setSection(sectionName<CategorySection>()); + CGM.addUsedGlobal(Cat); + } + auto createNullGlobal = [&](StringRef Name, ArrayRef<llvm::Constant*> Init, + StringRef Section) { + auto nullBuilder = builder.beginStruct(); + for (auto *F : Init) + nullBuilder.add(F); + auto GV = nullBuilder.finishAndCreateGlobal(Name, CGM.getPointerAlign(), + false, llvm::GlobalValue::LinkOnceODRLinkage); + GV->setSection(Section); + GV->setComdat(TheModule.getOrInsertComdat(Name)); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + CGM.addUsedGlobal(GV); + return GV; + }; + for (auto clsAlias : ClassAliases) + createNullGlobal(std::string(".objc_class_alias") + + clsAlias.second, { MakeConstantString(clsAlias.second), + GetClassVar(clsAlias.first) }, sectionName<ClassAliasSection>()); + // On ELF platforms, add a null value for each special section so that we + // can always guarantee that the _start and _stop symbols will exist and be + // meaningful. This is not required on COFF platforms, where our start and + // stop symbols will create the section. + if (!CGM.getTriple().isOSBinFormatCOFF()) { + createNullGlobal(".objc_null_selector", {NULLPtr, NULLPtr}, + sectionName<SelectorSection>()); + if (Categories.empty()) + createNullGlobal(".objc_null_category", {NULLPtr, NULLPtr, + NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr}, + sectionName<CategorySection>()); + if (!EmittedClass) { + createNullGlobal(".objc_null_cls_init_ref", NULLPtr, + sectionName<ClassSection>()); + createNullGlobal(".objc_null_class_ref", { NULLPtr, NULLPtr }, + sectionName<ClassReferenceSection>()); + } + if (!EmittedProtocol) + createNullGlobal(".objc_null_protocol", {NULLPtr, NULLPtr, NULLPtr, + NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, + NULLPtr}, sectionName<ProtocolSection>()); + if (!EmittedProtocolRef) + createNullGlobal(".objc_null_protocol_ref", {NULLPtr}, + sectionName<ProtocolReferenceSection>()); + if (ClassAliases.empty()) + createNullGlobal(".objc_null_class_alias", { NULLPtr, NULLPtr }, + sectionName<ClassAliasSection>()); + if (ConstantStrings.empty()) { + auto i32Zero = llvm::ConstantInt::get(Int32Ty, 0); + createNullGlobal(".objc_null_constant_string", { NULLPtr, i32Zero, + i32Zero, i32Zero, i32Zero, NULLPtr }, + sectionName<ConstantStringSection>()); + } + } + ConstantStrings.clear(); + Categories.clear(); + Classes.clear(); + + if (EarlyInitList.size() > 0) { + auto *Init = llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, + {}), llvm::GlobalValue::InternalLinkage, ".objc_early_init", + &CGM.getModule()); + llvm::IRBuilder<> b(llvm::BasicBlock::Create(CGM.getLLVMContext(), "entry", + Init)); + for (const auto &lateInit : EarlyInitList) { + auto *global = TheModule.getGlobalVariable(lateInit.first); + if (global) { + llvm::GlobalVariable *GV = lateInit.second.first; + b.CreateAlignedStore( + global, + b.CreateStructGEP(GV->getValueType(), GV, lateInit.second.second), + CGM.getPointerAlign().getAsAlign()); + } + } + b.CreateRetVoid(); + // We can't use the normal LLVM global initialisation array, because we + // need to specify that this runs early in library initialisation. + auto *InitVar = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + /*isConstant*/true, llvm::GlobalValue::InternalLinkage, + Init, ".objc_early_init_ptr"); + InitVar->setSection(".CRT$XCLb"); + CGM.addUsedGlobal(InitVar); + } + return nullptr; + } + /// In the v2 ABI, ivar offset variables use the type encoding in their name + /// to trigger linker failures if the types don't match. + std::string GetIVarOffsetVariableName(const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar) override { + std::string TypeEncoding; + CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding); + // Prevent the @ from being interpreted as a symbol version. + std::replace(TypeEncoding.begin(), TypeEncoding.end(), + '@', '\1'); + const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString() + + '.' + Ivar->getNameAsString() + '.' + TypeEncoding; + return Name; + } + llvm::Value *EmitIvarOffset(CodeGenFunction &CGF, + const ObjCInterfaceDecl *Interface, + const ObjCIvarDecl *Ivar) override { + const std::string Name = GetIVarOffsetVariableName(Ivar->getContainingInterface(), Ivar); + llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); + if (!IvarOffsetPointer) + IvarOffsetPointer = new llvm::GlobalVariable(TheModule, IntTy, false, + llvm::GlobalValue::ExternalLinkage, nullptr, Name); + CharUnits Align = CGM.getIntAlign(); + llvm::Value *Offset = + CGF.Builder.CreateAlignedLoad(IntTy, IvarOffsetPointer, Align); + if (Offset->getType() != PtrDiffTy) + Offset = CGF.Builder.CreateZExtOrBitCast(Offset, PtrDiffTy); + return Offset; + } + void GenerateClass(const ObjCImplementationDecl *OID) override { + ASTContext &Context = CGM.getContext(); + bool IsCOFF = CGM.getTriple().isOSBinFormatCOFF(); + + // Get the class name + ObjCInterfaceDecl *classDecl = + const_cast<ObjCInterfaceDecl *>(OID->getClassInterface()); + std::string className = classDecl->getNameAsString(); + auto *classNameConstant = MakeConstantString(className); + + ConstantInitBuilder builder(CGM); + auto metaclassFields = builder.beginStruct(); + // struct objc_class *isa; + metaclassFields.addNullPointer(PtrTy); + // struct objc_class *super_class; + metaclassFields.addNullPointer(PtrTy); + // const char *name; + metaclassFields.add(classNameConstant); + // long version; + metaclassFields.addInt(LongTy, 0); + // unsigned long info; + // objc_class_flag_meta + metaclassFields.addInt(LongTy, 1); + // long instance_size; + // Setting this to zero is consistent with the older ABI, but it might be + // more sensible to set this to sizeof(struct objc_class) + metaclassFields.addInt(LongTy, 0); + // struct objc_ivar_list *ivars; + metaclassFields.addNullPointer(PtrTy); + // struct objc_method_list *methods + // FIXME: Almost identical code is copied and pasted below for the + // class, but refactoring it cleanly requires C++14 generic lambdas. + if (OID->classmeth_begin() == OID->classmeth_end()) + metaclassFields.addNullPointer(PtrTy); + else { + SmallVector<ObjCMethodDecl*, 16> ClassMethods; + ClassMethods.insert(ClassMethods.begin(), OID->classmeth_begin(), + OID->classmeth_end()); + metaclassFields.addBitCast( + GenerateMethodList(className, "", ClassMethods, true), + PtrTy); + } + // void *dtable; + metaclassFields.addNullPointer(PtrTy); + // IMP cxx_construct; + metaclassFields.addNullPointer(PtrTy); + // IMP cxx_destruct; + metaclassFields.addNullPointer(PtrTy); + // struct objc_class *subclass_list + metaclassFields.addNullPointer(PtrTy); + // struct objc_class *sibling_class + metaclassFields.addNullPointer(PtrTy); + // struct objc_protocol_list *protocols; + metaclassFields.addNullPointer(PtrTy); + // struct reference_list *extra_data; + metaclassFields.addNullPointer(PtrTy); + // long abi_version; + metaclassFields.addInt(LongTy, 0); + // struct objc_property_list *properties + metaclassFields.add(GeneratePropertyList(OID, classDecl, /*isClassProperty*/true)); + + auto *metaclass = metaclassFields.finishAndCreateGlobal( + ManglePublicSymbol("OBJC_METACLASS_") + className, + CGM.getPointerAlign()); + + auto classFields = builder.beginStruct(); + // struct objc_class *isa; + classFields.add(metaclass); + // struct objc_class *super_class; + // Get the superclass name. + const ObjCInterfaceDecl * SuperClassDecl = + OID->getClassInterface()->getSuperClass(); + llvm::Constant *SuperClass = nullptr; + if (SuperClassDecl) { + auto SuperClassName = SymbolForClass(SuperClassDecl->getNameAsString()); + SuperClass = TheModule.getNamedGlobal(SuperClassName); + if (!SuperClass) + { + SuperClass = new llvm::GlobalVariable(TheModule, PtrTy, false, + llvm::GlobalValue::ExternalLinkage, nullptr, SuperClassName); + if (IsCOFF) { + auto Storage = llvm::GlobalValue::DefaultStorageClass; + if (SuperClassDecl->hasAttr<DLLImportAttr>()) + Storage = llvm::GlobalValue::DLLImportStorageClass; + else if (SuperClassDecl->hasAttr<DLLExportAttr>()) + Storage = llvm::GlobalValue::DLLExportStorageClass; + + cast<llvm::GlobalValue>(SuperClass)->setDLLStorageClass(Storage); + } + } + if (!IsCOFF) + classFields.add(llvm::ConstantExpr::getBitCast(SuperClass, PtrTy)); + else + classFields.addNullPointer(PtrTy); + } else + classFields.addNullPointer(PtrTy); + // const char *name; + classFields.add(classNameConstant); + // long version; + classFields.addInt(LongTy, 0); + // unsigned long info; + // !objc_class_flag_meta + classFields.addInt(LongTy, 0); + // long instance_size; + int superInstanceSize = !SuperClassDecl ? 0 : + Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); + // Instance size is negative for classes that have not yet had their ivar + // layout calculated. + classFields.addInt(LongTy, + 0 - (Context.getASTObjCImplementationLayout(OID).getSize().getQuantity() - + superInstanceSize)); + + if (classDecl->all_declared_ivar_begin() == nullptr) + classFields.addNullPointer(PtrTy); + else { + int ivar_count = 0; + for (const ObjCIvarDecl *IVD = classDecl->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) ivar_count++; + llvm::DataLayout td(&TheModule); + // struct objc_ivar_list *ivars; + ConstantInitBuilder b(CGM); + auto ivarListBuilder = b.beginStruct(); + // int count; + ivarListBuilder.addInt(IntTy, ivar_count); + // size_t size; + llvm::StructType *ObjCIvarTy = llvm::StructType::get( + PtrToInt8Ty, + PtrToInt8Ty, + PtrToInt8Ty, + Int32Ty, + Int32Ty); + ivarListBuilder.addInt(SizeTy, td.getTypeSizeInBits(ObjCIvarTy) / + CGM.getContext().getCharWidth()); + // struct objc_ivar ivars[] + auto ivarArrayBuilder = ivarListBuilder.beginArray(); + for (const ObjCIvarDecl *IVD = classDecl->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) { + auto ivarTy = IVD->getType(); + auto ivarBuilder = ivarArrayBuilder.beginStruct(); + // const char *name; + ivarBuilder.add(MakeConstantString(IVD->getNameAsString())); + // const char *type; + std::string TypeStr; + //Context.getObjCEncodingForType(ivarTy, TypeStr, IVD, true); + Context.getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, ivarTy, TypeStr, true); + ivarBuilder.add(MakeConstantString(TypeStr)); + // int *offset; + uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); + uint64_t Offset = BaseOffset - superInstanceSize; + llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset); + std::string OffsetName = GetIVarOffsetVariableName(classDecl, IVD); + llvm::GlobalVariable *OffsetVar = TheModule.getGlobalVariable(OffsetName); + if (OffsetVar) + OffsetVar->setInitializer(OffsetValue); + else + OffsetVar = new llvm::GlobalVariable(TheModule, IntTy, + false, llvm::GlobalValue::ExternalLinkage, + OffsetValue, OffsetName); + auto ivarVisibility = + (IVD->getAccessControl() == ObjCIvarDecl::Private || + IVD->getAccessControl() == ObjCIvarDecl::Package || + classDecl->getVisibility() == HiddenVisibility) ? + llvm::GlobalValue::HiddenVisibility : + llvm::GlobalValue::DefaultVisibility; + OffsetVar->setVisibility(ivarVisibility); + ivarBuilder.add(OffsetVar); + // Ivar size + ivarBuilder.addInt(Int32Ty, + CGM.getContext().getTypeSizeInChars(ivarTy).getQuantity()); + // Alignment will be stored as a base-2 log of the alignment. + unsigned align = + llvm::Log2_32(Context.getTypeAlignInChars(ivarTy).getQuantity()); + // Objects that require more than 2^64-byte alignment should be impossible! + assert(align < 64); + // uint32_t flags; + // Bits 0-1 are ownership. + // Bit 2 indicates an extended type encoding + // Bits 3-8 contain log2(aligment) + ivarBuilder.addInt(Int32Ty, + (align << 3) | (1<<2) | + FlagsForOwnership(ivarTy.getQualifiers().getObjCLifetime())); + ivarBuilder.finishAndAddTo(ivarArrayBuilder); + } + ivarArrayBuilder.finishAndAddTo(ivarListBuilder); + auto ivarList = ivarListBuilder.finishAndCreateGlobal(".objc_ivar_list", + CGM.getPointerAlign(), /*constant*/ false, + llvm::GlobalValue::PrivateLinkage); + classFields.add(ivarList); + } + // struct objc_method_list *methods + SmallVector<const ObjCMethodDecl*, 16> InstanceMethods; + InstanceMethods.insert(InstanceMethods.begin(), OID->instmeth_begin(), + OID->instmeth_end()); + for (auto *propImpl : OID->property_impls()) + if (propImpl->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize) { + auto addIfExists = [&](const ObjCMethodDecl *OMD) { + if (OMD && OMD->hasBody()) + InstanceMethods.push_back(OMD); + }; + addIfExists(propImpl->getGetterMethodDecl()); + addIfExists(propImpl->getSetterMethodDecl()); + } + + if (InstanceMethods.size() == 0) + classFields.addNullPointer(PtrTy); + else + classFields.addBitCast( + GenerateMethodList(className, "", InstanceMethods, false), + PtrTy); + // void *dtable; + classFields.addNullPointer(PtrTy); + // IMP cxx_construct; + classFields.addNullPointer(PtrTy); + // IMP cxx_destruct; + classFields.addNullPointer(PtrTy); + // struct objc_class *subclass_list + classFields.addNullPointer(PtrTy); + // struct objc_class *sibling_class + classFields.addNullPointer(PtrTy); + // struct objc_protocol_list *protocols; + auto RuntimeProtocols = GetRuntimeProtocolList(classDecl->protocol_begin(), + classDecl->protocol_end()); + SmallVector<llvm::Constant *, 16> Protocols; + for (const auto *I : RuntimeProtocols) + Protocols.push_back( + llvm::ConstantExpr::getBitCast(GenerateProtocolRef(I), + ProtocolPtrTy)); + if (Protocols.empty()) + classFields.addNullPointer(PtrTy); + else + classFields.add(GenerateProtocolList(Protocols)); + // struct reference_list *extra_data; + classFields.addNullPointer(PtrTy); + // long abi_version; + classFields.addInt(LongTy, 0); + // struct objc_property_list *properties + classFields.add(GeneratePropertyList(OID, classDecl)); + + llvm::GlobalVariable *classStruct = + classFields.finishAndCreateGlobal(SymbolForClass(className), + CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage); + + auto *classRefSymbol = GetClassVar(className); + classRefSymbol->setSection(sectionName<ClassReferenceSection>()); + classRefSymbol->setInitializer(llvm::ConstantExpr::getBitCast(classStruct, IdTy)); + + if (IsCOFF) { + // we can't import a class struct. + if (OID->getClassInterface()->hasAttr<DLLExportAttr>()) { + classStruct->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); + cast<llvm::GlobalValue>(classRefSymbol)->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); + } + + if (SuperClass) { + std::pair<llvm::GlobalVariable*, int> v{classStruct, 1}; + EarlyInitList.emplace_back(std::string(SuperClass->getName()), + std::move(v)); + } + + } + + + // Resolve the class aliases, if they exist. + // FIXME: Class pointer aliases shouldn't exist! + if (ClassPtrAlias) { + ClassPtrAlias->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(classStruct, IdTy)); + ClassPtrAlias->eraseFromParent(); + ClassPtrAlias = nullptr; + } + if (auto Placeholder = + TheModule.getNamedGlobal(SymbolForClass(className))) + if (Placeholder != classStruct) { + Placeholder->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(classStruct, Placeholder->getType())); + Placeholder->eraseFromParent(); + classStruct->setName(SymbolForClass(className)); + } + if (MetaClassPtrAlias) { + MetaClassPtrAlias->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(metaclass, IdTy)); + MetaClassPtrAlias->eraseFromParent(); + MetaClassPtrAlias = nullptr; + } + assert(classStruct->getName() == SymbolForClass(className)); + + auto classInitRef = new llvm::GlobalVariable(TheModule, + classStruct->getType(), false, llvm::GlobalValue::ExternalLinkage, + classStruct, ManglePublicSymbol("OBJC_INIT_CLASS_") + className); + classInitRef->setSection(sectionName<ClassSection>()); + CGM.addUsedGlobal(classInitRef); + + EmittedClass = true; + } + public: + CGObjCGNUstep2(CodeGenModule &Mod) : CGObjCGNUstep(Mod, 10, 4, 2) { + MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, + PtrToObjCSuperTy, SelectorTy); + // struct objc_property + // { + // const char *name; + // const char *attributes; + // const char *type; + // SEL getter; + // SEL setter; + // } + PropertyMetadataTy = + llvm::StructType::get(CGM.getLLVMContext(), + { PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty }); + } + +}; + +const char *const CGObjCGNUstep2::SectionsBaseNames[8] = +{ +"__objc_selectors", +"__objc_classes", +"__objc_class_refs", +"__objc_cats", +"__objc_protocols", +"__objc_protocol_refs", +"__objc_class_aliases", +"__objc_constant_string" +}; + +const char *const CGObjCGNUstep2::PECOFFSectionsBaseNames[8] = +{ +".objcrt$SEL", +".objcrt$CLS", +".objcrt$CLR", +".objcrt$CAT", +".objcrt$PCL", +".objcrt$PCR", +".objcrt$CAL", +".objcrt$STR" +}; + +/// Support for the ObjFW runtime. +class CGObjCObjFW: public CGObjCGNU { +protected: + /// The GCC ABI message lookup function. Returns an IMP pointing to the + /// method implementation for this message. + LazyRuntimeFunction MsgLookupFn; + /// stret lookup function. While this does not seem to make sense at the + /// first look, this is required to call the correct forwarding function. + LazyRuntimeFunction MsgLookupFnSRet; + /// The GCC ABI superclass message lookup function. Takes a pointer to a + /// structure describing the receiver and the class, and a selector as + /// arguments. Returns the IMP for the corresponding method. + LazyRuntimeFunction MsgLookupSuperFn, MsgLookupSuperFnSRet; + + llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, + llvm::Value *cmd, llvm::MDNode *node, + MessageSendInfo &MSI) override { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *args[] = { + EnforceType(Builder, Receiver, IdTy), + EnforceType(Builder, cmd, SelectorTy) }; + + llvm::CallBase *imp; + if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) + imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFnSRet, args); + else + imp = CGF.EmitRuntimeCallOrInvoke(MsgLookupFn, args); + + imp->setMetadata(msgSendMDKind, node); + return imp; + } + + llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, Address ObjCSuper, + llvm::Value *cmd, MessageSendInfo &MSI) override { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *lookupArgs[] = { + EnforceType(Builder, ObjCSuper.getPointer(), PtrToObjCSuperTy), cmd, + }; + + if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) + return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFnSRet, lookupArgs); + else + return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); + } + + llvm::Value *GetClassNamed(CodeGenFunction &CGF, const std::string &Name, + bool isWeak) override { + if (isWeak) + return CGObjCGNU::GetClassNamed(CGF, Name, isWeak); + + EmitClassRef(Name); + std::string SymbolName = "_OBJC_CLASS_" + Name; + llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(SymbolName); + if (!ClassSymbol) + ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false, + llvm::GlobalValue::ExternalLinkage, + nullptr, SymbolName); + return ClassSymbol; + } + +public: + CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) { + // IMP objc_msg_lookup(id, SEL); + MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy); + MsgLookupFnSRet.init(&CGM, "objc_msg_lookup_stret", IMPTy, IdTy, + SelectorTy); + // IMP objc_msg_lookup_super(struct objc_super*, SEL); + MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, + PtrToObjCSuperTy, SelectorTy); + MsgLookupSuperFnSRet.init(&CGM, "objc_msg_lookup_super_stret", IMPTy, + PtrToObjCSuperTy, SelectorTy); + } +}; +} // end anonymous namespace + +/// Emits a reference to a dummy variable which is emitted with each class. +/// This ensures that a linker error will be generated when trying to link +/// together modules where a referenced class is not defined. +void CGObjCGNU::EmitClassRef(const std::string &className) { + std::string symbolRef = "__objc_class_ref_" + className; + // Don't emit two copies of the same symbol + if (TheModule.getGlobalVariable(symbolRef)) + return; + std::string symbolName = "__objc_class_name_" + className; + llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName); + if (!ClassSymbol) { + ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false, + llvm::GlobalValue::ExternalLinkage, + nullptr, symbolName); + } + new llvm::GlobalVariable(TheModule, ClassSymbol->getType(), true, + llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef); +} + +CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion, + unsigned protocolClassVersion, unsigned classABI) + : CGObjCRuntime(cgm), TheModule(CGM.getModule()), + VMContext(cgm.getLLVMContext()), ClassPtrAlias(nullptr), + MetaClassPtrAlias(nullptr), RuntimeVersion(runtimeABIVersion), + ProtocolVersion(protocolClassVersion), ClassABIVersion(classABI) { + + msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend"); + usesSEHExceptions = + cgm.getContext().getTargetInfo().getTriple().isWindowsMSVCEnvironment(); + + CodeGenTypes &Types = CGM.getTypes(); + IntTy = cast<llvm::IntegerType>( + Types.ConvertType(CGM.getContext().IntTy)); + LongTy = cast<llvm::IntegerType>( + Types.ConvertType(CGM.getContext().LongTy)); + SizeTy = cast<llvm::IntegerType>( + Types.ConvertType(CGM.getContext().getSizeType())); + PtrDiffTy = cast<llvm::IntegerType>( + Types.ConvertType(CGM.getContext().getPointerDiffType())); + BoolTy = CGM.getTypes().ConvertType(CGM.getContext().BoolTy); + + Int8Ty = llvm::Type::getInt8Ty(VMContext); + // C string type. Used in lots of places. + PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty); + ProtocolPtrTy = llvm::PointerType::getUnqual( + Types.ConvertType(CGM.getContext().getObjCProtoType())); + + Zeros[0] = llvm::ConstantInt::get(LongTy, 0); + Zeros[1] = Zeros[0]; + NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty); + // Get the selector Type. + QualType selTy = CGM.getContext().getObjCSelType(); + if (QualType() == selTy) { + SelectorTy = PtrToInt8Ty; + SelectorElemTy = Int8Ty; + } else { + SelectorTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(selTy)); + SelectorElemTy = CGM.getTypes().ConvertTypeForMem(selTy->getPointeeType()); + } + + PtrToIntTy = llvm::PointerType::getUnqual(IntTy); + PtrTy = PtrToInt8Ty; + + Int32Ty = llvm::Type::getInt32Ty(VMContext); + Int64Ty = llvm::Type::getInt64Ty(VMContext); + + IntPtrTy = + CGM.getDataLayout().getPointerSizeInBits() == 32 ? Int32Ty : Int64Ty; + + // Object type + QualType UnqualIdTy = CGM.getContext().getObjCIdType(); + ASTIdTy = CanQualType(); + if (UnqualIdTy != QualType()) { + ASTIdTy = CGM.getContext().getCanonicalType(UnqualIdTy); + IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); + IdElemTy = CGM.getTypes().ConvertTypeForMem( + ASTIdTy.getTypePtr()->getPointeeType()); + } else { + IdTy = PtrToInt8Ty; + IdElemTy = Int8Ty; + } + PtrToIdTy = llvm::PointerType::getUnqual(IdTy); + ProtocolTy = llvm::StructType::get(IdTy, + PtrToInt8Ty, // name + PtrToInt8Ty, // protocols + PtrToInt8Ty, // instance methods + PtrToInt8Ty, // class methods + PtrToInt8Ty, // optional instance methods + PtrToInt8Ty, // optional class methods + PtrToInt8Ty, // properties + PtrToInt8Ty);// optional properties + + // struct objc_property_gsv1 + // { + // const char *name; + // char attributes; + // char attributes2; + // char unused1; + // char unused2; + // const char *getter_name; + // const char *getter_types; + // const char *setter_name; + // const char *setter_types; + // } + PropertyMetadataTy = llvm::StructType::get(CGM.getLLVMContext(), { + PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty, PtrToInt8Ty, + PtrToInt8Ty, PtrToInt8Ty }); + + ObjCSuperTy = llvm::StructType::get(IdTy, IdTy); + PtrToObjCSuperTy = llvm::PointerType::getUnqual(ObjCSuperTy); + + llvm::Type *VoidTy = llvm::Type::getVoidTy(VMContext); + + // void objc_exception_throw(id); + ExceptionThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy); + ExceptionReThrowFn.init(&CGM, "objc_exception_throw", VoidTy, IdTy); + // int objc_sync_enter(id); + SyncEnterFn.init(&CGM, "objc_sync_enter", IntTy, IdTy); + // int objc_sync_exit(id); + SyncExitFn.init(&CGM, "objc_sync_exit", IntTy, IdTy); + + // void objc_enumerationMutation (id) + EnumerationMutationFn.init(&CGM, "objc_enumerationMutation", VoidTy, IdTy); + + // id objc_getProperty(id, SEL, ptrdiff_t, BOOL) + GetPropertyFn.init(&CGM, "objc_getProperty", IdTy, IdTy, SelectorTy, + PtrDiffTy, BoolTy); + // void objc_setProperty(id, SEL, ptrdiff_t, id, BOOL, BOOL) + SetPropertyFn.init(&CGM, "objc_setProperty", VoidTy, IdTy, SelectorTy, + PtrDiffTy, IdTy, BoolTy, BoolTy); + // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL) + GetStructPropertyFn.init(&CGM, "objc_getPropertyStruct", VoidTy, PtrTy, PtrTy, + PtrDiffTy, BoolTy, BoolTy); + // void objc_setPropertyStruct(void*, void*, ptrdiff_t, BOOL, BOOL) + SetStructPropertyFn.init(&CGM, "objc_setPropertyStruct", VoidTy, PtrTy, PtrTy, + PtrDiffTy, BoolTy, BoolTy); + + // IMP type + llvm::Type *IMPArgs[] = { IdTy, SelectorTy }; + IMPTy = llvm::PointerType::getUnqual(llvm::FunctionType::get(IdTy, IMPArgs, + true)); + + const LangOptions &Opts = CGM.getLangOpts(); + if ((Opts.getGC() != LangOptions::NonGC) || Opts.ObjCAutoRefCount) + RuntimeVersion = 10; + + // Don't bother initialising the GC stuff unless we're compiling in GC mode + if (Opts.getGC() != LangOptions::NonGC) { + // This is a bit of an hack. We should sort this out by having a proper + // CGObjCGNUstep subclass for GC, but we may want to really support the old + // ABI and GC added in ObjectiveC2.framework, so we fudge it a bit for now + // Get selectors needed in GC mode + RetainSel = GetNullarySelector("retain", CGM.getContext()); + ReleaseSel = GetNullarySelector("release", CGM.getContext()); + AutoreleaseSel = GetNullarySelector("autorelease", CGM.getContext()); + + // Get functions needed in GC mode + + // id objc_assign_ivar(id, id, ptrdiff_t); + IvarAssignFn.init(&CGM, "objc_assign_ivar", IdTy, IdTy, IdTy, PtrDiffTy); + // id objc_assign_strongCast (id, id*) + StrongCastAssignFn.init(&CGM, "objc_assign_strongCast", IdTy, IdTy, + PtrToIdTy); + // id objc_assign_global(id, id*); + GlobalAssignFn.init(&CGM, "objc_assign_global", IdTy, IdTy, PtrToIdTy); + // id objc_assign_weak(id, id*); + WeakAssignFn.init(&CGM, "objc_assign_weak", IdTy, IdTy, PtrToIdTy); + // id objc_read_weak(id*); + WeakReadFn.init(&CGM, "objc_read_weak", IdTy, PtrToIdTy); + // void *objc_memmove_collectable(void*, void *, size_t); + MemMoveFn.init(&CGM, "objc_memmove_collectable", PtrTy, PtrTy, PtrTy, + SizeTy); + } +} + +llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF, + const std::string &Name, bool isWeak) { + llvm::Constant *ClassName = MakeConstantString(Name); + // With the incompatible ABI, this will need to be replaced with a direct + // reference to the class symbol. For the compatible nonfragile ABI we are + // still performing this lookup at run time but emitting the symbol for the + // class externally so that we can make the switch later. + // + // Libobjc2 contains an LLVM pass that replaces calls to objc_lookup_class + // with memoized versions or with static references if it's safe to do so. + if (!isWeak) + EmitClassRef(Name); + + llvm::FunctionCallee ClassLookupFn = CGM.CreateRuntimeFunction( + llvm::FunctionType::get(IdTy, PtrToInt8Ty, true), "objc_lookup_class"); + return CGF.EmitNounwindRuntimeCall(ClassLookupFn, ClassName); +} + +// This has to perform the lookup every time, since posing and related +// techniques can modify the name -> class mapping. +llvm::Value *CGObjCGNU::GetClass(CodeGenFunction &CGF, + const ObjCInterfaceDecl *OID) { + auto *Value = + GetClassNamed(CGF, OID->getNameAsString(), OID->isWeakImported()); + if (auto *ClassSymbol = dyn_cast<llvm::GlobalVariable>(Value)) + CGM.setGVProperties(ClassSymbol, OID); + return Value; +} + +llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) { + auto *Value = GetClassNamed(CGF, "NSAutoreleasePool", false); + if (CGM.getTriple().isOSBinFormatCOFF()) { + if (auto *ClassSymbol = dyn_cast<llvm::GlobalVariable>(Value)) { + IdentifierInfo &II = CGF.CGM.getContext().Idents.get("NSAutoreleasePool"); + TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl(); + DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl); + + const VarDecl *VD = nullptr; + for (const auto *Result : DC->lookup(&II)) + if ((VD = dyn_cast<VarDecl>(Result))) + break; + + CGM.setGVProperties(ClassSymbol, VD); + } + } + return Value; +} + +llvm::Value *CGObjCGNU::GetTypedSelector(CodeGenFunction &CGF, Selector Sel, + const std::string &TypeEncoding) { + SmallVectorImpl<TypedSelector> &Types = SelectorTable[Sel]; + llvm::GlobalAlias *SelValue = nullptr; + + for (SmallVectorImpl<TypedSelector>::iterator i = Types.begin(), + e = Types.end() ; i!=e ; i++) { + if (i->first == TypeEncoding) { + SelValue = i->second; + break; + } + } + if (!SelValue) { + SelValue = llvm::GlobalAlias::create(SelectorElemTy, 0, + llvm::GlobalValue::PrivateLinkage, + ".objc_selector_" + Sel.getAsString(), + &TheModule); + Types.emplace_back(TypeEncoding, SelValue); + } + + return SelValue; +} + +Address CGObjCGNU::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) { + llvm::Value *SelValue = GetSelector(CGF, Sel); + + // Store it to a temporary. Does this satisfy the semantics of + // GetAddrOfSelector? Hopefully. + Address tmp = CGF.CreateTempAlloca(SelValue->getType(), + CGF.getPointerAlign()); + CGF.Builder.CreateStore(SelValue, tmp); + return tmp; +} + +llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel) { + return GetTypedSelector(CGF, Sel, std::string()); +} + +llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, + const ObjCMethodDecl *Method) { + std::string SelTypes = CGM.getContext().getObjCEncodingForMethodDecl(Method); + return GetTypedSelector(CGF, Method->getSelector(), SelTypes); +} + +llvm::Constant *CGObjCGNU::GetEHType(QualType T) { + if (T->isObjCIdType() || T->isObjCQualifiedIdType()) { + // With the old ABI, there was only one kind of catchall, which broke + // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as + // a pointer indicating object catchalls, and NULL to indicate real + // catchalls + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { + return MakeConstantString("@id"); + } else { + return nullptr; + } + } + + // All other types should be Objective-C interface pointer types. + const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>(); + assert(OPT && "Invalid @catch type."); + const ObjCInterfaceDecl *IDecl = OPT->getObjectType()->getInterface(); + assert(IDecl && "Invalid @catch type."); + return MakeConstantString(IDecl->getIdentifier()->getName()); +} + +llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) { + if (usesSEHExceptions) + return CGM.getCXXABI().getAddrOfRTTIDescriptor(T); + + if (!CGM.getLangOpts().CPlusPlus) + return CGObjCGNU::GetEHType(T); + + // For Objective-C++, we want to provide the ability to catch both C++ and + // Objective-C objects in the same function. + + // There's a particular fixed type info for 'id'. + if (T->isObjCIdType() || + T->isObjCQualifiedIdType()) { + llvm::Constant *IDEHType = + CGM.getModule().getGlobalVariable("__objc_id_type_info"); + if (!IDEHType) + IDEHType = + new llvm::GlobalVariable(CGM.getModule(), PtrToInt8Ty, + false, + llvm::GlobalValue::ExternalLinkage, + nullptr, "__objc_id_type_info"); + return llvm::ConstantExpr::getBitCast(IDEHType, PtrToInt8Ty); + } + + const ObjCObjectPointerType *PT = + T->getAs<ObjCObjectPointerType>(); + assert(PT && "Invalid @catch type."); + const ObjCInterfaceType *IT = PT->getInterfaceType(); + assert(IT && "Invalid @catch type."); + std::string className = + std::string(IT->getDecl()->getIdentifier()->getName()); + + std::string typeinfoName = "__objc_eh_typeinfo_" + className; + + // Return the existing typeinfo if it exists + llvm::Constant *typeinfo = TheModule.getGlobalVariable(typeinfoName); + if (typeinfo) + return llvm::ConstantExpr::getBitCast(typeinfo, PtrToInt8Ty); + + // Otherwise create it. + + // vtable for gnustep::libobjc::__objc_class_type_info + // It's quite ugly hard-coding this. Ideally we'd generate it using the host + // platform's name mangling. + const char *vtableName = "_ZTVN7gnustep7libobjc22__objc_class_type_infoE"; + auto *Vtable = TheModule.getGlobalVariable(vtableName); + if (!Vtable) { + Vtable = new llvm::GlobalVariable(TheModule, PtrToInt8Ty, true, + llvm::GlobalValue::ExternalLinkage, + nullptr, vtableName); + } + llvm::Constant *Two = llvm::ConstantInt::get(IntTy, 2); + auto *BVtable = llvm::ConstantExpr::getBitCast( + llvm::ConstantExpr::getGetElementPtr(Vtable->getValueType(), Vtable, Two), + PtrToInt8Ty); + + llvm::Constant *typeName = + ExportUniqueString(className, "__objc_eh_typename_"); + + ConstantInitBuilder builder(CGM); + auto fields = builder.beginStruct(); + fields.add(BVtable); + fields.add(typeName); + llvm::Constant *TI = + fields.finishAndCreateGlobal("__objc_eh_typeinfo_" + className, + CGM.getPointerAlign(), + /*constant*/ false, + llvm::GlobalValue::LinkOnceODRLinkage); + return llvm::ConstantExpr::getBitCast(TI, PtrToInt8Ty); +} + +/// Generate an NSConstantString object. +ConstantAddress CGObjCGNU::GenerateConstantString(const StringLiteral *SL) { + + std::string Str = SL->getString().str(); + CharUnits Align = CGM.getPointerAlign(); + + // Look for an existing one + llvm::StringMap<llvm::Constant*>::iterator old = ObjCStrings.find(Str); + if (old != ObjCStrings.end()) + return ConstantAddress(old->getValue(), Int8Ty, Align); + + StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass; + + if (StringClass.empty()) StringClass = "NSConstantString"; + + std::string Sym = "_OBJC_CLASS_"; + Sym += StringClass; + + llvm::Constant *isa = TheModule.getNamedGlobal(Sym); + + if (!isa) + isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false, + llvm::GlobalValue::ExternalWeakLinkage, nullptr, Sym); + else if (isa->getType() != PtrToIdTy) + isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy); + + ConstantInitBuilder Builder(CGM); + auto Fields = Builder.beginStruct(); + Fields.add(isa); + Fields.add(MakeConstantString(Str)); + Fields.addInt(IntTy, Str.size()); + llvm::Constant *ObjCStr = + Fields.finishAndCreateGlobal(".objc_str", Align); + ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStr, PtrToInt8Ty); + ObjCStrings[Str] = ObjCStr; + ConstantStrings.push_back(ObjCStr); + return ConstantAddress(ObjCStr, Int8Ty, Align); +} + +///Generates a message send where the super is the receiver. This is a message +///send to self with special delivery semantics indicating which class's method +///should be called. +RValue +CGObjCGNU::GenerateMessageSendSuper(CodeGenFunction &CGF, + ReturnValueSlot Return, + QualType ResultType, + Selector Sel, + const ObjCInterfaceDecl *Class, + bool isCategoryImpl, + llvm::Value *Receiver, + bool IsClassMessage, + const CallArgList &CallArgs, + const ObjCMethodDecl *Method) { + CGBuilderTy &Builder = CGF.Builder; + if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) { + if (Sel == RetainSel || Sel == AutoreleaseSel) { + return RValue::get(EnforceType(Builder, Receiver, + CGM.getTypes().ConvertType(ResultType))); + } + if (Sel == ReleaseSel) { + return RValue::get(nullptr); + } + } + + llvm::Value *cmd = GetSelector(CGF, Sel); + CallArgList ActualArgs; + + ActualArgs.add(RValue::get(EnforceType(Builder, Receiver, IdTy)), ASTIdTy); + ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); + ActualArgs.addFrom(CallArgs); + + MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs); + + llvm::Value *ReceiverClass = nullptr; + bool isV2ABI = isRuntime(ObjCRuntime::GNUstep, 2); + if (isV2ABI) { + ReceiverClass = GetClassNamed(CGF, + Class->getSuperClass()->getNameAsString(), /*isWeak*/false); + if (IsClassMessage) { + // Load the isa pointer of the superclass is this is a class method. + ReceiverClass = Builder.CreateBitCast(ReceiverClass, + llvm::PointerType::getUnqual(IdTy)); + ReceiverClass = + Builder.CreateAlignedLoad(IdTy, ReceiverClass, CGF.getPointerAlign()); + } + ReceiverClass = EnforceType(Builder, ReceiverClass, IdTy); + } else { + if (isCategoryImpl) { + llvm::FunctionCallee classLookupFunction = nullptr; + if (IsClassMessage) { + classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( + IdTy, PtrTy, true), "objc_get_meta_class"); + } else { + classLookupFunction = CGM.CreateRuntimeFunction(llvm::FunctionType::get( + IdTy, PtrTy, true), "objc_get_class"); + } + ReceiverClass = Builder.CreateCall(classLookupFunction, + MakeConstantString(Class->getNameAsString())); + } else { + // Set up global aliases for the metaclass or class pointer if they do not + // already exist. These will are forward-references which will be set to + // pointers to the class and metaclass structure created for the runtime + // load function. To send a message to super, we look up the value of the + // super_class pointer from either the class or metaclass structure. + if (IsClassMessage) { + if (!MetaClassPtrAlias) { + MetaClassPtrAlias = llvm::GlobalAlias::create( + IdElemTy, 0, llvm::GlobalValue::InternalLinkage, + ".objc_metaclass_ref" + Class->getNameAsString(), &TheModule); + } + ReceiverClass = MetaClassPtrAlias; + } else { + if (!ClassPtrAlias) { + ClassPtrAlias = llvm::GlobalAlias::create( + IdElemTy, 0, llvm::GlobalValue::InternalLinkage, + ".objc_class_ref" + Class->getNameAsString(), &TheModule); + } + ReceiverClass = ClassPtrAlias; + } + } + // Cast the pointer to a simplified version of the class structure + llvm::Type *CastTy = llvm::StructType::get(IdTy, IdTy); + ReceiverClass = Builder.CreateBitCast(ReceiverClass, + llvm::PointerType::getUnqual(CastTy)); + // Get the superclass pointer + ReceiverClass = Builder.CreateStructGEP(CastTy, ReceiverClass, 1); + // Load the superclass pointer + ReceiverClass = + Builder.CreateAlignedLoad(IdTy, ReceiverClass, CGF.getPointerAlign()); + } + // Construct the structure used to look up the IMP + llvm::StructType *ObjCSuperTy = + llvm::StructType::get(Receiver->getType(), IdTy); + + Address ObjCSuper = CGF.CreateTempAlloca(ObjCSuperTy, + CGF.getPointerAlign()); + + Builder.CreateStore(Receiver, Builder.CreateStructGEP(ObjCSuper, 0)); + Builder.CreateStore(ReceiverClass, Builder.CreateStructGEP(ObjCSuper, 1)); + + // Get the IMP + llvm::Value *imp = LookupIMPSuper(CGF, ObjCSuper, cmd, MSI); + imp = EnforceType(Builder, imp, MSI.MessengerType); + + llvm::Metadata *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class->getSuperClass()->getNameAsString()), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + llvm::Type::getInt1Ty(VMContext), IsClassMessage))}; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); + + CGCallee callee(CGCalleeInfo(), imp); + + llvm::CallBase *call; + RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call); + call->setMetadata(msgSendMDKind, node); + return msgRet; +} + +/// Generate code for a message send expression. +RValue +CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, + ReturnValueSlot Return, + QualType ResultType, + Selector Sel, + llvm::Value *Receiver, + const CallArgList &CallArgs, + const ObjCInterfaceDecl *Class, + const ObjCMethodDecl *Method) { + CGBuilderTy &Builder = CGF.Builder; + + // Strip out message sends to retain / release in GC mode + if (CGM.getLangOpts().getGC() == LangOptions::GCOnly) { + if (Sel == RetainSel || Sel == AutoreleaseSel) { + return RValue::get(EnforceType(Builder, Receiver, + CGM.getTypes().ConvertType(ResultType))); + } + if (Sel == ReleaseSel) { + return RValue::get(nullptr); + } + } + + IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy)); + llvm::Value *cmd; + if (Method) + cmd = GetSelector(CGF, Method); + else + cmd = GetSelector(CGF, Sel); + cmd = EnforceType(Builder, cmd, SelectorTy); + Receiver = EnforceType(Builder, Receiver, IdTy); + + llvm::Metadata *impMD[] = { + llvm::MDString::get(VMContext, Sel.getAsString()), + llvm::MDString::get(VMContext, Class ? Class->getNameAsString() : ""), + llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( + llvm::Type::getInt1Ty(VMContext), Class != nullptr))}; + llvm::MDNode *node = llvm::MDNode::get(VMContext, impMD); + + CallArgList ActualArgs; + ActualArgs.add(RValue::get(Receiver), ASTIdTy); + ActualArgs.add(RValue::get(cmd), CGF.getContext().getObjCSelType()); + ActualArgs.addFrom(CallArgs); + + MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs); + + // Message sends are expected to return a zero value when the + // receiver is nil. At one point, this was only guaranteed for + // simple integer and pointer types, but expectations have grown + // over time. + // + // Given a nil receiver, the GNU runtime's message lookup will + // return a stub function that simply sets various return-value + // registers to zero and then returns. That's good enough for us + // if and only if (1) the calling conventions of that stub are + // compatible with the signature we're using and (2) the registers + // it sets are sufficient to produce a zero value of the return type. + // Rather than doing a whole target-specific analysis, we assume it + // only works for void, integer, and pointer types, and in all + // other cases we do an explicit nil check is emitted code. In + // addition to ensuring we produe a zero value for other types, this + // sidesteps the few outright CC incompatibilities we know about that + // could otherwise lead to crashes, like when a method is expected to + // return on the x87 floating point stack or adjust the stack pointer + // because of an indirect return. + bool hasParamDestroyedInCallee = false; + bool requiresExplicitZeroResult = false; + bool requiresNilReceiverCheck = [&] { + // We never need a check if we statically know the receiver isn't nil. + if (!canMessageReceiverBeNull(CGF, Method, /*IsSuper*/ false, + Class, Receiver)) + return false; + + // If there's a consumed argument, we need a nil check. + if (Method && Method->hasParamDestroyedInCallee()) { + hasParamDestroyedInCallee = true; + } + + // If the return value isn't flagged as unused, and the result + // type isn't in our narrow set where we assume compatibility, + // we need a nil check to ensure a nil value. + if (!Return.isUnused()) { + if (ResultType->isVoidType()) { + // void results are definitely okay. + } else if (ResultType->hasPointerRepresentation() && + CGM.getTypes().isZeroInitializable(ResultType)) { + // Pointer types should be fine as long as they have + // bitwise-zero null pointers. But do we need to worry + // about unusual address spaces? + } else if (ResultType->isIntegralOrEnumerationType()) { + // Bitwise zero should always be zero for integral types. + // FIXME: we probably need a size limit here, but we've + // never imposed one before + } else { + // Otherwise, use an explicit check just to be sure. + requiresExplicitZeroResult = true; + } + } + + return hasParamDestroyedInCallee || requiresExplicitZeroResult; + }(); + + // We will need to explicitly zero-initialize an aggregate result slot + // if we generally require explicit zeroing and we have an aggregate + // result. + bool requiresExplicitAggZeroing = + requiresExplicitZeroResult && CGF.hasAggregateEvaluationKind(ResultType); + + // The block we're going to end up in after any message send or nil path. + llvm::BasicBlock *continueBB = nullptr; + // The block that eventually branched to continueBB along the nil path. + llvm::BasicBlock *nilPathBB = nullptr; + // The block to do explicit work in along the nil path, if necessary. + llvm::BasicBlock *nilCleanupBB = nullptr; + + // Emit the nil-receiver check. + if (requiresNilReceiverCheck) { + llvm::BasicBlock *messageBB = CGF.createBasicBlock("msgSend"); + continueBB = CGF.createBasicBlock("continue"); + + // If we need to zero-initialize an aggregate result or destroy + // consumed arguments, we'll need a separate cleanup block. + // Otherwise we can just branch directly to the continuation block. + if (requiresExplicitAggZeroing || hasParamDestroyedInCallee) { + nilCleanupBB = CGF.createBasicBlock("nilReceiverCleanup"); + } else { + nilPathBB = Builder.GetInsertBlock(); + } + + llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, + llvm::Constant::getNullValue(Receiver->getType())); + Builder.CreateCondBr(isNil, nilCleanupBB ? nilCleanupBB : continueBB, + messageBB); + CGF.EmitBlock(messageBB); + } + + // Get the IMP to call + llvm::Value *imp; + + // If we have non-legacy dispatch specified, we try using the objc_msgSend() + // functions. These are not supported on all platforms (or all runtimes on a + // given platform), so we + switch (CGM.getCodeGenOpts().getObjCDispatchMethod()) { + case CodeGenOptions::Legacy: + imp = LookupIMP(CGF, Receiver, cmd, node, MSI); + break; + case CodeGenOptions::Mixed: + case CodeGenOptions::NonLegacy: + if (CGM.ReturnTypeUsesFPRet(ResultType)) { + imp = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true), + "objc_msgSend_fpret") + .getCallee(); + } else if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) { + // The actual types here don't matter - we're going to bitcast the + // function anyway + imp = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(IdTy, IdTy, true), + "objc_msgSend_stret") + .getCallee(); + } else { + imp = CGM.CreateRuntimeFunction( + llvm::FunctionType::get(IdTy, IdTy, true), "objc_msgSend") + .getCallee(); + } + } + + // Reset the receiver in case the lookup modified it + ActualArgs[0] = CallArg(RValue::get(Receiver), ASTIdTy); + + imp = EnforceType(Builder, imp, MSI.MessengerType); + + llvm::CallBase *call; + CGCallee callee(CGCalleeInfo(), imp); + RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call); + call->setMetadata(msgSendMDKind, node); + + if (requiresNilReceiverCheck) { + llvm::BasicBlock *nonNilPathBB = CGF.Builder.GetInsertBlock(); + CGF.Builder.CreateBr(continueBB); + + // Emit the nil path if we decided it was necessary above. + if (nilCleanupBB) { + CGF.EmitBlock(nilCleanupBB); + + if (hasParamDestroyedInCallee) { + destroyCalleeDestroyedArguments(CGF, Method, CallArgs); + } + + if (requiresExplicitAggZeroing) { + assert(msgRet.isAggregate()); + Address addr = msgRet.getAggregateAddress(); + CGF.EmitNullInitialization(addr, ResultType); + } + + nilPathBB = CGF.Builder.GetInsertBlock(); + CGF.Builder.CreateBr(continueBB); + } + + // Enter the continuation block and emit a phi if required. + CGF.EmitBlock(continueBB); + if (msgRet.isScalar()) { + // If the return type is void, do nothing + if (llvm::Value *v = msgRet.getScalarVal()) { + llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2); + phi->addIncoming(v, nonNilPathBB); + phi->addIncoming(CGM.EmitNullConstant(ResultType), nilPathBB); + msgRet = RValue::get(phi); + } + } else if (msgRet.isAggregate()) { + // Aggregate zeroing is handled in nilCleanupBB when it's required. + } else /* isComplex() */ { + std::pair<llvm::Value*,llvm::Value*> v = msgRet.getComplexVal(); + llvm::PHINode *phi = Builder.CreatePHI(v.first->getType(), 2); + phi->addIncoming(v.first, nonNilPathBB); + phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()), + nilPathBB); + llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType(), 2); + phi2->addIncoming(v.second, nonNilPathBB); + phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()), + nilPathBB); + msgRet = RValue::getComplex(phi, phi2); + } + } + return msgRet; +} + +/// Generates a MethodList. Used in construction of a objc_class and +/// objc_category structures. +llvm::Constant *CGObjCGNU:: +GenerateMethodList(StringRef ClassName, + StringRef CategoryName, + ArrayRef<const ObjCMethodDecl*> Methods, + bool isClassMethodList) { + if (Methods.empty()) + return NULLPtr; + + ConstantInitBuilder Builder(CGM); + + auto MethodList = Builder.beginStruct(); + MethodList.addNullPointer(CGM.Int8PtrTy); + MethodList.addInt(Int32Ty, Methods.size()); + + // Get the method structure type. + llvm::StructType *ObjCMethodTy = + llvm::StructType::get(CGM.getLLVMContext(), { + PtrToInt8Ty, // Really a selector, but the runtime creates it us. + PtrToInt8Ty, // Method types + IMPTy // Method pointer + }); + bool isV2ABI = isRuntime(ObjCRuntime::GNUstep, 2); + if (isV2ABI) { + // size_t size; + llvm::DataLayout td(&TheModule); + MethodList.addInt(SizeTy, td.getTypeSizeInBits(ObjCMethodTy) / + CGM.getContext().getCharWidth()); + ObjCMethodTy = + llvm::StructType::get(CGM.getLLVMContext(), { + IMPTy, // Method pointer + PtrToInt8Ty, // Selector + PtrToInt8Ty // Extended type encoding + }); + } else { + ObjCMethodTy = + llvm::StructType::get(CGM.getLLVMContext(), { + PtrToInt8Ty, // Really a selector, but the runtime creates it us. + PtrToInt8Ty, // Method types + IMPTy // Method pointer + }); + } + auto MethodArray = MethodList.beginArray(); + ASTContext &Context = CGM.getContext(); + for (const auto *OMD : Methods) { + llvm::Constant *FnPtr = + TheModule.getFunction(getSymbolNameForMethod(OMD)); + assert(FnPtr && "Can't generate metadata for method that doesn't exist"); + auto Method = MethodArray.beginStruct(ObjCMethodTy); + if (isV2ABI) { + Method.addBitCast(FnPtr, IMPTy); + Method.add(GetConstantSelector(OMD->getSelector(), + Context.getObjCEncodingForMethodDecl(OMD))); + Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(OMD, true))); + } else { + Method.add(MakeConstantString(OMD->getSelector().getAsString())); + Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(OMD))); + Method.addBitCast(FnPtr, IMPTy); + } + Method.finishAndAddTo(MethodArray); + } + MethodArray.finishAndAddTo(MethodList); + + // Create an instance of the structure + return MethodList.finishAndCreateGlobal(".objc_method_list", + CGM.getPointerAlign()); +} + +/// Generates an IvarList. Used in construction of a objc_class. +llvm::Constant *CGObjCGNU:: +GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames, + ArrayRef<llvm::Constant *> IvarTypes, + ArrayRef<llvm::Constant *> IvarOffsets, + ArrayRef<llvm::Constant *> IvarAlign, + ArrayRef<Qualifiers::ObjCLifetime> IvarOwnership) { + if (IvarNames.empty()) + return NULLPtr; + + ConstantInitBuilder Builder(CGM); + + // Structure containing array count followed by array. + auto IvarList = Builder.beginStruct(); + IvarList.addInt(IntTy, (int)IvarNames.size()); + + // Get the ivar structure type. + llvm::StructType *ObjCIvarTy = + llvm::StructType::get(PtrToInt8Ty, PtrToInt8Ty, IntTy); + + // Array of ivar structures. + auto Ivars = IvarList.beginArray(ObjCIvarTy); + for (unsigned int i = 0, e = IvarNames.size() ; i < e ; i++) { + auto Ivar = Ivars.beginStruct(ObjCIvarTy); + Ivar.add(IvarNames[i]); + Ivar.add(IvarTypes[i]); + Ivar.add(IvarOffsets[i]); + Ivar.finishAndAddTo(Ivars); + } + Ivars.finishAndAddTo(IvarList); + + // Create an instance of the structure + return IvarList.finishAndCreateGlobal(".objc_ivar_list", + CGM.getPointerAlign()); +} + +/// Generate a class structure +llvm::Constant *CGObjCGNU::GenerateClassStructure( + llvm::Constant *MetaClass, + llvm::Constant *SuperClass, + unsigned info, + const char *Name, + llvm::Constant *Version, + llvm::Constant *InstanceSize, + llvm::Constant *IVars, + llvm::Constant *Methods, + llvm::Constant *Protocols, + llvm::Constant *IvarOffsets, + llvm::Constant *Properties, + llvm::Constant *StrongIvarBitmap, + llvm::Constant *WeakIvarBitmap, + bool isMeta) { + // Set up the class structure + // Note: Several of these are char*s when they should be ids. This is + // because the runtime performs this translation on load. + // + // Fields marked New ABI are part of the GNUstep runtime. We emit them + // anyway; the classes will still work with the GNU runtime, they will just + // be ignored. + llvm::StructType *ClassTy = llvm::StructType::get( + PtrToInt8Ty, // isa + PtrToInt8Ty, // super_class + PtrToInt8Ty, // name + LongTy, // version + LongTy, // info + LongTy, // instance_size + IVars->getType(), // ivars + Methods->getType(), // methods + // These are all filled in by the runtime, so we pretend + PtrTy, // dtable + PtrTy, // subclass_list + PtrTy, // sibling_class + PtrTy, // protocols + PtrTy, // gc_object_type + // New ABI: + LongTy, // abi_version + IvarOffsets->getType(), // ivar_offsets + Properties->getType(), // properties + IntPtrTy, // strong_pointers + IntPtrTy // weak_pointers + ); + + ConstantInitBuilder Builder(CGM); + auto Elements = Builder.beginStruct(ClassTy); + + // Fill in the structure + + // isa + Elements.addBitCast(MetaClass, PtrToInt8Ty); + // super_class + Elements.add(SuperClass); + // name + Elements.add(MakeConstantString(Name, ".class_name")); + // version + Elements.addInt(LongTy, 0); + // info + Elements.addInt(LongTy, info); + // instance_size + if (isMeta) { + llvm::DataLayout td(&TheModule); + Elements.addInt(LongTy, + td.getTypeSizeInBits(ClassTy) / + CGM.getContext().getCharWidth()); + } else + Elements.add(InstanceSize); + // ivars + Elements.add(IVars); + // methods + Elements.add(Methods); + // These are all filled in by the runtime, so we pretend + // dtable + Elements.add(NULLPtr); + // subclass_list + Elements.add(NULLPtr); + // sibling_class + Elements.add(NULLPtr); + // protocols + Elements.addBitCast(Protocols, PtrTy); + // gc_object_type + Elements.add(NULLPtr); + // abi_version + Elements.addInt(LongTy, ClassABIVersion); + // ivar_offsets + Elements.add(IvarOffsets); + // properties + Elements.add(Properties); + // strong_pointers + Elements.add(StrongIvarBitmap); + // weak_pointers + Elements.add(WeakIvarBitmap); + // Create an instance of the structure + // This is now an externally visible symbol, so that we can speed up class + // messages in the next ABI. We may already have some weak references to + // this, so check and fix them properly. + std::string ClassSym((isMeta ? "_OBJC_METACLASS_": "_OBJC_CLASS_") + + std::string(Name)); + llvm::GlobalVariable *ClassRef = TheModule.getNamedGlobal(ClassSym); + llvm::Constant *Class = + Elements.finishAndCreateGlobal(ClassSym, CGM.getPointerAlign(), false, + llvm::GlobalValue::ExternalLinkage); + if (ClassRef) { + ClassRef->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(Class, + ClassRef->getType())); + ClassRef->removeFromParent(); + Class->setName(ClassSym); + } + return Class; +} + +llvm::Constant *CGObjCGNU:: +GenerateProtocolMethodList(ArrayRef<const ObjCMethodDecl*> Methods) { + // Get the method structure type. + llvm::StructType *ObjCMethodDescTy = + llvm::StructType::get(CGM.getLLVMContext(), { PtrToInt8Ty, PtrToInt8Ty }); + ASTContext &Context = CGM.getContext(); + ConstantInitBuilder Builder(CGM); + auto MethodList = Builder.beginStruct(); + MethodList.addInt(IntTy, Methods.size()); + auto MethodArray = MethodList.beginArray(ObjCMethodDescTy); + for (auto *M : Methods) { + auto Method = MethodArray.beginStruct(ObjCMethodDescTy); + Method.add(MakeConstantString(M->getSelector().getAsString())); + Method.add(MakeConstantString(Context.getObjCEncodingForMethodDecl(M))); + Method.finishAndAddTo(MethodArray); + } + MethodArray.finishAndAddTo(MethodList); + return MethodList.finishAndCreateGlobal(".objc_method_list", + CGM.getPointerAlign()); +} + +// Create the protocol list structure used in classes, categories and so on +llvm::Constant * +CGObjCGNU::GenerateProtocolList(ArrayRef<std::string> Protocols) { + + ConstantInitBuilder Builder(CGM); + auto ProtocolList = Builder.beginStruct(); + ProtocolList.add(NULLPtr); + ProtocolList.addInt(LongTy, Protocols.size()); + + auto Elements = ProtocolList.beginArray(PtrToInt8Ty); + for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end(); + iter != endIter ; iter++) { + llvm::Constant *protocol = nullptr; + llvm::StringMap<llvm::Constant*>::iterator value = + ExistingProtocols.find(*iter); + if (value == ExistingProtocols.end()) { + protocol = GenerateEmptyProtocol(*iter); + } else { + protocol = value->getValue(); + } + Elements.addBitCast(protocol, PtrToInt8Ty); + } + Elements.finishAndAddTo(ProtocolList); + return ProtocolList.finishAndCreateGlobal(".objc_protocol_list", + CGM.getPointerAlign()); +} + +llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF, + const ObjCProtocolDecl *PD) { + auto protocol = GenerateProtocolRef(PD); + llvm::Type *T = + CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType()); + return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); +} + +llvm::Constant *CGObjCGNU::GenerateProtocolRef(const ObjCProtocolDecl *PD) { + llvm::Constant *&protocol = ExistingProtocols[PD->getNameAsString()]; + if (!protocol) + GenerateProtocol(PD); + assert(protocol && "Unknown protocol"); + return protocol; +} + +llvm::Constant * +CGObjCGNU::GenerateEmptyProtocol(StringRef ProtocolName) { + llvm::Constant *ProtocolList = GenerateProtocolList({}); + llvm::Constant *MethodList = GenerateProtocolMethodList({}); + MethodList = llvm::ConstantExpr::getBitCast(MethodList, PtrToInt8Ty); + // Protocols are objects containing lists of the methods implemented and + // protocols adopted. + ConstantInitBuilder Builder(CGM); + auto Elements = Builder.beginStruct(); + + // The isa pointer must be set to a magic number so the runtime knows it's + // the correct layout. + Elements.add(llvm::ConstantExpr::getIntToPtr( + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); + + Elements.add(MakeConstantString(ProtocolName, ".objc_protocol_name")); + Elements.add(ProtocolList); /* .protocol_list */ + Elements.add(MethodList); /* .instance_methods */ + Elements.add(MethodList); /* .class_methods */ + Elements.add(MethodList); /* .optional_instance_methods */ + Elements.add(MethodList); /* .optional_class_methods */ + Elements.add(NULLPtr); /* .properties */ + Elements.add(NULLPtr); /* .optional_properties */ + return Elements.finishAndCreateGlobal(SymbolForProtocol(ProtocolName), + CGM.getPointerAlign()); +} + +void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { + if (PD->isNonRuntimeProtocol()) + return; + + std::string ProtocolName = PD->getNameAsString(); + + // Use the protocol definition, if there is one. + if (const ObjCProtocolDecl *Def = PD->getDefinition()) + PD = Def; + + SmallVector<std::string, 16> Protocols; + for (const auto *PI : PD->protocols()) + Protocols.push_back(PI->getNameAsString()); + SmallVector<const ObjCMethodDecl*, 16> InstanceMethods; + SmallVector<const ObjCMethodDecl*, 16> OptionalInstanceMethods; + for (const auto *I : PD->instance_methods()) + if (I->isOptional()) + OptionalInstanceMethods.push_back(I); + else + InstanceMethods.push_back(I); + // Collect information about class methods: + SmallVector<const ObjCMethodDecl*, 16> ClassMethods; + SmallVector<const ObjCMethodDecl*, 16> OptionalClassMethods; + for (const auto *I : PD->class_methods()) + if (I->isOptional()) + OptionalClassMethods.push_back(I); + else + ClassMethods.push_back(I); + + llvm::Constant *ProtocolList = GenerateProtocolList(Protocols); + llvm::Constant *InstanceMethodList = + GenerateProtocolMethodList(InstanceMethods); + llvm::Constant *ClassMethodList = + GenerateProtocolMethodList(ClassMethods); + llvm::Constant *OptionalInstanceMethodList = + GenerateProtocolMethodList(OptionalInstanceMethods); + llvm::Constant *OptionalClassMethodList = + GenerateProtocolMethodList(OptionalClassMethods); + + // Property metadata: name, attributes, isSynthesized, setter name, setter + // types, getter name, getter types. + // The isSynthesized value is always set to 0 in a protocol. It exists to + // simplify the runtime library by allowing it to use the same data + // structures for protocol metadata everywhere. + + llvm::Constant *PropertyList = + GeneratePropertyList(nullptr, PD, false, false); + llvm::Constant *OptionalPropertyList = + GeneratePropertyList(nullptr, PD, false, true); + + // Protocols are objects containing lists of the methods implemented and + // protocols adopted. + // The isa pointer must be set to a magic number so the runtime knows it's + // the correct layout. + ConstantInitBuilder Builder(CGM); + auto Elements = Builder.beginStruct(); + Elements.add( + llvm::ConstantExpr::getIntToPtr( + llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy)); + Elements.add(MakeConstantString(ProtocolName)); + Elements.add(ProtocolList); + Elements.add(InstanceMethodList); + Elements.add(ClassMethodList); + Elements.add(OptionalInstanceMethodList); + Elements.add(OptionalClassMethodList); + Elements.add(PropertyList); + Elements.add(OptionalPropertyList); + ExistingProtocols[ProtocolName] = + llvm::ConstantExpr::getBitCast( + Elements.finishAndCreateGlobal(".objc_protocol", CGM.getPointerAlign()), + IdTy); +} +void CGObjCGNU::GenerateProtocolHolderCategory() { + // Collect information about instance methods + + ConstantInitBuilder Builder(CGM); + auto Elements = Builder.beginStruct(); + + const std::string ClassName = "__ObjC_Protocol_Holder_Ugly_Hack"; + const std::string CategoryName = "AnotherHack"; + Elements.add(MakeConstantString(CategoryName)); + Elements.add(MakeConstantString(ClassName)); + // Instance method list + Elements.addBitCast(GenerateMethodList( + ClassName, CategoryName, {}, false), PtrTy); + // Class method list + Elements.addBitCast(GenerateMethodList( + ClassName, CategoryName, {}, true), PtrTy); + + // Protocol list + ConstantInitBuilder ProtocolListBuilder(CGM); + auto ProtocolList = ProtocolListBuilder.beginStruct(); + ProtocolList.add(NULLPtr); + ProtocolList.addInt(LongTy, ExistingProtocols.size()); + auto ProtocolElements = ProtocolList.beginArray(PtrTy); + for (auto iter = ExistingProtocols.begin(), endIter = ExistingProtocols.end(); + iter != endIter ; iter++) { + ProtocolElements.addBitCast(iter->getValue(), PtrTy); + } + ProtocolElements.finishAndAddTo(ProtocolList); + Elements.addBitCast( + ProtocolList.finishAndCreateGlobal(".objc_protocol_list", + CGM.getPointerAlign()), + PtrTy); + Categories.push_back(llvm::ConstantExpr::getBitCast( + Elements.finishAndCreateGlobal("", CGM.getPointerAlign()), + PtrTy)); +} + +/// Libobjc2 uses a bitfield representation where small(ish) bitfields are +/// stored in a 64-bit value with the low bit set to 1 and the remaining 63 +/// bits set to their values, LSB first, while larger ones are stored in a +/// structure of this / form: +/// +/// struct { int32_t length; int32_t values[length]; }; +/// +/// The values in the array are stored in host-endian format, with the least +/// significant bit being assumed to come first in the bitfield. Therefore, a +/// bitfield with the 64th bit set will be (int64_t)&{ 2, [0, 1<<31] }, while a +/// bitfield / with the 63rd bit set will be 1<<64. +llvm::Constant *CGObjCGNU::MakeBitField(ArrayRef<bool> bits) { + int bitCount = bits.size(); + int ptrBits = CGM.getDataLayout().getPointerSizeInBits(); + if (bitCount < ptrBits) { + uint64_t val = 1; + for (int i=0 ; i<bitCount ; ++i) { + if (bits[i]) val |= 1ULL<<(i+1); + } + return llvm::ConstantInt::get(IntPtrTy, val); + } + SmallVector<llvm::Constant *, 8> values; + int v=0; + while (v < bitCount) { + int32_t word = 0; + for (int i=0 ; (i<32) && (v<bitCount) ; ++i) { + if (bits[v]) word |= 1<<i; + v++; + } + values.push_back(llvm::ConstantInt::get(Int32Ty, word)); + } + + ConstantInitBuilder builder(CGM); + auto fields = builder.beginStruct(); + fields.addInt(Int32Ty, values.size()); + auto array = fields.beginArray(); + for (auto *v : values) array.add(v); + array.finishAndAddTo(fields); + + llvm::Constant *GS = + fields.finishAndCreateGlobal("", CharUnits::fromQuantity(4)); + llvm::Constant *ptr = llvm::ConstantExpr::getPtrToInt(GS, IntPtrTy); + return ptr; +} + +llvm::Constant *CGObjCGNU::GenerateCategoryProtocolList(const + ObjCCategoryDecl *OCD) { + const auto &RefPro = OCD->getReferencedProtocols(); + const auto RuntimeProtos = + GetRuntimeProtocolList(RefPro.begin(), RefPro.end()); + SmallVector<std::string, 16> Protocols; + for (const auto *PD : RuntimeProtos) + Protocols.push_back(PD->getNameAsString()); + return GenerateProtocolList(Protocols); +} + +void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) { + const ObjCInterfaceDecl *Class = OCD->getClassInterface(); + std::string ClassName = Class->getNameAsString(); + std::string CategoryName = OCD->getNameAsString(); + + // Collect the names of referenced protocols + const ObjCCategoryDecl *CatDecl = OCD->getCategoryDecl(); + + ConstantInitBuilder Builder(CGM); + auto Elements = Builder.beginStruct(); + Elements.add(MakeConstantString(CategoryName)); + Elements.add(MakeConstantString(ClassName)); + // Instance method list + SmallVector<ObjCMethodDecl*, 16> InstanceMethods; + InstanceMethods.insert(InstanceMethods.begin(), OCD->instmeth_begin(), + OCD->instmeth_end()); + Elements.addBitCast( + GenerateMethodList(ClassName, CategoryName, InstanceMethods, false), + PtrTy); + // Class method list + + SmallVector<ObjCMethodDecl*, 16> ClassMethods; + ClassMethods.insert(ClassMethods.begin(), OCD->classmeth_begin(), + OCD->classmeth_end()); + Elements.addBitCast( + GenerateMethodList(ClassName, CategoryName, ClassMethods, true), + PtrTy); + // Protocol list + Elements.addBitCast(GenerateCategoryProtocolList(CatDecl), PtrTy); + if (isRuntime(ObjCRuntime::GNUstep, 2)) { + const ObjCCategoryDecl *Category = + Class->FindCategoryDeclaration(OCD->getIdentifier()); + if (Category) { + // Instance properties + Elements.addBitCast(GeneratePropertyList(OCD, Category, false), PtrTy); + // Class properties + Elements.addBitCast(GeneratePropertyList(OCD, Category, true), PtrTy); + } else { + Elements.addNullPointer(PtrTy); + Elements.addNullPointer(PtrTy); + } + } + + Categories.push_back(llvm::ConstantExpr::getBitCast( + Elements.finishAndCreateGlobal( + std::string(".objc_category_")+ClassName+CategoryName, + CGM.getPointerAlign()), + PtrTy)); +} + +llvm::Constant *CGObjCGNU::GeneratePropertyList(const Decl *Container, + const ObjCContainerDecl *OCD, + bool isClassProperty, + bool protocolOptionalProperties) { + + SmallVector<const ObjCPropertyDecl *, 16> Properties; + llvm::SmallPtrSet<const IdentifierInfo*, 16> PropertySet; + bool isProtocol = isa<ObjCProtocolDecl>(OCD); + ASTContext &Context = CGM.getContext(); + + std::function<void(const ObjCProtocolDecl *Proto)> collectProtocolProperties + = [&](const ObjCProtocolDecl *Proto) { + for (const auto *P : Proto->protocols()) + collectProtocolProperties(P); + for (const auto *PD : Proto->properties()) { + if (isClassProperty != PD->isClassProperty()) + continue; + // Skip any properties that are declared in protocols that this class + // conforms to but are not actually implemented by this class. + if (!isProtocol && !Context.getObjCPropertyImplDeclForPropertyDecl(PD, Container)) + continue; + if (!PropertySet.insert(PD->getIdentifier()).second) + continue; + Properties.push_back(PD); + } + }; + + 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()); + Properties.push_back(PD); + } + + for (const auto *PD : OCD->properties()) { + if (isClassProperty != PD->isClassProperty()) + continue; + // If we're generating a list for a protocol, skip optional / required ones + // when generating the other list. + if (isProtocol && (protocolOptionalProperties != PD->isOptional())) + continue; + // Don't emit duplicate metadata for properties that were already in a + // class extension. + if (!PropertySet.insert(PD->getIdentifier()).second) + continue; + + Properties.push_back(PD); + } + + if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(OCD)) + for (const auto *P : OID->all_referenced_protocols()) + collectProtocolProperties(P); + else if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(OCD)) + for (const auto *P : CD->protocols()) + collectProtocolProperties(P); + + auto numProperties = Properties.size(); + + if (numProperties == 0) + return NULLPtr; + + ConstantInitBuilder builder(CGM); + auto propertyList = builder.beginStruct(); + auto properties = PushPropertyListHeader(propertyList, numProperties); + + // Add all of the property methods need adding to the method list and to the + // property metadata list. + for (auto *property : Properties) { + bool isSynthesized = false; + bool isDynamic = false; + if (!isProtocol) { + auto *propertyImpl = Context.getObjCPropertyImplDeclForPropertyDecl(property, Container); + if (propertyImpl) { + isSynthesized = (propertyImpl->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize); + isDynamic = (propertyImpl->getPropertyImplementation() == + ObjCPropertyImplDecl::Dynamic); + } + } + PushProperty(properties, property, Container, isSynthesized, isDynamic); + } + properties.finishAndAddTo(propertyList); + + return propertyList.finishAndCreateGlobal(".objc_property_list", + CGM.getPointerAlign()); +} + +void CGObjCGNU::RegisterAlias(const ObjCCompatibleAliasDecl *OAD) { + // Get the class declaration for which the alias is specified. + ObjCInterfaceDecl *ClassDecl = + const_cast<ObjCInterfaceDecl *>(OAD->getClassInterface()); + ClassAliases.emplace_back(ClassDecl->getNameAsString(), + OAD->getNameAsString()); +} + +void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { + ASTContext &Context = CGM.getContext(); + + // Get the superclass name. + const ObjCInterfaceDecl * SuperClassDecl = + OID->getClassInterface()->getSuperClass(); + std::string SuperClassName; + if (SuperClassDecl) { + SuperClassName = SuperClassDecl->getNameAsString(); + EmitClassRef(SuperClassName); + } + + // Get the class name + ObjCInterfaceDecl *ClassDecl = + const_cast<ObjCInterfaceDecl *>(OID->getClassInterface()); + std::string ClassName = ClassDecl->getNameAsString(); + + // Emit the symbol that is used to generate linker errors if this class is + // referenced in other modules but not declared. + std::string classSymbolName = "__objc_class_name_" + ClassName; + if (auto *symbol = TheModule.getGlobalVariable(classSymbolName)) { + symbol->setInitializer(llvm::ConstantInt::get(LongTy, 0)); + } else { + new llvm::GlobalVariable(TheModule, LongTy, false, + llvm::GlobalValue::ExternalLinkage, + llvm::ConstantInt::get(LongTy, 0), + classSymbolName); + } + + // Get the size of instances. + int instanceSize = + Context.getASTObjCImplementationLayout(OID).getSize().getQuantity(); + + // Collect information about instance variables. + SmallVector<llvm::Constant*, 16> IvarNames; + SmallVector<llvm::Constant*, 16> IvarTypes; + SmallVector<llvm::Constant*, 16> IvarOffsets; + SmallVector<llvm::Constant*, 16> IvarAligns; + SmallVector<Qualifiers::ObjCLifetime, 16> IvarOwnership; + + ConstantInitBuilder IvarOffsetBuilder(CGM); + auto IvarOffsetValues = IvarOffsetBuilder.beginArray(PtrToIntTy); + SmallVector<bool, 16> WeakIvars; + SmallVector<bool, 16> StrongIvars; + + int superInstanceSize = !SuperClassDecl ? 0 : + Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); + // For non-fragile ivars, set the instance size to 0 - {the size of just this + // class}. The runtime will then set this to the correct value on load. + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { + instanceSize = 0 - (instanceSize - superInstanceSize); + } + + for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) { + // Store the name + IvarNames.push_back(MakeConstantString(IVD->getNameAsString())); + // Get the type encoding for this ivar + std::string TypeStr; + Context.getObjCEncodingForType(IVD->getType(), TypeStr, IVD); + IvarTypes.push_back(MakeConstantString(TypeStr)); + IvarAligns.push_back(llvm::ConstantInt::get(IntTy, + Context.getTypeSize(IVD->getType()))); + // Get the offset + uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); + uint64_t Offset = BaseOffset; + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { + Offset = BaseOffset - superInstanceSize; + } + llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset); + // Create the direct offset value + std::string OffsetName = "__objc_ivar_offset_value_" + ClassName +"." + + IVD->getNameAsString(); + + llvm::GlobalVariable *OffsetVar = TheModule.getGlobalVariable(OffsetName); + if (OffsetVar) { + OffsetVar->setInitializer(OffsetValue); + // If this is the real definition, change its linkage type so that + // different modules will use this one, rather than their private + // copy. + OffsetVar->setLinkage(llvm::GlobalValue::ExternalLinkage); + } else + OffsetVar = new llvm::GlobalVariable(TheModule, Int32Ty, + false, llvm::GlobalValue::ExternalLinkage, + OffsetValue, OffsetName); + IvarOffsets.push_back(OffsetValue); + IvarOffsetValues.add(OffsetVar); + Qualifiers::ObjCLifetime lt = IVD->getType().getQualifiers().getObjCLifetime(); + IvarOwnership.push_back(lt); + switch (lt) { + case Qualifiers::OCL_Strong: + StrongIvars.push_back(true); + WeakIvars.push_back(false); + break; + case Qualifiers::OCL_Weak: + StrongIvars.push_back(false); + WeakIvars.push_back(true); + break; + default: + StrongIvars.push_back(false); + WeakIvars.push_back(false); + } + } + llvm::Constant *StrongIvarBitmap = MakeBitField(StrongIvars); + llvm::Constant *WeakIvarBitmap = MakeBitField(WeakIvars); + llvm::GlobalVariable *IvarOffsetArray = + IvarOffsetValues.finishAndCreateGlobal(".ivar.offsets", + CGM.getPointerAlign()); + + // Collect information about instance methods + SmallVector<const ObjCMethodDecl*, 16> InstanceMethods; + InstanceMethods.insert(InstanceMethods.begin(), OID->instmeth_begin(), + OID->instmeth_end()); + + SmallVector<const ObjCMethodDecl*, 16> ClassMethods; + ClassMethods.insert(ClassMethods.begin(), OID->classmeth_begin(), + OID->classmeth_end()); + + llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl); + + // Collect the names of referenced protocols + auto RefProtocols = ClassDecl->protocols(); + auto RuntimeProtocols = + GetRuntimeProtocolList(RefProtocols.begin(), RefProtocols.end()); + SmallVector<std::string, 16> Protocols; + for (const auto *I : RuntimeProtocols) + Protocols.push_back(I->getNameAsString()); + + // Get the superclass pointer. + llvm::Constant *SuperClass; + if (!SuperClassName.empty()) { + SuperClass = MakeConstantString(SuperClassName, ".super_class_name"); + } else { + SuperClass = llvm::ConstantPointerNull::get(PtrToInt8Ty); + } + // Empty vector used to construct empty method lists + SmallVector<llvm::Constant*, 1> empty; + // Generate the method and instance variable lists + llvm::Constant *MethodList = GenerateMethodList(ClassName, "", + InstanceMethods, false); + llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "", + ClassMethods, true); + llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes, + IvarOffsets, IvarAligns, IvarOwnership); + // Irrespective of whether we are compiling for a fragile or non-fragile ABI, + // we emit a symbol containing the offset for each ivar in the class. This + // allows code compiled for the non-Fragile ABI to inherit from code compiled + // for the legacy ABI, without causing problems. The converse is also + // possible, but causes all ivar accesses to be fragile. + + // Offset pointer for getting at the correct field in the ivar list when + // setting up the alias. These are: The base address for the global, the + // ivar array (second field), the ivar in this list (set for each ivar), and + // the offset (third field in ivar structure) + llvm::Type *IndexTy = Int32Ty; + llvm::Constant *offsetPointerIndexes[] = {Zeros[0], + llvm::ConstantInt::get(IndexTy, ClassABIVersion > 1 ? 2 : 1), nullptr, + llvm::ConstantInt::get(IndexTy, ClassABIVersion > 1 ? 3 : 2) }; + + unsigned ivarIndex = 0; + for (const ObjCIvarDecl *IVD = ClassDecl->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) { + const std::string Name = GetIVarOffsetVariableName(ClassDecl, IVD); + offsetPointerIndexes[2] = llvm::ConstantInt::get(IndexTy, ivarIndex); + // Get the correct ivar field + llvm::Constant *offsetValue = llvm::ConstantExpr::getGetElementPtr( + cast<llvm::GlobalVariable>(IvarList)->getValueType(), IvarList, + offsetPointerIndexes); + // Get the existing variable, if one exists. + llvm::GlobalVariable *offset = TheModule.getNamedGlobal(Name); + if (offset) { + offset->setInitializer(offsetValue); + // If this is the real definition, change its linkage type so that + // different modules will use this one, rather than their private + // copy. + offset->setLinkage(llvm::GlobalValue::ExternalLinkage); + } else + // Add a new alias if there isn't one already. + new llvm::GlobalVariable(TheModule, offsetValue->getType(), + false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name); + ++ivarIndex; + } + llvm::Constant *ZeroPtr = llvm::ConstantInt::get(IntPtrTy, 0); + + //Generate metaclass for class methods + llvm::Constant *MetaClassStruct = GenerateClassStructure( + NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), nullptr, Zeros[0], + NULLPtr, ClassMethodList, NULLPtr, NULLPtr, + GeneratePropertyList(OID, ClassDecl, true), ZeroPtr, ZeroPtr, true); + CGM.setGVProperties(cast<llvm::GlobalValue>(MetaClassStruct), + OID->getClassInterface()); + + // Generate the class structure + llvm::Constant *ClassStruct = GenerateClassStructure( + MetaClassStruct, SuperClass, 0x11L, ClassName.c_str(), nullptr, + llvm::ConstantInt::get(LongTy, instanceSize), IvarList, MethodList, + GenerateProtocolList(Protocols), IvarOffsetArray, Properties, + StrongIvarBitmap, WeakIvarBitmap); + CGM.setGVProperties(cast<llvm::GlobalValue>(ClassStruct), + OID->getClassInterface()); + + // Resolve the class aliases, if they exist. + if (ClassPtrAlias) { + ClassPtrAlias->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(ClassStruct, IdTy)); + ClassPtrAlias->eraseFromParent(); + ClassPtrAlias = nullptr; + } + if (MetaClassPtrAlias) { + MetaClassPtrAlias->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(MetaClassStruct, IdTy)); + MetaClassPtrAlias->eraseFromParent(); + MetaClassPtrAlias = nullptr; + } + + // Add class structure to list to be added to the symtab later + ClassStruct = llvm::ConstantExpr::getBitCast(ClassStruct, PtrToInt8Ty); + Classes.push_back(ClassStruct); +} + +llvm::Function *CGObjCGNU::ModuleInitFunction() { + // Only emit an ObjC load function if no Objective-C stuff has been called + if (Classes.empty() && Categories.empty() && ConstantStrings.empty() && + ExistingProtocols.empty() && SelectorTable.empty()) + return nullptr; + + // Add all referenced protocols to a category. + GenerateProtocolHolderCategory(); + + llvm::StructType *selStructTy = dyn_cast<llvm::StructType>(SelectorElemTy); + llvm::Type *selStructPtrTy = SelectorTy; + if (!selStructTy) { + selStructTy = llvm::StructType::get(CGM.getLLVMContext(), + { PtrToInt8Ty, PtrToInt8Ty }); + selStructPtrTy = llvm::PointerType::getUnqual(selStructTy); + } + + // Generate statics list: + llvm::Constant *statics = NULLPtr; + if (!ConstantStrings.empty()) { + llvm::GlobalVariable *fileStatics = [&] { + ConstantInitBuilder builder(CGM); + auto staticsStruct = builder.beginStruct(); + + StringRef stringClass = CGM.getLangOpts().ObjCConstantStringClass; + if (stringClass.empty()) stringClass = "NXConstantString"; + staticsStruct.add(MakeConstantString(stringClass, + ".objc_static_class_name")); + + auto array = staticsStruct.beginArray(); + array.addAll(ConstantStrings); + array.add(NULLPtr); + array.finishAndAddTo(staticsStruct); + + return staticsStruct.finishAndCreateGlobal(".objc_statics", + CGM.getPointerAlign()); + }(); + + ConstantInitBuilder builder(CGM); + auto allStaticsArray = builder.beginArray(fileStatics->getType()); + allStaticsArray.add(fileStatics); + allStaticsArray.addNullPointer(fileStatics->getType()); + + statics = allStaticsArray.finishAndCreateGlobal(".objc_statics_ptr", + CGM.getPointerAlign()); + statics = llvm::ConstantExpr::getBitCast(statics, PtrTy); + } + + // Array of classes, categories, and constant objects. + + SmallVector<llvm::GlobalAlias*, 16> selectorAliases; + unsigned selectorCount; + + // Pointer to an array of selectors used in this module. + llvm::GlobalVariable *selectorList = [&] { + ConstantInitBuilder builder(CGM); + auto selectors = builder.beginArray(selStructTy); + auto &table = SelectorTable; // MSVC workaround + std::vector<Selector> allSelectors; + for (auto &entry : table) + allSelectors.push_back(entry.first); + llvm::sort(allSelectors); + + for (auto &untypedSel : allSelectors) { + std::string selNameStr = untypedSel.getAsString(); + llvm::Constant *selName = ExportUniqueString(selNameStr, ".objc_sel_name"); + + for (TypedSelector &sel : table[untypedSel]) { + llvm::Constant *selectorTypeEncoding = NULLPtr; + if (!sel.first.empty()) + selectorTypeEncoding = + MakeConstantString(sel.first, ".objc_sel_types"); + + auto selStruct = selectors.beginStruct(selStructTy); + selStruct.add(selName); + selStruct.add(selectorTypeEncoding); + selStruct.finishAndAddTo(selectors); + + // Store the selector alias for later replacement + selectorAliases.push_back(sel.second); + } + } + + // Remember the number of entries in the selector table. + selectorCount = selectors.size(); + + // NULL-terminate the selector list. This should not actually be required, + // because the selector list has a length field. Unfortunately, the GCC + // runtime decides to ignore the length field and expects a NULL terminator, + // and GCC cooperates with this by always setting the length to 0. + auto selStruct = selectors.beginStruct(selStructTy); + selStruct.add(NULLPtr); + selStruct.add(NULLPtr); + selStruct.finishAndAddTo(selectors); + + return selectors.finishAndCreateGlobal(".objc_selector_list", + CGM.getPointerAlign()); + }(); + + // Now that all of the static selectors exist, create pointers to them. + for (unsigned i = 0; i < selectorCount; ++i) { + llvm::Constant *idxs[] = { + Zeros[0], + llvm::ConstantInt::get(Int32Ty, i) + }; + // FIXME: We're generating redundant loads and stores here! + llvm::Constant *selPtr = llvm::ConstantExpr::getGetElementPtr( + selectorList->getValueType(), selectorList, idxs); + // If selectors are defined as an opaque type, cast the pointer to this + // type. + selPtr = llvm::ConstantExpr::getBitCast(selPtr, SelectorTy); + selectorAliases[i]->replaceAllUsesWith(selPtr); + selectorAliases[i]->eraseFromParent(); + } + + llvm::GlobalVariable *symtab = [&] { + ConstantInitBuilder builder(CGM); + auto symtab = builder.beginStruct(); + + // Number of static selectors + symtab.addInt(LongTy, selectorCount); + + symtab.addBitCast(selectorList, selStructPtrTy); + + // Number of classes defined. + symtab.addInt(CGM.Int16Ty, Classes.size()); + // Number of categories defined + symtab.addInt(CGM.Int16Ty, Categories.size()); + + // Create an array of classes, then categories, then static object instances + auto classList = symtab.beginArray(PtrToInt8Ty); + classList.addAll(Classes); + classList.addAll(Categories); + // NULL-terminated list of static object instances (mainly constant strings) + classList.add(statics); + classList.add(NULLPtr); + classList.finishAndAddTo(symtab); + + // Construct the symbol table. + return symtab.finishAndCreateGlobal("", CGM.getPointerAlign()); + }(); + + // The symbol table is contained in a module which has some version-checking + // constants + llvm::Constant *module = [&] { + llvm::Type *moduleEltTys[] = { + LongTy, LongTy, PtrToInt8Ty, symtab->getType(), IntTy + }; + llvm::StructType *moduleTy = llvm::StructType::get( + CGM.getLLVMContext(), + ArrayRef(moduleEltTys).drop_back(unsigned(RuntimeVersion < 10))); + + ConstantInitBuilder builder(CGM); + auto module = builder.beginStruct(moduleTy); + // Runtime version, used for ABI compatibility checking. + module.addInt(LongTy, RuntimeVersion); + // sizeof(ModuleTy) + module.addInt(LongTy, CGM.getDataLayout().getTypeStoreSize(moduleTy)); + + // The path to the source file where this module was declared + SourceManager &SM = CGM.getContext().getSourceManager(); + OptionalFileEntryRef mainFile = SM.getFileEntryRefForID(SM.getMainFileID()); + std::string path = + (mainFile->getDir().getName() + "/" + mainFile->getName()).str(); + module.add(MakeConstantString(path, ".objc_source_file_name")); + module.add(symtab); + + if (RuntimeVersion >= 10) { + switch (CGM.getLangOpts().getGC()) { + case LangOptions::GCOnly: + module.addInt(IntTy, 2); + break; + case LangOptions::NonGC: + if (CGM.getLangOpts().ObjCAutoRefCount) + module.addInt(IntTy, 1); + else + module.addInt(IntTy, 0); + break; + case LangOptions::HybridGC: + module.addInt(IntTy, 1); + break; + } + } + + return module.finishAndCreateGlobal("", CGM.getPointerAlign()); + }(); + + // Create the load function calling the runtime entry point with the module + // structure + llvm::Function * LoadFunction = llvm::Function::Create( + llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), false), + llvm::GlobalValue::InternalLinkage, ".objc_load_function", + &TheModule); + llvm::BasicBlock *EntryBB = + llvm::BasicBlock::Create(VMContext, "entry", LoadFunction); + CGBuilderTy Builder(CGM, VMContext); + Builder.SetInsertPoint(EntryBB); + + llvm::FunctionType *FT = + llvm::FunctionType::get(Builder.getVoidTy(), module->getType(), true); + llvm::FunctionCallee Register = + CGM.CreateRuntimeFunction(FT, "__objc_exec_class"); + Builder.CreateCall(Register, module); + + if (!ClassAliases.empty()) { + llvm::Type *ArgTypes[2] = {PtrTy, PtrToInt8Ty}; + llvm::FunctionType *RegisterAliasTy = + llvm::FunctionType::get(Builder.getVoidTy(), + ArgTypes, false); + llvm::Function *RegisterAlias = llvm::Function::Create( + RegisterAliasTy, + llvm::GlobalValue::ExternalWeakLinkage, "class_registerAlias_np", + &TheModule); + llvm::BasicBlock *AliasBB = + llvm::BasicBlock::Create(VMContext, "alias", LoadFunction); + llvm::BasicBlock *NoAliasBB = + llvm::BasicBlock::Create(VMContext, "no_alias", LoadFunction); + + // Branch based on whether the runtime provided class_registerAlias_np() + llvm::Value *HasRegisterAlias = Builder.CreateICmpNE(RegisterAlias, + llvm::Constant::getNullValue(RegisterAlias->getType())); + Builder.CreateCondBr(HasRegisterAlias, AliasBB, NoAliasBB); + + // The true branch (has alias registration function): + Builder.SetInsertPoint(AliasBB); + // Emit alias registration calls: + for (std::vector<ClassAliasPair>::iterator iter = ClassAliases.begin(); + iter != ClassAliases.end(); ++iter) { + llvm::Constant *TheClass = + TheModule.getGlobalVariable("_OBJC_CLASS_" + iter->first, true); + if (TheClass) { + TheClass = llvm::ConstantExpr::getBitCast(TheClass, PtrTy); + Builder.CreateCall(RegisterAlias, + {TheClass, MakeConstantString(iter->second)}); + } + } + // Jump to end: + Builder.CreateBr(NoAliasBB); + + // Missing alias registration function, just return from the function: + Builder.SetInsertPoint(NoAliasBB); + } + Builder.CreateRetVoid(); + + return LoadFunction; +} + +llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) { + CodeGenTypes &Types = CGM.getTypes(); + llvm::FunctionType *MethodTy = + Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD)); + std::string FunctionName = getSymbolNameForMethod(OMD); + + llvm::Function *Method + = llvm::Function::Create(MethodTy, + llvm::GlobalValue::InternalLinkage, + FunctionName, + &TheModule); + return Method; +} + +void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF, + llvm::Function *Fn, + const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) { + // GNU runtime doesn't support direct calls at this time +} + +llvm::FunctionCallee CGObjCGNU::GetPropertyGetFunction() { + return GetPropertyFn; +} + +llvm::FunctionCallee CGObjCGNU::GetPropertySetFunction() { + return SetPropertyFn; +} + +llvm::FunctionCallee CGObjCGNU::GetOptimizedPropertySetFunction(bool atomic, + bool copy) { + return nullptr; +} + +llvm::FunctionCallee CGObjCGNU::GetGetStructFunction() { + return GetStructPropertyFn; +} + +llvm::FunctionCallee CGObjCGNU::GetSetStructFunction() { + return SetStructPropertyFn; +} + +llvm::FunctionCallee CGObjCGNU::GetCppAtomicObjectGetFunction() { + return nullptr; +} + +llvm::FunctionCallee CGObjCGNU::GetCppAtomicObjectSetFunction() { + return nullptr; +} + +llvm::FunctionCallee CGObjCGNU::EnumerationMutationFunction() { + return EnumerationMutationFn; +} + +void CGObjCGNU::EmitSynchronizedStmt(CodeGenFunction &CGF, + const ObjCAtSynchronizedStmt &S) { + EmitAtSynchronizedStmt(CGF, S, SyncEnterFn, SyncExitFn); +} + + +void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF, + const ObjCAtTryStmt &S) { + // Unlike the Apple non-fragile runtimes, which also uses + // unwind-based zero cost exceptions, the GNU Objective C runtime's + // EH support isn't a veneer over C++ EH. Instead, exception + // objects are created by objc_exception_throw and destroyed by + // the personality function; this avoids the need for bracketing + // catch handlers with calls to __blah_begin_catch/__blah_end_catch + // (or even _Unwind_DeleteException), but probably doesn't + // interoperate very well with foreign exceptions. + // + // In Objective-C++ mode, we actually emit something equivalent to the C++ + // exception handler. + EmitTryCatchStmt(CGF, S, EnterCatchFn, ExitCatchFn, ExceptionReThrowFn); +} + +void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, + const ObjCAtThrowStmt &S, + bool ClearInsertionPoint) { + llvm::Value *ExceptionAsObject; + bool isRethrow = false; + + if (const Expr *ThrowExpr = S.getThrowExpr()) { + llvm::Value *Exception = CGF.EmitObjCThrowOperand(ThrowExpr); + ExceptionAsObject = Exception; + } else { + assert((!CGF.ObjCEHValueStack.empty() && CGF.ObjCEHValueStack.back()) && + "Unexpected rethrow outside @catch block."); + ExceptionAsObject = CGF.ObjCEHValueStack.back(); + isRethrow = true; + } + if (isRethrow && usesSEHExceptions) { + // For SEH, ExceptionAsObject may be undef, because the catch handler is + // not passed it for catchalls and so it is not visible to the catch + // funclet. The real thrown object will still be live on the stack at this + // point and will be rethrown. If we are explicitly rethrowing the object + // that was passed into the `@catch` block, then this code path is not + // reached and we will instead call `objc_exception_throw` with an explicit + // argument. + llvm::CallBase *Throw = CGF.EmitRuntimeCallOrInvoke(ExceptionReThrowFn); + Throw->setDoesNotReturn(); + } + else { + ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy); + llvm::CallBase *Throw = + CGF.EmitRuntimeCallOrInvoke(ExceptionThrowFn, ExceptionAsObject); + Throw->setDoesNotReturn(); + } + CGF.Builder.CreateUnreachable(); + if (ClearInsertionPoint) + CGF.Builder.ClearInsertionPoint(); +} + +llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF, + Address AddrWeakObj) { + CGBuilderTy &B = CGF.Builder; + return B.CreateCall(WeakReadFn, + EnforceType(B, AddrWeakObj.getPointer(), PtrToIdTy)); +} + +void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF, + llvm::Value *src, Address dst) { + CGBuilderTy &B = CGF.Builder; + src = EnforceType(B, src, IdTy); + llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + B.CreateCall(WeakAssignFn, {src, dstVal}); +} + +void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF, + llvm::Value *src, Address dst, + bool threadlocal) { + CGBuilderTy &B = CGF.Builder; + src = EnforceType(B, src, IdTy); + llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + // FIXME. Add threadloca assign API + assert(!threadlocal && "EmitObjCGlobalAssign - Threal Local API NYI"); + B.CreateCall(GlobalAssignFn, {src, dstVal}); +} + +void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF, + llvm::Value *src, Address dst, + llvm::Value *ivarOffset) { + CGBuilderTy &B = CGF.Builder; + src = EnforceType(B, src, IdTy); + llvm::Value *dstVal = EnforceType(B, dst.getPointer(), IdTy); + B.CreateCall(IvarAssignFn, {src, dstVal, ivarOffset}); +} + +void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF, + llvm::Value *src, Address dst) { + CGBuilderTy &B = CGF.Builder; + src = EnforceType(B, src, IdTy); + llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + B.CreateCall(StrongCastAssignFn, {src, dstVal}); +} + +void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF, + Address DestPtr, + Address SrcPtr, + llvm::Value *Size) { + CGBuilderTy &B = CGF.Builder; + llvm::Value *DestPtrVal = EnforceType(B, DestPtr.getPointer(), PtrTy); + llvm::Value *SrcPtrVal = EnforceType(B, SrcPtr.getPointer(), PtrTy); + + B.CreateCall(MemMoveFn, {DestPtrVal, SrcPtrVal, Size}); +} + +llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable( + const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar) { + const std::string Name = GetIVarOffsetVariableName(ID, Ivar); + // Emit the variable and initialize it with what we think the correct value + // is. This allows code compiled with non-fragile ivars to work correctly + // when linked against code which isn't (most of the time). + llvm::GlobalVariable *IvarOffsetPointer = TheModule.getNamedGlobal(Name); + if (!IvarOffsetPointer) + IvarOffsetPointer = new llvm::GlobalVariable(TheModule, + llvm::Type::getInt32PtrTy(VMContext), false, + llvm::GlobalValue::ExternalLinkage, nullptr, Name); + return IvarOffsetPointer; +} + +LValue CGObjCGNU::EmitObjCValueForIvar(CodeGenFunction &CGF, + QualType ObjectTy, + llvm::Value *BaseValue, + const ObjCIvarDecl *Ivar, + unsigned CVRQualifiers) { + const ObjCInterfaceDecl *ID = + ObjectTy->castAs<ObjCObjectType>()->getInterface(); + return EmitValueForIvarAtOffset(CGF, ID, BaseValue, Ivar, CVRQualifiers, + EmitIvarOffset(CGF, ID, Ivar)); +} + +static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, + const ObjCInterfaceDecl *OID, + const ObjCIvarDecl *OIVD) { + for (const ObjCIvarDecl *next = OID->all_declared_ivar_begin(); next; + next = next->getNextIvar()) { + if (OIVD == next) + return OID; + } + + // Otherwise check in the super class. + if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) + return FindIvarInterface(Context, Super, OIVD); + + return nullptr; +} + +llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF, + const ObjCInterfaceDecl *Interface, + const ObjCIvarDecl *Ivar) { + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { + Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar); + + // The MSVC linker cannot have a single global defined as LinkOnceAnyLinkage + // and ExternalLinkage, so create a reference to the ivar global and rely on + // the definition being created as part of GenerateClass. + if (RuntimeVersion < 10 || + CGF.CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment()) + return CGF.Builder.CreateZExtOrBitCast( + CGF.Builder.CreateAlignedLoad( + Int32Ty, CGF.Builder.CreateAlignedLoad( + llvm::Type::getInt32PtrTy(VMContext), + ObjCIvarOffsetVariable(Interface, Ivar), + CGF.getPointerAlign(), "ivar"), + CharUnits::fromQuantity(4)), + PtrDiffTy); + std::string name = "__objc_ivar_offset_value_" + + Interface->getNameAsString() +"." + Ivar->getNameAsString(); + CharUnits Align = CGM.getIntAlign(); + llvm::Value *Offset = TheModule.getGlobalVariable(name); + if (!Offset) { + auto GV = new llvm::GlobalVariable(TheModule, IntTy, + false, llvm::GlobalValue::LinkOnceAnyLinkage, + llvm::Constant::getNullValue(IntTy), name); + GV->setAlignment(Align.getAsAlign()); + Offset = GV; + } + Offset = CGF.Builder.CreateAlignedLoad(IntTy, Offset, Align); + if (Offset->getType() != PtrDiffTy) + Offset = CGF.Builder.CreateZExtOrBitCast(Offset, PtrDiffTy); + return Offset; + } + uint64_t Offset = ComputeIvarBaseOffset(CGF.CGM, Interface, Ivar); + return llvm::ConstantInt::get(PtrDiffTy, Offset, /*isSigned*/true); +} + +CGObjCRuntime * +clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) { + auto Runtime = CGM.getLangOpts().ObjCRuntime; + switch (Runtime.getKind()) { + case ObjCRuntime::GNUstep: + if (Runtime.getVersion() >= VersionTuple(2, 0)) + return new CGObjCGNUstep2(CGM); + return new CGObjCGNUstep(CGM); + + case ObjCRuntime::GCC: + return new CGObjCGCC(CGM); + + case ObjCRuntime::ObjFW: + return new CGObjCObjFW(CGM); + + case ObjCRuntime::FragileMacOSX: + case ObjCRuntime::MacOSX: + case ObjCRuntime::iOS: + case ObjCRuntime::WatchOS: + llvm_unreachable("these runtimes are not GNU runtimes"); + } + llvm_unreachable("bad runtime"); +} |