[llvm] ec6b71d - [JITLink][ORC] Enable creation / linking of raw jitlink::LinkGraphs.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 15 19:02:10 PST 2020


Author: Lang Hames
Date: 2020-12-16T14:01:50+11:00
New Revision: ec6b71df70a09681cc0ae87945db9f71649cf188

URL: https://github.com/llvm/llvm-project/commit/ec6b71df70a09681cc0ae87945db9f71649cf188
DIFF: https://github.com/llvm/llvm-project/commit/ec6b71df70a09681cc0ae87945db9f71649cf188.diff

LOG: [JITLink][ORC] Enable creation / linking of raw jitlink::LinkGraphs.

Separates link graph creation from linking. This allows raw LinkGraphs to be
created and passed to a link. ObjectLinkingLayer is updated to support emission
of raw LinkGraphs in addition to object buffers.

Raw LinkGraphs can be created by in-memory compilers to bypass object encoding /
decoding (though this prevents caching, as LinkGraphs have do not have an
on-disk representation), and by utility code to add programatically generated
data structures to the JIT target process.

Added: 
    

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/ELF.h
    llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h
    llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
    llvm/include/llvm/ExecutionEngine/JITLink/MachO.h
    llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h
    llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h
    llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
    llvm/lib/ExecutionEngine/JITLink/ELF.cpp
    llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
    llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
    llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
    llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h
    llvm/lib/ExecutionEngine/JITLink/MachO.cpp
    llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
    llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h
    llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
    llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
    llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
    llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF.h
index 9f6ea5271f4b..8912f3a2db45 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/ELF.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF.h
@@ -19,11 +19,20 @@
 namespace llvm {
 namespace jitlink {
 
-/// jit-link the given ObjBuffer, which must be a ELF object file.
+/// Create a LinkGraph from an ELF relocatable object.
+///
+/// Note: The graph does not take ownership of the underlying buffer, nor copy
+/// its contents. The caller is responsible for ensuring that the object buffer
+/// outlives the graph.
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer);
+
+/// Link the given graph.
 ///
 /// Uses conservative defaults for GOT and stub handling based on the target
 /// platform.
-void jitLink_ELF(std::unique_ptr<JITLinkContext> Ctx);
+void link_ELF(std::unique_ptr<LinkGraph> G,
+              std::unique_ptr<JITLinkContext> Ctx);
 
 } // end namespace jitlink
 } // end namespace llvm

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h
index 1e1e282a8997..1423b0c30b2a 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h
@@ -44,8 +44,18 @@ enum ELFX86RelocationKind : Edge::Kind {
 
 } // end namespace ELF_x86_64_Edges
 
+/// Create a LinkGraph from an ELF/x86-64 relocatable object.
+///
+/// Note: The graph does not take ownership of the underlying buffer, nor copy
+/// its contents. The caller is responsible for ensuring that the object buffer
+/// outlives the graph.
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer);
+
 /// jit-link the given object buffer, which must be a ELF x86-64 object file.
