[ORC][ORC-RT][MachO] Use _objc_(map|load)_images for ObjC & Swift registration.
authorLang Hames <lhames@gmail.com>
Fri, 7 Apr 2023 21:40:05 +0000 (14:40 -0700)
committerLang Hames <lhames@gmail.com>
Sat, 8 Apr 2023 22:54:02 +0000 (15:54 -0700)
This patch drops the individual registration calls to the ObjC and Swift
runtimes (for selectors, classes, etc.), and instead creates a Mach header and
load commands that can be passed to _objc_map_images and _objc_load_images to
trigger registration and execution of +load methods. This approach supports
categories (for which there is no current registration API), and more closely
follows dyld's ObjC & Swift registration path.

compiler-rt/lib/orc/macho_platform.cpp
compiler-rt/test/orc/TestCases/Darwin/arm64/objc-category.S [new file with mode: 0644]
llvm/include/llvm/ExecutionEngine/Orc/MachOPlatform.h
llvm/include/llvm/ExecutionEngine/Orc/Shared/ObjectFormats.h
llvm/lib/ExecutionEngine/Orc/MachOPlatform.cpp
llvm/lib/ExecutionEngine/Orc/Shared/ObjectFormats.cpp

index 2c0248a..1ca51c4 100644 (file)
@@ -36,40 +36,18 @@ using namespace __orc_rt::macho;
 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_push_initializers_tag)
 ORC_RT_JIT_DISPATCH_TAG(__orc_rt_macho_symbol_lookup_tag)
 
-// Objective-C types.
-struct objc_class;
 struct objc_image_info;
-struct objc_object;
-struct objc_selector;
-
-using Class = objc_class *;
-using id = objc_object *;
-using SEL = objc_selector *;
+struct mach_header;
 
 // Objective-C registration functions.
 // These are weakly imported. If the Objective-C runtime has not been loaded
 // then code containing Objective-C sections will generate an error.
-extern "C" id objc_msgSend(id, SEL, ...) ORC_RT_WEAK_IMPORT;
-extern "C" Class objc_readClassPair(Class,
-                                    const objc_image_info *) ORC_RT_WEAK_IMPORT;
-extern "C" SEL sel_registerName(const char *) ORC_RT_WEAK_IMPORT;
-
-// Swift types.
-class ProtocolRecord;
-class ProtocolConformanceRecord;
-class TypeMetadataRecord;
-
 extern "C" void
-swift_registerProtocols(const ProtocolRecord *begin,
-                        const ProtocolRecord *end) ORC_RT_WEAK_IMPORT;
+_objc_map_images(unsigned count, const char *const paths[],
+                 const mach_header *const mhdrs[]) ORC_RT_WEAK_IMPORT;
 
