Skip to content

Commit 529c091

Browse files
committed
[ORC] Simplify JITLinkRedirectableSymbolManager, fix definition locations.
Redirectable stubs should be placed in the same JITDylib as their names, with their lifetimes managed according to the ResourceTracker used when adding them. The original implementation created a single pool of stubs in the JITDylib that is passed to the JITLinkRedirectableSymbolManager constructor, but this may cause the addresses of the redirectable symbols themselves (added to the JITDylibs passed to createRedirectableSymbols) to appear outside the address range of their defining JITDylib. This patch fixes the issue by dropping the pool and emitting a new graph for each set of requested redirectable symbols. We lose the ability to recycle stubs, but gain the ability to free them entirely. Since we don't expect stub reuse to be a common case this is likely the best trade-off. If in the future we do need to return to a stub pool we should create a separate one for each JITDylib to ensure that addresses behave as expected.
1 parent 1d657cf commit 529c091

File tree

5 files changed

+93
-219
lines changed

5 files changed

+93
-219
lines changed

llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,16 @@ class LinkGraph {
10771077
return MutableArrayRef<char>(AllocatedBuffer, SourceStr.size());
10781078
}
10791079

1080+
/// Allocate a copy of the given string using the LinkGraph's allocator
1081+
/// and return it as a StringRef.
1082+
///
1083+
/// This is a convenience wrapper around allocateContent(Twine) that is
1084+
/// handy when creating new symbol names within the graph.
1085+
StringRef allocateName(Twine Source) {
1086+
auto Buf = allocateContent(Source);
1087+
return {Buf.data(), Buf.size()};
1088+
}
1089+
10801090
/// Allocate a copy of the given string using the LinkGraph's allocator.
10811091
///
10821092
/// The allocated string will be terminated with a null character, and the

llvm/include/llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h

Lines changed: 9 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,16 @@
1717
#include "llvm/ExecutionEngine/Orc/RedirectionManager.h"
1818
#include "llvm/Support/StringSaver.h"
1919

