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

This is separate from (but builds on) the support added in ec6b71df70 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.
This commit is contained in:
Lang Hames 2021-05-13 21:35:34 -07:00
parent 9099c9ef78
commit 0fda4c4745
4 changed files with 173 additions and 0 deletions

View File

@ -129,6 +129,17 @@ public:
return *this; 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. /// Emit an object file.
void emit(std::unique_ptr<MaterializationResponsibility> R, void emit(std::unique_ptr<MaterializationResponsibility> R,
std::unique_ptr<MemoryBuffer> O) override; std::unique_ptr<MemoryBuffer> O) override;

View File

@ -21,6 +21,101 @@ using namespace llvm;
using namespace llvm::jitlink; using namespace llvm::jitlink;
using namespace llvm::orc; 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 llvm {
namespace orc { namespace orc {
@ -487,6 +582,13 @@ ObjectLinkingLayer::~ObjectLinkingLayer() {
getExecutionSession().deregisterResourceManager(*this); 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, void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
std::unique_ptr<MemoryBuffer> O) { std::unique_ptr<MemoryBuffer> O) {
assert(O && "Object must not be null"); assert(O && "Object must not be null");

View File

@ -18,6 +18,7 @@ add_llvm_unittest(OrcJITTests
IndirectionUtilsTest.cpp IndirectionUtilsTest.cpp
JITTargetMachineBuilderTest.cpp JITTargetMachineBuilderTest.cpp
LazyCallThroughAndReexportsTest.cpp LazyCallThroughAndReexportsTest.cpp
ObjectLinkingLayerTest.cpp
OrcCAPITest.cpp OrcCAPITest.cpp
OrcTestCommon.cpp OrcTestCommon.cpp
QueueChannel.cpp QueueChannel.cpp

View File

@ -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