Skip to content

Commit b3d2548

Browse files
authored
[ORC] Introduce LinkGraphLayer interface and LinkGraphLinkingLayer. (#120182)
Introduces a new layer interface, LinkGraphLayer, that can be used to add LinkGraphs to an ExecutionSession. This patch moves most of ObjectLinkingLayer's functionality into a new LinkGraphLinkingLayer which should (in the future) be able to be used without linking libObject. ObjectLinkingLayer now inherits from LinkGraphLinkingLayer and just handles conversion of object files to LinkGraphs, which are then handed down to LinkGraphLinkingLayer to be linked.
1 parent e83afbe commit b3d2548

File tree

8 files changed

+1122
-913
lines changed

8 files changed

+1122
-913
lines changed

llvm/include/llvm/ExecutionEngine/Orc/COFFPlatform.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
2323

2424
#include <future>
25+
#include <list>
2526
#include <memory>
2627
#include <thread>
2728
#include <vector>
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//===- LinkGraphLayer.h - Add LinkGraphs to an ExecutionSession -*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// LinkGraphLayer and associated utilities.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLAYER_H
14+
#define LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLAYER_H
15+
16+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
17+
#include "llvm/ExecutionEngine/Orc/Core.h"
18+
#include "llvm/Support/Error.h"
19+
#include "llvm/Support/MemoryBuffer.h"
20+
21+
#include <atomic>
22+
#include <memory>
23+
24+
namespace llvm::orc {
25+
26+
class LinkGraphLayer {
27+
public:
28+
LinkGraphLayer(ExecutionSession &ES) : ES(ES) {}
29+
30+
virtual ~LinkGraphLayer();
31+
32+
ExecutionSession &getExecutionSession() { return ES; }
33+
34+
/// Adds a LinkGraph to the JITDylib for the given ResourceTracker.
35+
virtual Error add(ResourceTrackerSP RT, std::unique_ptr<jitlink::LinkGraph> G,
36+
MaterializationUnit::Interface I);
37+
38+
/// Adds a LinkGraph to the JITDylib for the given ResourceTracker. The
39+
/// interface for the graph will be built using getLinkGraphInterface.
40+
Error add(ResourceTrackerSP RT, std::unique_ptr<jitlink::LinkGraph> G) {
41+
auto LGI = getInterface(*G);
42+
return add(std::move(RT), std::move(G), std::move(LGI));
43+
}
44+
45+
/// Adds a LinkGraph to the given JITDylib.
46+
Error add(JITDylib &JD, std::unique_ptr<jitlink::LinkGraph> G,
47+
MaterializationUnit::Interface I) {
48+
return add(JD.getDefaultResourceTracker(), std::move(G), std::move(I));
49+
}
50+
51+
/// Adds a LinkGraph to the given JITDylib. The interface for the object will
52+
/// be built using getLinkGraphInterface.
53+
Error add(JITDylib &JD, std::unique_ptr<jitlink::LinkGraph> G) {
54+
return add(JD.getDefaultResourceTracker(), std::move(G));
55+
}
56+
57+
/// Emit should materialize the given IR.
58+
virtual void emit(std::unique_ptr<MaterializationResponsibility> R,
59+
std::unique_ptr<jitlink::LinkGraph> G) = 0;
60+
61+
/// Get the interface for the given LinkGraph.
62+
MaterializationUnit::Interface getInterface(jitlink::LinkGraph &G);
63+
64+
/// Get the JITSymbolFlags for the given symbol.
65+
static JITSymbolFlags getJITSymbolFlagsForSymbol(jitlink::Symbol &Sym);
66+
67+
private:
68+
ExecutionSession &ES;
69+
std::atomic<uint64_t> Counter{0};
70+
};
71+
72+
/// MaterializationUnit for wrapping LinkGraphs.
73+
class LinkGraphMaterializationUnit : public MaterializationUnit {
74+
public:
75+
LinkGraphMaterializationUnit(LinkGraphLayer &LGLayer,
76+
std::unique_ptr<jitlink::LinkGraph> G,
77+
Interface I)
78+
: MaterializationUnit(I), LGLayer(LGLayer), G(std::move(G)) {}
79+
80+
LinkGraphMaterializationUnit(LinkGraphLayer &LGLayer,
81+
std::unique_ptr<jitlink::LinkGraph> G)
82+
: MaterializationUnit(LGLayer.getInterface(*G)), LGLayer(LGLayer),
83+
G(std::move(G)) {}
84+
85+
StringRef getName() const override;
86+
87+
void materialize(std::unique_ptr<MaterializationResponsibility> MR) override {
88+
LGLayer.emit(std::move(MR), std::move(G));
89+
}
90+
91+
private:
92+
void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
93+
94+
LinkGraphLayer &LGLayer;
95+
std::unique_ptr<jitlink::LinkGraph> G;
96+
};
97+
98+
inline Error LinkGraphLayer::add(ResourceTrackerSP RT,
99+
std::unique_ptr<jitlink::LinkGraph> G,
100+
MaterializationUnit::Interface I) {
101+
auto &JD = RT->getJITDylib();
102+
103+
return JD.define(std::make_unique<LinkGraphMaterializationUnit>(
104+
*this, std::move(G), std::move(I)),
105+
std::move(RT));
106+
}
107+
108+
} // end namespace llvm::orc
109+
110+
#endif // LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLAYER_H
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
//===-- LinkGraphLinkingLayer.h - Link LinkGraphs with JITLink --*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// LinkGraphLinkingLayer and associated utilities.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLINKINGLAYER_H
14+
#define LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLINKINGLAYER_H
15+
16+
#include "llvm/ADT/STLExtras.h"
17+
#include "llvm/ADT/StringRef.h"
18+
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
19+
#include "llvm/ExecutionEngine/Orc/Core.h"
20+
#include "llvm/ExecutionEngine/Orc/Layer.h"
21+
#include "llvm/ExecutionEngine/Orc/LinkGraphLayer.h"
22+
#include "llvm/Support/Error.h"
23+
#include <algorithm>
24+
#include <cassert>
25+
#include <functional>
26+
#include <memory>
27+
#include <mutex>
28+
#include <utility>
29+
#include <vector>
30+
31+
namespace llvm {
32+
33+
namespace jitlink {
34+
class EHFrameRegistrar;
35+
} // namespace jitlink
36+
37+
namespace orc {
38+
39+
/// LinkGraphLinkingLayer links LinkGraphs into the Executor using JITLink.
40+
///
41+
/// Clients can use this class to add LinkGraphs to an ExecutionSession, and it
42+
/// serves as a base for the ObjectLinkingLayer that can link object files.
43+
class LinkGraphLinkingLayer : public LinkGraphLayer, private ResourceManager {
44+
class JITLinkCtx;
45+
46+
public:
47+
/// Plugin instances can be added to the ObjectLinkingLayer to receive
48+
/// callbacks when code is loaded or emitted, and when JITLink is being
49+
/// configured.
50+
class Plugin {
51+
public:
52+
virtual ~Plugin();
53+
virtual void modifyPassConfig(MaterializationResponsibility &MR,
54+
jitlink::LinkGraph &G,
55+
jitlink::PassConfiguration &Config) {}
56+
57+
// Deprecated. Don't use this in new code. There will be a proper mechanism
58+
// for capturing object buffers.
59+
virtual void notifyMaterializing(MaterializationResponsibility &MR,
60+
jitlink::LinkGraph &G,
61+
jitlink::JITLinkContext &Ctx,
62+
MemoryBufferRef InputObject) {}
63+
64+
virtual void notifyLoaded(MaterializationResponsibility &MR) {}
65+
virtual Error notifyEmitted(MaterializationResponsibility &MR) {
66+
return Error::success();
67+
}
68+
virtual Error notifyFailed(MaterializationResponsibility &MR) = 0;
69+
virtual Error notifyRemovingResources(JITDylib &JD, ResourceKey K) = 0;
70+
virtual void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
71+
ResourceKey SrcKey) = 0;
72+
};
73+
74+
/// Construct a LinkGraphLinkingLayer using the ExecutorProcessControl
75+
/// instance's memory manager.
76+
LinkGraphLinkingLayer(ExecutionSession &ES);
77+
78+
/// Construct a LinkGraphLinkingLayer using a custom memory manager.
79+
LinkGraphLinkingLayer(ExecutionSession &ES,
80+
jitlink::JITLinkMemoryManager &MemMgr);
81+
82+
/// Construct an LinkGraphLinkingLayer. Takes ownership of the given
83+
/// JITLinkMemoryManager. This method is a temporary hack to simplify
84+
/// co-existence with RTDyldObjectLinkingLayer (which also owns its
85+
/// allocators).
86+
LinkGraphLinkingLayer(ExecutionSession &ES,
87+
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr);
88+
89+
/// Destroy the LinkGraphLinkingLayer.
90+
~LinkGraphLinkingLayer();
91+
92+
/// Add a plugin.
93+
LinkGraphLinkingLayer &addPlugin(std::shared_ptr<Plugin> P) {
94+
std::lock_guard<std::mutex> Lock(LayerMutex);
95+
Plugins.push_back(std::move(P));
96+
return *this;
97+
}
98+
99+
/// Remove a plugin. This remove applies only to subsequent links (links
100+
/// already underway will continue to use the plugin), and does not of itself
101+
/// destroy the plugin -- destruction will happen once all shared pointers
102+
/// (including those held by in-progress links) are destroyed.
103+
void removePlugin(Plugin &P) {
104+
std::lock_guard<std::mutex> Lock(LayerMutex);
105+
auto I = llvm::find_if(Plugins, [&](const std::shared_ptr<Plugin> &Elem) {
106+
return Elem.get() == &P;
107+
});
108+
assert(I != Plugins.end() && "Plugin not present");
109+
Plugins.erase(I);
110+
}
111+
112+
/// Emit a LinkGraph.
113+
void emit(std::unique_ptr<MaterializationResponsibility> R,
114+
std::unique_ptr<jitlink::LinkGraph> G) override;
115+
116+
/// Instructs this LinkgraphLinkingLayer instance to override the symbol flags
117+
/// found in the LinkGraph with the flags supplied by the
118+
/// MaterializationResponsibility instance. This is a workaround to support
119+
/// symbol visibility in COFF, which does not use the libObject's
120+
/// SF_Exported flag. Use only when generating / adding COFF object files.
121+
///
122+
/// FIXME: We should be able to remove this if/when COFF properly tracks
123+
/// exported symbols.
124+
LinkGraphLinkingLayer &
125+
setOverrideObjectFlagsWithResponsibilityFlags(bool OverrideObjectFlags) {
126+
this->OverrideObjectFlags = OverrideObjectFlags;
127+
return *this;
128+
}
129+
130+
/// If set, this LinkGraphLinkingLayer instance will claim responsibility
131+
/// for any symbols provided by a given object file that were not already in
132+
/// the MaterializationResponsibility instance. Setting this flag allows
133+
/// higher-level program representations (e.g. LLVM IR) to be added based on
134+
/// only a subset of the symbols they provide, without having to write
135+
/// intervening layers to scan and add the additional symbols. This trades
136+
/// diagnostic quality for convenience however: If all symbols are enumerated
137+
/// up-front then clashes can be detected and reported early (and usually
138+
/// deterministically). If this option is set, clashes for the additional
139+
/// symbols may not be detected until late, and detection may depend on
140+
/// the flow of control through JIT'd code. Use with care.
141+
LinkGraphLinkingLayer &
142+
setAutoClaimResponsibilityForObjectSymbols(bool AutoClaimObjectSymbols) {
143+
this->AutoClaimObjectSymbols = AutoClaimObjectSymbols;
144+
return *this;
145+
}
146+
147+
protected:
148+
/// Emit a LinkGraph with the given backing buffer.
149+
///
150+
/// This overload is intended for use by ObjectLinkingLayer.
151+
void emit(std::unique_ptr<MaterializationResponsibility> R,
152+
std::unique_ptr<jitlink::LinkGraph> G,
153+
std::unique_ptr<MemoryBuffer> ObjBuf);
154+
155+
std::function<void(std::unique_ptr<MemoryBuffer>)> ReturnObjectBuffer;
156+
157+
private:
158+
using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
159+
160+
Error recordFinalizedAlloc(MaterializationResponsibility &MR,
161+
FinalizedAlloc FA);
162+
163+
Error handleRemoveResources(JITDylib &JD, ResourceKey K) override;
164+
void handleTransferResources(JITDylib &JD, ResourceKey DstKey,
165+
ResourceKey SrcKey) override;
166+
167+
mutable std::mutex LayerMutex;
168+
jitlink::JITLinkMemoryManager &MemMgr;
169+
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgrOwnership;
170+
bool OverrideObjectFlags = false;
171+
bool AutoClaimObjectSymbols = false;
172+
DenseMap<ResourceKey, std::vector<FinalizedAlloc>> Allocs;
173+
std::vector<std::shared_ptr<Plugin>> Plugins;
174+
};
175+
176+
class EHFrameRegistrationPlugin : public LinkGraphLinkingLayer::Plugin {
177+
public:
178+
EHFrameRegistrationPlugin(
179+
ExecutionSession &ES,
180+
std::unique_ptr<jitlink::EHFrameRegistrar> Registrar);
181+
void modifyPassConfig(MaterializationResponsibility &MR,
182+
jitlink::LinkGraph &G,
183+
jitlink::PassConfiguration &PassConfig) override;
184+
Error notifyEmitted(MaterializationResponsibility &MR) override;
185+
Error notifyFailed(MaterializationResponsibility &MR) override;
186+
Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override;
187+
void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
188+
ResourceKey SrcKey) override;
189+
190+
private:
191+
std::mutex EHFramePluginMutex;
192+
ExecutionSession &ES;
193+
std::unique_ptr<jitlink::EHFrameRegistrar> Registrar;
194+
DenseMap<MaterializationResponsibility *, ExecutorAddrRange> InProcessLinks;
195+
DenseMap<ResourceKey, std::vector<ExecutorAddrRange>> EHFrameRanges;
196+
};
197+
198+
} // end namespace orc
199+
} // end namespace llvm
200+
201+
#endif // LLVM_EXECUTIONENGINE_ORC_LINKGRAPHLINKINGLAYER_H

0 commit comments

Comments
 (0)