-void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx);
+void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
+                     std::unique_ptr<JITLinkContext> Ctx);
+
 /// Return the string name of the given ELF x86-64 edge kind.
 StringRef getELFX86RelocationKindName(Edge::Kind R);
 } // end namespace jitlink

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
index 48e64335613b..6de0cd589aad 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
@@ -786,24 +786,40 @@ class LinkGraph {
                                  Section::const_block_iterator, const Block *,
                                  getSectionConstBlocks>;
 
-  LinkGraph(std::string Name, unsigned PointerSize,
+  LinkGraph(std::string Name, const Triple &TT, unsigned PointerSize,
             support::endianness Endianness)
-      : Name(std::move(Name)), PointerSize(PointerSize),
+      : Name(std::move(Name)), TT(TT), PointerSize(PointerSize),
         Endianness(Endianness) {}
 
   /// Returns the name of this graph (usually the name of the original
   /// underlying MemoryBuffer).
   const std::string &getName() { return Name; }
 
+  /// Returns the target triple for this Graph.
+  const Triple &getTargetTriple() const { return TT; }
+
   /// Returns the pointer size for use in this graph.
   unsigned getPointerSize() const { return PointerSize; }
 
   /// Returns the endianness of content in this graph.
   support::endianness getEndianness() const { return Endianness; }
 
-  /// Allocate a copy of the given String using the LinkGraph's allocator.
+  /// Allocate a copy of the given string using the LinkGraph's allocator.
   /// This can be useful when renaming symbols or adding new content to the
   /// graph.
+  StringRef allocateString(StringRef Source) {
+    auto *AllocatedBuffer = Allocator.Allocate<char>(Source.size());
+    llvm::copy(Source, AllocatedBuffer);
+    return StringRef(AllocatedBuffer, Source.size());
+  }
+
+  /// Allocate a copy of the given string using the LinkGraph's allocator.
+  /// This can be useful when renaming symbols or adding new content to the
+  /// graph.
+  ///
+  /// Note: This Twine-based overload requires an extra string copy and an
+  /// extra heap allocation for large strings. The StringRef overload should
+  /// be preferred where possible.
   StringRef allocateString(Twine Source) {
     SmallString<256> TmpBuffer;
     auto SourceStr = Source.toStringRef(TmpBuffer);
@@ -1034,6 +1050,7 @@ class LinkGraph {
   BumpPtrAllocator Allocator;
 
   std::string Name;
+  Triple TT;
   unsigned PointerSize;
   support::endianness Endianness;
   SectionList Sections;
@@ -1282,10 +1299,6 @@ class JITLinkContext {
   /// Return the MemoryManager to be used for this link.
   virtual JITLinkMemoryManager &getMemoryManager() = 0;
 
-  /// Returns a StringRef for the object buffer.
-  /// This method can not be called once takeObjectBuffer has been called.
-  virtual MemoryBufferRef getObjectBuffer() const = 0;
-
   /// Notify this context that linking failed.
   /// Called by JITLink if linking cannot be completed.
   virtual void notifyFailed(Error Err) = 0;
@@ -1339,10 +1352,16 @@ class JITLinkContext {
 /// conservative mark-live implementation.
 Error markAllSymbolsLive(LinkGraph &G);
 
-/// Basic JITLink implementation.
+/// Create a LinkGraph from the given object buffer.
 ///
-/// This function will use sensible defaults for GOT and Stub handling.
-void jitLink(std::unique_ptr<JITLinkContext> Ctx);
+/// Note: The graph does not take ownership of the underlying buffer, nor copy
+/// its contents. The caller is responsible for ensuring that the object buffer
+/// outlives the graph.
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromObject(MemoryBufferRef ObjectBuffer);
+
+/// Link the given graph.
+void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx);
 
 } // end namespace jitlink
 } // end namespace llvm

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/MachO.h b/llvm/include/llvm/ExecutionEngine/JITLink/MachO.h
index 7facb657a51c..b8432c4d26c6 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/MachO.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/MachO.h
@@ -18,11 +18,20 @@
 namespace llvm {
 namespace jitlink {
 
+/// Create a LinkGraph from a MachO relocatable object.
+///
+/// Note: The graph does not take ownership of the underlying buffer, nor copy
+/// its contents. The caller is responsible for ensuring that the object buffer
+/// outlives the graph.
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer);
+
 /// jit-link the given ObjBuffer, which must be a MachO object file.
 ///
 /// Uses conservative defaults for GOT and stub handling based on the target
 /// platform.
-void jitLink_MachO(std::unique_ptr<JITLinkContext> Ctx);
+void link_MachO(std::unique_ptr<LinkGraph> G,
+                std::unique_ptr<JITLinkContext> Ctx);
 
 } // end namespace jitlink
 } // end namespace llvm

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h
index d70b545fff86..c6aed2b60eac 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h
@@ -40,6 +40,14 @@ enum MachOARM64RelocationKind : Edge::Kind {
 
 } // namespace MachO_arm64_Edges
 
+/// Create a LinkGraph from a MachO/arm64 relocatable object.
+///
+/// Note: The graph does not take ownership of the underlying buffer, nor copy
+/// its contents. The caller is responsible for ensuring that the object buffer
+/// outlives the graph.
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer);
+
 /// jit-link the given object buffer, which must be a MachO arm64 object file.
 ///
 /// If PrePrunePasses is empty then a default mark-live pass will be inserted
@@ -49,7 +57,8 @@ enum MachOARM64RelocationKind : Edge::Kind {
 /// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
 /// be inserted. If PostPrunePasses is not empty then the caller is responsible
 /// for including a pass to insert GOT and stub edges.
-void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx);
+void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
+                      std::unique_ptr<JITLinkContext> Ctx);
 
 /// Return the string name of the given MachO arm64 edge kind.
 StringRef getMachOARM64RelocationKindName(Edge::Kind R);

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h
index 27fcdf4fa990..66c53d8c8291 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h
@@ -45,7 +45,15 @@ enum MachOX86RelocationKind : Edge::Kind {
 
 } // namespace MachO_x86_64_Edges
 
