1//===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Contains core ORC APIs.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H
15#define LLVM_EXECUTIONENGINE_ORC_CORE_H
16
17#include "llvm/ADT/BitmaskEnum.h"
18#include "llvm/ExecutionEngine/JITSymbol.h"
19#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
20#include "llvm/IR/Module.h"
21#include "llvm/Support/Debug.h"
22
23#include <memory>
24#include <vector>
25
26#define DEBUG_TYPE "orc"
27
28namespace llvm {
29namespace orc {
30
31// Forward declare some classes.
32class AsynchronousSymbolQuery;
33class ExecutionSession;
34class MaterializationUnit;
35class MaterializationResponsibility;
36class JITDylib;
37
38/// VModuleKey provides a unique identifier (allocated and managed by
39/// ExecutionSessions) for a module added to the JIT.
40using VModuleKey = uint64_t;
41
42/// A set of symbol names (represented by SymbolStringPtrs for
43// efficiency).
44using SymbolNameSet = DenseSet<SymbolStringPtr>;
45
46/// A map from symbol names (as SymbolStringPtrs) to JITSymbols
47/// (address/flags pairs).
48using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>;
49
50/// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
51using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>;
52
53/// A base class for materialization failures that allows the failing
54/// symbols to be obtained for logging.
55using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>;
56
57/// A list of (JITDylib*, bool) pairs.
58using JITDylibSearchList = std::vector<std::pair<JITDylib *, bool>>;
59
60/// Render a SymbolStringPtr.
61raw_ostream &operator<<(raw_ostream &OS, const SymbolStringPtr &Sym);
62
63/// Render a SymbolNameSet.
64raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
65
66/// Render a SymbolFlagsMap entry.
67raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap::value_type &KV);
68
69/// Render a SymbolMap entry.
70raw_ostream &operator<<(raw_ostream &OS, const SymbolMap::value_type &KV);
71
72/// Render a SymbolFlagsMap.
73raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &SymbolFlags);
74
75/// Render a SymbolMap.
76raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
77
78/// Render a SymbolDependenceMap entry.
79raw_ostream &operator<<(raw_ostream &OS,
80 const SymbolDependenceMap::value_type &KV);
81
82/// Render a SymbolDependendeMap.
83raw_ostream &operator<<(raw_ostream &OS, const SymbolDependenceMap &Deps);
84
85/// Render a MaterializationUnit.
86raw_ostream &operator<<(raw_ostream &OS, const MaterializationUnit &MU);
87
88/// Render a JITDylibSearchList.
89raw_ostream &operator<<(raw_ostream &OS, const JITDylibSearchList &JDs);
90
91/// Callback to notify client that symbols have been resolved.
92using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
93
94/// Callback to notify client that symbols are ready for execution.
95using SymbolsReadyCallback = std::function<void(Error)>;
96
97/// Callback to register the dependencies for a given query.
98using RegisterDependenciesFunction =
99 std::function<void(const SymbolDependenceMap &)>;
100
101/// This can be used as the value for a RegisterDependenciesFunction if there
102/// are no dependants to register with.
103extern RegisterDependenciesFunction NoDependenciesToRegister;
104
105/// Used to notify a JITDylib that the given set of symbols failed to
106/// materialize.
107class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
108public:
109 static char ID;
110
111 FailedToMaterialize(SymbolNameSet Symbols);
112 std::error_code convertToErrorCode() const override;
113 void log(raw_ostream &OS) const override;
114 const SymbolNameSet &getSymbols() const { return Symbols; }
115
116private:
117 SymbolNameSet Symbols;
118};
119
120/// Used to notify clients when symbols can not be found during a lookup.
121class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> {
122public:
123 static char ID;
124
125 SymbolsNotFound(SymbolNameSet Symbols);
126 std::error_code convertToErrorCode() const override;
127 void log(raw_ostream &OS) const override;
128 const SymbolNameSet &getSymbols() const { return Symbols; }
129
130private:
131 SymbolNameSet Symbols;
132};
133
134/// Used to notify clients that a set of symbols could not be removed.
135class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> {
136public:
137 static char ID;
138
139 SymbolsCouldNotBeRemoved(SymbolNameSet Symbols);
140 std::error_code convertToErrorCode() const override;
141 void log(raw_ostream &OS) const override;
142 const SymbolNameSet &getSymbols() const { return Symbols; }
143
144private:
145 SymbolNameSet Symbols;
146};
147
148/// Tracks responsibility for materialization, and mediates interactions between
149/// MaterializationUnits and JDs.
150///
151/// An instance of this class is passed to MaterializationUnits when their
152/// materialize method is called. It allows MaterializationUnits to resolve and
153/// emit symbols, or abandon materialization by notifying any unmaterialized
154/// symbols of an error.
155class MaterializationResponsibility {
156 friend class MaterializationUnit;
157public:
158 MaterializationResponsibility(MaterializationResponsibility &&) = default;
159 MaterializationResponsibility &
160 operator=(MaterializationResponsibility &&) = delete;
161
162 /// Destruct a MaterializationResponsibility instance. In debug mode
163 /// this asserts that all symbols being tracked have been either
164 /// emitted or notified of an error.
165 ~MaterializationResponsibility();
166
167 /// Returns the target JITDylib that these symbols are being materialized
168 /// into.
169 JITDylib &getTargetJITDylib() const { return JD; }
170
171 /// Returns the VModuleKey for this instance.
172 VModuleKey getVModuleKey() const { return K; }
173
174 /// Returns the symbol flags map for this responsibility instance.
175 /// Note: The returned flags may have transient flags (Lazy, Materializing)
176 /// set. These should be stripped with JITSymbolFlags::stripTransientFlags
177 /// before using.
178 const SymbolFlagsMap &getSymbols() { return SymbolFlags; }
179
180 /// Returns the names of any symbols covered by this
181 /// MaterializationResponsibility object that have queries pending. This
182 /// information can be used to return responsibility for unrequested symbols
183 /// back to the JITDylib via the delegate method.
184 SymbolNameSet getRequestedSymbols() const;
185
186 /// Notifies the target JITDylib that the given symbols have been resolved.
187 /// This will update the given symbols' addresses in the JITDylib, and notify
188 /// any pending queries on the given symbols of their resolution. The given
189 /// symbols must be ones covered by this MaterializationResponsibility
190 /// instance. Individual calls to this method may resolve a subset of the
191 /// symbols, but all symbols must have been resolved prior to calling emit.
192 void resolve(const SymbolMap &Symbols);
193
194 /// Notifies the target JITDylib (and any pending queries on that JITDylib)
195 /// that all symbols covered by this MaterializationResponsibility instance
196 /// have been emitted.
197 void emit();
198
199 /// Adds new symbols to the JITDylib and this responsibility instance.
200 /// JITDylib entries start out in the materializing state.
201 ///
202 /// This method can be used by materialization units that want to add
203 /// additional symbols at materialization time (e.g. stubs, compile
204 /// callbacks, metadata).
205 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
206
207 /// Notify all not-yet-emitted covered by this MaterializationResponsibility
208 /// instance that an error has occurred.
209 /// This will remove all symbols covered by this MaterializationResponsibilty
210 /// from the target JITDylib, and send an error to any queries waiting on
211 /// these symbols.
212 void failMaterialization();
213
214 /// Transfers responsibility to the given MaterializationUnit for all
215 /// symbols defined by that MaterializationUnit. This allows
216 /// materializers to break up work based on run-time information (e.g.
217 /// by introspecting which symbols have actually been looked up and
218 /// materializing only those).
219 void replace(std::unique_ptr<MaterializationUnit> MU);
220
221 /// Delegates responsibility for the given symbols to the returned
222 /// materialization responsibility. Useful for breaking up work between
223 /// threads, or different kinds of materialization processes.
224 MaterializationResponsibility delegate(const SymbolNameSet &Symbols,
225 VModuleKey NewKey = VModuleKey());
226
227 void addDependencies(const SymbolStringPtr &Name,
228 const SymbolDependenceMap &Dependencies);
229
230 /// Add dependencies that apply to all symbols covered by this instance.
231 void addDependenciesForAll(const SymbolDependenceMap &Dependencies);
232
233private:
234 /// Create a MaterializationResponsibility for the given JITDylib and
235 /// initial symbols.
236 MaterializationResponsibility(JITDylib &JD, SymbolFlagsMap SymbolFlags,
237 VModuleKey K);
238
239 JITDylib &JD;
240 SymbolFlagsMap SymbolFlags;
241 VModuleKey K;
242};
243
244/// A MaterializationUnit represents a set of symbol definitions that can
245/// be materialized as a group, or individually discarded (when
246/// overriding definitions are encountered).
247///
248/// MaterializationUnits are used when providing lazy definitions of symbols to
249/// JITDylibs. The JITDylib will call materialize when the address of a symbol
250/// is requested via the lookup method. The JITDylib will call discard if a
251/// stronger definition is added or already present.
252class MaterializationUnit {
253public:
254 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, VModuleKey K)
255 : SymbolFlags(std::move(InitalSymbolFlags)), K(std::move(K)) {}
256
257 virtual ~MaterializationUnit() {}
258
259 /// Return the name of this materialization unit. Useful for debugging
260 /// output.
261 virtual StringRef getName() const = 0;
262
263 /// Return the set of symbols that this source provides.
264 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; }
265
266 /// Called by materialization dispatchers (see
267 /// ExecutionSession::DispatchMaterializationFunction) to trigger
268 /// materialization of this MaterializationUnit.
269 void doMaterialize(JITDylib &JD) {
270 materialize(MaterializationResponsibility(JD, std::move(SymbolFlags),
271 std::move(K)));
272 }
273
274 /// Called by JITDylibs to notify MaterializationUnits that the given symbol
275 /// has been overridden.
276 void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) {
277 SymbolFlags.erase(Name);
278 discard(JD, std::move(Name));
279 }
280
281protected:
282 SymbolFlagsMap SymbolFlags;
283 VModuleKey K;
284
285private:
286 virtual void anchor();
287
288 /// Implementations of this method should materialize all symbols
289 /// in the materialzation unit, except for those that have been
290 /// previously discarded.
291 virtual void materialize(MaterializationResponsibility R) = 0;
292
293 /// Implementations of this method should discard the given symbol
294 /// from the source (e.g. if the source is an LLVM IR Module and the
295 /// symbol is a function, delete the function body or mark it available
296 /// externally).
297 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0;
298};
299
300using MaterializationUnitList =
301 std::vector<std::unique_ptr<MaterializationUnit>>;
302
303/// A MaterializationUnit implementation for pre-existing absolute symbols.
304///
305/// All symbols will be resolved and marked ready as soon as the unit is
306/// materialized.
307class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit {
308public:
309 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K);
310
311 StringRef getName() const override;
312
313private:
314 void materialize(MaterializationResponsibility R) override;
315 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
316 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols);
317
318 SymbolMap Symbols;
319};
320
321/// Create an AbsoluteSymbolsMaterializationUnit with the given symbols.
322/// Useful for inserting absolute symbols into a JITDylib. E.g.:
323/// \code{.cpp}
324/// JITDylib &JD = ...;
325/// SymbolStringPtr Foo = ...;
326/// JITEvaluatedSymbol FooSym = ...;
327/// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}})))
328/// return Err;
329/// \endcode
330///
331inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit>
332absoluteSymbols(SymbolMap Symbols, VModuleKey K = VModuleKey()) {
333 return llvm::make_unique<AbsoluteSymbolsMaterializationUnit>(
334 std::move(Symbols), std::move(K));
335}
336
337struct SymbolAliasMapEntry {
338 SymbolAliasMapEntry() = default;
339 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags)
340 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {}
341
342 SymbolStringPtr Aliasee;
343 JITSymbolFlags AliasFlags;
344};
345
346/// A map of Symbols to (Symbol, Flags) pairs.
347using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>;
348
349/// A materialization unit for symbol aliases. Allows existing symbols to be
350/// aliased with alternate flags.
351class ReExportsMaterializationUnit : public MaterializationUnit {
352public:
353 /// SourceJD is allowed to be nullptr, in which case the source JITDylib is
354 /// taken to be whatever JITDylib these definitions are materialized in (and
355 /// MatchNonExported has no effect). This is useful for defining aliases
356 /// within a JITDylib.
357 ///
358 /// Note: Care must be taken that no sets of aliases form a cycle, as such
359 /// a cycle will result in a deadlock when any symbol in the cycle is
360 /// resolved.
361 ReExportsMaterializationUnit(JITDylib *SourceJD, bool MatchNonExported,
362 SymbolAliasMap Aliases, VModuleKey K);
363
364 StringRef getName() const override;
365
366private:
367 void materialize(MaterializationResponsibility R) override;
368 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
369 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases);
370
371 JITDylib *SourceJD = nullptr;
372 bool MatchNonExported = false;
373 SymbolAliasMap Aliases;
374};
375
376/// Create a ReExportsMaterializationUnit with the given aliases.
377/// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing
378/// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux"
379/// (for "bar") with: \code{.cpp}
380/// SymbolStringPtr Baz = ...;
381/// SymbolStringPtr Qux = ...;
382/// if (auto Err = JD.define(symbolAliases({
383/// {Baz, { Foo, JITSymbolFlags::Exported }},
384/// {Qux, { Bar, JITSymbolFlags::Weak }}}))
385/// return Err;
386/// \endcode
387inline std::unique_ptr<ReExportsMaterializationUnit>
388symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) {
389 return llvm::make_unique<ReExportsMaterializationUnit>(
390 nullptr, true, std::move(Aliases), std::move(K));
391}
392
393/// Create a materialization unit for re-exporting symbols from another JITDylib
394/// with alternative names/flags.
395/// If MatchNonExported is true then non-exported symbols from SourceJD can be
396/// re-exported. If it is false, attempts to re-export a non-exported symbol
397/// will result in a "symbol not found" error.
398inline std::unique_ptr<ReExportsMaterializationUnit>
399reexports(JITDylib &SourceJD, SymbolAliasMap Aliases,
400 bool MatchNonExported = false, VModuleKey K = VModuleKey()) {
401 return llvm::make_unique<ReExportsMaterializationUnit>(
402 &SourceJD, MatchNonExported, std::move(Aliases), std::move(K));
403}
404
405/// Build a SymbolAliasMap for the common case where you want to re-export
406/// symbols from another JITDylib with the same linkage/flags.
407Expected<SymbolAliasMap>
408buildSimpleReexportsAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols);
409
410/// ReexportsGenerator can be used with JITDylib::setGenerator to automatically
411/// re-export a subset of the source JITDylib's symbols in the target.
412class ReexportsGenerator {
413public:
414 using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
415
416 /// Create a reexports generator. If an Allow predicate is passed, only
417 /// symbols for which the predicate returns true will be reexported. If no
418 /// Allow predicate is passed, all symbols will be exported.
419 ReexportsGenerator(JITDylib &SourceJD, bool MatchNonExported = false,
420 SymbolPredicate Allow = SymbolPredicate());
421
422 SymbolNameSet operator()(JITDylib &JD, const SymbolNameSet &Names);
423
424private:
425 JITDylib &SourceJD;
426 bool MatchNonExported = false;
427 SymbolPredicate Allow;
428};
429
430/// A symbol query that returns results via a callback when results are
431/// ready.
432///
433/// makes a callback when all symbols are available.
434class AsynchronousSymbolQuery {
435 friend class ExecutionSession;
436 friend class JITDylib;
437 friend class JITSymbolResolverAdapter;
438
439public:
440
441 /// Create a query for the given symbols, notify-resolved and
442 /// notify-ready callbacks.
443 AsynchronousSymbolQuery(const SymbolNameSet &Symbols,
444 SymbolsResolvedCallback NotifySymbolsResolved,
445 SymbolsReadyCallback NotifySymbolsReady);
446
447 /// Set the resolved symbol information for the given symbol name.
448 void resolve(const SymbolStringPtr &Name, JITEvaluatedSymbol Sym);
449
450 /// Returns true if all symbols covered by this query have been
451 /// resolved.
452 bool isFullyResolved() const { return NotYetResolvedCount == 0; }
453
454 /// Call the NotifySymbolsResolved callback.
455 ///
456 /// This should only be called if all symbols covered by the query have been
457 /// resolved.
458 void handleFullyResolved();
459
460 /// Notify the query that a requested symbol is ready for execution.
461 void notifySymbolReady();
462
463 /// Returns true if all symbols covered by this query are ready.
464 bool isFullyReady() const { return NotYetReadyCount == 0; }
465
466 /// Calls the NotifySymbolsReady callback.
467 ///
468 /// This should only be called if all symbols covered by this query are ready.
469 void handleFullyReady();
470
471private:
472 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name);
473
474 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name);
475
476 bool canStillFail();
477
478 void handleFailed(Error Err);
479
480 void detach();
481
482 SymbolsResolvedCallback NotifySymbolsResolved;
483 SymbolsReadyCallback NotifySymbolsReady;
484 SymbolDependenceMap QueryRegistrations;
485 SymbolMap ResolvedSymbols;
486 size_t NotYetResolvedCount;
487 size_t NotYetReadyCount;
488};
489
490/// A symbol table that supports asynchoronous symbol queries.
491///
492/// Represents a virtual shared object. Instances can not be copied or moved, so
493/// their addresses may be used as keys for resource management.
494/// JITDylib state changes must be made via an ExecutionSession to guarantee
495/// that they are synchronized with respect to other JITDylib operations.
496class JITDylib {
497 friend class AsynchronousSymbolQuery;
498 friend class ExecutionSession;
499 friend class MaterializationResponsibility;
500public:
501 using GeneratorFunction = std::function<SymbolNameSet(
502 JITDylib &Parent, const SymbolNameSet &Names)>;
503
504 using AsynchronousSymbolQuerySet =
505 std::set<std::shared_ptr<AsynchronousSymbolQuery>>;
506
507 JITDylib(const JITDylib &) = delete;
508 JITDylib &operator=(const JITDylib &) = delete;
509 JITDylib(JITDylib &&) = delete;
510 JITDylib &operator=(JITDylib &&) = delete;
511
512 /// Get the name for this JITDylib.
513 const std::string &getName() const { return JITDylibName; }
514
515 /// Get a reference to the ExecutionSession for this JITDylib.
516 ExecutionSession &getExecutionSession() const { return ES; }
517
518 /// Set a definition generator. If set, whenever a symbol fails to resolve
519 /// within this JITDylib, lookup and lookupFlags will pass the unresolved
520 /// symbols set to the definition generator. The generator can optionally
521 /// add a definition for the unresolved symbols to the dylib.
522 void setGenerator(GeneratorFunction DefGenerator) {
523 this->DefGenerator = std::move(DefGenerator);
524 }
525
526 /// Set the search order to be used when fixing up definitions in JITDylib.
527 /// This will replace the previous search order, and apply to any symbol
528 /// resolutions made for definitions in this JITDylib after the call to
529 /// setSearchOrder (even if the definition itself was added before the
530 /// call).
531 ///
532 /// If SearchThisJITDylibFirst is set, which by default it is, then this
533 /// JITDylib will add itself to the beginning of the SearchOrder (Clients
534 /// should *not* put this JITDylib in the list in this case, to avoid
535 /// redundant lookups).
536 ///
537 /// If SearchThisJITDylibFirst is false then the search order will be used as
538 /// given. The main motivation for this feature is to support deliberate
539 /// shadowing of symbols in this JITDylib by a facade JITDylib. For example,
540 /// the facade may resolve function names to stubs, and the stubs may compile
541 /// lazily by looking up symbols in this dylib. Adding the facade dylib
542 /// as the first in the search order (instead of this dylib) ensures that
543 /// definitions within this dylib resolve to the lazy-compiling stubs,
544 /// rather than immediately materializing the definitions in this dylib.
545 void setSearchOrder(JITDylibSearchList NewSearchOrder,
546 bool SearchThisJITDylibFirst = true,
547 bool MatchNonExportedInThisDylib = true);
548
549 /// Add the given JITDylib to the search order for definitions in this
550 /// JITDylib.
551 void addToSearchOrder(JITDylib &JD, bool MatcNonExported = false);
552
553 /// Replace OldJD with NewJD in the search order if OldJD is present.
554 /// Otherwise this operation is a no-op.
555 void replaceInSearchOrder(JITDylib &OldJD, JITDylib &NewJD,
556 bool MatchNonExported = false);
557
558 /// Remove the given JITDylib from the search order for this JITDylib if it is
559 /// present. Otherwise this operation is a no-op.
560 void removeFromSearchOrder(JITDylib &JD);
561
562 /// Do something with the search order (run under the session lock).
563 template <typename Func>
564 auto withSearchOrderDo(Func &&F)
565 -> decltype(F(std::declval<const JITDylibSearchList &>()));
566
567 /// Define all symbols provided by the materialization unit to be part of this
568 /// JITDylib.
569 ///
570 /// This overload always takes ownership of the MaterializationUnit. If any
571 /// errors occur, the MaterializationUnit consumed.
572 template <typename MaterializationUnitType>
573 Error define(std::unique_ptr<MaterializationUnitType> &&MU);
574
575 /// Define all symbols provided by the materialization unit to be part of this
576 /// JITDylib.
577 ///
578 /// This overload only takes ownership of the MaterializationUnit no error is
579 /// generated. If an error occurs, ownership remains with the caller. This
580 /// may allow the caller to modify the MaterializationUnit to correct the
581 /// issue, then re-call define.
582 template <typename MaterializationUnitType>
583 Error define(std::unique_ptr<MaterializationUnitType> &MU);
584
585 /// Tries to remove the given symbols.
586 ///
587 /// If any symbols are not defined in this JITDylib this method will return
588 /// a SymbolsNotFound error covering the missing symbols.
589 ///
590 /// If all symbols are found but some symbols are in the process of being
591 /// materialized this method will return a SymbolsCouldNotBeRemoved error.
592 ///
593 /// On success, all symbols are removed. On failure, the JITDylib state is
594 /// left unmodified (no symbols are removed).
595 Error remove(const SymbolNameSet &Names);
596
597 /// Search the given JITDylib for the symbols in Symbols. If found, store
598 /// the flags for each symbol in Flags. Returns any unresolved symbols.
599 SymbolFlagsMap lookupFlags(const SymbolNameSet &Names);
600
601 /// Dump current JITDylib state to OS.
602 void dump(raw_ostream &OS);
603
604 /// FIXME: Remove this when we remove the old ORC layers.
605 /// Search the given JITDylibs in order for the symbols in Symbols. Results
606 /// (once they become available) will be returned via the given Query.
607 ///
608 /// If any symbol is not found then the unresolved symbols will be returned,
609 /// and the query will not be applied. The Query is not failed and can be
610 /// re-used in a subsequent lookup once the symbols have been added, or
611 /// manually failed.
612 SymbolNameSet legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q,
613 SymbolNameSet Names);
614
615private:
616 using AsynchronousSymbolQueryList =
617 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
618
619 struct UnmaterializedInfo {
620 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU)
621 : MU(std::move(MU)) {}
622
623 std::unique_ptr<MaterializationUnit> MU;
624 };
625
626 using UnmaterializedInfosMap =
627 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>;
628
629 struct MaterializingInfo {
630 AsynchronousSymbolQueryList PendingQueries;
631 SymbolDependenceMap Dependants;
632 SymbolDependenceMap UnemittedDependencies;
633 bool IsEmitted = false;
634 };
635
636 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>;
637
638 using LookupImplActionFlags = enum {
639 None = 0,
640 NotifyFullyResolved = 1 << 0U,
641 NotifyFullyReady = 1 << 1U,
642 LLVM_MARK_AS_BITMASK_ENUM(NotifyFullyReady)
643 };
644
645 JITDylib(ExecutionSession &ES, std::string Name);
646
647 Error defineImpl(MaterializationUnit &MU);
648
649 SymbolNameSet lookupFlagsImpl(SymbolFlagsMap &Flags,
650 const SymbolNameSet &Names);
651
652 void lodgeQuery(std::shared_ptr<AsynchronousSymbolQuery> &Q,
653 SymbolNameSet &Unresolved, bool MatchNonExported,
654 MaterializationUnitList &MUs);
655
656 void lodgeQueryImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
657 SymbolNameSet &Unresolved, bool MatchNonExported,
658 MaterializationUnitList &MUs);
659
660 LookupImplActionFlags
661 lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q,
662 std::vector<std::unique_ptr<MaterializationUnit>> &MUs,
663 SymbolNameSet &Unresolved);
664
665 void detachQueryHelper(AsynchronousSymbolQuery &Q,
666 const SymbolNameSet &QuerySymbols);
667
668 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI,
669 const SymbolStringPtr &DependantName,
670 MaterializingInfo &EmittedMI);
671
672 Error defineMaterializing(const SymbolFlagsMap &SymbolFlags);
673
674 void replace(std::unique_ptr<MaterializationUnit> MU);
675
676 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const;
677
678 void addDependencies(const SymbolStringPtr &Name,
679 const SymbolDependenceMap &Dependants);
680
681 void resolve(const SymbolMap &Resolved);
682
683 void emit(const SymbolFlagsMap &Emitted);
684
685 void notifyFailed(const SymbolNameSet &FailedSymbols);
686
687 ExecutionSession &ES;
688 std::string JITDylibName;
689 SymbolMap Symbols;
690 UnmaterializedInfosMap UnmaterializedInfos;
691 MaterializingInfosMap MaterializingInfos;
692 GeneratorFunction DefGenerator;
693 JITDylibSearchList SearchOrder;
694};
695
696/// An ExecutionSession represents a running JIT program.
697class ExecutionSession {
698 // FIXME: Remove this when we remove the old ORC layers.
699 friend class JITDylib;
700
701public:
702 /// For reporting errors.
703 using ErrorReporter = std::function<void(Error)>;
704
705 /// For dispatching MaterializationUnit::materialize calls.
706 using DispatchMaterializationFunction = std::function<void(
707 JITDylib &JD, std::unique_ptr<MaterializationUnit> MU)>;
708
709 /// Construct an ExecutionSession.
710 ///
711 /// SymbolStringPools may be shared between ExecutionSessions.
712 ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr);
713
714 /// Add a symbol name to the SymbolStringPool and return a pointer to it.
715 SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); }
716
717 /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession.
718 std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }
719
720 /// Run the given lambda with the session mutex locked.
721 template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
722 std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
723 return F();
724 }
725
726 /// Get the "main" JITDylib, which is created automatically on construction of
727 /// the ExecutionSession.
728 JITDylib &getMainJITDylib();
729
730 /// Add a new JITDylib to this ExecutionSession.
731 JITDylib &createJITDylib(std::string Name,
732 bool AddToMainDylibSearchOrder = true);
733
734 /// Allocate a module key for a new module to add to the JIT.
735 VModuleKey allocateVModule() {
736 return runSessionLocked([this]() { return ++LastKey; });
737 }
738
739 /// Return a module key to the ExecutionSession so that it can be
740 /// re-used. This should only be done once all resources associated
741 /// with the original key have been released.
742 void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */
743 }
744
745 /// Set the error reporter function.
746 ExecutionSession &setErrorReporter(ErrorReporter ReportError) {
747 this->ReportError = std::move(ReportError);
748 return *this;
749 }
750
751 /// Report a error for this execution session.
752 ///
753 /// Unhandled errors can be sent here to log them.
754 void reportError(Error Err) { ReportError(std::move(Err)); }
755
756 /// Set the materialization dispatch function.
757 ExecutionSession &setDispatchMaterialization(
758 DispatchMaterializationFunction DispatchMaterialization) {
759 this->DispatchMaterialization = std::move(DispatchMaterialization);
760 return *this;
761 }
762
763 void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err);
764
765 using LegacyAsyncLookupFunction = std::function<SymbolNameSet(
766 std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>;
767
768 /// A legacy lookup function for JITSymbolResolverAdapter.
769 /// Do not use -- this will be removed soon.
770 Expected<SymbolMap>
771 legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names,
772 bool WaiUntilReady,
773 RegisterDependenciesFunction RegisterDependencies);
774
775 /// Search the given JITDylib list for the given symbols.
776 ///
777 /// SearchOrder lists the JITDylibs to search. For each dylib, the associated
778 /// boolean indicates whether the search should match against non-exported
779 /// (hidden visibility) symbols in that dylib (true means match against
780 /// non-exported symbols, false means do not match).
781 ///
782 /// The OnResolve callback will be called once all requested symbols are
783 /// resolved, or if an error occurs prior to resolution.
784 ///
785 /// The OnReady callback will be called once all requested symbols are ready,
786 /// or if an error occurs after resolution but before all symbols are ready.
787 ///
788 /// If all symbols are found, the RegisterDependencies function will be called
789 /// while the session lock is held. This gives clients a chance to register
790 /// dependencies for on the queried symbols for any symbols they are
791 /// materializing (if a MaterializationResponsibility instance is present,
792 /// this can be implemented by calling
793 /// MaterializationResponsibility::addDependencies). If there are no
794 /// dependenant symbols for this query (e.g. it is being made by a top level
795 /// client to get an address to call) then the value NoDependenciesToRegister
796 /// can be used.
797 void lookup(const JITDylibSearchList &SearchOrder, SymbolNameSet Symbols,
798 SymbolsResolvedCallback OnResolve, SymbolsReadyCallback OnReady,
799 RegisterDependenciesFunction RegisterDependencies);
800
801 /// Blocking version of lookup above. Returns the resolved symbol map.
802 /// If WaitUntilReady is true (the default), will not return until all
803 /// requested symbols are ready (or an error occurs). If WaitUntilReady is
804 /// false, will return as soon as all requested symbols are resolved,
805 /// or an error occurs. If WaitUntilReady is false and an error occurs
806 /// after resolution, the function will return a success value, but the
807 /// error will be reported via reportErrors.
808 Expected<SymbolMap> lookup(const JITDylibSearchList &SearchOrder,
809 const SymbolNameSet &Symbols,
810 RegisterDependenciesFunction RegisterDependencies =
811 NoDependenciesToRegister,
812 bool WaitUntilReady = true);
813
814 /// Convenience version of blocking lookup.
815 /// Searches each of the JITDylibs in the search order in turn for the given
816 /// symbol.
817 Expected<JITEvaluatedSymbol> lookup(const JITDylibSearchList &SearchOrder,
818 SymbolStringPtr Symbol);
819
820 /// Convenience version of blocking lookup.
821 /// Searches each of the JITDylibs in the search order in turn for the given
822 /// symbol. The search will not find non-exported symbols.
823 Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
824 SymbolStringPtr Symbol);
825
826 /// Convenience version of blocking lookup.
827 /// Searches each of the JITDylibs in the search order in turn for the given
828 /// symbol. The search will not find non-exported symbols.
829 Expected<JITEvaluatedSymbol> lookup(ArrayRef<JITDylib *> SearchOrder,
830 StringRef Symbol);
831
832 /// Materialize the given unit.
833 void dispatchMaterialization(JITDylib &JD,
834 std::unique_ptr<MaterializationUnit> MU) {
835 LLVM_DEBUG(runSessionLocked([&]() {
836 dbgs() << "Compiling, for " << JD.getName() << ", " << *MU
837 << "\n";
838 }););
839 DispatchMaterialization(JD, std::move(MU));
840 }
841
842 /// Dump the state of all the JITDylibs in this session.
843 void dump(raw_ostream &OS);
844
845private:
846 static void logErrorsToStdErr(Error Err) {
847 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: ");
848 }
849
850 static void
851 materializeOnCurrentThread(JITDylib &JD,
852 std::unique_ptr<MaterializationUnit> MU) {
853 MU->doMaterialize(JD);
854 }
855
856 void runOutstandingMUs();
857
858 mutable std::recursive_mutex SessionMutex;
859 std::shared_ptr<SymbolStringPool> SSP;
860 VModuleKey LastKey = 0;
861 ErrorReporter ReportError = logErrorsToStdErr;
862 DispatchMaterializationFunction DispatchMaterialization =
863 materializeOnCurrentThread;
864
865 std::vector<std::unique_ptr<JITDylib>> JDs;
866
867 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works
868 // with callbacks from asynchronous queries.
869 mutable std::recursive_mutex OutstandingMUsMutex;
870 std::vector<std::pair<JITDylib *, std::unique_ptr<MaterializationUnit>>>
871 OutstandingMUs;
872};
873
874template <typename Func>
875auto JITDylib::withSearchOrderDo(Func &&F)
876 -> decltype(F(std::declval<const JITDylibSearchList &>())) {
877 return ES.runSessionLocked([&]() { return F(SearchOrder); });
878}
879
880template <typename MaterializationUnitType>
881Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) {
882 assert(MU && "Can not define with a null MU");
883 return ES.runSessionLocked([&, this]() -> Error {
884 if (auto Err = defineImpl(*MU))
885 return Err;
886
887 /// defineImpl succeeded.
888 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
889 for (auto &KV : UMI->MU->getSymbols())
890 UnmaterializedInfos[KV.first] = UMI;
891
892 return Error::success();
893 });
894}
895
896template <typename MaterializationUnitType>
897Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) {
898 assert(MU && "Can not define with a null MU");
899
900 return ES.runSessionLocked([&, this]() -> Error {
901 if (auto Err = defineImpl(*MU))
902 return Err;
903
904 /// defineImpl succeeded.
905 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU));
906 for (auto &KV : UMI->MU->getSymbols())
907 UnmaterializedInfos[KV.first] = UMI;
908
909 return Error::success();
910 });
911}
912
913/// Mangles symbol names then uniques them in the context of an
914/// ExecutionSession.
915class MangleAndInterner {
916public:
917 MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
918 SymbolStringPtr operator()(StringRef Name);
919
920private:
921 ExecutionSession &ES;
922 const DataLayout &DL;
923};
924
925} // End namespace orc
926} // End namespace llvm
927
928#undef DEBUG_TYPE // "orc"
929
930#endif // LLVM_EXECUTIONENGINE_ORC_CORE_H
931