1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
|
//===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Contains core ORC APIs.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H
#define LLVM_EXECUTIONENGINE_ORC_CORE_H
#include "llvm/ExecutionEngine/JITSymbol.h"
#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
#include <list>
#include <map>
#include <memory>
#include <set>
#include <vector>
namespace llvm {
namespace orc {
// Forward declare some classes.
class VSO;
/// VModuleKey provides a unique identifier (allocated and managed by
/// ExecutionSessions) for a module added to the JIT.
using VModuleKey = uint64_t;
/// @brief A set of symbol names (represented by SymbolStringPtrs for
// efficiency).
using SymbolNameSet = std::set<SymbolStringPtr>;
/// @brief Render a SymbolNameSet to an ostream.
raw_ostream &operator<<(raw_ostream &OS, const SymbolNameSet &Symbols);
/// @brief A map from symbol names (as SymbolStringPtrs) to JITSymbols
/// (address/flags pairs).
using SymbolMap = std::map<SymbolStringPtr, JITEvaluatedSymbol>;
/// @brief Render a SymbolMap to an ostream.
raw_ostream &operator<<(raw_ostream &OS, const SymbolMap &Symbols);
/// @brief A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags.
using SymbolFlagsMap = std::map<SymbolStringPtr, JITSymbolFlags>;
/// @brief Render a SymbolMap to an ostream.
raw_ostream &operator<<(raw_ostream &OS, const SymbolFlagsMap &Symbols);
/// @brief A base class for materialization failures that allows the failing
/// symbols to be obtained for logging.
class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> {
public:
static char ID;
virtual const SymbolNameSet &getSymbols() const = 0;
};
/// @brief Used to notify a VSO that the given set of symbols failed to resolve.
class FailedToResolve : public ErrorInfo<FailedToResolve, FailedToMaterialize> {
public:
static char ID;
FailedToResolve(SymbolNameSet Symbols);
std::error_code convertToErrorCode() const override;
void log(raw_ostream &OS) const override;
const SymbolNameSet &getSymbols() const override { return Symbols; }
private:
SymbolNameSet Symbols;
};
/// @brief Used to notify a VSO that the given set of symbols failed to
/// finalize.
class FailedToFinalize
: public ErrorInfo<FailedToFinalize, FailedToMaterialize> {
public:
static char ID;
FailedToFinalize(SymbolNameSet Symbols);
std::error_code convertToErrorCode() const override;
void log(raw_ostream &OS) const override;
const SymbolNameSet &getSymbols() const override { return Symbols; }
private:
SymbolNameSet Symbols;
};
/// @brief A symbol query that returns results via a callback when results are
/// ready.
///
/// makes a callback when all symbols are available.
class AsynchronousSymbolQuery {
public:
/// @brief Callback to notify client that symbols have been resolved.
using SymbolsResolvedCallback = std::function<void(Expected<SymbolMap>)>;
/// @brief Callback to notify client that symbols are ready for execution.
using SymbolsReadyCallback = std::function<void(Error)>;
/// @brief Create a query for the given symbols, notify-resolved and
/// notify-ready callbacks.
AsynchronousSymbolQuery(const SymbolNameSet &Symbols,
SymbolsResolvedCallback NotifySymbolsResolved,
SymbolsReadyCallback NotifySymbolsReady);
/// @brief Notify client that the query failed.
///
/// If the notify-resolved callback has not been made yet, then it is called
/// with the given error, and the notify-finalized callback is never made.
///
/// If the notify-resolved callback has already been made then then the
/// notify-finalized callback is called with the given error.
///
/// It is illegal to call setFailed after both callbacks have been made.
void notifyFailed(Error Err);
/// @brief Set the resolved symbol information for the given symbol name.
///
/// If this symbol was the last one not resolved, this will trigger a call to
/// the notify-finalized callback passing the completed sybol map.
void resolve(SymbolStringPtr Name, JITEvaluatedSymbol Sym);
/// @brief Notify the query that a requested symbol is ready for execution.
///
/// This decrements the query's internal count of not-yet-ready symbols. If
/// this call to notifySymbolFinalized sets the counter to zero, it will call
/// the notify-finalized callback with Error::success as the value.
void finalizeSymbol();
private:
SymbolMap Symbols;
size_t OutstandingResolutions = 0;
size_t OutstandingFinalizations = 0;
SymbolsResolvedCallback NotifySymbolsResolved;
SymbolsReadyCallback NotifySymbolsReady;
};
/// @brief SymbolResolver is a composable interface for looking up symbol flags
/// and addresses using the AsynchronousSymbolQuery type. It will
/// eventually replace the LegacyJITSymbolResolver interface as the
/// stardard ORC symbol resolver type.
class SymbolResolver {
public:
virtual ~SymbolResolver() = default;
/// @brief Returns the flags for each symbol in Symbols that can be found,
/// along with the set of symbol that could not be found.
virtual SymbolNameSet lookupFlags(SymbolFlagsMap &Flags,
const SymbolNameSet &Symbols) = 0;
/// @brief For each symbol in Symbols that can be found, assigns that symbols
/// value in Query. Returns the set of symbols that could not be found.
virtual SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
SymbolNameSet Symbols) = 0;
private:
virtual void anchor();
};
/// @brief Implements SymbolResolver with a pair of supplied function objects
/// for convenience. See createSymbolResolver.
template <typename LookupFlagsFn, typename LookupFn>
class LambdaSymbolResolver final : public SymbolResolver {
public:
template <typename LookupFlagsFnRef, typename LookupFnRef>
LambdaSymbolResolver(LookupFlagsFnRef &&LookupFlags, LookupFnRef &&Lookup)
: LookupFlags(std::forward<LookupFlagsFnRef>(LookupFlags)),
Lookup(std::forward<LookupFnRef>(Lookup)) {}
SymbolNameSet lookupFlags(SymbolFlagsMap &Flags,
const SymbolNameSet &Symbols) final {
return LookupFlags(Flags, Symbols);
}
SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
SymbolNameSet Symbols) final {
return Lookup(std::move(Query), std::move(Symbols));
}
private:
LookupFlagsFn LookupFlags;
LookupFn Lookup;
};
/// @brief Creates a SymbolResolver implementation from the pair of supplied
/// function objects.
template <typename LookupFlagsFn, typename LookupFn>
std::unique_ptr<LambdaSymbolResolver<
typename std::remove_cv<
typename std::remove_reference<LookupFlagsFn>::type>::type,
typename std::remove_cv<
typename std::remove_reference<LookupFn>::type>::type>>
createSymbolResolver(LookupFlagsFn &&LookupFlags, LookupFn &&Lookup) {
using LambdaSymbolResolverImpl = LambdaSymbolResolver<
typename std::remove_cv<
typename std::remove_reference<LookupFlagsFn>::type>::type,
typename std::remove_cv<
typename std::remove_reference<LookupFn>::type>::type>;
return llvm::make_unique<LambdaSymbolResolverImpl>(
std::forward<LookupFlagsFn>(LookupFlags), std::forward<LookupFn>(Lookup));
}
/// @brief A MaterializationUnit represents a set of symbol definitions that can
/// be materialized as a group, or individually discarded (when
/// overriding definitions are encountered).
///
/// MaterializationUnits are used when providing lazy definitions of symbols to
/// VSOs. The VSO will call materialize when the address of a symbol is
/// requested via the lookup method. The VSO will call discard if a stronger
/// definition is added or already present.
class MaterializationUnit {
public:
virtual ~MaterializationUnit() {}
/// @brief Return the set of symbols that this source provides.
virtual SymbolFlagsMap getSymbols() = 0;
/// @brief Implementations of this method should materialize all symbols
/// in the materialzation unit, except for those that have been
/// previously discarded.
virtual Error materialize(VSO &V) = 0;
/// @brief Implementations of this method should discard the given symbol
/// from the source (e.g. if the source is an LLVM IR Module and the
/// symbol is a function, delete the function body or mark it available
/// externally).
virtual void discard(VSO &V, SymbolStringPtr Name) = 0;
private:
virtual void anchor();
};
/// @brief Represents a dynamic linkage unit in a JIT process.
///
/// VSO acts as a symbol table (symbol definitions can be set and the dylib
/// queried to find symbol addresses) and as a key for tracking resources
/// (since a VSO's address is fixed).
class VSO {
friend class ExecutionSession;
public:
enum RelativeLinkageStrength {
NewDefinitionIsStronger,
DuplicateDefinition,
ExistingDefinitionIsStronger
};
using SetDefinitionsResult =
std::map<SymbolStringPtr, RelativeLinkageStrength>;
using MaterializationUnitList =
std::vector<std::unique_ptr<MaterializationUnit>>;
struct LookupResult {
MaterializationUnitList MaterializationUnits;
SymbolNameSet UnresolvedSymbols;
};
VSO() = default;
VSO(const VSO &) = delete;
VSO &operator=(const VSO &) = delete;
VSO(VSO &&) = delete;
VSO &operator=(VSO &&) = delete;
/// @brief Compare new linkage with existing linkage.
static RelativeLinkageStrength
compareLinkage(Optional<JITSymbolFlags> OldFlags, JITSymbolFlags NewFlags);
/// @brief Compare new linkage with an existing symbol's linkage.
RelativeLinkageStrength compareLinkage(SymbolStringPtr Name,
JITSymbolFlags NewFlags) const;
/// @brief Adds the given symbols to the mapping as resolved, finalized
/// symbols.
///
/// FIXME: We can take this by const-ref once symbol-based laziness is
/// removed.
Error define(SymbolMap NewSymbols);
/// @brief Adds the given symbols to the mapping as lazy symbols.
Error defineLazy(std::unique_ptr<MaterializationUnit> Source);
/// @brief Add the given symbol/address mappings to the dylib, but do not
/// mark the symbols as finalized yet.
void resolve(const SymbolMap &SymbolValues);
/// @brief Finalize the given symbols.
void finalize(const SymbolNameSet &SymbolsToFinalize);
/// @brief Notify the VSO that the given symbols failed to materialized.
void notifyMaterializationFailed(const SymbolNameSet &Names);
/// @brief Look up the flags for the given symbols.
///
/// Returns the flags for the give symbols, together with the set of symbols
/// not found.
SymbolNameSet lookupFlags(SymbolFlagsMap &Flags, SymbolNameSet Symbols);
/// @brief Apply the given query to the given symbols in this VSO.
///
/// For symbols in this VSO that have already been materialized, their address
/// will be set in the query immediately.
///
/// For symbols in this VSO that have not been materialized, the query will be
/// recorded and the source for those symbols (plus the set of symbols to be
/// materialized by that source) will be returned as the MaterializationWork
/// field of the LookupResult.
///
/// Any symbols not found in this VSO will be returned in the
/// UnresolvedSymbols field of the LookupResult.
LookupResult lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
SymbolNameSet Symbols);
private:
class UnmaterializedInfo {
public:
UnmaterializedInfo(size_t SymbolsRemaining,
std::unique_ptr<MaterializationUnit> MU);
uint64_t SymbolsRemaining;
std::unique_ptr<MaterializationUnit> MU;
};
using UnmaterializedInfoList = std::list<UnmaterializedInfo>;
using UnmaterializedInfoIterator = UnmaterializedInfoList::iterator;
class MaterializingInfo {
public:
using QueryList = std::vector<std::shared_ptr<AsynchronousSymbolQuery>>;
QueryList PendingResolution;
QueryList PendingFinalization;
};
using MaterializingInfoMap = std::map<SymbolStringPtr, MaterializingInfo>;
using MaterializingInfoIterator = MaterializingInfoMap::iterator;
class SymbolTableEntry {
public:
SymbolTableEntry(JITSymbolFlags SymbolFlags,
UnmaterializedInfoIterator UnmaterializedInfoItr);
SymbolTableEntry(JITEvaluatedSymbol Sym);
SymbolTableEntry(SymbolTableEntry &&Other);
SymbolTableEntry &operator=(SymbolTableEntry &&Other);
~SymbolTableEntry();
// Change definition due to override. Only usable prior to materialization.
void replaceWith(VSO &V, SymbolStringPtr Name, JITEvaluatedSymbol Sym);
// Change definition due to override. Only usable prior to materialization.
void replaceWith(VSO &V, SymbolStringPtr Name, JITSymbolFlags Flags,
UnmaterializedInfoIterator NewUMII);
// Move entry to materializing state, detach from UMII.
std::unique_ptr<MaterializationUnit> initMaterialize(VSO &V);
// Move entry to resolved state.
void resolve(VSO &V, JITEvaluatedSymbol Sym);
// Move entry to finalized state.
void finalize();
JITSymbolFlags Flags;
union {
JITTargetAddress Address;
UnmaterializedInfoIterator UMII;
};
private:
void destroy();
};
void detach(UnmaterializedInfoIterator UMII);
std::map<SymbolStringPtr, SymbolTableEntry> Symbols;
UnmaterializedInfoList UnmaterializedInfos;
MaterializingInfoMap MaterializingInfos;
};
/// @brief An ExecutionSession represents a running JIT program.
class ExecutionSession {
public:
using ErrorReporter = std::function<void(Error)>;
/// @brief Construct an ExecutionEngine.
///
/// SymbolStringPools may be shared between ExecutionSessions.
ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr)
: SSP(SSP ? std::move(SSP) : std::make_shared<SymbolStringPool>()) {}
/// @brief Returns the SymbolStringPool for this ExecutionSession.
SymbolStringPool &getSymbolStringPool() const { return *SSP; }
/// @brief Set the error reporter function.
void setErrorReporter(ErrorReporter ReportError) {
this->ReportError = std::move(ReportError);
}
/// @brief Report a error for this execution session.
///
/// Unhandled errors can be sent here to log them.
void reportError(Error Err) { ReportError(std::move(Err)); }
/// @brief Allocate a module key for a new module to add to the JIT.
VModuleKey allocateVModule() { return ++LastKey; }
/// @brief Return a module key to the ExecutionSession so that it can be
/// re-used. This should only be done once all resources associated
//// with the original key have been released.
void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ }
public:
static void logErrorsToStdErr(Error Err);
std::shared_ptr<SymbolStringPool> SSP;
VModuleKey LastKey = 0;
ErrorReporter ReportError = logErrorsToStdErr;
};
/// Runs Materializers on the current thread and reports errors to the given
/// ExecutionSession.
class MaterializeOnCurrentThread {
public:
MaterializeOnCurrentThread(ExecutionSession &ES) : ES(ES) {}
void operator()(VSO &V, std::unique_ptr<MaterializationUnit> MU) {
if (auto Err = MU->materialize(V))
ES.reportError(std::move(Err));
}
private:
ExecutionSession &ES;
};
/// Materialization function object wrapper for the lookup method.
using MaterializationDispatcher =
std::function<void(VSO &V, std::unique_ptr<MaterializationUnit> S)>;
/// @brief Look up a set of symbols by searching a list of VSOs.
///
/// All VSOs in the list should be non-null.
Expected<SymbolMap> lookup(const std::vector<VSO *> &VSOs, SymbolNameSet Names,
MaterializationDispatcher DispatchMaterialization);
/// @brief Look up a symbol by searching a list of VSOs.
Expected<JITEvaluatedSymbol>
lookup(const std::vector<VSO *> VSOs, SymbolStringPtr Name,
MaterializationDispatcher DispatchMaterialization);
} // End namespace orc
} // End namespace llvm
#endif // LLVM_EXECUTIONENGINE_ORC_CORE_H
|