-/// jit-link the given object buffer, which must be a MachO x86-64 object file.
+/// Create a LinkGraph from a MachO/x86-64 relocatable object.
+///
+/// Note: The graph does not take ownership of the underlying buffer, nor copy
+/// its contents. The caller is responsible for ensuring that the object buffer
+/// outlives the graph.
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer);
+
+/// jit-link the given LinkGraph.
 ///
 /// If PrePrunePasses is empty then a default mark-live pass will be inserted
 /// that will mark all exported atoms live. If PrePrunePasses is not empty, the
@@ -54,7 +62,8 @@ enum MachOX86RelocationKind : Edge::Kind {
 /// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
 /// be inserted. If PostPrunePasses is not empty then the caller is responsible
 /// for including a pass to insert GOT and stub edges.
-void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx);
+void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
+                       std::unique_ptr<JITLinkContext> Ctx);
 
 /// Return the string name of the given MachO x86-64 edge kind.
 StringRef getMachOX86RelocationKindName(Edge::Kind R);

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
index b73217f09b54..f2975e29fcd6 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
@@ -35,6 +35,7 @@ namespace llvm {
 
 namespace jitlink {
 class EHFrameRegistrar;
+class LinkGraph;
 class Symbol;
 } // namespace jitlink
 
@@ -118,10 +119,14 @@ class ObjectLinkingLayer : public ObjectLayer, private ResourceManager {
     return *this;
   }
 
-  /// Emit the object.
+  /// Emit an object file.
   void emit(std::unique_ptr<MaterializationResponsibility> R,
             std::unique_ptr<MemoryBuffer> O) override;
 
+  /// Emit a LinkGraph.
+  void emit(std::unique_ptr<MaterializationResponsibility> R,
+            std::unique_ptr<jitlink::LinkGraph> G);
+
   /// Instructs this ObjectLinkingLayer instance to override the symbol flags
   /// found in the AtomGraph with the flags supplied by the
   /// MaterializationResponsibility instance. This is a workaround to support

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
index 19b878257709..27eb7d576e2d 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp
@@ -50,32 +50,39 @@ Expected<uint16_t> readTargetMachineArch(StringRef Buffer) {
   return ELF::EM_NONE;
 }
 
-void jitLink_ELF(std::unique_ptr<JITLinkContext> Ctx) {
-  StringRef Buffer = Ctx->getObjectBuffer().getBuffer();
-  if (Buffer.size() < ELF::EI_MAG3 + 1) {
-    Ctx->notifyFailed(make_error<JITLinkError>("Truncated ELF buffer"));
-    return;
-  }
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer) {
+  StringRef Buffer = ObjectBuffer.getBuffer();
+  if (Buffer.size() < ELF::EI_MAG3 + 1)
+    return make_error<JITLinkError>("Truncated ELF buffer");
 
-  if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0) {
-    Ctx->notifyFailed(make_error<JITLinkError>("ELF magic not valid"));
-    return;
-  }
+  if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0)
+    return make_error<JITLinkError>("ELF magic not valid");
 
   Expected<uint16_t> TargetMachineArch = readTargetMachineArch(Buffer);
