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