[llvm] 0fda4c4 - [ORC] Add support for adding LinkGraphs directly to ObjectLinkingLayer.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Thu May 13 21:55:42 PDT 2021


Author: Lang Hames
Date: 2021-05-13T21:44:13-07:00
New Revision: 0fda4c4745b81e8a0eed2b80b0b03f33c16c2b99

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

LOG: [ORC] Add support for adding LinkGraphs directly to ObjectLinkingLayer.

This is separate from (but builds on) the support added in ec6b71df70a for
emitting LinkGraphs in the context of an active materialization. This commit
makes LinkGraphs a first-class data structure with features equivalent to
object files within ObjectLinkingLayer.

Added: 
    llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp

Modified: 
    llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
    llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
    llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
index e26c5089991c1..55d0634a82ae5 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
@@ -129,6 +129,17 @@ class ObjectLinkingLayer : public RTTIExtends<ObjectLinkingLayer, ObjectLayer>,
     return *this;
   }
 
+  /// Add a LinkGraph to the JITDylib targeted by the given tracker.
+  Error add(ResourceTrackerSP, std::unique_ptr<jitlink::LinkGraph> G);
+
+  /// Add a LinkGraph to the given JITDylib.
+  Error add(JITDylib &JD, std::unique_ptr<jitlink::LinkGraph> G) {
+    return add(JD.getDefaultResourceTracker(), std::move(G));
+  }
+
+  // Un-hide ObjectLayer add methods.
+  using ObjectLayer::add;
+
   /// Emit an object file.
   void emit(std::unique_ptr<MaterializationResponsibility> R,
             std::unique_ptr<MemoryBuffer> O) override;

diff  --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
index ccac4b8c545b4..44dc45f93f297 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
@@ -21,6 +21,101 @@ using namespace llvm;
 using namespace llvm::jitlink;
 using namespace llvm::orc;
 