-  if (!TargetMachineArch) {
-    Ctx->notifyFailed(TargetMachineArch.takeError());
-    return;
-  }
+  if (!TargetMachineArch)
+    return TargetMachineArch.takeError();
 
   switch (*TargetMachineArch) {
   case ELF::EM_X86_64:
-    jitLink_ELF_x86_64(std::move(Ctx));
+    return createLinkGraphFromELFObject_x86_64(std::move(ObjectBuffer));
+  default:
+    return make_error<JITLinkError>(
+        "Unsupported target machine architecture in ELF object " +
+        ObjectBuffer.getBufferIdentifier());
+  }
+}
+
+void link_ELF(std::unique_ptr<LinkGraph> G,
+              std::unique_ptr<JITLinkContext> Ctx) {
+  switch (G->getTargetTriple().getArch()) {
+  case Triple::x86_64:
+    link_ELF_x86_64(std::move(G), std::move(Ctx));
     return;
   default:
     Ctx->notifyFailed(make_error<JITLinkError>(
-        "Unsupported target machine architecture in ELF object " +
-        Ctx->getObjectBuffer().getBufferIdentifier()));
+        "Unsupported target machine architecture in ELF link graph " +
+        G->getName()));
     return;
   }
 }

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
index 20504b861155..ea05b6c7e638 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
@@ -571,10 +571,11 @@ class ELFLinkGraphBuilder_x86_64 {
   }
 
 public:
-  ELFLinkGraphBuilder_x86_64(std::string filename,
+  ELFLinkGraphBuilder_x86_64(StringRef FileName,
                              const object::ELFFile<object::ELF64LE> &Obj)
-      : G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj),
-                                      getEndianness(Obj))),
+      : G(std::make_unique<LinkGraph>(FileName.str(),
+                                      Triple("x86_64-unknown-linux"),
+                                      getPointerSize(Obj), getEndianness(Obj))),
         Obj(Obj) {}
 
   Expected<std::unique_ptr<LinkGraph>> buildGraph() {
@@ -610,27 +611,15 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
 
 public:
   ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
+                      std::unique_ptr<LinkGraph> G,
                       PassConfiguration PassConfig)
-      : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
+      : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
 
 private:
   StringRef getEdgeKindName(Edge::Kind R) const override {
     return getELFX86RelocationKindName(R);
   }
 
-  Expected<std::unique_ptr<LinkGraph>>
-  buildGraph(MemoryBufferRef ObjBuffer) override {
-    auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer);
-    if (!ELFObj)
-      return ELFObj.takeError();
-
-    auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
-    std::string fileName(ELFObj->get()->getFileName());
-    return ELFLinkGraphBuilder_x86_64(std::move(fileName),
-                                      ELFObjFile.getELFFile())
-        .buildGraph();
-  }
-
   Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
     using namespace ELF_x86_64_Edges;
     using namespace llvm::support;
@@ -655,12 +644,30 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
   }
 };
 
