LLVM  10.0.0svn
ObjectLinkingLayer.cpp
Go to the documentation of this file.
1 //===------- ObjectLinkingLayer.cpp - JITLink backed ORC ObjectLayer ------===//
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 
10 
11 #include "llvm/ADT/Optional.h"
13 
14 #include <vector>
15 
16 #define DEBUG_TYPE "orc"
17 
18 using namespace llvm;
19 using namespace llvm::jitlink;
20 using namespace llvm::orc;
21 
22 namespace llvm {
23 namespace orc {
24 
26 public:
29  std::unique_ptr<MemoryBuffer> ObjBuffer)
30  : Layer(Layer), MR(std::move(MR)), ObjBuffer(std::move(ObjBuffer)) {}
31 
32  JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
33 
34  MemoryBufferRef getObjectBuffer() const override {
35  return ObjBuffer->getMemBufferRef();
36  }
37 
38  void notifyFailed(Error Err) override {
39  Layer.getExecutionSession().reportError(std::move(Err));
40  MR.failMaterialization();
41  }
42 
43  void lookup(const DenseSet<StringRef> &Symbols,
44  JITLinkAsyncLookupContinuation LookupContinuation) override {
45 
46  JITDylibSearchList SearchOrder;
47  MR.getTargetJITDylib().withSearchOrderDo(
48  [&](const JITDylibSearchList &JDs) { SearchOrder = JDs; });
49 
50  auto &ES = Layer.getExecutionSession();
51 
52  SymbolNameSet InternedSymbols;
53  for (auto &S : Symbols)
54  InternedSymbols.insert(ES.intern(S));
55 
56  // OnResolve -- De-intern the symbols and pass the result to the linker.
57  // FIXME: Capture LookupContinuation by move once we have c++14.
58  auto SharedLookupContinuation =
59  std::make_shared<JITLinkAsyncLookupContinuation>(
60  std::move(LookupContinuation));
61  auto OnResolve = [SharedLookupContinuation](Expected<SymbolMap> Result) {
62  if (!Result)
63  (*SharedLookupContinuation)(Result.takeError());
64  else {
66  for (auto &KV : *Result)
67  LR[*KV.first] = KV.second;
68  (*SharedLookupContinuation)(std::move(LR));
69  }
70  };
71 
72  ES.lookup(SearchOrder, std::move(InternedSymbols), SymbolState::Resolved,
73  std::move(OnResolve), [this](const SymbolDependenceMap &Deps) {
74  registerDependencies(Deps);
75  });
76  }
77 
78  void notifyResolved(AtomGraph &G) override {
79  auto &ES = Layer.getExecutionSession();
80 
81  SymbolFlagsMap ExtraSymbolsToClaim;
82  bool AutoClaim = Layer.AutoClaimObjectSymbols;
83 
84  SymbolMap InternedResult;
85  for (auto *DA : G.defined_atoms())
86  if (DA->hasName() && DA->isGlobal()) {
87  auto InternedName = ES.intern(DA->getName());
88  JITSymbolFlags Flags;
89 
90  if (DA->isExported())
91  Flags |= JITSymbolFlags::Exported;
92  if (DA->isWeak())
93  Flags |= JITSymbolFlags::Weak;
94  if (DA->isCallable())
95  Flags |= JITSymbolFlags::Callable;
96  if (DA->isCommon())
97  Flags |= JITSymbolFlags::Common;
98 
99  InternedResult[InternedName] =
100  JITEvaluatedSymbol(DA->getAddress(), Flags);
101  if (AutoClaim && !MR.getSymbols().count(InternedName)) {
102  assert(!ExtraSymbolsToClaim.count(InternedName) &&
103  "Duplicate symbol to claim?");
104  ExtraSymbolsToClaim[InternedName] = Flags;
105  }
106  }
107 
108  for (auto *A : G.absolute_atoms())
109  if (A->hasName()) {
110  auto InternedName = ES.intern(A->getName());
111  JITSymbolFlags Flags;
112  Flags |= JITSymbolFlags::Absolute;
113  if (A->isWeak())
114  Flags |= JITSymbolFlags::Weak;
115  if (A->isCallable())
116  Flags |= JITSymbolFlags::Callable;
117  InternedResult[InternedName] =
118  JITEvaluatedSymbol(A->getAddress(), Flags);
119  if (AutoClaim && !MR.getSymbols().count(InternedName)) {
120  assert(!ExtraSymbolsToClaim.count(InternedName) &&
121  "Duplicate symbol to claim?");
122  ExtraSymbolsToClaim[InternedName] = Flags;
123  }
124  }
125 
126  if (!ExtraSymbolsToClaim.empty())
127  if (auto Err = MR.defineMaterializing(ExtraSymbolsToClaim))
128  return notifyFailed(std::move(Err));
129 
130  MR.notifyResolved(InternedResult);
131 
132  Layer.notifyLoaded(MR);
133  }
134 
136  std::unique_ptr<JITLinkMemoryManager::Allocation> A) override {
137 
138  if (auto Err = Layer.notifyEmitted(MR, std::move(A))) {
139  Layer.getExecutionSession().reportError(std::move(Err));
140  MR.failMaterialization();
141 
142  return;
143  }
144  MR.notifyEmitted();
145  }
146 
148  return [this](AtomGraph &G) { return markResponsibilitySymbolsLive(G); };
149  }
150 
151  Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override {
152  // Add passes to mark duplicate defs as should-discard, and to walk the
153  // atom graph to build the symbol dependence graph.
154  Config.PrePrunePasses.push_back(
155  [this](AtomGraph &G) { return markSymbolsToDiscard(G); });
156  Config.PostPrunePasses.push_back(
157  [this](AtomGraph &G) { return computeNamedSymbolDependencies(G); });
158 
159  Layer.modifyPassConfig(MR, TT, Config);
160 
161  return Error::success();
162  }
163 
164 private:
167 
168  Error markSymbolsToDiscard(AtomGraph &G) {
169  auto &ES = Layer.getExecutionSession();
170  for (auto *DA : G.defined_atoms())
171  if (DA->isWeak() && DA->hasName()) {
172  auto S = ES.intern(DA->getName());
173  auto I = MR.getSymbols().find(S);
174  if (I == MR.getSymbols().end())
175  DA->setShouldDiscard(true);
176  }
177 
178  for (auto *A : G.absolute_atoms())
179  if (A->isWeak() && A->hasName()) {
180  auto S = ES.intern(A->getName());
181  auto I = MR.getSymbols().find(S);
182  if (I == MR.getSymbols().end())
183  A->setShouldDiscard(true);
184  }
185 
186  return Error::success();
187  }
188 
189  Error markResponsibilitySymbolsLive(AtomGraph &G) const {
190  auto &ES = Layer.getExecutionSession();
191  for (auto *DA : G.defined_atoms())
192  if (DA->hasName() &&
193  MR.getSymbols().count(ES.intern(DA->getName())))
194  DA->setLive(true);
195  return Error::success();
196  }
197 
198  Error computeNamedSymbolDependencies(AtomGraph &G) {
199  auto &ES = MR.getTargetJITDylib().getExecutionSession();
200  auto AnonDeps = computeAnonDeps(G);
201 
202  for (auto *DA : G.defined_atoms()) {
203 
204  // Skip anonymous and non-global atoms: we do not need dependencies for
205  // these.
206  if (!DA->hasName() || !DA->isGlobal())
207  continue;
208 
209  auto DAName = ES.intern(DA->getName());
210  SymbolNameSet &DADeps = NamedSymbolDeps[DAName];
211 
212  for (auto &E : DA->edges()) {
213  auto &TA = E.getTarget();
214 
215  if (TA.hasName())
216  DADeps.insert(ES.intern(TA.getName()));
217  else {
218  assert(TA.isDefined() && "Anonymous atoms must be defined");
219  auto &DTA = static_cast<DefinedAtom &>(TA);
220  auto I = AnonDeps.find(&DTA);
221  if (I != AnonDeps.end())
222  for (auto &S : I->second)
223  DADeps.insert(S);
224  }
225  }
226  }
227 
228  return Error::success();
229  }
230 
231  AnonAtomNamedDependenciesMap computeAnonDeps(AtomGraph &G) {
232 
233  auto &ES = MR.getTargetJITDylib().getExecutionSession();
235 
236  // For all anonymous atoms:
237  // (1) Add their named dependencies.
238  // (2) Add them to the worklist for further iteration if they have any
239  // depend on any other anonymous atoms.
240  struct WorklistEntry {
241  WorklistEntry(DefinedAtom *DA, DenseSet<DefinedAtom *> DAAnonDeps)
242  : DA(DA), DAAnonDeps(std::move(DAAnonDeps)) {}
243 
244  DefinedAtom *DA = nullptr;
245  DenseSet<DefinedAtom *> DAAnonDeps;
246  };
247  std::vector<WorklistEntry> Worklist;
248  for (auto *DA : G.defined_atoms())
249  if (!DA->hasName()) {
250  auto &DANamedDeps = DepMap[DA];
251  DenseSet<DefinedAtom *> DAAnonDeps;
252 
253  for (auto &E : DA->edges()) {
254  auto &TA = E.getTarget();
255  if (TA.hasName())
256  DANamedDeps.insert(ES.intern(TA.getName()));
257  else {
258  assert(TA.isDefined() && "Anonymous atoms must be defined");
259  DAAnonDeps.insert(static_cast<DefinedAtom *>(&TA));
260  }
261  }
262 
263  if (!DAAnonDeps.empty())
264  Worklist.push_back(WorklistEntry(DA, std::move(DAAnonDeps)));
265  }
266 
267  // Loop over all anonymous atoms with anonymous dependencies, propagating
268  // their respective *named* dependencies. Iterate until we hit a stable
269  // state.
270  bool Changed;
271  do {
272  Changed = false;
273  for (auto &WLEntry : Worklist) {
274  auto *DA = WLEntry.DA;
275  auto &DANamedDeps = DepMap[DA];
276  auto &DAAnonDeps = WLEntry.DAAnonDeps;
277 
278  for (auto *TA : DAAnonDeps) {
279  auto I = DepMap.find(TA);
280  if (I != DepMap.end())
281  for (const auto &S : I->second)
282  Changed |= DANamedDeps.insert(S).second;
283  }
284  }
285  } while (Changed);
286 
287  return DepMap;
288  }
289 
290  void registerDependencies(const SymbolDependenceMap &QueryDeps) {
291  for (auto &NamedDepsEntry : NamedSymbolDeps) {
292  auto &Name = NamedDepsEntry.first;
293  auto &NameDeps = NamedDepsEntry.second;
294  SymbolDependenceMap SymbolDeps;
295 
296  for (const auto &QueryDepsEntry : QueryDeps) {
297  JITDylib &SourceJD = *QueryDepsEntry.first;
298  const SymbolNameSet &Symbols = QueryDepsEntry.second;
299  auto &DepsForJD = SymbolDeps[&SourceJD];
300 
301  for (const auto &S : Symbols)
302  if (NameDeps.count(S))
303  DepsForJD.insert(S);
304 
305  if (DepsForJD.empty())
306  SymbolDeps.erase(&SourceJD);
307  }
308 
309  MR.addDependencies(Name, SymbolDeps);
310  }
311  }
312 
313  ObjectLinkingLayer &Layer;
315  std::unique_ptr<MemoryBuffer> ObjBuffer;
317 };
318 
319 ObjectLinkingLayer::Plugin::~Plugin() {}
320 
321 ObjectLinkingLayer::ObjectLinkingLayer(ExecutionSession &ES,
322  JITLinkMemoryManager &MemMgr)
323  : ObjectLayer(ES), MemMgr(MemMgr) {}
324 
326  if (auto Err = removeAllModules())
327  getExecutionSession().reportError(std::move(Err));
328 }
329 
331  std::unique_ptr<MemoryBuffer> O) {
332  assert(O && "Object must not be null");
333  jitLink(std::make_unique<ObjectLinkingLayerJITLinkContext>(
334  *this, std::move(R), std::move(O)));
335 }
336 
337 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
338  const Triple &TT,
339  PassConfiguration &PassConfig) {
340  for (auto &P : Plugins)
341  P->modifyPassConfig(MR, TT, PassConfig);
342 }
343 
344 void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
345  for (auto &P : Plugins)
346  P->notifyLoaded(MR);
347 }
348 
349 Error ObjectLinkingLayer::notifyEmitted(MaterializationResponsibility &MR,
350  AllocPtr Alloc) {
351  Error Err = Error::success();
352  for (auto &P : Plugins)
353  Err = joinErrors(std::move(Err), P->notifyEmitted(MR));
354 
355  if (Err)
356  return Err;
357 
358  {
359  std::lock_guard<std::mutex> Lock(LayerMutex);
360  UntrackedAllocs.push_back(std::move(Alloc));
361  }
362 
363  return Error::success();
364 }
365 
366 Error ObjectLinkingLayer::removeModule(VModuleKey K) {
367  Error Err = Error::success();
368 
369  for (auto &P : Plugins)
370  Err = joinErrors(std::move(Err), P->notifyRemovingModule(K));
371 
372  AllocPtr Alloc;
373 
374  {
375  std::lock_guard<std::mutex> Lock(LayerMutex);
376  auto AllocItr = TrackedAllocs.find(K);
377  Alloc = std::move(AllocItr->second);
378  TrackedAllocs.erase(AllocItr);
379  }
380 
381  assert(Alloc && "No allocation for key K");
382 
383  return joinErrors(std::move(Err), Alloc->deallocate());
384 }
385 
386 Error ObjectLinkingLayer::removeAllModules() {
387 
388  Error Err = Error::success();
389 
390  for (auto &P : Plugins)
391  Err = joinErrors(std::move(Err), P->notifyRemovingAllModules());
392 
393  std::vector<AllocPtr> Allocs;
394  {
395  std::lock_guard<std::mutex> Lock(LayerMutex);
396  Allocs = std::move(UntrackedAllocs);
397 
398  for (auto &KV : TrackedAllocs)
399  Allocs.push_back(std::move(KV.second));
400 
401  TrackedAllocs.clear();
402  }
403 
404  while (!Allocs.empty()) {
405  Err = joinErrors(std::move(Err), Allocs.back()->deallocate());
406  Allocs.pop_back();
407  }
408 
409  return Err;
410 }
411 
413  jitlink::EHFrameRegistrar &Registrar)
414  : Registrar(Registrar) {}
415 
417  MaterializationResponsibility &MR, const Triple &TT,
418  PassConfiguration &PassConfig) {
419  assert(!InProcessLinks.count(&MR) && "Link for MR already being tracked?");
420 
421  PassConfig.PostFixupPasses.push_back(
422  createEHFrameRecorderPass(TT, [this, &MR](JITTargetAddress Addr) {
423  if (Addr)
424  InProcessLinks[&MR] = Addr;
425  }));
426 }
427 
430 
431  auto EHFrameAddrItr = InProcessLinks.find(&MR);
432  if (EHFrameAddrItr == InProcessLinks.end())
433  return Error::success();
434 
435  auto EHFrameAddr = EHFrameAddrItr->second;
436  assert(EHFrameAddr && "eh-frame addr to register can not be null");
437 
438  InProcessLinks.erase(EHFrameAddrItr);
439  if (auto Key = MR.getVModuleKey())
440  TrackedEHFrameAddrs[Key] = EHFrameAddr;
441  else
442  UntrackedEHFrameAddrs.push_back(EHFrameAddr);
443 
444  return Registrar.registerEHFrames(EHFrameAddr);
445 }
446 
448  auto EHFrameAddrItr = TrackedEHFrameAddrs.find(K);
449  if (EHFrameAddrItr == TrackedEHFrameAddrs.end())
450  return Error::success();
451 
452  auto EHFrameAddr = EHFrameAddrItr->second;
453  assert(EHFrameAddr && "Tracked eh-frame addr must not be null");
454 
455  TrackedEHFrameAddrs.erase(EHFrameAddrItr);
456 
457  return Registrar.deregisterEHFrames(EHFrameAddr);
458 }
459 
461 
462  std::vector<JITTargetAddress> EHFrameAddrs = std::move(UntrackedEHFrameAddrs);
463  EHFrameAddrs.reserve(EHFrameAddrs.size() + TrackedEHFrameAddrs.size());
464 
465  for (auto &KV : TrackedEHFrameAddrs)
466  EHFrameAddrs.push_back(KV.second);
467 
468  TrackedEHFrameAddrs.clear();
469 
470  Error Err = Error::success();
471 
472  while (!EHFrameAddrs.empty()) {
473  auto EHFrameAddr = EHFrameAddrs.back();
474  assert(EHFrameAddr && "Untracked eh-frame addr must not be null");
475  EHFrameAddrs.pop_back();
476  Err = joinErrors(std::move(Err), Registrar.deregisterEHFrames(EHFrameAddr));
477  }
478 
479  return Err;
480 }
481 
482 } // End namespace orc.
483 } // End namespace llvm.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
Implements a dense probed hash-table based set.
Definition: DenseSet.h:249
static sys::Mutex Lock
EHFrameRegistrationPlugin(jitlink::EHFrameRegistrar &Registrar)
void notifyFailed(Error Err) override
Notify this context that linking failed.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:221
Definition: BitVector.h:937
std::vector< std::pair< JITDylib *, bool > > JITDylibSearchList
A list of (JITDylib*, bool) pairs.
Definition: Core.h:59
An ObjectLayer implementation built on JITLink.
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, jitlink::PassConfiguration &PassConfig) override
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition: Core.h:171
Key
PAL metadata keys.
ExecutionSession & getExecutionSession()
Returns the execution session for this layer.
Definition: Layer.h:119
uint64_t JITTargetAddress
Represents an address in the target process&#39;s address space.
Definition: JITSymbol.h:40
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:176
void lookup(const DenseSet< StringRef > &Symbols, JITLinkAsyncLookupContinuation LookupContinuation) override
Called by JITLink to resolve external symbols.
#define P(N)
bool erase(const KeyT &Val)
Definition: DenseMap.h:298
VModuleKey getVModuleKey() const
Returns the VModuleKey for this instance.
Definition: Core.h:188
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:187
Flags for symbols in the JIT.
Definition: JITSymbol.h:55
unsigned size() const
Definition: DenseMap.h:125
Error notifyRemovingModule(VModuleKey K) override
~ObjectLinkingLayer()
Destruct an ObjectLinkingLayer.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:43
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
void notifyFinalized(std::unique_ptr< JITLinkMemoryManager::Allocation > A) override
Called by JITLink to notify the context that the object has been finalized (i.e.
MemoryBufferRef getObjectBuffer() const override
Returns a StringRef for the object buffer.
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
Error notifyEmitted(MaterializationResponsibility &MR) override
An ExecutionSession represents a running JIT program.
Definition: Core.h:743
ObjectLinkingLayerJITLinkContext(ObjectLinkingLayer &Layer, MaterializationResponsibility MR, std::unique_ptr< MemoryBuffer > ObjBuffer)
Represents a symbol that has been evaluated to an address already.
Definition: JITSymbol.h:189
uint8_t uint64_t VModuleKey
VModuleKey provides a unique identifier (allocated and managed by ExecutionSessions) for a module add...
Definition: Core.h:41
void reportError(Error Err)
Report a error for this execution session.
Definition: Core.h:808
Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override
Called by JITLink to modify the pass pipeline prior to linking.
AtomGraphPassFunction getMarkLivePass(const Triple &TT) const override
Returns the mark-live pass to be used for this link.
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:423
#define I(x, y, z)
Definition: MD5.cpp:58
void emit(MaterializationResponsibility R, std::unique_ptr< MemoryBuffer > O) override
Emit the object.
iterator end()
Definition: DenseMap.h:108
void notifyResolved(AtomGraph &G) override
Called by JITLink once all defined atoms in the graph have been assigned their final memory locations...
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition: DenseMap.h:171
LLVM_NODISCARD bool empty() const
Definition: DenseMap.h:122
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
Definition: DenseMap.h:211
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
Interface for Layers that accept object files.
Definition: Layer.h:113
JITLinkMemoryManager & getMemoryManager() override
Return the MemoryManager to be used for this link.
A symbol table that supports asynchoronous symbol queries.
Definition: Core.h:480