+namespace {
+
+class LinkGraphMaterializationUnit : public MaterializationUnit {
+private:
+  struct LinkGraphInterface {
+    SymbolFlagsMap SymbolFlags;
+    SymbolStringPtr InitSymbol;
+  };
+
+public:
+  static std::unique_ptr<LinkGraphMaterializationUnit>
+  Create(ObjectLinkingLayer &ObjLinkingLayer, std::unique_ptr<LinkGraph> G) {
+    auto LGI = scanLinkGraph(ObjLinkingLayer.getExecutionSession(), *G);
+    return std::unique_ptr<LinkGraphMaterializationUnit>(
+        new LinkGraphMaterializationUnit(ObjLinkingLayer, std::move(G),
+                                         std::move(LGI)));
+  }
+
+  StringRef getName() const override { return G->getName(); }
+  void materialize(std::unique_ptr<MaterializationResponsibility> MR) override {
+    ObjLinkingLayer.emit(std::move(MR), std::move(G));
+  }
+
+private:
+  static LinkGraphInterface scanLinkGraph(ExecutionSession &ES, LinkGraph &G) {
+
+    LinkGraphInterface LGI;
+
+    for (auto *Sym : G.defined_symbols()) {
+      // Skip local symbols.
+      if (Sym->getScope() == Scope::Local)
+        continue;
+      assert(Sym->hasName() && "Anonymous non-local symbol?");
+
+      JITSymbolFlags Flags;
+      if (Sym->getScope() == Scope::Default)
+        Flags |= JITSymbolFlags::Exported;
+
+      if (Sym->isCallable())
+        Flags |= JITSymbolFlags::Callable;
+
+      LGI.SymbolFlags[ES.intern(Sym->getName())] = Flags;
+    }
+
+    if (G.getTargetTriple().isOSBinFormatMachO())
+      if (hasMachOInitSection(G))
+        LGI.InitSymbol = makeInitSymbol(ES, G);
+
+    return LGI;
+  }
+
+  static bool hasMachOInitSection(LinkGraph &G) {
+    for (auto &Sec : G.sections())
+      if (Sec.getName() == "__DATA,__obj_selrefs" ||
+          Sec.getName() == "__DATA,__objc_classlist" ||
+          Sec.getName() == "__TEXT,__swift5_protos" ||
+          Sec.getName() == "__TEXT,__swift5_proto" ||
+          Sec.getName() == "__DATA,__mod_init_func")
+        return true;
+    return false;
+  }
+
+  static SymbolStringPtr makeInitSymbol(ExecutionSession &ES, LinkGraph &G) {
+    std::string InitSymString;
+    raw_string_ostream(InitSymString)
+        << "$." << G.getName() << ".__inits" << Counter++;
+    return ES.intern(InitSymString);
+  }
+
+  LinkGraphMaterializationUnit(ObjectLinkingLayer &ObjLinkingLayer,
+                               std::unique_ptr<LinkGraph> G,
+                               LinkGraphInterface LGI)
+      : MaterializationUnit(std::move(LGI.SymbolFlags),
+                            std::move(LGI.InitSymbol)),
+        ObjLinkingLayer(ObjLinkingLayer), G(std::move(G)) {}
+
+  void discard(const JITDylib &JD, const SymbolStringPtr &Name) override {
+    for (auto *Sym : G->defined_symbols())
+      if (Sym->getName() == *Name) {
+        assert(Sym->getLinkage() == Linkage::Weak &&
+               "Discarding non-weak definition");
+        G->makeExternal(*Sym);
+        break;
+      }
+  }
+
+  ObjectLinkingLayer &ObjLinkingLayer;
+  std::unique_ptr<LinkGraph> G;
+  static std::atomic<uint64_t> Counter;
+};
+
+std::atomic<uint64_t> LinkGraphMaterializationUnit::Counter{0};
+
+} // end anonymous namespace
+
 namespace llvm {
 namespace orc {
 
@@ -487,6 +582,13 @@ ObjectLinkingLayer::~ObjectLinkingLayer() {
   getExecutionSession().deregisterResourceManager(*this);
 }
 
+Error ObjectLinkingLayer::add(ResourceTrackerSP RT,
+                              std::unique_ptr<LinkGraph> G) {
+  auto &JD = RT->getJITDylib();
+  return JD.define(LinkGraphMaterializationUnit::Create(*this, std::move(G)),
+                   std::move(RT));
+}
+
 void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
                               std::unique_ptr<MemoryBuffer> O) {
   assert(O && "Object must not be null");

diff  --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
index 48421058a6eb8..ee0e904c52078 100644
--- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -18,6 +18,7 @@ add_llvm_unittest(OrcJITTests
   IndirectionUtilsTest.cpp
   JITTargetMachineBuilderTest.cpp
   LazyCallThroughAndReexportsTest.cpp
+  ObjectLinkingLayerTest.cpp
   OrcCAPITest.cpp
   OrcTestCommon.cpp
   QueueChannel.cpp

diff  --git a/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
new file mode 100644
index 0000000000000..a628b86b9c5b4
--- /dev/null
+++ b/llvm/unittests/ExecutionEngine/Orc/ObjectLinkingLayerTest.cpp
@@ -0,0 +1,59 @@
+//===-------- ObjectLinkingLayerTest.cpp - ObjectLinkingLayer tests -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
+#include "llvm/ExecutionEngine/JITLink/x86_64.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::jitlink;
+using namespace llvm::orc;
+
+namespace {
+
+auto RWFlags =
+    sys::Memory::ProtectionFlags(sys::Memory::MF_READ | sys::Memory::MF_WRITE);
+
+const char BlockContentBytes[] = {0x01, 0x02, 0x03, 0x04,
+                                  0x05, 0x06, 0x07, 0x08};
+
+ArrayRef<char> BlockContent(BlockContentBytes);
+
+class ObjectLinkingLayerTest : public testing::Test {
+public:
+  ~ObjectLinkingLayerTest() {
+    if (auto Err = ES.endSession())
+      ES.reportError(std::move(Err));
+  }
+
+protected:
+  ExecutionSession ES;
+  JITDylib &JD = ES.createBareJITDylib("main");
+  ObjectLinkingLayer ObjLinkingLayer{
+      ES, std::make_unique<InProcessMemoryManager>()};
+};
+
+TEST_F(ObjectLinkingLayerTest, AddLinkGraph) {
+  auto G =
+      std::make_unique<LinkGraph>("foo", Triple("x86_64-apple-darwin"), 8,
+                                  support::little, x86_64::getEdgeKindName);
+
+  auto &Sec1 = G->createSection("__data", RWFlags);
+  auto &B1 = G->createContentBlock(Sec1, BlockContent, 0x1000, 8, 0);
+  G->addDefinedSymbol(B1, 4, "_X", 4, Linkage::Strong, Scope::Default, false,
+                      false);
+
+  EXPECT_THAT_ERROR(ObjLinkingLayer.add(JD, std::move(G)), Succeeded());
+
+  EXPECT_THAT_EXPECTED(ES.lookup(&JD, "_X"), Succeeded());
+}
+
+} // end anonymous namespace


        


More information about the llvm-commits mailing list