-void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer) {
+  LLVM_DEBUG({
+    dbgs() << "Building jitlink graph for new input "
+           << ObjectBuffer.getBufferIdentifier() << "...\n";
+  });
+
+  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
+  if (!ELFObj)
+    return ELFObj.takeError();
+
+  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
+  return ELFLinkGraphBuilder_x86_64((*ELFObj)->getFileName(),
+                                    ELFObjFile.getELFFile())
+      .buildGraph();
+}
+
+void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
+                     std::unique_ptr<JITLinkContext> Ctx) {
   PassConfiguration Config;
-  Triple TT("x86_64-linux");
+
   // Construct a JITLinker and run the link function.
   // Add a mark-live pass.
-  if (auto MarkLive = Ctx->getMarkLivePass(TT))
+  if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
     Config.PrePrunePasses.push_back(std::move(MarkLive));
   else
     Config.PrePrunePasses.push_back(markAllSymbolsLive);
@@ -674,10 +681,10 @@ void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
   // Add GOT/Stubs optimizer pass.
   Config.PostAllocationPasses.push_back(optimizeELF_x86_64_GOTAndStubs);
 
-  if (auto Err = Ctx->modifyPassConfig(TT, Config))
+  if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
     return Ctx->notifyFailed(std::move(Err));
 
-  ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
+  ELFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
 }
 StringRef getELFX86RelocationKindName(Edge::Kind R) {
   switch (R) {

diff  --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
index 71ec88639a5b..41b5423dc335 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp
@@ -322,15 +322,27 @@ Error markAllSymbolsLive(LinkGraph &G) {
   return Error::success();
 }
 
-void jitLink(std::unique_ptr<JITLinkContext> Ctx) {
-  auto Magic = identify_magic(Ctx->getObjectBuffer().getBuffer());
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromObject(MemoryBufferRef ObjectBuffer) {
+  auto Magic = identify_magic(ObjectBuffer.getBuffer());
   switch (Magic) {
   case file_magic::macho_object:
-    return jitLink_MachO(std::move(Ctx));
+    return createLinkGraphFromMachOObject(std::move(ObjectBuffer));
   case file_magic::elf_relocatable:
-    return jitLink_ELF(std::move(Ctx));
+    return createLinkGraphFromELFObject(std::move(ObjectBuffer));
   default:
-    Ctx->notifyFailed(make_error<JITLinkError>("Unsupported file format"));
+    return make_error<JITLinkError>("Unsupported file format");
+  };
+}
+
+void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx) {
+  switch (G->getTargetTriple().getObjectFormat()) {
+  case Triple::MachO:
+    return link_MachO(std::move(G), std::move(Ctx));
+  case Triple::ELF:
+    return link_ELF(std::move(G), std::move(Ctx));
+  default:
+    Ctx->notifyFailed(make_error<JITLinkError>("Unsupported object format"));
   };
 }
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
index 393ed0ea7093..f29f6592e6ff 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp
@@ -24,18 +24,6 @@ JITLinkerBase::~JITLinkerBase() {}
 
 void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) {
 
-  LLVM_DEBUG({
-    dbgs() << "Building jitlink graph for new input "
-           << Ctx->getObjectBuffer().getBufferIdentifier() << "...\n";
-  });
-
-  // Build the link graph.
-  if (auto GraphOrErr = buildGraph(Ctx->getObjectBuffer()))
-    G = std::move(*GraphOrErr);
-  else
-    return Ctx->notifyFailed(GraphOrErr.takeError());
-  assert(G && "Graph should have been created by buildGraph above");
-
   LLVM_DEBUG({
     dbgs() << "Starting link phase 1 for graph " << G->getName() << "\n";
   });

diff  --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h
index 87e5e8bbc98d..1d28f5006b2b 100644
--- a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h
+++ b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h
@@ -32,9 +32,11 @@ namespace jitlink {
 /// remaining linker work) to allow them to be performed asynchronously.
 class JITLinkerBase {
 public:
-  JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, PassConfiguration Passes)
-      : Ctx(std::move(Ctx)), Passes(std::move(Passes)) {
+  JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx,
+                std::unique_ptr<LinkGraph> G, PassConfiguration Passes)
+      : Ctx(std::move(Ctx)), G(std::move(G)), Passes(std::move(Passes)) {
     assert(this->Ctx && "Ctx can not be null");
+    assert(this->G && "G can not be null");
   }
 
   virtual ~JITLinkerBase();
@@ -50,8 +52,7 @@ class JITLinkerBase {
   using SegmentLayoutMap = DenseMap<unsigned, SegmentLayout>;
 
   // Phase 1:
-  //   1.1: Build link graph
-  //   1.2: Run pre-prune passes
+  //   1.1: Run pre-prune passes
   //   1.2: Prune graph
   //   1.3: Run post-prune passes
   //   1.4: Sort blocks into segments
@@ -72,11 +73,6 @@ class JITLinkerBase {
   //   3.1: Call OnFinalized callback, handing off allocation.
   void linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err);
 
-  // Build a graph from the given object buffer.
-  // To be implemented by the client.
-  virtual Expected<std::unique_ptr<LinkGraph>>
-  buildGraph(MemoryBufferRef ObjBuffer) = 0;
-
   // For debug dumping of the link graph.
   virtual StringRef getEdgeKindName(Edge::Kind K) const = 0;
 
@@ -113,8 +109,8 @@ class JITLinkerBase {
   void dumpGraph(raw_ostream &OS);
 
   std::unique_ptr<JITLinkContext> Ctx;
-  PassConfiguration Passes;
   std::unique_ptr<LinkGraph> G;
+  PassConfiguration Passes;
   std::unique_ptr<JITLinkMemoryManager::Allocation> Alloc;
 };
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachO.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO.cpp
index b3e45868ab22..e9327df6da41 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO.cpp
@@ -27,39 +27,29 @@ using namespace llvm;
 namespace llvm {
 namespace jitlink {
 
-void jitLink_MachO(std::unique_ptr<JITLinkContext> Ctx) {
-
-  // We don't want to do full MachO validation here. Just parse enough of the
-  // header to find out what MachO linker to use.
-
-  StringRef Data = Ctx->getObjectBuffer().getBuffer();
-  if (Data.size() < 4) {
-    StringRef BufferName = Ctx->getObjectBuffer().getBufferIdentifier();
-    Ctx->notifyFailed(make_error<JITLinkError>("Truncated MachO buffer \"" +
-                                               BufferName + "\""));
-    return;
-  }
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer) {
+  StringRef Data = ObjectBuffer.getBuffer();
+  if (Data.size() < 4)
+    return make_error<JITLinkError>("Truncated MachO buffer \"" +
+                                    ObjectBuffer.getBufferIdentifier() + "\"");
 
   uint32_t Magic;
   memcpy(&Magic, Data.data(), sizeof(uint32_t));
   LLVM_DEBUG({
     dbgs() << "jitLink_MachO: magic = " << format("0x%08" PRIx32, Magic)
-           << ", identifier = \""
-           << Ctx->getObjectBuffer().getBufferIdentifier() << "\"\n";
+           << ", identifier = \"" << ObjectBuffer.getBufferIdentifier()
+           << "\"\n";
   });
 
-  if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM) {
-    Ctx->notifyFailed(
-        make_error<JITLinkError>("MachO 32-bit platforms not supported"));
-    return;
-  } else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) {
+  if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM)
+    return make_error<JITLinkError>("MachO 32-bit platforms not supported");
+  else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) {
 
-    if (Data.size() < sizeof(MachO::mach_header_64)) {
-      StringRef BufferName = Ctx->getObjectBuffer().getBufferIdentifier();
-      Ctx->notifyFailed(make_error<JITLinkError>("Truncated MachO buffer \"" +
-                                                 BufferName + "\""));
-      return;
-    }
+    if (Data.size() < sizeof(MachO::mach_header_64))
+      return make_error<JITLinkError>("Truncated MachO buffer \"" +
+                                      ObjectBuffer.getBufferIdentifier() +
+                                      "\"");
 
     // Read the CPU type from the header.
     uint32_t CPUType;
@@ -74,15 +64,27 @@ void jitLink_MachO(std::unique_ptr<JITLinkContext> Ctx) {
 
     switch (CPUType) {
     case MachO::CPU_TYPE_ARM64:
-      return jitLink_MachO_arm64(std::move(Ctx));
+      return createLinkGraphFromMachOObject_arm64(std::move(ObjectBuffer));
     case MachO::CPU_TYPE_X86_64:
-      return jitLink_MachO_x86_64(std::move(Ctx));
+      return createLinkGraphFromMachOObject_x86_64(std::move(ObjectBuffer));
     }
+    return make_error<JITLinkError>("MachO-64 CPU type not valid");
+  } else
+    return make_error<JITLinkError>("Unrecognized MachO magic value");
+}
+
+void link_MachO(std::unique_ptr<LinkGraph> G,
+                std::unique_ptr<JITLinkContext> Ctx) {
+
+  switch (G->getTargetTriple().getArch()) {
+  case Triple::aarch64:
+    return link_MachO_arm64(std::move(G), std::move(Ctx));
+  case Triple::x86_64:
+    return link_MachO_x86_64(std::move(G), std::move(Ctx));
+  default:
     Ctx->notifyFailed(make_error<JITLinkError>("MachO-64 CPU type not valid"));
     return;
   }
-
-  Ctx->notifyFailed(make_error<JITLinkError>("MachO magic not valid"));
 }
 
 } // end namespace jitlink

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
index cf1bb23da665..4602154eb579 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp
@@ -45,10 +45,12 @@ Expected<std::unique_ptr<LinkGraph>> MachOLinkGraphBuilder::buildGraph() {
   return std::move(G);
 }
 
-MachOLinkGraphBuilder::MachOLinkGraphBuilder(const object::MachOObjectFile &Obj)
+MachOLinkGraphBuilder::MachOLinkGraphBuilder(const object::MachOObjectFile &Obj,
+                                             Triple TT)
     : Obj(Obj),
       G(std::make_unique<LinkGraph>(std::string(Obj.getFileName()),
-                                    getPointerSize(Obj), getEndianness(Obj))) {}
+                                    std::move(TT), getPointerSize(Obj),
+                                    getEndianness(Obj))) {}
 
 void MachOLinkGraphBuilder::addCustomSectionParser(
     StringRef SectionName, SectionParserFunction Parser) {

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h
index dd3bcf27494c..3555d66ace35 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h
+++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h
@@ -81,7 +81,7 @@ class MachOLinkGraphBuilder {
 
   using SectionParserFunction = std::function<Error(NormalizedSection &S)>;
 
-  MachOLinkGraphBuilder(const object::MachOObjectFile &Obj);
+  MachOLinkGraphBuilder(const object::MachOObjectFile &Obj, Triple TT);
 
   LinkGraph &getGraph() const { return *G; }
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
index a7178aa1e450..8366e9658539 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
@@ -26,7 +26,7 @@ namespace {
 class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
 public:
   MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj)
-      : MachOLinkGraphBuilder(Obj),
+      : MachOLinkGraphBuilder(Obj, Triple("arm64-apple-darwin")),
         NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
 
 private:
@@ -501,22 +501,15 @@ class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
 
 public:
   MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
+                       std::unique_ptr<LinkGraph> G,
                        PassConfiguration PassConfig)
-      : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
+      : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
 
 private:
   StringRef getEdgeKindName(Edge::Kind R) const override {
     return getMachOARM64RelocationKindName(R);
   }
 
-  Expected<std::unique_ptr<LinkGraph>>
-  buildGraph(MemoryBufferRef ObjBuffer) override {
-    auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
-    if (!MachOObj)
-      return MachOObj.takeError();
-    return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
-  }
-
   static Error targetOutOfRangeError(const Block &B, const Edge &E) {
     std::string ErrMsg;
     {
@@ -681,13 +674,22 @@ class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
   uint64_t NullValue = 0;
 };
 
-void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx) {
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer) {
+  auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
+  if (!MachOObj)
+    return MachOObj.takeError();
+  return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
+}
+
+void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
+                      std::unique_ptr<JITLinkContext> Ctx) {
+
   PassConfiguration Config;
-  Triple TT("arm64-apple-ios");
 
-  if (Ctx->shouldAddDefaultTargetPasses(TT)) {
+  if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
     // Add a mark-live pass.
-    if (auto MarkLive = Ctx->getMarkLivePass(TT))
+    if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
       Config.PrePrunePasses.push_back(std::move(MarkLive));
     else
       Config.PrePrunePasses.push_back(markAllSymbolsLive);
@@ -699,11 +701,11 @@ void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx) {
     });
   }
 