-extern "C" void swift_registerProtocolConformances(
-    const ProtocolConformanceRecord *begin,
-    const ProtocolConformanceRecord *end) ORC_RT_WEAK_IMPORT;
-
-extern "C" void swift_registerTypeMetadataRecords(
-    const TypeMetadataRecord *begin,
-    const TypeMetadataRecord *end) ORC_RT_WEAK_IMPORT;
+extern "C" void _objc_load_image(const char *path,
+                                 const mach_header *mh) ORC_RT_WEAK_IMPORT;
 
 // Libunwind prototypes.
 struct unw_dynamic_unwind_sections {
@@ -290,11 +268,7 @@ private:
     std::unordered_map<void *, size_t> ZeroInitRanges;
     UnwindSectionsMap UnwindSections;
     RecordSectionsTracker<void (*)()> ModInitsSections;
-    RecordSectionsTracker<void *> ObjCClassListSections;
-    RecordSectionsTracker<void *> ObjCSelRefsSections;
-    RecordSectionsTracker<char> Swift5ProtocolsSections;
-    RecordSectionsTracker<char> Swift5ProtocolConformancesSections;
-    RecordSectionsTracker<char> Swift5TypesSections;
+    RecordSectionsTracker<char> ObjCRuntimeRegistrationObjects;
 
     bool referenced() const {
       return LinkedAgainstRefCount != 0 || DlRefCount != 0;
@@ -357,11 +331,7 @@ private:
   static Error registerEHFrames(span<const char> EHFrameSection);
   static Error deregisterEHFrames(span<const char> EHFrameSection);
 
-  static Error registerObjCSelectors(JITDylibState &JDS);
-  static Error registerObjCClasses(JITDylibState &JDS);
-  static Error registerSwift5Protocols(JITDylibState &JDS);
-  static Error registerSwift5ProtocolConformances(JITDylibState &JDS);
-  static Error registerSwift5Types(JITDylibState &JDS);
+  static Error registerObjCRegistrationObjects(JITDylibState &JDS);
   static Error runModInits(std::unique_lock<std::mutex> &JDStatesLock,
                            JITDylibState &JDS);
 
@@ -580,22 +550,12 @@ Error MachOPlatformRuntimeState::registerObjectPlatformSections(
       JDS->DataSectionContent[KV.second.Start.toPtr<char *>()] =
           std::vector<char>(S.begin(), S.end());
     } else if (KV.first == "__DATA,__common") {
-      // fprintf(stderr, "Adding zero-init range %llx -- %llx\n",
-      // KV.second.Start.getValue(), KV.second.size());
       JDS->ZeroInitRanges[KV.second.Start.toPtr<char *>()] = KV.second.size();
     } else if (KV.first == "__DATA,__thread_data") {
       if (auto Err = registerThreadDataSection(KV.second.toSpan<const char>()))
         return Err;
-    } else if (KV.first == "__DATA,__objc_selrefs")
-      JDS->ObjCSelRefsSections.add(KV.second.toSpan<void *>());
-    else if (KV.first == "__DATA,__objc_classlist")
-      JDS->ObjCClassListSections.add(KV.second.toSpan<void *>());
-    else if (KV.first == "__TEXT,__swift5_protos")
-      JDS->Swift5ProtocolsSections.add(KV.second.toSpan<char>());
-    else if (KV.first == "__TEXT,__swift5_proto")
-      JDS->Swift5ProtocolConformancesSections.add(KV.second.toSpan<char>());
-    else if (KV.first == "__TEXT,__swift5_types")
-      JDS->Swift5TypesSections.add(KV.second.toSpan<char>());
+    } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
+      JDS->ObjCRuntimeRegistrationObjects.add(KV.second.toSpan<char>());
     else if (KV.first == "__DATA,__mod_init_func")
       JDS->ModInitsSections.add(KV.second.toSpan<void (*)()>());
     else {
@@ -675,16 +635,8 @@ Error MachOPlatformRuntimeState::deregisterObjectPlatformSections(
       if (auto Err =
               deregisterThreadDataSection(KV.second.toSpan<const char>()))
         return Err;
-    } else if (KV.first == "__DATA,__objc_selrefs")
-      JDS->ObjCSelRefsSections.removeIfPresent(KV.second);
-    else if (KV.first == "__DATA,__objc_classlist")
-      JDS->ObjCClassListSections.removeIfPresent(KV.second);
-    else if (KV.first == "__TEXT,__swift5_protos")
-      JDS->Swift5ProtocolsSections.removeIfPresent(KV.second);
-    else if (KV.first == "__TEXT,__swift5_proto")
-      JDS->Swift5ProtocolConformancesSections.removeIfPresent(KV.second);
-    else if (KV.first == "__TEXT,__swift5_types")
-      JDS->Swift5TypesSections.removeIfPresent(KV.second);
+    } else if (KV.first == "__llvm_jitlink_ObjCRuntimeRegistrationObject")
+      JDS->ObjCRuntimeRegistrationObjects.removeIfPresent(KV.second);
     else if (KV.first == "__DATA,__mod_init_func")
       JDS->ModInitsSections.removeIfPresent(KV.second);
     else {
@@ -905,115 +857,24 @@ Error MachOPlatformRuntimeState::deregisterEHFrames(
   return Error::success();
 }
 
-Error MachOPlatformRuntimeState::registerObjCSelectors(JITDylibState &JDS) {
-  if (!JDS.ObjCSelRefsSections.hasNewSections())
-    return Error::success();
-
-  if (ORC_RT_UNLIKELY(!sel_registerName))
-    return make_error<StringError>("sel_registerName is not available");
-
-  JDS.ObjCSelRefsSections.processNewSections([](span<void *> SelRefs) {
-    for (void *&SelEntry : SelRefs) {
-      const char *SelName = reinterpret_cast<const char *>(SelEntry);
-      auto Sel = sel_registerName(SelName);
-      *reinterpret_cast<SEL *>(&SelEntry) = Sel;
-    }
-  });
-
-  return Error::success();
-}
-
-Error MachOPlatformRuntimeState::registerObjCClasses(JITDylibState &JDS) {
-  if (!JDS.ObjCClassListSections.hasNewSections())
-    return Error::success();
-
-  if (ORC_RT_UNLIKELY(!objc_msgSend))
-    return make_error<StringError>("objc_msgSend is not available");
-  if (ORC_RT_UNLIKELY(!objc_readClassPair))
-    return make_error<StringError>("objc_readClassPair is not available");
-
-  struct ObjCClassCompiled {
-    void *Metaclass;
-    void *Parent;
-    void *Cache1;
-    void *Cache2;
-    void *Data;
-  };
-
-  auto ClassSelector = sel_registerName("class");
-
-  return JDS.ObjCClassListSections.processNewSections(
-      [&](span<void *> ClassPtrs) -> Error {
-        for (void *ClassPtr : ClassPtrs) {
-          auto *Cls = reinterpret_cast<Class>(ClassPtr);
-          auto *ClassCompiled = reinterpret_cast<ObjCClassCompiled *>(ClassPtr);
-          objc_msgSend(reinterpret_cast<id>(ClassCompiled->Parent),
-                       ClassSelector);
-          auto Registered = objc_readClassPair(Cls, JDS.ObjCImageInfo);
-          // FIXME: Improve diagnostic by reporting the failed class's name.
-          if (Registered != Cls)
-            return make_error<StringError>(
-                "Unable to register Objective-C class");
-        }
-        return Error::success();
-      });
-}
-
-Error MachOPlatformRuntimeState::registerSwift5Protocols(JITDylibState &JDS) {
-
-  if (!JDS.Swift5ProtocolsSections.hasNewSections())
-    return Error::success();
-
-  if (ORC_RT_UNLIKELY(!swift_registerProtocols))
-    return make_error<StringError>("swift_registerProtocols is not available");
-
-  JDS.Swift5ProtocolsSections.processNewSections([](span<char> ProtoSec) {
-    swift_registerProtocols(
-        reinterpret_cast<const ProtocolRecord *>(ProtoSec.data()),
-        reinterpret_cast<const ProtocolRecord *>(ProtoSec.data() +
-                                                 ProtoSec.size()));
-  });
-
-  return Error::success();
-}
-
-Error MachOPlatformRuntimeState::registerSwift5ProtocolConformances(
+Error MachOPlatformRuntimeState::registerObjCRegistrationObjects(
     JITDylibState &JDS) {
-
-  if (!JDS.Swift5ProtocolConformancesSections.hasNewSections())
-    return Error::success();
-
-  if (ORC_RT_UNLIKELY(!swift_registerProtocolConformances))
+  if (!_objc_map_images || !_objc_load_image)
     return make_error<StringError>(
-        "swift_registerProtocolConformances is not available");
-
-  JDS.Swift5ProtocolConformancesSections.processNewSections(
-      [](span<char> ProtoConfSec) {
-        swift_registerProtocolConformances(
-            reinterpret_cast<const ProtocolConformanceRecord *>(
-                ProtoConfSec.data()),
-            reinterpret_cast<const ProtocolConformanceRecord *>(
-                ProtoConfSec.data() + ProtoConfSec.size()));
-      });
+        "Could not register Objective-C / Swift metadata: _objc_map_images / "
+        "_objc_load_image not found");
 
-  return Error::success();
-}
-
-Error MachOPlatformRuntimeState::registerSwift5Types(JITDylibState &JDS) {
+  std::vector<char *> RegObjBases;
+  JDS.ObjCRuntimeRegistrationObjects.processNewSections(
+      [&](span<char> RegObj) { RegObjBases.push_back(RegObj.data()); });
 
-  if (!JDS.Swift5TypesSections.hasNewSections())
-    return Error::success();
+  std::vector<char *> Paths;
+  Paths.resize(RegObjBases.size());
+  _objc_map_images(RegObjBases.size(), Paths.data(),
+                   reinterpret_cast<mach_header **>(RegObjBases.data()));
 
-  if (ORC_RT_UNLIKELY(!swift_registerTypeMetadataRecords))
-    return make_error<StringError>(
-        "swift_registerTypeMetadataRecords is not available");
-
-  JDS.Swift5TypesSections.processNewSections([&](span<char> TypesSec) {
-    swift_registerTypeMetadataRecords(
-        reinterpret_cast<const TypeMetadataRecord *>(TypesSec.data()),
-        reinterpret_cast<const TypeMetadataRecord *>(TypesSec.data() +
-                                                     TypesSec.size()));
-  });
+  for (void *RegObjBase : RegObjBases)
+    _objc_load_image(nullptr, reinterpret_cast<mach_header *>(RegObjBase));
 
   return Error::success();
 }
@@ -1151,15 +1012,7 @@ Error MachOPlatformRuntimeState::dlopenInitialize(
   }
 
   // Initialize this JITDylib.
-  if (auto Err = registerObjCSelectors(JDS))
-    return Err;
-  if (auto Err = registerObjCClasses(JDS))
-    return Err;
-  if (auto Err = registerSwift5Protocols(JDS))
-    return Err;
-  if (auto Err = registerSwift5ProtocolConformances(JDS))
-    return Err;
-  if (auto Err = registerSwift5Types(JDS))
+  if (auto Err = registerObjCRegistrationObjects(JDS))
     return Err;
   if (auto Err = runModInits(JDStatesLock, JDS))
     return Err;
diff --git a/compiler-rt/test/orc/TestCases/Darwin/arm64/objc-category.S b/compiler-rt/test/orc/TestCases/Darwin/arm64/objc-category.S
new file mode 100644 (file)
index 0000000..9fe3b92
--- /dev/null
@@ -0,0 +1,190 @@
+// Test that we can handle calls to methods on categories.
+// The following assembly defines an ObjC class Foo with an instance method
+// -foo, then uses a category (Bar) to add an extra instance method -bar.
+// The main function calls both -foo and -bar on an instance of Foo to check
+// that the calls behave as expected.
+//
+// RUN: %clang -c -o %t.o %s
+// RUN: %llvm_jitlink -preload libobjc.A.dylib %t.o
+
+       .section        __TEXT,__text,regular,pure_instructions
+       .build_version macos, 14, 0
+       .p2align        2
+"-[Foo foo]":
+       mov     w0, #1
+       ret
+
+       .p2align        2
+"-[Foo(Bar) bar]":
+       mov     w0, #1
+       ret
+
+       .globl  _main
+       .p2align        2
+_main:
+       stp     x20, x19, [sp, #-32]!
+       stp     x29, x30, [sp, #16]
+       add     x29, sp, #16
+Lloh0:
+       adrp    x8, _OBJC_CLASSLIST_REFERENCES_$_@PAGE
+Lloh1:
+       ldr     x0, [x8, _OBJC_CLASSLIST_REFERENCES_$_@PAGEOFF]
+       bl      _objc_alloc_init
+       mov     x19, x0
+Lloh2:
+       adrp    x8, _OBJC_SELECTOR_REFERENCES_@PAGE
+Lloh3:
+       ldr     x1, [x8, _OBJC_SELECTOR_REFERENCES_@PAGEOFF]
+       bl      _objc_msgSend
+       cmp     w0, #1
+       b.ne    LBB2_2
+
+Lloh4:
+       adrp    x8, _OBJC_SELECTOR_REFERENCES_.3@PAGE
+Lloh5:
+       ldr     x1, [x8, _OBJC_SELECTOR_REFERENCES_.3@PAGEOFF]
+       mov     x0, x19
+       bl      _objc_msgSend
+       cmp     w0, #1
+       cset    w0, ne
+       ldp     x29, x30, [sp, #16]
+       ldp     x20, x19, [sp], #32
+       ret
+LBB2_2:
+       mov     w0, #1
+       ldp     x29, x30, [sp, #16]
+       ldp     x20, x19, [sp], #32
+       ret
+       .loh AdrpLdr    Lloh2, Lloh3
+       .loh AdrpLdr    Lloh0, Lloh1
+       .loh AdrpLdr    Lloh4, Lloh5
+
+       .section        __TEXT,__objc_classname,cstring_literals
+l_OBJC_CLASS_NAME_:
+       .asciz  "Foo"
+
+       .section        __DATA,__objc_const
+       .p2align        3, 0x0
+__OBJC_METACLASS_RO_$_Foo:
+       .long   1
+       .long   40
+       .long   40
+       .space  4
+       .quad   0
+       .quad   l_OBJC_CLASS_NAME_
+       .quad   0
+       .quad   0
+       .quad   0
+       .quad   0
+       .quad   0
+
+       .section        __DATA,__objc_data
+       .globl  _OBJC_METACLASS_$_Foo
+       .p2align        3, 0x0
+_OBJC_METACLASS_$_Foo:
+       .quad   _OBJC_METACLASS_$_NSObject
+       .quad   _OBJC_METACLASS_$_NSObject
+       .quad   __objc_empty_cache
+       .quad   0
+       .quad   __OBJC_METACLASS_RO_$_Foo
+
+       .section        __TEXT,__objc_methname,cstring_literals
+l_OBJC_METH_VAR_NAME_:
+       .asciz  "foo"
+
+       .section        __TEXT,__objc_methtype,cstring_literals
+l_OBJC_METH_VAR_TYPE_:
+       .asciz  "i16@0:8"
+
+       .section        __DATA,__objc_const
+       .p2align        3, 0x0
+__OBJC_$_INSTANCE_METHODS_Foo:
+       .long   24
+       .long   1
+       .quad   l_OBJC_METH_VAR_NAME_
+       .quad   l_OBJC_METH_VAR_TYPE_
+       .quad   "-[Foo foo]"
+
+       .p2align        3, 0x0
+__OBJC_CLASS_RO_$_Foo:
+       .long   0
+       .long   8
+       .long   8
+       .space  4
+       .quad   0
+       .quad   l_OBJC_CLASS_NAME_
+       .quad   __OBJC_$_INSTANCE_METHODS_Foo
+       .quad   0
+       .quad   0
+       .quad   0
+       .quad   0
+
+       .section        __DATA,__objc_data
+       .globl  _OBJC_CLASS_$_Foo
+       .p2align        3, 0x0
+_OBJC_CLASS_$_Foo:
+       .quad   _OBJC_METACLASS_$_Foo
+       .quad   _OBJC_CLASS_$_NSObject
+       .quad   __objc_empty_cache
+       .quad   0
+       .quad   __OBJC_CLASS_RO_$_Foo
+
+       .section        __TEXT,__objc_classname,cstring_literals
+l_OBJC_CLASS_NAME_.1:
+       .asciz  "Bar"
+
+       .section        __TEXT,__objc_methname,cstring_literals
+l_OBJC_METH_VAR_NAME_.2:
+       .asciz  "bar"
+
+       .section        __DATA,__objc_const
+       .p2align        3, 0x0
+__OBJC_$_CATEGORY_INSTANCE_METHODS_Foo_$_Bar:
+       .long   24
+       .long   1
+       .quad   l_OBJC_METH_VAR_NAME_.2
+       .quad   l_OBJC_METH_VAR_TYPE_
+       .quad   "-[Foo(Bar) bar]"
+
+       .p2align        3, 0x0
+__OBJC_$_CATEGORY_Foo_$_Bar:
+       .quad   l_OBJC_CLASS_NAME_.1
+       .quad   _OBJC_CLASS_$_Foo
+       .quad   __OBJC_$_CATEGORY_INSTANCE_METHODS_Foo_$_Bar
+       .quad   0
+       .quad   0
+       .quad   0
+       .quad   0
+       .long   64
+       .space  4
+
+       .section        __DATA,__objc_classrefs,regular,no_dead_strip
+       .p2align        3, 0x0
+_OBJC_CLASSLIST_REFERENCES_$_:
+       .quad   _OBJC_CLASS_$_Foo
+
+       .section        __DATA,__objc_selrefs,literal_pointers,no_dead_strip
+       .p2align        3, 0x0
+_OBJC_SELECTOR_REFERENCES_:
+       .quad   l_OBJC_METH_VAR_NAME_
+
+       .p2align        3, 0x0
+_OBJC_SELECTOR_REFERENCES_.3:
+       .quad   l_OBJC_METH_VAR_NAME_.2
+
+       .section        __DATA,__objc_classlist,regular,no_dead_strip
+       .p2align        3, 0x0
+l_OBJC_LABEL_CLASS_$:
+       .quad   _OBJC_CLASS_$_Foo
+
+       .section        __DATA,__objc_catlist,regular,no_dead_strip
+       .p2align        3, 0x0
+l_OBJC_LABEL_CATEGORY_$:
+       .quad   __OBJC_$_CATEGORY_Foo_$_Bar
+
+       .section        __DATA,__objc_imageinfo,regular,no_dead_strip
+L_OBJC_IMAGE_INFO:
+       .long   0
+       .long   64
+
+.subsections_via_symbols
index a8b32f8..a89ed60 100644 (file)
@@ -156,6 +156,12 @@ private:
       ExecutorAddrRange CompactUnwindSection;
     };
 
+    struct ObjCImageInfo {
+      uint32_t Version = 0;
+      uint32_t Flags = 0;
+      ExecutorAddr Addr;
+    };
+
     Error bootstrapPipelineStart(jitlink::LinkGraph &G);
     Error bootstrapPipelineRecordRuntimeFunctions(jitlink::LinkGraph &G);
     Error bootstrapPipelineEnd(jitlink::LinkGraph &G);
@@ -165,8 +171,8 @@ private:
     Error associateJITDylibHeaderSymbol(jitlink::LinkGraph &G,
                                         MaterializationResponsibility &MR);
 
-    Error preserveInitSections(jitlink::LinkGraph &G,
-                               MaterializationResponsibility &MR);
+    Error preserveImportantSections(jitlink::LinkGraph &G,
+                                    MaterializationResponsibility &MR);
 
     Error processObjCImageInfo(jitlink::LinkGraph &G,
                                MaterializationResponsibility &MR);
@@ -178,12 +184,16 @@ private:
     Error registerObjectPlatformSections(jitlink::LinkGraph &G, JITDylib &JD,
                                          bool InBootstrapPhase);
 
+    Error createObjCRuntimeObject(jitlink::LinkGraph &G);
+    Error populateObjCRuntimeObject(jitlink::LinkGraph &G,
+                                    MaterializationResponsibility &MR);
+
     std::mutex PluginMutex;
     MachOPlatform &MP;
 
     // FIXME: ObjCImageInfos and HeaderAddrs need to be cleared when
     // JITDylibs are removed.
-    DenseMap<JITDylib *, std::pair<uint32_t, uint32_t>> ObjCImageInfos;
+    DenseMap<JITDylib *, ObjCImageInfo> ObjCImageInfos;
     DenseMap<JITDylib *, ExecutorAddr> HeaderAddrs;
     InitSymbolDepMap InitSymbolDeps;
   };
@@ -253,6 +263,10 @@ private:
       ES.intern("___orc_rt_macho_deregister_object_platform_sections")};
   RuntimeFunction CreatePThreadKey{
       ES.intern("___orc_rt_macho_create_pthread_key")};
+  RuntimeFunction RegisterObjCRuntimeObject{
+      ES.intern("___orc_rt_macho_register_objc_runtime_object")};
+  RuntimeFunction DeregisterObjCRuntimeObject{
+      ES.intern("___orc_rt_macho_deregister_objc_runtime_object")};
 
   DenseMap<JITDylib *, SymbolLookupSet> RegisteredInitSymbols;
 
index 3911bc1..b7bc54b 100644 (file)
@@ -19,21 +19,35 @@ namespace llvm {
 namespace orc {
 
 // MachO section names.
+
 extern StringRef MachODataCommonSectionName;
 extern StringRef MachODataDataSectionName;
 extern StringRef MachOEHFrameSectionName;
 extern StringRef MachOCompactUnwindInfoSectionName;
 extern StringRef MachOModInitFuncSectionName;
+extern StringRef MachOObjCCatListSectionName;
+extern StringRef MachOObjCCatList2SectionName;
 extern StringRef MachOObjCClassListSectionName;
+extern StringRef MachOObjCClassNameSectionName;
+extern StringRef MachOObjCClassRefsSectionName;
+extern StringRef MachOObjCConstSectionName;
+extern StringRef MachOObjCDataSectionName;
 extern StringRef MachOObjCImageInfoSectionName;
+extern StringRef MachOObjCMethNameSectionName;
+extern StringRef MachOObjCMethTypeSectionName;
+extern StringRef MachOObjCNLCatListSectionName;
 extern StringRef MachOObjCSelRefsSectionName;
 extern StringRef MachOSwift5ProtoSectionName;
 extern StringRef MachOSwift5ProtosSectionName;
 extern StringRef MachOSwift5TypesSectionName;
+extern StringRef MachOSwift5TypeRefSectionName;
+extern StringRef MachOSwift5FieldMetadataSectionName;
+extern StringRef MachOSwift5EntrySectionName;
 extern StringRef MachOThreadBSSSectionName;
 extern StringRef MachOThreadDataSectionName;
 extern StringRef MachOThreadVarsSectionName;
-extern StringRef MachOInitSectionNames[6];
+
+extern StringRef MachOInitSectionNames[19];
 
 // ELF section names.
 extern StringRef ELFEHFrameSectionName;
index 10364e4..685d5f0 100644 (file)
@@ -9,6 +9,7 @@
 #include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
 
 #include "llvm/BinaryFormat/MachO.h"
+#include "llvm/ExecutionEngine/JITLink/MachO.h"
 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
 #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
@@ -246,6 +247,21 @@ private:
   ExecutorAddr MachOHeaderAddr;
 };
 
+static StringRef ObjCRuntimeObjectSectionsData[] = {
+    MachOObjCCatListSectionName,   MachOObjCClassListSectionName,
+    MachOObjCClassRefsSectionName, MachOObjCConstSectionName,
+    MachOObjCDataSectionName,      MachOObjCSelRefsSectionName};
+
+static StringRef ObjCRuntimeObjectSectionsText[] = {
+    MachOObjCClassNameSectionName, MachOObjCMethNameSectionName,
+    MachOObjCMethTypeSectionName,  MachOSwift5TypesSectionName,
+    MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,
+    MachOSwift5EntrySectionName,   MachOSwift5ProtoSectionName,
+    MachOSwift5ProtosSectionName};
+
+static StringRef ObjCRuntimeObjectSectionName =
+    "__llvm_jitlink_ObjCRuntimeRegistrationObject";
+
 } // end anonymous namespace
 
 namespace llvm {
@@ -742,10 +758,14 @@ void MachOPlatform::MachOPlatformPlugin::modifyPassConfig(
     // If the object contains an init symbol other than the header start symbol
     // then add passes to preserve, process and register the init
     // sections/symbols.
-    Config.PrePrunePasses.push_back([this, &MR](LinkGraph &G) {
-      if (auto Err = preserveInitSections(G, MR))
+    Config.PrePrunePasses.push_back(
+        [this, &MR](LinkGraph &G) { return preserveImportantSections(G, MR); });
+    Config.PostPrunePasses.push_back(
+        [this](LinkGraph &G) { return createObjCRuntimeObject(G); });
+    Config.PostAllocationPasses.push_back([this, &MR](LinkGraph &G) {
+      if (auto Err = processObjCImageInfo(G, MR))
         return Err;
-      return processObjCImageInfo(G, MR);
+      return populateObjCRuntimeObject(G, MR);
     });
   }
 
@@ -806,7 +826,10 @@ Error MachOPlatform::MachOPlatformPlugin::
        &MP.RegisterObjectPlatformSections.Addr},
       {*MP.DeregisterObjectPlatformSections.Name,
        &MP.DeregisterObjectPlatformSections.Addr},
-      {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr}};
+      {*MP.CreatePThreadKey.Name, &MP.CreatePThreadKey.Addr},
+      {*MP.RegisterObjCRuntimeObject.Name, &MP.RegisterObjCRuntimeObject.Addr},
+      {*MP.DeregisterObjCRuntimeObject.Name,
+       &MP.DeregisterObjCRuntimeObject.Addr}};
 
   bool RegisterMachOHeader = false;
 
@@ -875,9 +898,25 @@ Error MachOPlatform::MachOPlatformPlugin::associateJITDylibHeaderSymbol(
   return Error::success();
 }
 
-Error MachOPlatform::MachOPlatformPlugin::preserveInitSections(
+Error MachOPlatform::MachOPlatformPlugin::preserveImportantSections(
     jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
+  // __objc_imageinfo is "important": we want to preserve it and record its
+  // address in the first graph that it appears in, then verify and discard it
+  // in all subsequent graphs. In this pass we preserve unconditionally -- we'll
+  // manually throw it away in the processObjCImageInfo pass.
+  if (auto *ObjCImageInfoSec = G.findSectionByName("__DATA,__objc_imageinfo")) {
+    if (ObjCImageInfoSec->blocks_size() != 1)
+      return make_error<StringError>(
+          "In " + G.getName() +
+              "__DATA,__objc_imageinfo contains multiple blocks",
+          inconvertibleErrorCode());
+    G.addAnonymousSymbol(**ObjCImageInfoSec->blocks().begin(), 0, 0, false,
+                         true);
+  }
 
+  // Init sections are important: We need to preserve them and so that their
+  // addresses can be captured and reported to the ORC runtime in
+  // registerObjectPlatformSections.
   JITLinkSymbolSet InitSectionSymbols;
   for (auto &InitSectionName : MachOInitSectionNames) {
     // Skip non-init sections.
@@ -967,12 +1006,12 @@ Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
   if (ObjCImageInfoItr != ObjCImageInfos.end()) {
     // We've already registered an __objc_imageinfo section. Verify the
     // content of this new section matches, then delete it.
-    if (ObjCImageInfoItr->second.first != Version)
+    if (ObjCImageInfoItr->second.Version != Version)
       return make_error<StringError>(
           "ObjC version in " + G.getName() +
               " does not match first registered version",
           inconvertibleErrorCode());
-    if (ObjCImageInfoItr->second.second != Flags)
+    if (ObjCImageInfoItr->second.Flags != Flags)
       return make_error<StringError>("ObjC flags in " + G.getName() +
                                          " do not match first registered flags",
                                      inconvertibleErrorCode());
@@ -984,7 +1023,8 @@ Error MachOPlatform::MachOPlatformPlugin::processObjCImageInfo(
   } else {
     // We haven't registered an __objc_imageinfo section yet. Register and
     // move on. The section should already be marked no-dead-strip.
-    ObjCImageInfos[&MR.getTargetJITDylib()] = std::make_pair(Version, Flags);
+    ObjCImageInfos[&MR.getTargetJITDylib()] = {Version, Flags,
+                                               ObjCImageInfoBlock.getAddress()};
   }
 
   return Error::success();
@@ -1165,11 +1205,8 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
 
   // If any platform sections were found then add an allocation action to call
   // the registration function.
-  StringRef PlatformSections[] = {
-      MachOModInitFuncSectionName, MachOObjCClassListSectionName,
-      MachOObjCSelRefsSectionName, MachOSwift5ProtoSectionName,
-      MachOSwift5ProtosSectionName, MachOSwift5TypesSectionName,
-  };
+  StringRef PlatformSections[] = {MachOModInitFuncSectionName,
+                                  ObjCRuntimeObjectSectionName};
 
   for (auto &SecName : PlatformSections) {
     auto *Sec = G.findSectionByName(SecName);
@@ -1230,5 +1267,154 @@ Error MachOPlatform::MachOPlatformPlugin::registerObjectPlatformSections(
   return Error::success();
 }
 
+Error MachOPlatform::MachOPlatformPlugin::createObjCRuntimeObject(
+    jitlink::LinkGraph &G) {
+
+  bool NeedTextSegment = false;
+  size_t NumRuntimeSections = 0;
+
+  for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData)
+    if (auto *Sec = G.findSectionByName(ObjCRuntimeSectionName))
+      ++NumRuntimeSections;
+
+  for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
+    if (auto *Sec = G.findSectionByName(ObjCRuntimeSectionName)) {
+      ++NumRuntimeSections;
+      NeedTextSegment = true;
+    }
+  }
+
+  // Early out for no runtime sections.
+  if (NumRuntimeSections == 0)
+    return Error::success();
+
+  // If there were any runtime sections then we need to add an __objc_imageinfo
+  // section.
+  ++NumRuntimeSections;
+
+  size_t MachOSize = sizeof(MachO::mach_header_64) +
+                     (NeedTextSegment + 1) * sizeof(MachO::segment_command_64) +
+                     NumRuntimeSections * sizeof(MachO::section_64);
+
+  auto &Sec = G.createSection(ObjCRuntimeObjectSectionName,
+                              MemProt::Read | MemProt::Write);
+  G.createMutableContentBlock(Sec, MachOSize, ExecutorAddr(), 16, 0, true);
+
+  return Error::success();
+}
+
+Error MachOPlatform::MachOPlatformPlugin::populateObjCRuntimeObject(
+    jitlink::LinkGraph &G, MaterializationResponsibility &MR) {
+
+  auto *ObjCRuntimeObjectSec =
+      G.findSectionByName(ObjCRuntimeObjectSectionName);
+
+  if (!ObjCRuntimeObjectSec)
+    return Error::success();
+
+  auto &SecBlock = **ObjCRuntimeObjectSec->blocks().begin();
+
+  std::vector<MachO::section_64> TextSections, DataSections;
+  auto AddSection = [&](MachO::section_64 &Sec, jitlink::Section &GraphSec) {
+    jitlink::SectionRange SR(GraphSec);
+    StringRef FQName = GraphSec.getName();
+    memset(&Sec, 0, sizeof(MachO::section_64));
+    memcpy(Sec.sectname, FQName.drop_front(7).data(), FQName.size() - 7);
+    memcpy(Sec.segname, FQName.data(), 6);
+    Sec.addr = SR.getStart() - SecBlock.getAddress();
+    Sec.size = SR.getSize();
+    Sec.flags = MachO::S_REGULAR;
+  };
+
+  // Add the __objc_imageinfo section.
+  {
+    DataSections.push_back({});
+    auto &Sec = DataSections.back();
+    memset(&Sec, 0, sizeof(Sec));
+    strcpy(Sec.sectname, "__objc_imageinfo");
+    strcpy(Sec.segname, "__DATA");
+    std::lock_guard<std::mutex> Lock(PluginMutex);
+    auto I = ObjCImageInfos.find(&MR.getTargetJITDylib());
+    assert(I != ObjCImageInfos.end() && "Missing __objc_imageinfo");
+    assert(std::get<2>(I->second) && "Null __objc_imageinfo");
+    Sec.addr = I->second.Addr - SecBlock.getAddress();
+    Sec.size = 8;
+  }
+
+  for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsData) {
+    if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
+      DataSections.push_back({});
+      AddSection(DataSections.back(), *GraphSec);
+    }
+  }
+
+  for (auto ObjCRuntimeSectionName : ObjCRuntimeObjectSectionsText) {
+    if (auto *GraphSec = G.findSectionByName(ObjCRuntimeSectionName)) {
+      TextSections.push_back({});
+      AddSection(TextSections.back(), *GraphSec);
+    }
+  }
+
+  MachO::mach_header_64 Hdr;
+  Hdr.magic = MachO::MH_MAGIC_64;
+  switch (G.getTargetTriple().getArch()) {
+  case Triple::aarch64:
+    Hdr.cputype = MachO::CPU_TYPE_ARM64;
+    Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
+    break;
+  case Triple::x86_64:
+    Hdr.cputype = MachO::CPU_TYPE_X86_64;
+    Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
+    break;
+  default:
+    return make_error<StringError>("Unrecognized MachO arch in triple " +
+                                       G.getTargetTriple().str(),
+                                   inconvertibleErrorCode());
+  }
+
+  Hdr.filetype = MachO::MH_DYLIB;
+  Hdr.ncmds = 1 + !TextSections.empty();
+  Hdr.sizeofcmds =
+      Hdr.ncmds * sizeof(MachO::segment_command_64) +
+      (TextSections.size() + DataSections.size()) * sizeof(MachO::section_64);
+  Hdr.flags = 0;
+  Hdr.reserved = 0;
+
+  assert(ObjCRuntimeObjectSec->blocks_size() == 1 &&
+         "Unexpected number of blocks in runtime sections object");
+  auto SecContent = SecBlock.getAlreadyMutableContent();
+
+  char *P = SecContent.data();
+  auto WriteMachOStruct = [&](auto S) {
+    if (G.getEndianness() != support::endian::system_endianness())
+      MachO::swapStruct(S);
+    memcpy(P, &S, sizeof(S));
+    P += sizeof(S);
+  };
+
+  auto WriteSegment = [&](StringRef Name,
+                          const std::vector<MachO::section_64> &Secs) {
+    MachO::segment_command_64 SegLC;
+    memset(&SegLC, 0, sizeof(SegLC));
+    memcpy(SegLC.segname, Name.data(), Name.size());
+    SegLC.cmd = MachO::LC_SEGMENT_64;
+    SegLC.cmdsize = sizeof(MachO::segment_command_64) +
+                    Secs.size() * sizeof(MachO::section_64);
+    SegLC.nsects = Secs.size();
+    WriteMachOStruct(SegLC);
+    for (auto &Sec : Secs)
+      WriteMachOStruct(Sec);
+  };
+
+  WriteMachOStruct(Hdr);
+  if (!TextSections.empty())
+    WriteSegment("__TEXT", TextSections);
+  if (!DataSections.empty())
+    WriteSegment("__DATA", DataSections);
+
+  assert(P == SecContent.end() && "Underflow writing ObjC runtime object");
+  return Error::success();
+}
+
 } // End namespace orc.
 } // End namespace llvm.
index f3e735d..ecf5e29 100644 (file)
@@ -20,20 +20,40 @@ StringRef MachODataDataSectionName = "__DATA,__data";
 StringRef MachOEHFrameSectionName = "__TEXT,__eh_frame";
 StringRef MachOCompactUnwindInfoSectionName = "__TEXT,__unwind_info";
 StringRef MachOModInitFuncSectionName = "__DATA,__mod_init_func";
+StringRef MachOObjCCatListSectionName = "__DATA,__objc_catlist";
+StringRef MachOObjCCatList2SectionName = "__DATA,__objc_catlist2";
 StringRef MachOObjCClassListSectionName = "__DATA,__objc_classlist";
+StringRef MachOObjCClassNameSectionName = "__TEXT,__objc_classname";
+StringRef MachOObjCClassRefsSectionName = "__DATA,__objc_classrefs";
+StringRef MachOObjCConstSectionName = "__DATA,__objc_const";
+StringRef MachOObjCDataSectionName = "__DATA,__objc_data";
 StringRef MachOObjCImageInfoSectionName = "__DATA,__objc_imageinfo";
+StringRef MachOObjCMethNameSectionName = "__TEXT,__objc_methname";
+StringRef MachOObjCMethTypeSectionName = "__TEXT,__objc_methtype";
+StringRef MachOObjCNLCatListSectionName = "__DATA,__objc_nlcatlist";
 StringRef MachOObjCSelRefsSectionName = "__DATA,__objc_selrefs";
 StringRef MachOSwift5ProtoSectionName = "__TEXT,__swift5_proto";
 StringRef MachOSwift5ProtosSectionName = "__TEXT,__swift5_protos";
 StringRef MachOSwift5TypesSectionName = "__TEXT,__swift5_types";
+StringRef MachOSwift5TypeRefSectionName = "__TEXT,__swift5_typeref";
+StringRef MachOSwift5FieldMetadataSectionName = "__TEXT,__swift5_fieldmd";
+StringRef MachOSwift5EntrySectionName = "__TEXT,__swift5_entry";
 StringRef MachOThreadBSSSectionName = "__DATA,__thread_bss";
 StringRef MachOThreadDataSectionName = "__DATA,__thread_data";
 StringRef MachOThreadVarsSectionName = "__DATA,__thread_vars";
 
-StringRef MachOInitSectionNames[6] = {
-    MachOModInitFuncSectionName,   MachOObjCSelRefsSectionName,
-    MachOObjCClassListSectionName, MachOSwift5ProtosSectionName,
-    MachOSwift5ProtoSectionName,   MachOSwift5TypesSectionName};
+StringRef MachOInitSectionNames[19] = {
+    MachOModInitFuncSectionName,   MachOObjCCatListSectionName,
+    MachOObjCCatList2SectionName,  MachOObjCClassListSectionName,
+    MachOObjCClassNameSectionName, MachOObjCClassRefsSectionName,
+    MachOObjCConstSectionName,     MachOObjCDataSectionName,
+    MachOObjCImageInfoSectionName, MachOObjCMethNameSectionName,
+    MachOObjCMethTypeSectionName,  MachOObjCNLCatListSectionName,
+    MachOObjCSelRefsSectionName,   MachOSwift5ProtoSectionName,
+    MachOSwift5ProtosSectionName,  MachOSwift5TypesSectionName,
+    MachOSwift5TypeRefSectionName, MachOSwift5FieldMetadataSectionName,
+    MachOSwift5EntrySectionName,
+};
 
 StringRef ELFEHFrameSectionName = ".eh_frame";
 StringRef ELFInitArrayFuncSectionName = ".init_array";