r332963 - Revert "Revert r332955 "GNUstep Objective-C ABI version 2""
Mikael Holmén via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 14 01:50:03 PDT 2018
Hi David,
Compiling top-of-tree with gcc (5.4.0) I get a few compilation warnings
that I think are related to this commit:
[2705/3384] Building CXX object
tools/clang/lib/CodeGen/CMakeFiles/clangCodeGen.dir/CGObjCGNU.cpp.o
../tools/clang/lib/CodeGen/CGObjCGNU.cpp:589:16: warning: 'virtual
llvm::Value*
{anonymous}::CGObjCGNU::GetSelector(clang::CodeGen::CodeGenFunction&,
const clang::ObjCMethodDecl*)' was hidden [-Woverloaded-virtual]
llvm::Value *GetSelector(CodeGenFunction &CGF,
^
../tools/clang/lib/CodeGen/CGObjCGNU.cpp:1345:16: warning: by 'virtual
llvm::Value*
{anonymous}::CGObjCGNUstep2::GetSelector(clang::CodeGen::CodeGenFunction&,
clang::Selector, const string&)' [-Woverloaded-virtual]
llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
^
../tools/clang/lib/CodeGen/CGObjCGNU.cpp:587:16: warning: 'virtual
llvm::Value*
{anonymous}::CGObjCGNU::GetSelector(clang::CodeGen::CodeGenFunction&,
clang::Selector)' was hidden [-Woverloaded-virtual]
llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override;
^
../tools/clang/lib/CodeGen/CGObjCGNU.cpp:1345:16: warning: by 'virtual
llvm::Value*
{anonymous}::CGObjCGNUstep2::GetSelector(clang::CodeGen::CodeGenFunction&,
clang::Selector, const string&)' [-Woverloaded-virtual]
llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
Regards,
Mikael
On 05/22/2018 12:13 PM, David Chisnall via cfe-commits wrote:
> Author: theraven
> Date: Tue May 22 03:13:06 2018
> New Revision: 332963
>
> URL: http://llvm.org/viewvc/llvm-project?rev=332963&view=rev
> Log:
> Revert "Revert r332955 "GNUstep Objective-C ABI version 2""
>
> Added:
> cfe/trunk/test/CodeGenObjC/forward-declare-protocol-gnu.m
> cfe/trunk/test/CodeGenObjC/gnu-init.m
> cfe/trunk/test/CodeGenObjC/gnustep2-category.m
> cfe/trunk/test/CodeGenObjC/gnustep2-class.m
> cfe/trunk/test/CodeGenObjC/gnustep2-ivar-offset.m
> cfe/trunk/test/CodeGenObjC/gnustep2-proto.m
> Modified:
> cfe/trunk/include/clang/AST/Expr.h
> cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
> cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
> cfe/trunk/lib/Driver/ToolChains/Clang.cpp
> cfe/trunk/lib/Frontend/InitPreprocessor.cpp
> cfe/trunk/test/CodeGenObjC/constant-strings.m
> cfe/trunk/test/CodeGenObjC/gnu-empty-protocol-v3.m
> cfe/trunk/test/CodeGenObjC/ivar-type-encoding.m
> cfe/trunk/test/Preprocessor/init.c
>
> Modified: cfe/trunk/include/clang/AST/Expr.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Expr.h (original)
> +++ cfe/trunk/include/clang/AST/Expr.h Tue May 22 03:13:06 2018
> @@ -1620,6 +1620,14 @@ public:
> bool isUTF32() const { return Kind == UTF32; }
> bool isPascal() const { return IsPascal; }
>
> + bool containsNonAscii() const {
> + StringRef Str = getString();
> + for (unsigned i = 0, e = Str.size(); i != e; ++i)
> + if (!isASCII(Str[i]))
> + return true;
> + return false;
> + }
> +
> bool containsNonAsciiOrNull() const {
> StringRef Str = getString();
> for (unsigned i = 0, e = Str.size(); i != e; ++i)
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td Tue May 22 03:13:06 2018
> @@ -193,6 +193,8 @@ def err_drv_mg_requires_m_or_mm : Error<
> "option '-MG' requires '-M' or '-MM'">;
> def err_drv_unknown_objc_runtime : Error<
> "unknown or ill-formed Objective-C runtime '%0'">;
> +def err_drv_gnustep_objc_runtime_incompatible_binary : Error<
> + "GNUstep Objective-C runtime version %0 incompatible with target binary format">;
> def err_drv_emit_llvm_link : Error<
> "-emit-llvm cannot be used when linking">;
> def err_drv_optimization_remark_pattern : Error<
>
> Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Tue May 22 03:13:06 2018
> @@ -35,11 +35,23 @@
> #include "llvm/IR/Module.h"
> #include "llvm/Support/Compiler.h"
> #include "llvm/Support/ConvertUTF.h"
> +#include <cctype>
>
> using namespace clang;
> using namespace CodeGen;
>
> namespace {
> +
> +std::string SymbolNameForMethod( StringRef ClassName,
> + StringRef CategoryName, const Selector MethodName,
> + bool isClassMethod) {
> + std::string MethodNameColonStripped = MethodName.getAsString();
> + std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
> + ':', '_');
> + return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
> + CategoryName + "_" + MethodNameColonStripped).str();
> +}
> +
> /// 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.
> @@ -114,6 +126,10 @@ protected:
> /// 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
> @@ -156,11 +172,29 @@ protected:
> 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;
>
> + /// 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 SymbolForProtocol(StringRef Name) {
> + return (StringRef("._OBJC_PROTOCOL_") + Name).str();
> + }
> +
> + std::string SymbolForProtocolRef(StringRef Name) {
> + return (StringRef("._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*.
> @@ -174,39 +208,28 @@ protected:
> /// 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, StringRef Prefix) {
> - std::string Name = Prefix.str() + Str;
> - auto *ConstStr = TheModule.getGlobalVariable(Name);
> + 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);
> - ConstStr = new llvm::GlobalVariable(TheModule, value->getType(), true,
> - llvm::GlobalValue::LinkOnceODRLinkage,
> - value, Name);
> + auto *GV = new llvm::GlobalVariable(TheModule, value->getType(), true,
> + llvm::GlobalValue::LinkOnceODRLinkage, value, name);
> + if (Private)
> + GV->setVisibility(llvm::GlobalValue::HiddenVisibility);
> + ConstStr = GV;
> }
> return llvm::ConstantExpr::getGetElementPtr(ConstStr->getValueType(),
> ConstStr, Zeros);
> }
>
> - /// Generates a global structure, initialized by the elements in the vector.
> - /// The element types must match the types of the structure elements in the
> - /// first argument.
> - llvm::GlobalVariable *MakeGlobal(llvm::Constant *C,
> - CharUnits Align,
> - StringRef Name="",
> - llvm::GlobalValue::LinkageTypes linkage
> - =llvm::GlobalValue::InternalLinkage) {
> - auto GV = new llvm::GlobalVariable(TheModule, C->getType(), false,
> - linkage, C, Name);
> - GV->setAlignment(Align.getQuantity());
> - return GV;
> - }
> -
> /// Returns a property name and encoding string.
> llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD,
> const Decl *Container) {
> - const ObjCRuntime &R = CGM.getLangOpts().ObjCRuntime;
> - if ((R.getKind() == ObjCRuntime::GNUstep) &&
> - (R.getVersion() >= VersionTuple(1, 6))) {
> + assert(!isRuntime(ObjCRuntime::GNUstep, 2));
> + if (isRuntime(ObjCRuntime::GNUstep, 1, 6)) {
> std::string NameAndAttributes;
> std::string TypeStr =
> CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container);
> @@ -222,7 +245,7 @@ protected:
>
> /// Push the property attributes into two structure fields.
> void PushPropertyAttributes(ConstantStructBuilder &Fields,
> - ObjCPropertyDecl *property, bool isSynthesized=true, bool
> + const ObjCPropertyDecl *property, bool isSynthesized=true, bool
> isDynamic=true) {
> int attrs = property->getPropertyAttributes();
> // For read-only properties, clear the copy and retain flags
> @@ -249,6 +272,46 @@ protected:
> Fields.addInt(Int8Ty, 0);
> }
>
> + 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.
> @@ -268,7 +331,8 @@ protected:
> /// LLVM context.
> llvm::LLVMContext &VMContext;
>
> -private:
> +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
> @@ -352,6 +416,7 @@ private:
> /// 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;
> @@ -362,14 +427,18 @@ private:
> /// 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.
> - llvm::Constant *GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
> - ArrayRef<llvm::Constant *> IvarTypes,
> - ArrayRef<llvm::Constant *> IvarOffsets);
> + 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.
> @@ -378,20 +447,20 @@ private:
> /// pointer allowing them to be chained together in a linked list.
> llvm::Constant *GenerateMethodList(StringRef ClassName,
> StringRef CategoryName,
> - ArrayRef<Selector> MethodSels,
> - ArrayRef<llvm::Constant *> MethodTypes,
> + 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.
> - llvm::Constant *GenerateEmptyProtocol(const std::string &ProtocolName);
> + 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 ObjCImplementationDecl *OID,
> - SmallVectorImpl<Selector> &InstanceMethodSels,
> - SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes);
> + 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.
> @@ -422,22 +491,42 @@ private:
>
> /// Generates a method list. This is used by protocols to define the required
> /// and optional methods.
> - llvm::Constant *GenerateProtocolMethodList(
> - ArrayRef<llvm::Constant *> MethodNames,
> - ArrayRef<llvm::Constant *> MethodTypes);
> + 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).
> - llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel,
> + virtual llvm::Value *GetSelector(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.
> -
> -protected:
> void EmitClassRef(const std::string &className);
>
> /// Emits a pointer to the named class
> @@ -476,7 +565,7 @@ protected:
>
> public:
> CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
> - unsigned protocolClassVersion);
> + unsigned protocolClassVersion, unsigned classABI=1);
>
> ConstantAddress GenerateConstantString(const StringLiteral *) override;
>
> @@ -499,6 +588,14 @@ public:
> 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,
> @@ -698,7 +795,10 @@ class CGObjCGNUstep : public CGObjCGNU {
> }
>
> public:
> - CGObjCGNUstep(CodeGenModule &Mod) : CGObjCGNU(Mod, 9, 3) {
> + 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;
>
> llvm::StructType *SlotStructTy =
> @@ -707,7 +807,7 @@ class CGObjCGNUstep : public CGObjCGNU {
> // 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_msg_lookup_super(struct objc_super*, SEL);
> + // 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
> @@ -784,6 +884,951 @@ class CGObjCGNUstep : public CGObjCGNU {
> }
> };
>
> +/// 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 {
> + /// The section for selectors.
> + static constexpr const char *const SelSection = "__objc_selectors";
> + /// The section for classes.
> + static constexpr const char *const ClsSection = "__objc_classes";
> + /// The section for references to classes.
> + static constexpr const char *const ClsRefSection = "__objc_class_refs";
> + /// The section for categories.
> + static constexpr const char *const CatSection = "__objc_cats";
> + /// The section for protocols.
> + static constexpr const char *const ProtocolSection = "__objc_protocols";
> + /// The section for protocol references.
> + static constexpr const char *const ProtocolRefSection = "__objc_protocol_refs";
> + /// The section for class aliases
> + static constexpr const char *const ClassAliasSection = "__objc_class_aliases";
> + /// The section for constexpr constant strings
> + static constexpr const char *const ConstantStringSection = "__objc_constant_string";
> + /// 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.
> + std::string SymbolForClassRef(StringRef Name, bool isWeak) {
> + if (isWeak)
> + return (StringRef("._OBJC_WEAK_REF_CLASS_") + Name).str();
> + else
> + return (StringRef("._OBJC_REF_CLASS_") + Name).str();
> + }
> + /// Generate the name of a class symbol.
> + std::string SymbolForClass(StringRef Name) {
> + return (StringRef("._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::Value *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(), Align);
> +
> + bool isNonASCII = SL->containsNonAscii();
> +
> + auto LiteralLength = SL->getLength();
> +
> + if ((CGM.getTarget().getPointerWidth(0) == 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, 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);
> + 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();
> + Fields.add(isa);
> + // 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::makeArrayRef(&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) {
> + char c = Str[i];
> + if (isalpha(c) || isnumber(c))
> + StringName += c;
> + else if (c == ' ')
> + StringName += '_';
> + else {
> + isNamed = false;
> + break;
> + }
> + }
> + }
> + auto *ObjCStrGV =
> + Fields.finishAndCreateGlobal(
> + isNamed ? StringRef(StringName) : ".objc_string",
> + Align, false, isNamed ? llvm::GlobalValue::LinkOnceODRLinkage
> + : llvm::GlobalValue::PrivateLinkage);
> + ObjCStrGV->setSection(ConstantStringSection);
> + if (isNamed) {
> + ObjCStrGV->setComdat(TheModule.getOrInsertComdat(StringName));
> + ObjCStrGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
> + }
> + llvm::Constant *ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStrGV, IdTy);
> + ObjCStrings[Str] = ObjCStr;
> + ConstantStrings.push_back(ObjCStr);
> + return ConstantAddress(ObjCStr, 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::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,
> + PtrToObjCSuperTy).getPointer(), 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)));
> + 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),
> + 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().getQuantity());
> + }
> + 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::ExternalLinkage,
> + llvm::ConstantExpr::getBitCast(Protocol, ProtocolPtrTy), RefName);
> + GV->setSection(ProtocolRefSection);
> + GV->setAlignment(CGM.getPointerAlign().getQuantity());
> + Ref = GV;
> + }
> + EmittedProtocolRef = true;
> + return CGF.Builder.CreateAlignedLoad(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) {
> + std::string ProtocolName = PD->getNameAsString();
> + auto *&Protocol = ExistingProtocols[ProtocolName];
> + if (Protocol)
> + return Protocol;
> +
> + EmittedProtocol = true;
> +
> + // Use the protocol definition, if there is one.
> + if (const ObjCProtocolDecl *Def = PD->getDefinition())
> + PD = Def;
> +
> + SmallVector<llvm::Constant*, 16> Protocols;
> + for (const auto *PI : PD->protocols())
> + 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);
> +
> + auto SymName = SymbolForProtocol(ProtocolName);
> + auto *OldGV = TheModule.getGlobalVariable(SymName);
> + // 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(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 *GetSelector(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 = 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->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(SelSection);
> + auto *SelVal = EnforceType(GV, SelectorTy);
> + return SelVal;
> + }
> + std::pair<llvm::Constant*,llvm::Constant*>
> + GetSectionBounds(StringRef Section) {
> + 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 };
> + }
> + 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 addSection = [&](const char *section) {
> + auto bounds = GetSectionBounds(section);
> + InitStructBuilder.add(bounds.first);
> + InitStructBuilder.add(bounds.second);
> + };
> + addSection(SelSection);
> + addSection(ClsSection);
> + addSection(ClsRefSection);
> + addSection(CatSection);
> + addSection(ProtocolSection);
> + addSection(ProtocolRefSection);
> + addSection(ClassAliasSection);
> + addSection(ConstantStringSection);
> + 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*/true, 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");
> + InitVar->setSection(".ctors");
> + InitVar->setVisibility(llvm::GlobalValue::HiddenVisibility);
> + InitVar->setComdat(TheModule.getOrInsertComdat(".objc_ctor"));
> + CGM.addCompilerUsedGlobal(InitVar);
> + for (auto *C : Categories) {
> + auto *Cat = cast<llvm::GlobalVariable>(C->stripPointerCasts());
> + Cat->setSection(CatSection);
> + CGM.addUsedGlobal(Cat);
> + }
> + // Add a null value fore each special section so that we can always
> + // guarantee that the _start and _stop symbols will exist and be
> + // meaningful.
> + 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;
> + };
> + createNullGlobal(".objc_null_selector", {NULLPtr, NULLPtr}, SelSection);
> + if (Categories.empty())
> + createNullGlobal(".objc_null_category", {NULLPtr, NULLPtr,
> + NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr}, CatSection);
> + if (!EmittedClass) {
> + createNullGlobal(".objc_null_cls_init_ref", NULLPtr, ClsSection);
> + createNullGlobal(".objc_null_class_ref", { NULLPtr, NULLPtr },
> + ClsRefSection);
> + }
> + if (!EmittedProtocol)
> + createNullGlobal(".objc_null_protocol", {NULLPtr, NULLPtr, NULLPtr,
> + NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr, NULLPtr,
> + NULLPtr}, ProtocolSection);
> + if (!EmittedProtocolRef)
> + createNullGlobal(".objc_null_protocol_ref", {NULLPtr}, ProtocolRefSection);
> + if (!ClassAliases.empty())
> + for (auto clsAlias : ClassAliases)
> + createNullGlobal(std::string(".objc_class_alias") +
> + clsAlias.second, { MakeConstantString(clsAlias.second),
> + GetClassVar(clsAlias.first) }, ClassAliasSection);
> + else
> + createNullGlobal(".objc_null_class_alias", { NULLPtr, NULLPtr },
> + ClassAliasSection);
> + if (ConstantStrings.empty()) {
> + auto i32Zero = llvm::ConstantInt::get(Int32Ty, 0);
> + createNullGlobal(".objc_null_constant_string", { NULLPtr, i32Zero,
> + i32Zero, i32Zero, i32Zero, NULLPtr }, ConstantStringSection);
> + }
> + ConstantStrings.clear();
> + Categories.clear();
> + Classes.clear();
> + return nullptr;//CGObjCGNU::ModuleInitFunction();
> + }
> + /// 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(IvarOffsetPointer, Align);
> + if (Offset->getType() != PtrDiffTy)
> + Offset = CGF.Builder.CreateZExtOrBitCast(Offset, PtrDiffTy);
> + return Offset;
> + }
> + void GenerateClass(const ObjCImplementationDecl *OID) override {
> + ASTContext &Context = CGM.getContext();
> +
> + // 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("._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();
> + if (SuperClassDecl) {
> + auto SuperClassName = SymbolForClass(SuperClassDecl->getNameAsString());
> + llvm::Constant *SuperClass = TheModule.getNamedGlobal(SuperClassName);
> + if (!SuperClass)
> + {
> + SuperClass = new llvm::GlobalVariable(TheModule, PtrTy, false,
> + llvm::GlobalValue::ExternalLinkage, nullptr, SuperClassName);
> + }
> + classFields.add(llvm::ConstantExpr::getBitCast(SuperClass, 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();
> + CodeGenTypes &Types = CGM.getTypes();
> + 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,
> + td.getTypeSizeInBits(Types.ConvertType(ivarTy)) /
> + CGM.getContext().getCharWidth());
> + // Alignment will be stored as a base-2 log of the alignment.
> + int 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) {
> + ObjCPropertyDecl *prop = propImpl->getPropertyDecl();
> + auto addIfExists = [&](const ObjCMethodDecl* OMD) {
> + if (OMD)
> + InstanceMethods.push_back(OMD);
> + };
> + addIfExists(prop->getGetterMethodDecl());
> + addIfExists(prop->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;
> + SmallVector<llvm::Constant*, 16> Protocols;
> + for (const auto *I : classDecl->protocols())
> + 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));
> +
> + auto *classStruct =
> + classFields.finishAndCreateGlobal(SymbolForClass(className),
> + CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage);
> +
> + if (CGM.getTriple().isOSBinFormatCOFF()) {
> + auto Storage = llvm::GlobalValue::DefaultStorageClass;
> + if (OID->getClassInterface()->hasAttr<DLLImportAttr>())
> + Storage = llvm::GlobalValue::DLLImportStorageClass;
> + else if (OID->getClassInterface()->hasAttr<DLLExportAttr>())
> + Storage = llvm::GlobalValue::DLLExportStorageClass;
> + cast<llvm::GlobalValue>(classStruct)->setDLLStorageClass(Storage);
> + }
> +
> + auto *classRefSymbol = GetClassVar(className);
> + classRefSymbol->setSection(ClsRefSection);
> + classRefSymbol->setInitializer(llvm::ConstantExpr::getBitCast(classStruct, IdTy));
> +
> +
> + // 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, "._OBJC_INIT_CLASS_" + className);
> + classInitRef->setSection(ClsSection);
> + 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 });
> + }
> +
> +};
> +
> /// Support for the ObjFW runtime.
> class CGObjCObjFW: public CGObjCGNU {
> protected:
> @@ -878,22 +1923,12 @@ void CGObjCGNU::EmitClassRef(const std::
> llvm::GlobalValue::WeakAnyLinkage, ClassSymbol, symbolRef);
> }
>
> -static std::string SymbolNameForMethod( StringRef ClassName,
> - StringRef CategoryName, const Selector MethodName,
> - bool isClassMethod) {
> - std::string MethodNameColonStripped = MethodName.getAsString();
> - std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
> - ':', '_');
> - return (Twine(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
> - CategoryName + "_" + MethodNameColonStripped).str();
> -}
> -
> CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
> - unsigned protocolClassVersion)
> + unsigned protocolClassVersion, unsigned classABI)
> : CGObjCRuntime(cgm), TheModule(CGM.getModule()),
> VMContext(cgm.getLLVMContext()), ClassPtrAlias(nullptr),
> MetaClassPtrAlias(nullptr), RuntimeVersion(runtimeABIVersion),
> - ProtocolVersion(protocolClassVersion) {
> + ProtocolVersion(protocolClassVersion), ClassABIVersion(classABI) {
>
> msgSendMDKind = VMContext.getMDKindID("GNUObjCMessageSend");
>
> @@ -911,6 +1946,8 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm,
> 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];
> @@ -942,6 +1979,31 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm,
> IdTy = PtrToInt8Ty;
> }
> 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);
> @@ -1203,7 +2265,7 @@ ConstantAddress CGObjCGNU::GenerateConst
>
> StringRef StringClass = CGM.getLangOpts().ObjCConstantStringClass;
>
> - if (StringClass.empty()) StringClass = "NXConstantString";
> + if (StringClass.empty()) StringClass = "NSConstantString";
>
> std::string Sym = "_OBJC_CLASS_";
> Sym += StringClass;
> @@ -1264,54 +2326,67 @@ CGObjCGNU::GenerateMessageSendSuper(Code
> MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs);
>
> llvm::Value *ReceiverClass = nullptr;
> - if (isCategoryImpl) {
> - llvm::Constant *classLookupFunction = nullptr;
> + bool isV2ABI = isRuntime(ObjCRuntime::GNUstep, 2);
> + if (isV2ABI) {
> + ReceiverClass = GetClassNamed(CGF,
> + Class->getSuperClass()->getNameAsString(), /*isWeak*/false);
> 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");
> + // Load the isa pointer of the superclass is this is a class method.
> + ReceiverClass = Builder.CreateBitCast(ReceiverClass,
> + llvm::PointerType::getUnqual(IdTy));
> + ReceiverClass =
> + Builder.CreateAlignedLoad(ReceiverClass, CGF.getPointerAlign());
> }
> - ReceiverClass = Builder.CreateCall(classLookupFunction,
> - MakeConstantString(Class->getNameAsString()));
> + ReceiverClass = EnforceType(Builder, ReceiverClass, IdTy);
> } 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(
> - IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage,
> - ".objc_metaclass_ref" + Class->getNameAsString(), &TheModule);
> + if (isCategoryImpl) {
> + llvm::Constant *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 = MetaClassPtrAlias;
> + ReceiverClass = Builder.CreateCall(classLookupFunction,
> + MakeConstantString(Class->getNameAsString()));
> } else {
> - if (!ClassPtrAlias) {
> - ClassPtrAlias = llvm::GlobalAlias::create(
> - IdTy->getElementType(), 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(ReceiverClass, CGF.getPointerAlign());
> + // 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(
> + IdTy->getElementType(), 0, llvm::GlobalValue::InternalLinkage,
> + ".objc_metaclass_ref" + Class->getNameAsString(), &TheModule);
> + }
> + ReceiverClass = MetaClassPtrAlias;
> + } else {
> + if (!ClassPtrAlias) {
> + ClassPtrAlias = llvm::GlobalAlias::create(
> + IdTy->getElementType(), 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(ReceiverClass, CGF.getPointerAlign());
> + }
> // Construct the structure used to look up the IMP
> llvm::StructType *ObjCSuperTy =
> llvm::StructType::get(Receiver->getType(), IdTy);
>
> - // FIXME: Is this really supposed to be a dynamic alloca?
> - Address ObjCSuper = Address(Builder.CreateAlloca(ObjCSuperTy),
> + Address ObjCSuper = CGF.CreateTempAlloca(ObjCSuperTy,
> CGF.getPointerAlign());
>
> Builder.CreateStore(Receiver,
> @@ -1492,17 +2567,16 @@ CGObjCGNU::GenerateMessageSend(CodeGenFu
> llvm::Constant *CGObjCGNU::
> GenerateMethodList(StringRef ClassName,
> StringRef CategoryName,
> - ArrayRef<Selector> MethodSels,
> - ArrayRef<llvm::Constant *> MethodTypes,
> + ArrayRef<const ObjCMethodDecl*> Methods,
> bool isClassMethodList) {
> - if (MethodSels.empty())
> + if (Methods.empty())
> return NULLPtr;
>
> ConstantInitBuilder Builder(CGM);
>
> auto MethodList = Builder.beginStruct();
> MethodList.addNullPointer(CGM.Int8PtrTy);
> - MethodList.addInt(Int32Ty, MethodTypes.size());
> + MethodList.addInt(Int32Ty, Methods.size());
>
> // Get the method structure type.
> llvm::StructType *ObjCMethodTy =
> @@ -1511,20 +2585,48 @@ GenerateMethodList(StringRef ClassName,
> PtrToInt8Ty, // Method types
> IMPTy // Method pointer
> });
> - auto Methods = MethodList.beginArray();
> - for (unsigned int i = 0, e = MethodTypes.size(); i < e; ++i) {
> + 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(SymbolNameForMethod(ClassName, CategoryName,
> - MethodSels[i],
> + OMD->getSelector(),
> isClassMethodList));
> assert(FnPtr && "Can't generate metadata for method that doesn't exist");
> - auto Method = Methods.beginStruct(ObjCMethodTy);
> - Method.add(MakeConstantString(MethodSels[i].getAsString()));
> - Method.add(MethodTypes[i]);
> - Method.addBitCast(FnPtr, IMPTy);
> - Method.finishAndAddTo(Methods);
> + 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);
> }
> - Methods.finishAndAddTo(MethodList);
> + MethodArray.finishAndAddTo(MethodList);
>
> // Create an instance of the structure
> return MethodList.finishAndCreateGlobal(".objc_method_list",
> @@ -1535,7 +2637,9 @@ GenerateMethodList(StringRef ClassName,
> llvm::Constant *CGObjCGNU::
> GenerateIvarList(ArrayRef<llvm::Constant *> IvarNames,
> ArrayRef<llvm::Constant *> IvarTypes,
> - ArrayRef<llvm::Constant *> IvarOffsets) {
> + ArrayRef<llvm::Constant *> IvarOffsets,
> + ArrayRef<llvm::Constant *> IvarAlign,
> + ArrayRef<Qualifiers::ObjCLifetime> IvarOwnership) {
> if (IvarNames.empty())
> return NULLPtr;
>
> @@ -1650,7 +2754,7 @@ llvm::Constant *CGObjCGNU::GenerateClass
> // gc_object_type
> Elements.add(NULLPtr);
> // abi_version
> - Elements.addInt(LongTy, 1);
> + Elements.addInt(LongTy, ClassABIVersion);
> // ivar_offsets
> Elements.add(IvarOffsets);
> // properties
> @@ -1679,22 +2783,22 @@ llvm::Constant *CGObjCGNU::GenerateClass
> }
>
> llvm::Constant *CGObjCGNU::
> -GenerateProtocolMethodList(ArrayRef<llvm::Constant *> MethodNames,
> - ArrayRef<llvm::Constant *> MethodTypes) {
> +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, MethodNames.size());
> - auto Methods = MethodList.beginArray(ObjCMethodDescTy);
> - for (unsigned int i = 0, e = MethodTypes.size() ; i < e ; i++) {
> - auto Method = Methods.beginStruct(ObjCMethodDescTy);
> - Method.add(MethodNames[i]);
> - Method.add(MethodTypes[i]);
> - Method.finishAndAddTo(Methods);
> + 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);
> }
> - Methods.finishAndAddTo(MethodList);
> + MethodArray.finishAndAddTo(MethodList);
> return MethodList.finishAndCreateGlobal(".objc_method_list",
> CGM.getPointerAlign());
> }
> @@ -1728,16 +2832,19 @@ CGObjCGNU::GenerateProtocolList(ArrayRef
>
> llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF,
> const ObjCProtocolDecl *PD) {
> - llvm::Value *protocol = ExistingProtocols[PD->getNameAsString()];
> + llvm::Constant *&protocol = ExistingProtocols[PD->getNameAsString()];
> + if (!protocol)
> + GenerateProtocol(PD);
> llvm::Type *T =
> CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType());
> return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T));
> }
>
> llvm::Constant *
> -CGObjCGNU::GenerateEmptyProtocol(const std::string &ProtocolName) {
> +CGObjCGNU::GenerateEmptyProtocol(StringRef ProtocolName) {
> llvm::Constant *ProtocolList = GenerateProtocolList({});
> - llvm::Constant *MethodList = GenerateProtocolMethodList({}, {});
> + 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);
> @@ -1756,12 +2863,11 @@ CGObjCGNU::GenerateEmptyProtocol(const s
> Elements.add(MethodList); /* .optional_class_methods */
> Elements.add(NULLPtr); /* .properties */
> Elements.add(NULLPtr); /* .optional_properties */
> - return Elements.finishAndCreateGlobal(".objc_protocol",
> + return Elements.finishAndCreateGlobal(SymbolForProtocol(ProtocolName),
> CGM.getPointerAlign());
> }
>
> void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) {
> - ASTContext &Context = CGM.getContext();
> std::string ProtocolName = PD->getNameAsString();
>
> // Use the protocol definition, if there is one.
> @@ -1771,51 +2877,31 @@ void CGObjCGNU::GenerateProtocol(const O
> SmallVector<std::string, 16> Protocols;
> for (const auto *PI : PD->protocols())
> Protocols.push_back(PI->getNameAsString());
> - SmallVector<llvm::Constant*, 16> InstanceMethodNames;
> - SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
> - SmallVector<llvm::Constant*, 16> OptionalInstanceMethodNames;
> - SmallVector<llvm::Constant*, 16> OptionalInstanceMethodTypes;
> - for (const auto *I : PD->instance_methods()) {
> - std::string TypeStr = Context.getObjCEncodingForMethodDecl(I);
> - if (I->getImplementationControl() == ObjCMethodDecl::Optional) {
> - OptionalInstanceMethodNames.push_back(
> - MakeConstantString(I->getSelector().getAsString()));
> - OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr));
> - } else {
> - InstanceMethodNames.push_back(
> - MakeConstantString(I->getSelector().getAsString()));
> - InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
> - }
> - }
> + 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<llvm::Constant*, 16> ClassMethodNames;
> - SmallVector<llvm::Constant*, 16> ClassMethodTypes;
> - SmallVector<llvm::Constant*, 16> OptionalClassMethodNames;
> - SmallVector<llvm::Constant*, 16> OptionalClassMethodTypes;
> - for (const auto *I : PD->class_methods()) {
> - std::string TypeStr = Context.getObjCEncodingForMethodDecl(I);
> - if (I->getImplementationControl() == ObjCMethodDecl::Optional) {
> - OptionalClassMethodNames.push_back(
> - MakeConstantString(I->getSelector().getAsString()));
> - OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr));
> - } else {
> - ClassMethodNames.push_back(
> - MakeConstantString(I->getSelector().getAsString()));
> - ClassMethodTypes.push_back(MakeConstantString(TypeStr));
> - }
> - }
> + 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(InstanceMethodNames, InstanceMethodTypes);
> + GenerateProtocolMethodList(InstanceMethods);
> llvm::Constant *ClassMethodList =
> - GenerateProtocolMethodList(ClassMethodNames, ClassMethodTypes);
> + GenerateProtocolMethodList(ClassMethods);
> llvm::Constant *OptionalInstanceMethodList =
> - GenerateProtocolMethodList(OptionalInstanceMethodNames,
> - OptionalInstanceMethodTypes);
> + GenerateProtocolMethodList(OptionalInstanceMethods);
> llvm::Constant *OptionalClassMethodList =
> - GenerateProtocolMethodList(OptionalClassMethodNames,
> - OptionalClassMethodTypes);
> + GenerateProtocolMethodList(OptionalClassMethods);
>
> // Property metadata: name, attributes, isSynthesized, setter name, setter
> // types, getter name, getter types.
> @@ -1823,78 +2909,10 @@ void CGObjCGNU::GenerateProtocol(const O
> // simplify the runtime library by allowing it to use the same data
> // structures for protocol metadata everywhere.
>
> - llvm::Constant *PropertyList;
> - llvm::Constant *OptionalPropertyList;
> - {
> - llvm::StructType *propertyMetadataTy =
> - llvm::StructType::get(CGM.getLLVMContext(),
> - { PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
> - PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty });
> -
> - unsigned numReqProperties = 0, numOptProperties = 0;
> - for (auto property : PD->instance_properties()) {
> - if (property->isOptional())
> - numOptProperties++;
> - else
> - numReqProperties++;
> - }
> -
> - ConstantInitBuilder reqPropertyListBuilder(CGM);
> - auto reqPropertiesList = reqPropertyListBuilder.beginStruct();
> - reqPropertiesList.addInt(IntTy, numReqProperties);
> - reqPropertiesList.add(NULLPtr);
> - auto reqPropertiesArray = reqPropertiesList.beginArray(propertyMetadataTy);
> -
> - ConstantInitBuilder optPropertyListBuilder(CGM);
> - auto optPropertiesList = optPropertyListBuilder.beginStruct();
> - optPropertiesList.addInt(IntTy, numOptProperties);
> - optPropertiesList.add(NULLPtr);
> - auto optPropertiesArray = optPropertiesList.beginArray(propertyMetadataTy);
> -
> - // Add all of the property methods need adding to the method list and to the
> - // property metadata list.
> - for (auto *property : PD->instance_properties()) {
> - auto &propertiesArray =
> - (property->isOptional() ? optPropertiesArray : reqPropertiesArray);
> - auto fields = propertiesArray.beginStruct(propertyMetadataTy);
> -
> - fields.add(MakePropertyEncodingString(property, nullptr));
> - PushPropertyAttributes(fields, property);
> -
> - if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
> - std::string typeStr = Context.getObjCEncodingForMethodDecl(getter);
> - llvm::Constant *typeEncoding = MakeConstantString(typeStr);
> - InstanceMethodTypes.push_back(typeEncoding);
> - fields.add(MakeConstantString(getter->getSelector().getAsString()));
> - fields.add(typeEncoding);
> - } else {
> - fields.add(NULLPtr);
> - fields.add(NULLPtr);
> - }
> - if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) {
> - std::string typeStr = Context.getObjCEncodingForMethodDecl(setter);
> - llvm::Constant *typeEncoding = MakeConstantString(typeStr);
> - InstanceMethodTypes.push_back(typeEncoding);
> - fields.add(MakeConstantString(setter->getSelector().getAsString()));
> - fields.add(typeEncoding);
> - } else {
> - fields.add(NULLPtr);
> - fields.add(NULLPtr);
> - }
> -
> - fields.finishAndAddTo(propertiesArray);
> - }
> -
> - reqPropertiesArray.finishAndAddTo(reqPropertiesList);
> - PropertyList =
> - reqPropertiesList.finishAndCreateGlobal(".objc_property_list",
> - CGM.getPointerAlign());
> -
> - optPropertiesArray.finishAndAddTo(optPropertiesList);
> - OptionalPropertyList =
> - optPropertiesList.finishAndCreateGlobal(".objc_property_list",
> - CGM.getPointerAlign());
> - }
> + 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.
> @@ -1905,8 +2923,7 @@ void CGObjCGNU::GenerateProtocol(const O
> Elements.add(
> llvm::ConstantExpr::getIntToPtr(
> llvm::ConstantInt::get(Int32Ty, ProtocolVersion), IdTy));
> - Elements.add(
> - MakeConstantString(ProtocolName, ".objc_protocol_name"));
> + Elements.add(MakeConstantString(ProtocolName));
> Elements.add(ProtocolList);
> Elements.add(InstanceMethodList);
> Elements.add(ClassMethodList);
> @@ -1921,8 +2938,6 @@ void CGObjCGNU::GenerateProtocol(const O
> }
> void CGObjCGNU::GenerateProtocolHolderCategory() {
> // Collect information about instance methods
> - SmallVector<Selector, 1> MethodSels;
> - SmallVector<llvm::Constant*, 1> MethodTypes;
>
> ConstantInitBuilder Builder(CGM);
> auto Elements = Builder.beginStruct();
> @@ -1933,10 +2948,10 @@ void CGObjCGNU::GenerateProtocolHolderCa
> Elements.add(MakeConstantString(ClassName));
> // Instance method list
> Elements.addBitCast(GenerateMethodList(
> - ClassName, CategoryName, MethodSels, MethodTypes, false), PtrTy);
> + ClassName, CategoryName, {}, false), PtrTy);
> // Class method list
> Elements.addBitCast(GenerateMethodList(
> - ClassName, CategoryName, MethodSels, MethodTypes, true), PtrTy);
> + ClassName, CategoryName, {}, true), PtrTy);
>
> // Protocol list
> ConstantInitBuilder ProtocolListBuilder(CGM);
> @@ -2004,25 +3019,9 @@ llvm::Constant *CGObjCGNU::MakeBitField(
> }
>
> void CGObjCGNU::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
> - std::string ClassName = OCD->getClassInterface()->getNameAsString();
> + const ObjCInterfaceDecl *Class = OCD->getClassInterface();
> + std::string ClassName = Class->getNameAsString();
> std::string CategoryName = OCD->getNameAsString();
> - // Collect information about instance methods
> - SmallVector<Selector, 16> InstanceMethodSels;
> - SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
> - for (const auto *I : OCD->instance_methods()) {
> - InstanceMethodSels.push_back(I->getSelector());
> - std::string TypeStr = CGM.getContext().getObjCEncodingForMethodDecl(I);
> - InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
> - }
> -
> - // Collect information about class methods
> - SmallVector<Selector, 16> ClassMethodSels;
> - SmallVector<llvm::Constant*, 16> ClassMethodTypes;
> - for (const auto *I : OCD->class_methods()) {
> - ClassMethodSels.push_back(I->getSelector());
> - std::string TypeStr = CGM.getContext().getObjCEncodingForMethodDecl(I);
> - ClassMethodTypes.push_back(MakeConstantString(TypeStr));
> - }
>
> // Collect the names of referenced protocols
> SmallVector<std::string, 16> Protocols;
> @@ -2037,84 +3036,125 @@ void CGObjCGNU::GenerateCategory(const O
> 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, InstanceMethodSels,
> - InstanceMethodTypes, false),
> + 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, ClassMethodSels,
> - ClassMethodTypes, true),
> + GenerateMethodList(ClassName, CategoryName, ClassMethods, true),
> PtrTy);
> // Protocol list
> Elements.addBitCast(GenerateProtocolList(Protocols), 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("", CGM.getPointerAlign()),
> + Elements.finishAndCreateGlobal(
> + std::string(".objc_category_")+ClassName+CategoryName,
> + CGM.getPointerAlign()),
> PtrTy));
> }
>
> -llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OID,
> - SmallVectorImpl<Selector> &InstanceMethodSels,
> - SmallVectorImpl<llvm::Constant*> &InstanceMethodTypes) {
> +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();
> - // Property metadata: name, attributes, attributes2, padding1, padding2,
> - // setter name, setter types, getter name, getter types.
> - llvm::StructType *propertyMetadataTy =
> - llvm::StructType::get(CGM.getLLVMContext(),
> - { PtrToInt8Ty, Int8Ty, Int8Ty, Int8Ty, Int8Ty, PtrToInt8Ty,
> - PtrToInt8Ty, PtrToInt8Ty, PtrToInt8Ty });
> -
> - unsigned numProperties = 0;
> - for (auto *propertyImpl : OID->property_impls()) {
> - (void) propertyImpl;
> - numProperties++;
> - }
> +
> + 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();
> - propertyList.addInt(IntTy, numProperties);
> - propertyList.add(NULLPtr);
> - auto properties = propertyList.beginArray(propertyMetadataTy);
> + 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 *propertyImpl : OID->property_impls()) {
> - auto fields = properties.beginStruct(propertyMetadataTy);
> - ObjCPropertyDecl *property = propertyImpl->getPropertyDecl();
> - bool isSynthesized = (propertyImpl->getPropertyImplementation() ==
> - ObjCPropertyImplDecl::Synthesize);
> - bool isDynamic = (propertyImpl->getPropertyImplementation() ==
> - ObjCPropertyImplDecl::Dynamic);
> -
> - fields.add(MakePropertyEncodingString(property, OID));
> - PushPropertyAttributes(fields, property, isSynthesized, isDynamic);
> - if (ObjCMethodDecl *getter = property->getGetterMethodDecl()) {
> - std::string TypeStr = Context.getObjCEncodingForMethodDecl(getter);
> - llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
> - if (isSynthesized) {
> - InstanceMethodTypes.push_back(TypeEncoding);
> - InstanceMethodSels.push_back(getter->getSelector());
> + 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);
> }
> - fields.add(MakeConstantString(getter->getSelector().getAsString()));
> - fields.add(TypeEncoding);
> - } else {
> - fields.add(NULLPtr);
> - fields.add(NULLPtr);
> }
> - if (ObjCMethodDecl *setter = property->getSetterMethodDecl()) {
> - std::string TypeStr = Context.getObjCEncodingForMethodDecl(setter);
> - llvm::Constant *TypeEncoding = MakeConstantString(TypeStr);
> - if (isSynthesized) {
> - InstanceMethodTypes.push_back(TypeEncoding);
> - InstanceMethodSels.push_back(setter->getSelector());
> - }
> - fields.add(MakeConstantString(setter->getSelector().getAsString()));
> - fields.add(TypeEncoding);
> - } else {
> - fields.add(NULLPtr);
> - fields.add(NULLPtr);
> - }
> - fields.finishAndAddTo(properties);
> + PushProperty(properties, property, Container, isSynthesized, isDynamic);
> }
> properties.finishAndAddTo(propertyList);
>
> @@ -2167,6 +3207,8 @@ void CGObjCGNU::GenerateClass(const ObjC
> 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);
> @@ -2189,6 +3231,8 @@ void CGObjCGNU::GenerateClass(const ObjC
> 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;
> @@ -2199,6 +3243,7 @@ void CGObjCGNU::GenerateClass(const ObjC
> // 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);
> @@ -2207,14 +3252,13 @@ void CGObjCGNU::GenerateClass(const ObjC
> // copy.
> OffsetVar->setLinkage(llvm::GlobalValue::ExternalLinkage);
> } else
> - OffsetVar = new llvm::GlobalVariable(TheModule, IntTy,
> + OffsetVar = new llvm::GlobalVariable(TheModule, Int32Ty,
> false, llvm::GlobalValue::ExternalLinkage,
> - OffsetValue,
> - "__objc_ivar_offset_value_" + ClassName +"." +
> - IVD->getNameAsString());
> + 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);
> @@ -2236,25 +3280,30 @@ void CGObjCGNU::GenerateClass(const ObjC
> CGM.getPointerAlign());
>
> // Collect information about instance methods
> - SmallVector<Selector, 16> InstanceMethodSels;
> - SmallVector<llvm::Constant*, 16> InstanceMethodTypes;
> - for (const auto *I : OID->instance_methods()) {
> - InstanceMethodSels.push_back(I->getSelector());
> - std::string TypeStr = Context.getObjCEncodingForMethodDecl(I);
> - InstanceMethodTypes.push_back(MakeConstantString(TypeStr));
> - }
> -
> - llvm::Constant *Properties = GeneratePropertyList(OID, InstanceMethodSels,
> - InstanceMethodTypes);
> -
> - // Collect information about class methods
> - SmallVector<Selector, 16> ClassMethodSels;
> - SmallVector<llvm::Constant*, 16> ClassMethodTypes;
> - for (const auto *I : OID->class_methods()) {
> - ClassMethodSels.push_back(I->getSelector());
> - std::string TypeStr = Context.getObjCEncodingForMethodDecl(I);
> - ClassMethodTypes.push_back(MakeConstantString(TypeStr));
> - }
> + 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());
> +
> + // Collect the same information about synthesized properties, which don't
> + // show up in the instance method lists.
> + for (auto *propertyImpl : OID->property_impls())
> + if (propertyImpl->getPropertyImplementation() ==
> + ObjCPropertyImplDecl::Synthesize) {
> + ObjCPropertyDecl *property = propertyImpl->getPropertyDecl();
> + auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) {
> + if (accessor)
> + InstanceMethods.push_back(accessor);
> + };
> + addPropertyMethod(property->getGetterMethodDecl());
> + addPropertyMethod(property->getSetterMethodDecl());
> + }
> +
> + llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl);
> +
> // Collect the names of referenced protocols
> SmallVector<std::string, 16> Protocols;
> for (const auto *I : ClassDecl->protocols())
> @@ -2271,11 +3320,11 @@ void CGObjCGNU::GenerateClass(const ObjC
> SmallVector<llvm::Constant*, 1> empty;
> // Generate the method and instance variable lists
> llvm::Constant *MethodList = GenerateMethodList(ClassName, "",
> - InstanceMethodSels, InstanceMethodTypes, false);
> + InstanceMethods, false);
> llvm::Constant *ClassMethodList = GenerateMethodList(ClassName, "",
> - ClassMethodSels, ClassMethodTypes, true);
> + ClassMethods, true);
> llvm::Constant *IvarList = GenerateIvarList(IvarNames, IvarTypes,
> - IvarOffsets);
> + 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
> @@ -2288,14 +3337,13 @@ void CGObjCGNU::GenerateClass(const ObjC
> // the offset (third field in ivar structure)
> llvm::Type *IndexTy = Int32Ty;
> llvm::Constant *offsetPointerIndexes[] = {Zeros[0],
> - llvm::ConstantInt::get(IndexTy, 1), nullptr,
> - llvm::ConstantInt::get(IndexTy, 2) };
> + 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 = "__objc_ivar_offset_" + ClassName + '.'
> - + IVD->getNameAsString();
> + 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(
> @@ -2309,12 +3357,10 @@ void CGObjCGNU::GenerateClass(const ObjC
> // different modules will use this one, rather than their private
> // copy.
> offset->setLinkage(llvm::GlobalValue::ExternalLinkage);
> - } else {
> + } else
> // Add a new alias if there isn't one already.
> - offset = new llvm::GlobalVariable(TheModule, offsetValue->getType(),
> + new llvm::GlobalVariable(TheModule, offsetValue->getType(),
> false, llvm::GlobalValue::ExternalLinkage, offsetValue, Name);
> - (void) offset; // Silence dead store warning.
> - }
> ++ivarIndex;
> }
> llvm::Constant *ZeroPtr = llvm::ConstantInt::get(IntPtrTy, 0);
> @@ -2322,8 +3368,8 @@ void CGObjCGNU::GenerateClass(const ObjC
> //Generate metaclass for class methods
> llvm::Constant *MetaClassStruct = GenerateClassStructure(
> NULLPtr, NULLPtr, 0x12L, ClassName.c_str(), nullptr, Zeros[0],
> - GenerateIvarList(empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr,
> - NULLPtr, ZeroPtr, ZeroPtr, true);
> + NULLPtr, ClassMethodList, NULLPtr, NULLPtr,
> + GeneratePropertyList(OID, ClassDecl, true), ZeroPtr, ZeroPtr, true);
> CGM.setGVProperties(cast<llvm::GlobalValue>(MetaClassStruct),
> OID->getClassInterface());
>
> @@ -2761,8 +3807,7 @@ void CGObjCGNU::EmitGCMemmoveCollectable
> llvm::GlobalVariable *CGObjCGNU::ObjCIvarOffsetVariable(
> const ObjCInterfaceDecl *ID,
> const ObjCIvarDecl *Ivar) {
> - const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
> - + '.' + Ivar->getNameAsString();
> + 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).
> @@ -2871,8 +3916,11 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(C
>
> CGObjCRuntime *
> clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) {
> - switch (CGM.getLangOpts().ObjCRuntime.getKind()) {
> + 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:
>
> Modified: cfe/trunk/lib/Driver/ToolChains/Clang.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains/Clang.cpp?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Driver/ToolChains/Clang.cpp (original)
> +++ cfe/trunk/lib/Driver/ToolChains/Clang.cpp Tue May 22 03:13:06 2018
> @@ -4852,6 +4852,13 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(co
> getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime)
> << value;
> }
> + if ((runtime.getKind() == ObjCRuntime::GNUstep) &&
> + (runtime.getVersion() >= VersionTuple(2, 0)))
> + if (!getToolChain().getTriple().isOSBinFormatELF()) {
> + getToolChain().getDriver().Diag(
> + diag::err_drv_gnustep_objc_runtime_incompatible_binary)
> + << runtime.getVersion().getMajor();
> + }
>
> runtimeArg->render(args, cmdArgs);
> return runtime;
> @@ -4945,7 +4952,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(co
> // Legacy behaviour is to target the gnustep runtime if we are in
> // non-fragile mode or the GCC runtime in fragile mode.
> if (isNonFragile)
> - runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6));
> + runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(2, 0));
> else
> runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple());
> }
>
> Modified: cfe/trunk/lib/Frontend/InitPreprocessor.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/InitPreprocessor.cpp?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/InitPreprocessor.cpp (original)
> +++ cfe/trunk/lib/Frontend/InitPreprocessor.cpp Tue May 22 03:13:06 2018
> @@ -645,6 +645,19 @@ static void InitializePredefinedMacros(c
> if (LangOpts.ObjCRuntime.isNeXTFamily())
> Builder.defineMacro("__NEXT_RUNTIME__");
>
> + if (LangOpts.ObjCRuntime.getKind() == ObjCRuntime::GNUstep) {
> + auto version = LangOpts.ObjCRuntime.getVersion();
> + std::string versionString = "1";
> + // Don't rely on the tuple argument, because we can be asked to target
> + // later ABIs than we actually support, so clamp these values to those
> + // currently supported
> + if (version >= VersionTuple(2, 0))
> + Builder.defineMacro("__OBJC_GNUSTEP_RUNTIME_ABI__", "20");
> + else
> + Builder.defineMacro("__OBJC_GNUSTEP_RUNTIME_ABI__",
> + "1" + Twine(std::min(8U, version.getMinor().getValueOr(0))));
> + }
> +
> if (LangOpts.ObjCRuntime.getKind() == ObjCRuntime::ObjFW) {
> VersionTuple tuple = LangOpts.ObjCRuntime.getVersion();
>
>
> Modified: cfe/trunk/test/CodeGenObjC/constant-strings.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/constant-strings.m?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/constant-strings.m (original)
> +++ cfe/trunk/test/CodeGenObjC/constant-strings.m Tue May 22 03:13:06 2018
> @@ -14,5 +14,18 @@
> // RUN: %clang_cc1 -triple x86_64-macho -fobjc-runtime=gcc -fconstant-string-class NSConstantString -emit-llvm -o %t %s
> // RUN: FileCheck --check-prefix=CHECK-GNU-WITH-CLASS < %t %s
> // CHECK-GNU-WITH-CLASS: NSConstantString
> -id a = @"Hello World!";
> +//
> +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -fobjc-runtime=gnustep-2.0 -emit-llvm -o %t %s
> +// RUN: FileCheck --check-prefix=CHECK-GNUSTEP2 < %t %s
>
> +// CHECK-GNUSTEP2: @._OBJC_CLASS_NSConstantString = external global i8*
> +// CHECK-GNUSTEP2: @0 = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1
> +// CHECK-GNUSTEP2: @.objc_string = private global { i8**, i32, i32, i32, i32, i8* } { i8** @._OBJC_CLASS_NSConstantString, i32 0, i32 12, i32 12, i32 0, i8* getelementptr inbounds ([13 x i8], [13 x i8]* @0, i64 0, i64 0) }, section "__objc_constant_string", align 8
> +// CHECK-GNUSTEP2: @b = global i8* inttoptr (i64 -3340545023602065388 to i8*), align 8
> +// CHECK-GNUSTEP2: @.objc_str_Hello_World = linkonce_odr hidden global { i8**, i32, i32, i32, i32, i8* } { i8** @._OBJC_CLASS_NSConstantString, i32 0, i32 11, i32 11, i32 0, i8* getelementptr inbounds ([12 x i8], [12 x i8]* @1, i64 0, i64 0) }, section "__objc_constant_string", comdat, align 8
> +// CHECK-GNUSTEP2: @c =
> +// CHECK-SAME-GNUSTEP2: @.objc_str_Hello_World
> +//
> +id a = @"Hello World!";
> +id b = @"hi";
> +id c = @"Hello World";
>
> Added: cfe/trunk/test/CodeGenObjC/forward-declare-protocol-gnu.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/forward-declare-protocol-gnu.m?rev=332963&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/forward-declare-protocol-gnu.m (added)
> +++ cfe/trunk/test/CodeGenObjC/forward-declare-protocol-gnu.m Tue May 22 03:13:06 2018
> @@ -0,0 +1,11 @@
> +// RUN: %clang -S -emit-llvm %s -o - -x objective-c -fobjc-runtime=gnustep-1.5 | FileCheck %s
> +
> +// Regression test: check that we don't crash when referencing a forward-declared protocol.
> + at protocol P;
> +
> +Protocol *getProtocol(void)
> +{
> + return @protocol(P);
> +}
> +
> +// CHECK: @.objc_protocol
>
> Modified: cfe/trunk/test/CodeGenObjC/gnu-empty-protocol-v3.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/gnu-empty-protocol-v3.m?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/gnu-empty-protocol-v3.m (original)
> +++ cfe/trunk/test/CodeGenObjC/gnu-empty-protocol-v3.m Tue May 22 03:13:06 2018
> @@ -9,17 +9,18 @@ __attribute__((objc_root_class))
> @implementation Z
> @end
>
> +
> // CHECK: @.objc_protocol_list = internal global { i8*, i32, [0 x i8*] } zeroinitializer, align 4
> // CHECK: @.objc_method_list = internal global { i32, [0 x { i8*, i8* }] } zeroinitializer, align 4
> // CHECK: @.objc_protocol_name = private unnamed_addr constant [2 x i8] c"X\00", align 1
> -// CHECK: @.objc_protocol = internal global { i8*, i8*, { i8*, i32, [0 x i8*] }*, { i32, [0 x { i8*, i8* }] }*, { i32, [0 x { i8*, i8* }] }*, { i32, [0 x { i8*, i8* }] }*, { i32, [0 x { i8*, i8* }] }*, i8*, i8* } {
> +// CHECK: @._OBJC_PROTOCOL_X = internal global { i8*, i8*, { i8*, i32, [0 x i8*] }*, i8*, i8*, i8*, i8*, i8*, i8* } {
> // CHECK-SAME: i8* inttoptr (i32 3 to i8*),
> // CHECK-SAME: i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.objc_protocol_name, i32 0, i32 0),
> -// CHECK-SAME: { i8*, i32, [0 x i8*] }* @.objc_protocol_list,
> -// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list,
> -// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list,
> -// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list,
> -// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list,
> -// CHECK-SAME: i8* null,
> +// CHECK-SAME: { i8*, i32, [0 x i8*] }* @.objc_protocol_list
> +// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list
> +// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list
> +// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list
> +// CHECK-SAME: { i32, [0 x { i8*, i8* }] }* @.objc_method_list
> +// CHECK-SAME: i8* null
> // CHECK-SAME: i8* null
> // CHECK-SAME: }, align 4
>
> Added: cfe/trunk/test/CodeGenObjC/gnu-init.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/gnu-init.m?rev=332963&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/gnu-init.m (added)
> +++ cfe/trunk/test/CodeGenObjC/gnu-init.m Tue May 22 03:13:06 2018
> @@ -0,0 +1,69 @@
> +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s -check-prefix=CHECK-NEW
> +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-1.8 -o - %s | FileCheck %s -check-prefix=CHECK-OLD
> +
> +// Almost minimal Objective-C file, check that it emits calls to the correct
> +// runtime entry points.
> + at interface X @end
> + at implementation X @end
> +
> +
> +// Check that we emit a class ref
> +// CHECK-NEW: @._OBJC_REF_CLASS_X
> +// CHECK-NEW-SAME: section "__objc_class_refs"
> +
> +// Check that we get a class ref to the defined class.
> +// CHECK-NEW: @._OBJC_INIT_CLASS_X = global
> +// CHECK-NEW-SAME* @._OBJC_CLASS_X, section "__objc_classes"
> +
> +// Check that we emit the section start and end symbols as hidden globals.
> +// CHECK-NEW: @__start___objc_selectors = external hidden global i8*
> +// CHECK-NEW: @__stop___objc_selectors = external hidden global i8*
> +// CHECK-NEW: @__start___objc_classes = external hidden global i8*
> +// CHECK-NEW: @__stop___objc_classes = external hidden global i8*
> +// CHECK-NEW: @__start___objc_class_refs = external hidden global i8*
> +// CHECK-NEW: @__stop___objc_class_refs = external hidden global i8*
> +// CHECK-NEW: @__start___objc_cats = external hidden global i8*
> +// CHECK-NEW: @__stop___objc_cats = external hidden global i8*
> +// CHECK-NEW: @__start___objc_protocols = external hidden global i8*
> +// CHECK-NEW: @__stop___objc_protocols = external hidden global i8*
> +// CHECK-NEW: @__start___objc_protocol_refs = external hidden global i8*
> +// CHECK-NEW: @__stop___objc_protocol_refs = external hidden global i8*
> +// CHECK-NEW: @__start___objc_class_aliases = external hidden global i8*
> +// CHECK-NEW: @__stop___objc_class_aliases = external hidden global i8*
> +// CHECK-NEW: @__start___objc_constant_string = external hidden global i8*
> +// CHECK-NEW: @__stop___objc_constant_string = external hidden global i8*
> +
> +// Check that we emit the init structure correctly, including in a comdat.
> +// CHECK-NEW: @.objc_init = linkonce_odr hidden global { i64, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8**, i8** } { i64 0, i8** @__start___objc_selectors, i8** @__stop___objc_selectors, i8** @__start___objc_classes, i8** @__stop___objc_classes, i8** @__start___objc_class_refs, i8** @__stop___objc_class_refs, i8** @__start___objc_cats, i8** @__stop___objc_cats, i8** @__start___objc_protocols, i8** @__stop___objc_protocols, i8** @__start___objc_protocol_refs, i8** @__stop___objc_protocol_refs, i8** @__start___objc_class_aliases, i8** @__stop___objc_class_aliases, i8** @__start___objc_constant_string, i8** @__stop___objc_constant_string }, comdat, align 8
> +
> +// Check that the load function is manually inserted into .ctors.
> +// CHECK-NEW: @.objc_ctor = linkonce hidden constant void ()* @.objcv2_load_function, section ".ctors", comdat
> +
> +
> +// Make sure that we provide null versions of everything so the __start /
> +// __stop symbols work.
> +// CHECK-NEW: @.objc_null_selector = linkonce_odr hidden global { i8*, i8* } zeroinitializer, section "__objc_selectors", comdat, align 8
> +// CHECK-NEW: @.objc_null_category = linkonce_odr hidden global { i8*, i8*, i8*, i8*, i8*, i8*, i8* } zeroinitializer, section "__objc_cats", comdat, align 8
> +// CHECK-NEW: @.objc_null_protocol = linkonce_odr hidden global { i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8* } zeroinitializer, section "__objc_protocols", comdat, align 8
> +// CHECK-NEW: @.objc_null_protocol_ref = linkonce_odr hidden global { i8* } zeroinitializer, section "__objc_protocol_refs", comdat, align 8
> +// CHECK-NEW: @.objc_null_class_alias = linkonce_odr hidden global { i8*, i8* } zeroinitializer, section "__objc_class_aliases", comdat, align 8
> +// CHECK-NEW: @.objc_null_constant_string = linkonce_odr hidden global { i8*, i32, i32, i32, i32, i8* } zeroinitializer, section "__objc_constant_string", comdat, align 8
> +// Make sure that the null symbols are not going to be removed, even by linking.
> +// CHECK-NEW: @llvm.used = appending global [7 x i8*] [i8* bitcast ({ { i8*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }** @._OBJC_INIT_CLASS_X to i8*), i8* bitcast ({ i8*, i8* }* @.objc_null_selector to i8*), i8* bitcast ({ i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @.objc_null_category to i8*), i8* bitcast ({ i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @.objc_null_protocol to i8*), i8* bitcast ({ i8* }* @.objc_null_protocol_ref to i8*), i8* bitcast ({ i8*, i8* }* @.objc_null_class_alias to i8*), i8* bitcast ({ i8*, i32, i32, i32, i32, i8* }* @.objc_null_constant_string to i8*)], section "llvm.metadata"
> +// Make sure that the load function and the reference to it are marked as used.
> +// CHECK-NEW: @llvm.compiler.used = appending global [2 x i8*] [i8* bitcast (void ()* @.objcv2_load_function to i8*), i8* bitcast (void ()** @.objc_ctor to i8*)], section "llvm.metadata"
> +
> +// Check that we emit the load function in a comdat and that it does the right thing.
> +// CHECK-NEW: define linkonce_odr hidden void @.objcv2_load_function() comdat {
> +// CHECK-NEW-NEXT: entry:
> +// CHECK-NEW-NEXT: call void @__objc_load(
> +// CHECK-NEW-SAME: @.objc_init
> +// CHECK-NEW-NEXT: ret void
> +
> +// CHECK-OLD: @4 = internal global { i64, i64, i8*, { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* } { i64 9, i64 32, i8* getelementptr inbounds ([103 x i8], [103 x i8]* @.objc_source_file_name, i64 0, i64 0), { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* @3 }, align 8
> +// CHECK-OLD: @llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @.objc_load_function, i8* null }]
> +
> +// CHECK-OLD: define internal void @.objc_load_function() {
> +// CHECK-OLD-NEXT: entry:
> +// CHECK-OLD-NEXT: call void ({ i64, i64, i8*, { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* }*, ...) @__objc_exec_class({ i64, i64, i8*, { i64, { i8*, i8* }*, i16, i16, [4 x i8*] }* }* @4)
> +
>
> Added: cfe/trunk/test/CodeGenObjC/gnustep2-category.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/gnustep2-category.m?rev=332963&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/gnustep2-category.m (added)
> +++ cfe/trunk/test/CodeGenObjC/gnustep2-category.m Tue May 22 03:13:06 2018
> @@ -0,0 +1,26 @@
> +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s
> +
> +
> +// Check that we have a method list that refers to the correct thing method:
> +// CHECK: internal global { i8*, i32, i64, [1 x { i8* (i8*, i8*, ...)*, i8*, i8* }] } { i8* null, i32 1, i64 24,
> +// CHECK-SAME: @_i_X_Cat_x
> +// CHECK-SAME: @".objc_selector_x_i16\010:8"
> +
> +// Check that we emit the correct encoding for the property (somewhere)
> +// CHECK: c"Ti,R\00"
> +
> +// Check that we emit a single-element property list of the correct form.
> +// CHECK: internal global { i32, i32, i8*, [1 x { i8*, i8*, i8*, i8*, i8* }] }
> +
> +// CHECK: @.objc_category_XCat = internal global { i8*, i8*, i8*, i8*, i8*, i8*, i8* }
> +// CHECK-SAME: section "__objc_cats", align 8
> +
> + at interface X @end
> +
> + at interface X (Cat)
> + at property (readonly) int x;
> + at end
> +
> + at implementation X (Cat)
> +- (int)x { return 12; }
> + at end
>
> Added: cfe/trunk/test/CodeGenObjC/gnustep2-class.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/gnustep2-class.m?rev=332963&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/gnustep2-class.m (added)
> +++ cfe/trunk/test/CodeGenObjC/gnustep2-class.m Tue May 22 03:13:06 2018
> @@ -0,0 +1,55 @@
> +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s
> +
> + at interface Super @end
> +
> + at interface X : Super
> +{
> + int ivar1;
> + id ivar2;
> +}
> + at property (readonly) int x;
> + at property id y;
> + at end
> +
> + at implementation X
> + at synthesize y;
> +
> +- (int)x { return 12; }
> ++ (int)clsMeth { return 42; }
> +- (id)meth { return ivar2; }
> + at end
> +
> +// Check that we get an ivar offset variable for the synthesised ivar.
> +// CHECK: @"__objc_ivar_offset_X.y.\01" = hidden global i32 16
> +//
> +// Check that we get a sensible metaclass method list.
> +// CHECK: internal global { i8*, i32, i64, [1 x { i8* (i8*, i8*, ...)*, i8*, i8* }] }
> +// CHECK-SAME: @_c_X__clsMeth
> +
> +// Check that we get a metaclass and that it is not an exposed symbol:
> +// CHECK: @._OBJC_METACLASS_X = internal global
> +
> +// Check that we get a reference to the superclass symbol:
> +// CHECK: @._OBJC_CLASS_Super = external global i8*
> +
> +// Check that we get an ivar list with all three ivars, in the correct order
> +// CHECK: private global { i32, i64, [3 x { i8*, i8*, i32*, i32, i32 }] }
> +// CHECK-SAME: @__objc_ivar_offset_X.ivar1.i
> +// CHECK-SAME: @"__objc_ivar_offset_X.ivar2.\01"
> +// CHECK-SAME: @"__objc_ivar_offset_X.y.\01"
> +
> +// Check that we get some plausible property metadata.
> +// CHECK: private unnamed_addr constant [5 x i8] c"Ti,R\00", align 1
> +// CHECK: private unnamed_addr constant [6 x i8] c"T@,Vy\00", align 1
> +// CHECK: = internal global { i32, i32, i8*, [2 x { i8*, i8*, i8*, i8*, i8* }] } { i32 2, i32 40, i8* null,
> +
> +// Check that we get a class structure.
> +// CHECK: @._OBJC_CLASS_X = global { { i8*, i8*, i8*, i64, i64, i64, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, i8* }*, i8*, i8*, i64, i64, i64, { i32, i64, [3 x { i8*, i8*, i32*, i32, i32 }] }*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i64, { i32, i32, i8*, [2 x { i8*, i8*, i8*, i8*, i8* }] }* }
> +// CHECK-SAME: @._OBJC_METACLASS_X
> +// CHECK-SAME: @._OBJC_CLASS_Super
> +
> +// And check that we get a pointer to it in the right place
> +// CHECK: @._OBJC_REF_CLASS_X = global
> +// CHECK-SAME: @._OBJC_CLASS_X
> +// CHECK-SAMEsection "__objc_class_refs"
> +
>
> Added: cfe/trunk/test/CodeGenObjC/gnustep2-ivar-offset.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/gnustep2-ivar-offset.m?rev=332963&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/gnustep2-ivar-offset.m (added)
> +++ cfe/trunk/test/CodeGenObjC/gnustep2-ivar-offset.m Tue May 22 03:13:06 2018
> @@ -0,0 +1,28 @@
> +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s
> +
> +
> + at class NSString;
> +
> + at interface ANObject {
> + at public
> +// Public ivars have default visibility
> +// CHECK: @"__objc_ivar_offset_ANObject.isa.\01" = global i32 0
> + struct objc_object *isa;
> + at private
> +// Private and package ivars should have hidden linkage.
> +// Check that in the GNUstep v2 ABI, instance variable offset names include
> +// type encodings (with @ mangled to \01 to avoid collisions with ELF symbol
> +// versions).
> +// CHECK: private unnamed_addr constant [12 x i8] c"@\22NSString\22\00"
> +// CHECK: @"__objc_ivar_offset_ANObject._stringIvar.\01" = hidden global i32 8
> + NSString *_stringIvar;
> + at package
> +// CHECK: @__objc_ivar_offset_ANObject._intIvar.i = hidden global i32 16
> + int _intIvar;
> +}
> + at end
> + at implementation ANObject @end
> +
> +// Check that the ivar metadata contains 3 entries of the correct form and correctly sets the size.
> +// CHECK: @.objc_ivar_list = private global { i32, i64, [3 x { i8*, i8*, i32*, i32, i32 }] } { i32 3, i64 32,
> +// Check that we're emitting the extended type encoding for the string ivar.
>
> Added: cfe/trunk/test/CodeGenObjC/gnustep2-proto.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/gnustep2-proto.m?rev=332963&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/gnustep2-proto.m (added)
> +++ cfe/trunk/test/CodeGenObjC/gnustep2-proto.m Tue May 22 03:13:06 2018
> @@ -0,0 +1,39 @@
> +// RUN: %clang_cc1 -triple x86_64-unknown-freebsd -S -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck %s
> +
> + at protocol X
> + at optional
> +- (id)x;
> + at required
> ++ (void*)y;
> + at property int reqProp;
> + at optional
> + at property int optProp;
> + at end
> +
> +// Check that we get some plausible-looking method lists.
> +// CHECK: internal global { i32, i32, [2 x { i8*, i8* }] } { i32 2, i32 16,
> +// CHECK-SAME: @".objc_selector_reqProp_i16\010:8"
> +// CHECK-SAME: @".objc_selector_setReqProp:_v20\010:8i16"
> +// CHECK: internal global { i32, i32, [3 x { i8*, i8* }] } { i32 3, i32 16,
> +// CHECK-SAME: @".objc_selector_x_\0116\010:8"
> +// CHECK-SAME: @".objc_selector_optProp_i16\010:8"
> +// CHECK-SAME: @".objc_selector_setOptProp:_v20\010:8i16"
> +
> +
> +// Check that we're emitting the protocol and a correctly initialised
> +// indirection variable.
> +// CHECK: @._OBJC_PROTOCOL_X = global
> +// CHECK-SAME: , section "__objc_protocols", comdat, align 8
> +// CHECK: @._OBJC_REF_PROTOCOL_X = global
> +// CHECK-SAME: @._OBJC_PROTOCOL_X
> +// CHECK-SAME: , section "__objc_protocol_refs", align 8
> +
> +
> +// Check that we load from the indirection variable on protocol references.
> +// CHECK: define i8* @x()
> +// CHECK: = load
> +// CHECK-SAME: @._OBJC_REF_PROTOCOL_X, align 8
> +void *x()
> +{
> + return @protocol(X);
> +}
>
> Modified: cfe/trunk/test/CodeGenObjC/ivar-type-encoding.m
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/ivar-type-encoding.m?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/test/CodeGenObjC/ivar-type-encoding.m (original)
> +++ cfe/trunk/test/CodeGenObjC/ivar-type-encoding.m Tue May 22 03:13:06 2018
> @@ -29,10 +29,10 @@ int main() {
> return 0;
> }
>
> -// CHECK: @0 = private unnamed_addr constant [12 x i8] c"_stringIvar\00"
> -// CHECK: @1 = private unnamed_addr constant [12 x i8] c"@\22NSString\22\00"
> -// CHECK: @2 = private unnamed_addr constant [9 x i8] c"_intIvar\00"
> -// CHECK: @3 = private unnamed_addr constant [2 x i8] c"i\00"
> +// CHECK: = private unnamed_addr constant [12 x i8] c"_stringIvar\00"
> +// CHECK: = private unnamed_addr constant [12 x i8] c"@\22NSString\22\00"
> +// CHECK: = private unnamed_addr constant [9 x i8] c"_intIvar\00"
> +// CHECK: = private unnamed_addr constant [2 x i8] c"i\00"
>
> @interface Class1 {
> int : 3;
>
> Modified: cfe/trunk/test/Preprocessor/init.c
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Preprocessor/init.c?rev=332963&r1=332962&r2=332963&view=diff
> ==============================================================================
> --- cfe/trunk/test/Preprocessor/init.c (original)
> +++ cfe/trunk/test/Preprocessor/init.c Tue May 22 03:13:06 2018
> @@ -9002,6 +9002,13 @@
> // RUN: %clang_cc1 -x c++ -triple sparc-rtems-elf -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GNUSOURCE %s
> // GNUSOURCE:#define _GNU_SOURCE 1
> //
> +// Check that the GNUstep Objective-C ABI defines exist and are clamped at the
> +// highest supported version.
> +// RUN: %clang_cc1 -x objective-c -triple i386-unknown-freebsd -fobjc-runtime=gnustep-1.9 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GNUSTEP1 %s
> +// GNUSTEP1:#define __OBJC_GNUSTEP_RUNTIME_ABI__ 18
> +// RUN: %clang_cc1 -x objective-c -triple i386-unknown-freebsd -fobjc-runtime=gnustep-2.5 -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GNUSTEP2 %s
> +// GNUSTEP2:#define __OBJC_GNUSTEP_RUNTIME_ABI__ 20
> +//
> // RUN: %clang_cc1 -x c++ -std=c++98 -fno-rtti -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix NORTTI %s
> // NORTTI: #define __GXX_ABI_VERSION {{.*}}
> // NORTTI-NOT:#define __GXX_RTTI
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
More information about the cfe-commits
mailing list