-  if (auto Err = Ctx->modifyPassConfig(TT, Config))
+  if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
     return Ctx->notifyFailed(std::move(Err));
 
   // Construct a JITLinker and run the link function.
-  MachOJITLinker_arm64::link(std::move(Ctx), std::move(Config));
+  MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config));
 }
 
 StringRef getMachOARM64RelocationKindName(Edge::Kind R) {

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
index a70b0dcd8f85..34e0c3250495 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
@@ -26,7 +26,7 @@ namespace {
 class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
 public:
   MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
-      : MachOLinkGraphBuilder(Obj) {}
+      : MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin")) {}
 
 private:
   static Expected<MachOX86RelocationKind>
@@ -548,22 +548,15 @@ class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
 
 public:
   MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
+                        std::unique_ptr<LinkGraph> G,
                         PassConfiguration PassConfig)
-      : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
+      : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
 
 private:
   StringRef getEdgeKindName(Edge::Kind R) const override {
     return getMachOX86RelocationKindName(R);
   }
 
-  Expected<std::unique_ptr<LinkGraph>>
-  buildGraph(MemoryBufferRef ObjBuffer) override {
-    auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
-    if (!MachOObj)
-      return MachOObj.takeError();
-    return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
-  }
-
   static Error targetOutOfRangeError(const Block &B, const Edge &E) {
     std::string ErrMsg;
     {
@@ -660,18 +653,27 @@ class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
   uint64_t NullValue = 0;
 };
 
-void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
+Expected<std::unique_ptr<LinkGraph>>
+createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
+  auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
+  if (!MachOObj)
+    return MachOObj.takeError();
+  return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
+}
+
+void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
+                       std::unique_ptr<JITLinkContext> Ctx) {
+
   PassConfiguration Config;
-  Triple TT("x86_64-apple-macosx");
 
-  if (Ctx->shouldAddDefaultTargetPasses(TT)) {
+  if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
     // Add eh-frame passses.
     Config.PrePrunePasses.push_back(EHFrameSplitter("__eh_frame"));
     Config.PrePrunePasses.push_back(
         EHFrameEdgeFixer("__eh_frame", NegDelta32, Delta64, Delta64));
 
     // Add a mark-live pass.
-    if (auto MarkLive = Ctx->getMarkLivePass(TT))
+    if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
       Config.PrePrunePasses.push_back(std::move(MarkLive));
     else
       Config.PrePrunePasses.push_back(markAllSymbolsLive);
@@ -686,11 +688,11 @@ void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
     Config.PostAllocationPasses.push_back(optimizeMachO_x86_64_GOTAndStubs);
   }
 
-  if (auto Err = Ctx->modifyPassConfig(TT, Config))
+  if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
     return Ctx->notifyFailed(std::move(Err));
 
   // Construct a JITLinker and run the link function.
-  MachOJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
+  MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
 }
 
 StringRef getMachOX86RelocationKindName(Edge::Kind R) {

diff  --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
index f8eb1dcfce41..161a30e44616 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
@@ -34,16 +34,12 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext {
   ~ObjectLinkingLayerJITLinkContext() {
     // If there is an object buffer return function then use it to
     // return ownership of the buffer.
-    if (Layer.ReturnObjectBuffer)
+    if (Layer.ReturnObjectBuffer && ObjBuffer)
       Layer.ReturnObjectBuffer(std::move(ObjBuffer));
   }
 
   JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
 
-  MemoryBufferRef getObjectBuffer() const override {
-    return ObjBuffer->getMemBufferRef();
-  }
-
   void notifyFailed(Error Err) override {
     for (auto &P : Layer.Plugins)
       Err = joinErrors(std::move(Err), P->notifyFailed(*MR));
@@ -463,8 +459,19 @@ ObjectLinkingLayer::~ObjectLinkingLayer() {
 void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
                               std::unique_ptr<MemoryBuffer> O) {
   assert(O && "Object must not be null");
-  jitLink(std::make_unique<ObjectLinkingLayerJITLinkContext>(
-      *this, std::move(R), std::move(O)));
+  auto ObjBuffer = O->getMemBufferRef();
+  auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
+      *this, std::move(R), std::move(O));
+  if (auto G = createLinkGraphFromObject(std::move(ObjBuffer)))
+    link(std::move(*G), std::move(Ctx));
+  else
+    Ctx->notifyFailed(G.takeError());
+}
+
+void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
+                              std::unique_ptr<LinkGraph> G) {
+  link(std::move(G), std::make_unique<ObjectLinkingLayerJITLinkContext>(
+                         *this, std::move(R), nullptr));
 }
 
 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,

diff  --git a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
index 0c2d1b63ad4d..360bc8811f1e 100644
--- a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
+++ b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp
@@ -20,8 +20,9 @@ static auto RWFlags =
 
 TEST(LinkGraphTest, Construction) {
   // Check that LinkGraph construction works as expected.
-  LinkGraph G("foo", 8, support::little);
+  LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little);
   EXPECT_EQ(G.getName(), "foo");
+  EXPECT_EQ(G.getTargetTriple().str(), "x86_64-apple-darwin");
   EXPECT_EQ(G.getPointerSize(), 8U);
   EXPECT_EQ(G.getEndianness(), support::little);
   EXPECT_TRUE(llvm::empty(G.external_symbols()));
@@ -38,7 +39,7 @@ TEST(LinkGraphTest, BlockAndSymbolIteration) {
                                     0x1C, 0x1D, 0x1E, 0x1F, 0x00};
   StringRef BlockContent(BlockContentBytes);
 
-  LinkGraph G("foo", 8, support::little);
+  LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little);
   auto &Sec1 = G.createSection("__data.1", RWFlags);
   auto &B1 = G.createContentBlock(Sec1, BlockContent, 0x1000, 8, 0);
   auto &B2 = G.createContentBlock(Sec1, BlockContent, 0x2000, 8, 0);
@@ -90,7 +91,7 @@ TEST(LinkGraphTest, SplitBlock) {
                                     0x1C, 0x1D, 0x1E, 0x1F, 0x00};
   StringRef BlockContent(BlockContentBytes);
 
-  LinkGraph G("foo", 8, support::little);
+  LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little);
   auto &Sec = G.createSection("__data", RWFlags);
 
   // Create the block to split.


        


More information about the llvm-commits mailing list