20+
#include <atomic>
21+
2022
namespace llvm {
2123
namespace orc {
2224

23-
class JITLinkRedirectableSymbolManager : public RedirectableSymbolManager,
24-
public ResourceManager {
25+
class JITLinkRedirectableSymbolManager : public RedirectableSymbolManager {
2526
public:
2627
/// Create redirection manager that uses JITLink based implementaion.
2728
static Expected<std::unique_ptr<RedirectableSymbolManager>>
28-
Create(ObjectLinkingLayer &ObjLinkingLayer, JITDylib &JD) {
29+
Create(ObjectLinkingLayer &ObjLinkingLayer) {
2930
auto AnonymousPtrCreator(jitlink::getAnonymousPointerCreator(
3031
ObjLinkingLayer.getExecutionSession().getTargetTriple()));
3132
auto PtrJumpStubCreator(jitlink::getPointerJumpStubCreator(
@@ -35,69 +36,27 @@ class JITLinkRedirectableSymbolManager : public RedirectableSymbolManager,
3536
inconvertibleErrorCode());
3637
return std::unique_ptr<RedirectableSymbolManager>(
3738
new JITLinkRedirectableSymbolManager(
38-
ObjLinkingLayer, JD, AnonymousPtrCreator, PtrJumpStubCreator));
39+
ObjLinkingLayer, AnonymousPtrCreator, PtrJumpStubCreator));
3940
}
4041

4142
void emitRedirectableSymbols(std::unique_ptr<MaterializationResponsibility> R,
4243
const SymbolAddrMap &InitialDests) override;
4344

4445
Error redirect(JITDylib &TargetJD, const SymbolAddrMap &NewDests) override;
4546

46-
Error handleRemoveResources(JITDylib &TargetJD, ResourceKey K) override;
47-
48-
void handleTransferResources(JITDylib &TargetJD, ResourceKey DstK,
49-
ResourceKey SrcK) override;
50-
5147
private:
52-
using StubHandle = unsigned;
53-
constexpr static unsigned StubBlockSize = 256;
54-
constexpr static StringRef JumpStubPrefix = "$__IND_JUMP_STUBS";
55-
constexpr static StringRef StubPtrPrefix = "$IND_JUMP_PTR_";
56-
constexpr static StringRef JumpStubTableName = "$IND_JUMP_";
57-
constexpr static StringRef StubPtrTableName = "$__IND_JUMP_PTRS";
58-
5948
JITLinkRedirectableSymbolManager(
60-
ObjectLinkingLayer &ObjLinkingLayer, JITDylib &JD,
49+
ObjectLinkingLayer &ObjLinkingLayer,
6150
jitlink::AnonymousPointerCreator &AnonymousPtrCreator,
6251
jitlink::PointerJumpStubCreator &PtrJumpStubCreator)
63-
: ObjLinkingLayer(ObjLinkingLayer), JD(JD),
52+
: ObjLinkingLayer(ObjLinkingLayer),
6453
AnonymousPtrCreator(std::move(AnonymousPtrCreator)),
65-
PtrJumpStubCreator(std::move(PtrJumpStubCreator)) {
66-
ObjLinkingLayer.getExecutionSession().registerResourceManager(*this);
67-
}
68-
69-
~JITLinkRedirectableSymbolManager() {
70-
ObjLinkingLayer.getExecutionSession().deregisterResourceManager(*this);
71-
}
72-
73-
StringRef JumpStubSymbolName(unsigned I) {
74-
return *ObjLinkingLayer.getExecutionSession().intern(
75-
(JumpStubPrefix + Twine(I)).str());
76-
}
77-
78-
StringRef StubPtrSymbolName(unsigned I) {
79-
return *ObjLinkingLayer.getExecutionSession().intern(
80-
(StubPtrPrefix + Twine(I)).str());
81-
}
82-
83-
unsigned GetNumAvailableStubs() const { return AvailableStubs.size(); }
84-
85-
Error redirectInner(JITDylib &TargetJD, const SymbolAddrMap &NewDests);
86-
Error grow(unsigned Need);
54+
PtrJumpStubCreator(std::move(PtrJumpStubCreator)) {}
8755

8856
ObjectLinkingLayer &ObjLinkingLayer;
89-
JITDylib &JD;
9057
jitlink::AnonymousPointerCreator AnonymousPtrCreator;
9158
jitlink::PointerJumpStubCreator PtrJumpStubCreator;
92-
93-
std::vector<StubHandle> AvailableStubs;
94-
using SymbolToStubMap = DenseMap<SymbolStringPtr, StubHandle>;
95-
DenseMap<JITDylib *, SymbolToStubMap> SymbolToStubs;
96-
std::vector<ExecutorSymbolDef> JumpStubs;
97-
std::vector<ExecutorSymbolDef> StubPointers;
98-
DenseMap<ResourceKey, std::vector<SymbolStringPtr>> TrackedResources;
99-
100-
std::mutex Mutex;
59+
std::atomic_size_t StubGraphIdx{0};
10160
};
10261

10362
} // namespace orc

llvm/lib/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.cpp

Lines changed: 58 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -9,171 +9,88 @@
99
#include "llvm/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.h"
1010
#include "llvm/ExecutionEngine/Orc/Core.h"
1111

12+
#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
13+
1214
#define DEBUG_TYPE "orc"
1315

1416
using namespace llvm;
1517
using namespace llvm::orc;
1618

19+
namespace {
20+
constexpr StringRef JumpStubSectionName = "__orc_stubs";
21+
constexpr StringRef StubPtrSectionName = "__orc_stub_ptrs";
22+
constexpr StringRef StubSuffix = "$__stub_ptr";
23+
} // namespace
24+
1725
void JITLinkRedirectableSymbolManager::emitRedirectableSymbols(
1826
std::unique_ptr<MaterializationResponsibility> R,
1927
const SymbolAddrMap &InitialDests) {
20-
auto &ES = ObjLinkingLayer.getExecutionSession();
21-
std::unique_lock<std::mutex> Lock(Mutex);
22-
if (GetNumAvailableStubs() < InitialDests.size())
23-
if (auto Err = grow(InitialDests.size() - GetNumAvailableStubs())) {
24-
ES.reportError(std::move(Err));
25-
R->failMaterialization();
26-
return;
27-
}
2828

29-
JITDylib &TargetJD = R->getTargetJITDylib();
30-
SymbolMap NewSymbolDefs;
31-
std::vector<SymbolStringPtr> Symbols;
32-
for (auto &[K, V] : InitialDests) {
33-
StubHandle StubID = AvailableStubs.back();
34-
if (SymbolToStubs[&TargetJD].count(K)) {
35-
ES.reportError(make_error<StringError>(
36-
"Tried to create duplicate redirectable symbols",
37-
inconvertibleErrorCode()));
38-
R->failMaterialization();
39-
return;
40-
}
41-
SymbolToStubs[&TargetJD][K] = StubID;
42-
NewSymbolDefs[K] = JumpStubs[StubID];
43-
NewSymbolDefs[K].setFlags(V.getFlags());
44-
Symbols.push_back(K);
45-
AvailableStubs.pop_back();
46-
}
29+
auto &ES = ObjLinkingLayer.getExecutionSession();
30+
Triple TT = ES.getTargetTriple();
4731

48-
// FIXME: when this fails we can return stubs to the pool
49-
if (auto Err = redirectInner(TargetJD, InitialDests)) {
50-
ES.reportError(std::move(Err));
51-
R->failMaterialization();
52-
return;
32+
auto G = std::make_unique<jitlink::LinkGraph>(
33+
("<INDIRECT STUBS #" + Twine(++StubGraphIdx) + ">").str(), TT,
34+
TT.isArch64Bit() ? 8 : 4,
35+
TT.isLittleEndian() ? endianness::little : endianness::big,
36+
jitlink::getGenericEdgeKindName);
37+
auto &PointerSection =
38+
G->createSection(StubPtrSectionName, MemProt::Write | MemProt::Read);
39+
auto &StubsSection =
40+
G->createSection(JumpStubSectionName, MemProt::Exec | MemProt::Read);
41+
42+
SymbolFlagsMap NewSymbols;
43+
for (auto &[Name, Def] : InitialDests) {
44+
jitlink::Symbol *TargetSym = nullptr;
45+
if (Def.getAddress())
46+
TargetSym = &G->addAbsoluteSymbol(
47+
G->allocateName(*Name + "$__init_tgt"), Def.getAddress(), 0,
48+
jitlink::Linkage::Strong, jitlink::Scope::Local, false);
49+
50+
auto PtrName = ES.intern((*Name + StubSuffix).str());
51+
auto &Ptr = AnonymousPtrCreator(*G, PointerSection, TargetSym, 0);
52+
Ptr.setName(*PtrName);
53+
Ptr.setScope(jitlink::Scope::Hidden);
54+
auto &Stub = PtrJumpStubCreator(*G, StubsSection, Ptr);
55+
Stub.setName(*Name);
56+
Stub.setScope(jitlink::Scope::Default);
57+
NewSymbols[std::move(PtrName)] = JITSymbolFlags();
5358
}
5459

55-
// FIXME: return stubs to the pool here too.
56-
if (auto Err = R->replace(absoluteSymbols(NewSymbolDefs))) {
60+
// Try to claim responsibility for the new stub symbols.
61+
if (auto Err = R->defineMaterializing(std::move(NewSymbols))) {
5762
ES.reportError(std::move(Err));
58-
R->failMaterialization();
59-
return;
63+
return R->failMaterialization();
6064
}
6165

62-
// FIXME: return stubs to the pool here too.
63-
if (auto Err = R->withResourceKeyDo([&](ResourceKey Key) {
64-
TrackedResources[Key].insert(TrackedResources[Key].end(),
65-
Symbols.begin(), Symbols.end());
66-
})) {
67-
ES.reportError(std::move(Err));
68-
R->failMaterialization();
69-
return;
70-
}
66+
ObjLinkingLayer.emit(std::move(R), std::move(G));
7167
}
7268

7369
Error JITLinkRedirectableSymbolManager::redirect(
7470
JITDylib &TargetJD, const SymbolAddrMap &NewDests) {
75-
std::unique_lock<std::mutex> Lock(Mutex);
76-
return redirectInner(TargetJD, NewDests);
77-
}
71+
auto &ES = ObjLinkingLayer.getExecutionSession();
72+
SymbolLookupSet LS;
73+
DenseMap<NonOwningSymbolStringPtr, SymbolStringPtr> PtrToStub;
74+
for (auto &[StubName, Sym] : NewDests) {
75+
auto PtrName = ES.intern((*StubName + StubSuffix).str());
76+
PtrToStub[NonOwningSymbolStringPtr(PtrName)] = StubName;
77+
LS.add(std::move(PtrName));
78+
}
79+
auto PtrSyms = ES.lookup({{&TargetJD, JITDylibLookupFlags::MatchAllSymbols}},
80+
std::move(LS));
81+
if (!PtrSyms)
82+
return PtrSyms.takeError();
7883

79-
Error JITLinkRedirectableSymbolManager::redirectInner(
80-
JITDylib &TargetJD, const SymbolAddrMap &NewDests) {
8184
std::vector<tpctypes::PointerWrite> PtrWrites;
82-
for (auto &[K, V] : NewDests) {
83-
if (!SymbolToStubs[&TargetJD].count(K))
84-
return make_error<StringError>(
85-
"Tried to redirect non-existent redirectalbe symbol",
86-
inconvertibleErrorCode());
87-
StubHandle StubID = SymbolToStubs[&TargetJD].at(K);
88-
PtrWrites.push_back({StubPointers[StubID].getAddress(), V.getAddress()});
85+
for (auto &[PtrName, PtrSym] : *PtrSyms) {
86+
auto DestSymI = NewDests.find(PtrToStub[NonOwningSymbolStringPtr(PtrName)]);
87+
assert(DestSymI != NewDests.end() && "Bad ptr -> stub mapping");
88+
auto &DestSym = DestSymI->second;
89+
PtrWrites.push_back({PtrSym.getAddress(), DestSym.getAddress()});
8990
}
91+
9092
return ObjLinkingLayer.getExecutionSession()
9193
.getExecutorProcessControl()
9294
.getMemoryAccess()
9395
.writePointers(PtrWrites);
9496
}
95-
96-
Error JITLinkRedirectableSymbolManager::grow(unsigned Need) {
97-
unsigned OldSize = JumpStubs.size();
98-
unsigned NumNewStubs = alignTo(Need, StubBlockSize);
99-
unsigned NewSize = OldSize + NumNewStubs;
100-
101-
JumpStubs.resize(NewSize);
102-
StubPointers.resize(NewSize);
103-
AvailableStubs.reserve(NewSize);
104-
105-
SymbolLookupSet LookupSymbols;
106-
DenseMap<SymbolStringPtr, ExecutorSymbolDef *> NewDefsMap;
107-
108-
auto &ES = ObjLinkingLayer.getExecutionSession();
109-
Triple TT = ES.getTargetTriple();
110-
auto G = std::make_unique<jitlink::LinkGraph>(
111-
"<INDIRECT STUBS>", TT, TT.isArch64Bit() ? 8 : 4,
112-
TT.isLittleEndian() ? endianness::little : endianness::big,
113-
jitlink::getGenericEdgeKindName);
114-
auto &PointerSection =
115-
G->createSection(StubPtrTableName, MemProt::Write | MemProt::Read);
116-
auto &StubsSection =
117-
G->createSection(JumpStubTableName, MemProt::Exec | MemProt::Read);
118-
119-
// FIXME: We can batch the stubs into one block and use address to access them
120-
for (size_t I = OldSize; I < NewSize; I++) {
121-
auto &Pointer = AnonymousPtrCreator(*G, PointerSection, nullptr, 0);
122-
123-
StringRef PtrSymName = StubPtrSymbolName(I);
124-
Pointer.setName(PtrSymName);
125-
Pointer.setScope(jitlink::Scope::Default);
126-
LookupSymbols.add(ES.intern(PtrSymName));
127-
NewDefsMap[ES.intern(PtrSymName)] = &StubPointers[I];
128-
129-
auto &Stub = PtrJumpStubCreator(*G, StubsSection, Pointer);
130-
131-
StringRef JumpStubSymName = JumpStubSymbolName(I);
132-
Stub.setName(JumpStubSymName);
133-
Stub.setScope(jitlink::Scope::Default);
134-
LookupSymbols.add(ES.intern(JumpStubSymName));
135-
NewDefsMap[ES.intern(JumpStubSymName)] = &JumpStubs[I];
136-
}
137-
138-
if (auto Err = ObjLinkingLayer.add(JD, std::move(G)))
139-
return Err;
140-
141-
auto LookupResult = ES.lookup(makeJITDylibSearchOrder(&JD), LookupSymbols);
142-
if (auto Err = LookupResult.takeError())
143-
return Err;
144-
145-
for (auto &[K, V] : *LookupResult)
146-
*NewDefsMap.at(K) = V;
147-
148-
for (size_t I = OldSize; I < NewSize; I++)
149-
AvailableStubs.push_back(I);
150-
151-
return Error::success();
152-
}
153-
154-
Error JITLinkRedirectableSymbolManager::handleRemoveResources(
155-
JITDylib &TargetJD, ResourceKey K) {
156-
std::unique_lock<std::mutex> Lock(Mutex);
157-
for (auto &Symbol : TrackedResources[K]) {
158-
if (!SymbolToStubs[&TargetJD].count(Symbol))
159-
return make_error<StringError>(
160-
"Tried to remove non-existent redirectable symbol",
161-
inconvertibleErrorCode());
162-
AvailableStubs.push_back(SymbolToStubs[&TargetJD].at(Symbol));
163-
SymbolToStubs[&TargetJD].erase(Symbol);
164-
if (SymbolToStubs[&TargetJD].empty())
165-
SymbolToStubs.erase(&TargetJD);
166-
}
167-
TrackedResources.erase(K);
168-
169-
return Error::success();
170-
}
171-
172-
void JITLinkRedirectableSymbolManager::handleTransferResources(
173-
JITDylib &TargetJD, ResourceKey DstK, ResourceKey SrcK) {
174-
std::unique_lock<std::mutex> Lock(Mutex);
175-
TrackedResources[DstK].insert(TrackedResources[DstK].end(),
176-
TrackedResources[SrcK].begin(),
177-
TrackedResources[SrcK].end());
178-
TrackedResources.erase(SrcK);
179-
}

0 commit comments

Comments
 (0)