1 //===------ Core.h -- Core ORC APIs (Layer, JITDylib, etc.) -----*- C++ -*-===// 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 // 9 // Contains core ORC APIs. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_EXECUTIONENGINE_ORC_CORE_H 14 #define LLVM_EXECUTIONENGINE_ORC_CORE_H 15 16 #include "llvm/ADT/BitmaskEnum.h" 17 #include "llvm/ADT/DenseSet.h" 18 #include "llvm/ADT/FunctionExtras.h" 19 #include "llvm/ADT/IntrusiveRefCntPtr.h" 20 #include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h" 21 #include "llvm/ExecutionEngine/JITSymbol.h" 22 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" 23 #include "llvm/ExecutionEngine/OrcV1Deprecation.h" 24 #include "llvm/Support/Debug.h" 25 #include "llvm/Support/ExtensibleRTTI.h" 26 27 #include <atomic> 28 #include <memory> 29 #include <vector> 30 31 namespace llvm { 32 namespace orc { 33 34 // Forward declare some classes. 35 class AsynchronousSymbolQuery; 36 class ExecutionSession; 37 class MaterializationUnit; 38 class MaterializationResponsibility; 39 class JITDylib; 40 class ResourceTracker; 41 class InProgressLookupState; 42 43 enum class SymbolState : uint8_t; 44 45 using ResourceTrackerSP = IntrusiveRefCntPtr<ResourceTracker>; 46 using JITDylibSP = IntrusiveRefCntPtr<JITDylib>; 47 48 using ResourceKey = uintptr_t; 49 50 /// API to remove / transfer ownership of JIT resources. 51 class ResourceTracker : public ThreadSafeRefCountedBase<ResourceTracker> { 52 private: 53 friend class ExecutionSession; 54 friend class JITDylib; 55 friend class MaterializationResponsibility; 56 57 public: 58 ResourceTracker(const ResourceTracker &) = delete; 59 ResourceTracker &operator=(const ResourceTracker &) = delete; 60 ResourceTracker(ResourceTracker &&) = delete; 61 ResourceTracker &operator=(ResourceTracker &&) = delete; 62 63 ~ResourceTracker(); 64 65 /// Return the JITDylib targeted by this tracker. 66 JITDylib &getJITDylib() const { 67 return *reinterpret_cast<JITDylib *>(JDAndFlag.load() & 68 ~static_cast<uintptr_t>(1)); 69 } 70 71 /// Remove all resources associated with this key. 72 Error remove(); 73 74 /// Transfer all resources associated with this key to the given 75 /// tracker, which must target the same JITDylib as this one. 76 void transferTo(ResourceTracker &DstRT); 77 78 /// Return true if this tracker has become defunct. 79 bool isDefunct() const { return JDAndFlag.load() & 0x1; } 80 81 /// Returns the key associated with this tracker. 82 /// This method should not be used except for debug logging: there is no 83 /// guarantee that the returned value will remain valid. 84 ResourceKey getKeyUnsafe() const { return reinterpret_cast<uintptr_t>(this); } 85 86 private: 87 ResourceTracker(JITDylibSP JD); 88 89 void makeDefunct(); 90 91 std::atomic_uintptr_t JDAndFlag; 92 }; 93 94 /// Listens for ResourceTracker operations. 95 class ResourceManager { 96 public: 97 virtual ~ResourceManager(); 98 virtual Error handleRemoveResources(ResourceKey K) = 0; 99 virtual void handleTransferResources(ResourceKey DstK, ResourceKey SrcK) = 0; 100 }; 101 102 /// A set of symbol names (represented by SymbolStringPtrs for 103 // efficiency). 104 using SymbolNameSet = DenseSet<SymbolStringPtr>; 105 106 /// A vector of symbol names. 107 using SymbolNameVector = std::vector<SymbolStringPtr>; 108 109 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols 110 /// (address/flags pairs). 111 using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>; 112 113 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags. 114 using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>; 115 116 /// A map from JITDylibs to sets of symbols. 117 using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>; 118 119 /// Lookup flags that apply to each dylib in the search order for a lookup. 120 /// 121 /// If MatchHiddenSymbolsOnly is used (the default) for a given dylib, then 122 /// only symbols in that Dylib's interface will be searched. If 123 /// MatchHiddenSymbols is used then symbols with hidden visibility will match 124 /// as well. 125 enum class JITDylibLookupFlags { MatchExportedSymbolsOnly, MatchAllSymbols }; 126 127 /// Lookup flags that apply to each symbol in a lookup. 128 /// 129 /// If RequiredSymbol is used (the default) for a given symbol then that symbol 130 /// must be found during the lookup or the lookup will fail returning a 131 /// SymbolNotFound error. If WeaklyReferencedSymbol is used and the given 132 /// symbol is not found then the query will continue, and no result for the 133 /// missing symbol will be present in the result (assuming the rest of the 134 /// lookup succeeds). 135 enum class SymbolLookupFlags { RequiredSymbol, WeaklyReferencedSymbol }; 136 137 /// Describes the kind of lookup being performed. The lookup kind is passed to 138 /// symbol generators (if they're invoked) to help them determine what 139 /// definitions to generate. 140 /// 141 /// Static -- Lookup is being performed as-if at static link time (e.g. 142 /// generators representing static archives should pull in new 143 /// definitions). 144 /// 145 /// DLSym -- Lookup is being performed as-if at runtime (e.g. generators 146 /// representing static archives should not pull in new definitions). 147 enum class LookupKind { Static, DLSym }; 148 149 /// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search 150 /// order during symbol lookup. 151 using JITDylibSearchOrder = 152 std::vector<std::pair<JITDylib *, JITDylibLookupFlags>>; 153 154 /// Convenience function for creating a search order from an ArrayRef of 155 /// JITDylib*, all with the same flags. 156 inline JITDylibSearchOrder makeJITDylibSearchOrder( 157 ArrayRef<JITDylib *> JDs, 158 JITDylibLookupFlags Flags = JITDylibLookupFlags::MatchExportedSymbolsOnly) { 159 JITDylibSearchOrder O; 160 O.reserve(JDs.size()); 161 for (auto *JD : JDs) 162 O.push_back(std::make_pair(JD, Flags)); 163 return O; 164 } 165 166 /// A set of symbols to look up, each associated with a SymbolLookupFlags 167 /// value. 168 /// 169 /// This class is backed by a vector and optimized for fast insertion, 170 /// deletion and iteration. It does not guarantee a stable order between 171 /// operations, and will not automatically detect duplicate elements (they 172 /// can be manually checked by calling the validate method). 173 class SymbolLookupSet { 174 public: 175 using value_type = std::pair<SymbolStringPtr, SymbolLookupFlags>; 176 using UnderlyingVector = std::vector<value_type>; 177 using iterator = UnderlyingVector::iterator; 178 using const_iterator = UnderlyingVector::const_iterator; 179 180 SymbolLookupSet() = default; 181 182 explicit SymbolLookupSet( 183 SymbolStringPtr Name, 184 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 185 add(std::move(Name), Flags); 186 } 187 188 /// Construct a SymbolLookupSet from an initializer list of SymbolStringPtrs. 189 explicit SymbolLookupSet( 190 std::initializer_list<SymbolStringPtr> Names, 191 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 192 Symbols.reserve(Names.size()); 193 for (auto &Name : Names) 194 add(std::move(Name), Flags); 195 } 196 197 /// Construct a SymbolLookupSet from a SymbolNameSet with the given 198 /// Flags used for each value. 199 explicit SymbolLookupSet( 200 const SymbolNameSet &Names, 201 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 202 Symbols.reserve(Names.size()); 203 for (const auto &Name : Names) 204 add(Name, Flags); 205 } 206 207 /// Construct a SymbolLookupSet from a vector of symbols with the given Flags 208 /// used for each value. 209 /// If the ArrayRef contains duplicates it is up to the client to remove these 210 /// before using this instance for lookup. 211 explicit SymbolLookupSet( 212 ArrayRef<SymbolStringPtr> Names, 213 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 214 Symbols.reserve(Names.size()); 215 for (const auto &Name : Names) 216 add(Name, Flags); 217 } 218 219 /// Add an element to the set. The client is responsible for checking that 220 /// duplicates are not added. 221 SymbolLookupSet & 222 add(SymbolStringPtr Name, 223 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 224 Symbols.push_back(std::make_pair(std::move(Name), Flags)); 225 return *this; 226 } 227 228 /// Quickly append one lookup set to another. 229 SymbolLookupSet &append(SymbolLookupSet Other) { 230 Symbols.reserve(Symbols.size() + Other.size()); 231 for (auto &KV : Other) 232 Symbols.push_back(std::move(KV)); 233 return *this; 234 } 235 236 bool empty() const { return Symbols.empty(); } 237 UnderlyingVector::size_type size() const { return Symbols.size(); } 238 iterator begin() { return Symbols.begin(); } 239 iterator end() { return Symbols.end(); } 240 const_iterator begin() const { return Symbols.begin(); } 241 const_iterator end() const { return Symbols.end(); } 242 243 /// Removes the Ith element of the vector, replacing it with the last element. 244 void remove(UnderlyingVector::size_type I) { 245 std::swap(Symbols[I], Symbols.back()); 246 Symbols.pop_back(); 247 } 248 249 /// Removes the element pointed to by the given iterator. This iterator and 250 /// all subsequent ones (including end()) are invalidated. 251 void remove(iterator I) { remove(I - begin()); } 252 253 /// Removes all elements matching the given predicate, which must be callable 254 /// as bool(const SymbolStringPtr &, SymbolLookupFlags Flags). 255 template <typename PredFn> void remove_if(PredFn &&Pred) { 256 UnderlyingVector::size_type I = 0; 257 while (I != Symbols.size()) { 258 const auto &Name = Symbols[I].first; 259 auto Flags = Symbols[I].second; 260 if (Pred(Name, Flags)) 261 remove(I); 262 else 263 ++I; 264 } 265 } 266 267 /// Loop over the elements of this SymbolLookupSet, applying the Body function 268 /// to each one. Body must be callable as 269 /// bool(const SymbolStringPtr &, SymbolLookupFlags). 270 /// If Body returns true then the element just passed in is removed from the 271 /// set. If Body returns false then the element is retained. 272 template <typename BodyFn> 273 auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t< 274 std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(), 275 std::declval<SymbolLookupFlags>())), 276 bool>::value> { 277 UnderlyingVector::size_type I = 0; 278 while (I != Symbols.size()) { 279 const auto &Name = Symbols[I].first; 280 auto Flags = Symbols[I].second; 281 if (Body(Name, Flags)) 282 remove(I); 283 else 284 ++I; 285 } 286 } 287 288 /// Loop over the elements of this SymbolLookupSet, applying the Body function 289 /// to each one. Body must be callable as 290 /// Expected<bool>(const SymbolStringPtr &, SymbolLookupFlags). 291 /// If Body returns a failure value, the loop exits immediately. If Body 292 /// returns true then the element just passed in is removed from the set. If 293 /// Body returns false then the element is retained. 294 template <typename BodyFn> 295 auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t< 296 std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(), 297 std::declval<SymbolLookupFlags>())), 298 Expected<bool>>::value, 299 Error> { 300 UnderlyingVector::size_type I = 0; 301 while (I != Symbols.size()) { 302 const auto &Name = Symbols[I].first; 303 auto Flags = Symbols[I].second; 304 auto Remove = Body(Name, Flags); 305 if (!Remove) 306 return Remove.takeError(); 307 if (*Remove) 308 remove(I); 309 else 310 ++I; 311 } 312 return Error::success(); 313 } 314 315 /// Construct a SymbolNameVector from this instance by dropping the Flags 316 /// values. 317 SymbolNameVector getSymbolNames() const { 318 SymbolNameVector Names; 319 Names.reserve(Symbols.size()); 320 for (auto &KV : Symbols) 321 Names.push_back(KV.first); 322 return Names; 323 } 324 325 /// Sort the lookup set by pointer value. This sort is fast but sensitive to 326 /// allocation order and so should not be used where a consistent order is 327 /// required. 328 void sortByAddress() { 329 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) { 330 return LHS.first < RHS.first; 331 }); 332 } 333 334 /// Sort the lookup set lexicographically. This sort is slow but the order 335 /// is unaffected by allocation order. 336 void sortByName() { 337 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) { 338 return *LHS.first < *RHS.first; 339 }); 340 } 341 342 /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free 343 /// by construction, this method can be used to turn it into a proper set. 344 void removeDuplicates() { 345 sortByAddress(); 346 auto LastI = std::unique(Symbols.begin(), Symbols.end()); 347 Symbols.erase(LastI, Symbols.end()); 348 } 349 350 #ifndef NDEBUG 351 /// Returns true if this set contains any duplicates. This should only be used 352 /// in assertions. 353 bool containsDuplicates() { 354 if (Symbols.size() < 2) 355 return false; 356 sortByAddress(); 357 for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I) 358 if (Symbols[I].first == Symbols[I - 1].first) 359 return true; 360 return false; 361 } 362 #endif 363 364 private: 365 UnderlyingVector Symbols; 366 }; 367 368 struct SymbolAliasMapEntry { 369 SymbolAliasMapEntry() = default; 370 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags) 371 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {} 372 373 SymbolStringPtr Aliasee; 374 JITSymbolFlags AliasFlags; 375 }; 376 377 /// A map of Symbols to (Symbol, Flags) pairs. 378 using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>; 379 380 /// Callback to notify client that symbols have been resolved. 381 using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>; 382 383 /// Callback to register the dependencies for a given query. 384 using RegisterDependenciesFunction = 385 std::function<void(const SymbolDependenceMap &)>; 386 387 /// This can be used as the value for a RegisterDependenciesFunction if there 388 /// are no dependants to register with. 389 extern RegisterDependenciesFunction NoDependenciesToRegister; 390 391 class ResourceTrackerDefunct : public ErrorInfo<ResourceTrackerDefunct> { 392 public: 393 static char ID; 394 395 ResourceTrackerDefunct(ResourceTrackerSP RT); 396 std::error_code convertToErrorCode() const override; 397 void log(raw_ostream &OS) const override; 398 399 private: 400 ResourceTrackerSP RT; 401 }; 402 403 /// Used to notify a JITDylib that the given set of symbols failed to 404 /// materialize. 405 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> { 406 public: 407 static char ID; 408 409 FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols); 410 std::error_code convertToErrorCode() const override; 411 void log(raw_ostream &OS) const override; 412 const SymbolDependenceMap &getSymbols() const { return *Symbols; } 413 414 private: 415 std::shared_ptr<SymbolDependenceMap> Symbols; 416 }; 417 418 /// Used to notify clients when symbols can not be found during a lookup. 419 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> { 420 public: 421 static char ID; 422 423 SymbolsNotFound(SymbolNameSet Symbols); 424 SymbolsNotFound(SymbolNameVector Symbols); 425 std::error_code convertToErrorCode() const override; 426 void log(raw_ostream &OS) const override; 427 const SymbolNameVector &getSymbols() const { return Symbols; } 428 429 private: 430 SymbolNameVector Symbols; 431 }; 432 433 /// Used to notify clients that a set of symbols could not be removed. 434 class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> { 435 public: 436 static char ID; 437 438 SymbolsCouldNotBeRemoved(SymbolNameSet Symbols); 439 std::error_code convertToErrorCode() const override; 440 void log(raw_ostream &OS) const override; 441 const SymbolNameSet &getSymbols() const { return Symbols; } 442 443 private: 444 SymbolNameSet Symbols; 445 }; 446 447 /// Errors of this type should be returned if a module fails to include 448 /// definitions that are claimed by the module's associated 449 /// MaterializationResponsibility. If this error is returned it is indicative of 450 /// a broken transformation / compiler / object cache. 451 class MissingSymbolDefinitions : public ErrorInfo<MissingSymbolDefinitions> { 452 public: 453 static char ID; 454 455 MissingSymbolDefinitions(std::string ModuleName, SymbolNameVector Symbols) 456 : ModuleName(std::move(ModuleName)), Symbols(std::move(Symbols)) {} 457 std::error_code convertToErrorCode() const override; 458 void log(raw_ostream &OS) const override; 459 const std::string &getModuleName() const { return ModuleName; } 460 const SymbolNameVector &getSymbols() const { return Symbols; } 461 private: 462 std::string ModuleName; 463 SymbolNameVector Symbols; 464 }; 465 466 /// Errors of this type should be returned if a module contains definitions for 467 /// symbols that are not claimed by the module's associated 468 /// MaterializationResponsibility. If this error is returned it is indicative of 469 /// a broken transformation / compiler / object cache. 470 class UnexpectedSymbolDefinitions : public ErrorInfo<UnexpectedSymbolDefinitions> { 471 public: 472 static char ID; 473 474 UnexpectedSymbolDefinitions(std::string ModuleName, SymbolNameVector Symbols) 475 : ModuleName(std::move(ModuleName)), Symbols(std::move(Symbols)) {} 476 std::error_code convertToErrorCode() const override; 477 void log(raw_ostream &OS) const override; 478 const std::string &getModuleName() const { return ModuleName; } 479 const SymbolNameVector &getSymbols() const { return Symbols; } 480 private: 481 std::string ModuleName; 482 SymbolNameVector Symbols; 483 }; 484 485 /// Tracks responsibility for materialization, and mediates interactions between 486 /// MaterializationUnits and JDs. 487 /// 488 /// An instance of this class is passed to MaterializationUnits when their 489 /// materialize method is called. It allows MaterializationUnits to resolve and 490 /// emit symbols, or abandon materialization by notifying any unmaterialized 491 /// symbols of an error. 492 class MaterializationResponsibility { 493 friend class ExecutionSession; 494 495 public: 496 MaterializationResponsibility(MaterializationResponsibility &&) = delete; 497 MaterializationResponsibility & 498 operator=(MaterializationResponsibility &&) = delete; 499 500 /// Destruct a MaterializationResponsibility instance. In debug mode 501 /// this asserts that all symbols being tracked have been either 502 /// emitted or notified of an error. 503 ~MaterializationResponsibility(); 504 505 /// Returns the ResourceTracker for this instance. 506 template <typename Func> Error withResourceKeyDo(Func &&F) const; 507 508 /// Returns the target JITDylib that these symbols are being materialized 509 /// into. 510 JITDylib &getTargetJITDylib() const { return *JD; } 511 512 /// Returns the ExecutionSession for this instance. 513 ExecutionSession &getExecutionSession(); 514 515 /// Returns the symbol flags map for this responsibility instance. 516 /// Note: The returned flags may have transient flags (Lazy, Materializing) 517 /// set. These should be stripped with JITSymbolFlags::stripTransientFlags 518 /// before using. 519 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } 520 521 /// Returns the initialization pseudo-symbol, if any. This symbol will also 522 /// be present in the SymbolFlagsMap for this MaterializationResponsibility 523 /// object. 524 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; } 525 526 /// Returns the names of any symbols covered by this 527 /// MaterializationResponsibility object that have queries pending. This 528 /// information can be used to return responsibility for unrequested symbols 529 /// back to the JITDylib via the delegate method. 530 SymbolNameSet getRequestedSymbols() const; 531 532 /// Notifies the target JITDylib that the given symbols have been resolved. 533 /// This will update the given symbols' addresses in the JITDylib, and notify 534 /// any pending queries on the given symbols of their resolution. The given 535 /// symbols must be ones covered by this MaterializationResponsibility 536 /// instance. Individual calls to this method may resolve a subset of the 537 /// symbols, but all symbols must have been resolved prior to calling emit. 538 /// 539 /// This method will return an error if any symbols being resolved have been 540 /// moved to the error state due to the failure of a dependency. If this 541 /// method returns an error then clients should log it and call 542 /// failMaterialize. If no dependencies have been registered for the 543 /// symbols covered by this MaterializationResponsibiility then this method 544 /// is guaranteed to return Error::success() and can be wrapped with cantFail. 545 Error notifyResolved(const SymbolMap &Symbols); 546 547 /// Notifies the target JITDylib (and any pending queries on that JITDylib) 548 /// that all symbols covered by this MaterializationResponsibility instance 549 /// have been emitted. 550 /// 551 /// This method will return an error if any symbols being resolved have been 552 /// moved to the error state due to the failure of a dependency. If this 553 /// method returns an error then clients should log it and call 554 /// failMaterialize. If no dependencies have been registered for the 555 /// symbols covered by this MaterializationResponsibiility then this method 556 /// is guaranteed to return Error::success() and can be wrapped with cantFail. 557 Error notifyEmitted(); 558 559 /// Attempt to claim responsibility for new definitions. This method can be 560 /// used to claim responsibility for symbols that are added to a 561 /// materialization unit during the compilation process (e.g. literal pool 562 /// symbols). Symbol linkage rules are the same as for symbols that are 563 /// defined up front: duplicate strong definitions will result in errors. 564 /// Duplicate weak definitions will be discarded (in which case they will 565 /// not be added to this responsibility instance). 566 /// 567 /// This method can be used by materialization units that want to add 568 /// additional symbols at materialization time (e.g. stubs, compile 569 /// callbacks, metadata). 570 Error defineMaterializing(SymbolFlagsMap SymbolFlags); 571 572 /// Define the given symbols as non-existent, removing it from the symbol 573 /// table and notifying any pending queries. Queries that lookup up the 574 /// symbol using the SymbolLookupFlags::WeaklyReferencedSymbol flag will 575 /// behave as if the symbol had not been matched in the first place. Queries 576 /// that required this symbol will fail with a missing symbol definition 577 /// error. 578 /// 579 /// This method is intended to support cleanup of special symbols like 580 /// initializer symbols: Queries using 581 /// SymbolLookupFlags::WeaklyReferencedSymbol can be used to trigger their 582 /// emission, and this method can be used to remove them from the JITDylib 583 /// once materialization is complete. 584 void defineNonExistent(ArrayRef<SymbolStringPtr> Symbols); 585 586 /// Notify all not-yet-emitted covered by this MaterializationResponsibility 587 /// instance that an error has occurred. 588 /// This will remove all symbols covered by this MaterializationResponsibilty 589 /// from the target JITDylib, and send an error to any queries waiting on 590 /// these symbols. 591 void failMaterialization(); 592 593 /// Transfers responsibility to the given MaterializationUnit for all 594 /// symbols defined by that MaterializationUnit. This allows 595 /// materializers to break up work based on run-time information (e.g. 596 /// by introspecting which symbols have actually been looked up and 597 /// materializing only those). 598 Error replace(std::unique_ptr<MaterializationUnit> MU); 599 600 /// Delegates responsibility for the given symbols to the returned 601 /// materialization responsibility. Useful for breaking up work between 602 /// threads, or different kinds of materialization processes. 603 Expected<std::unique_ptr<MaterializationResponsibility>> 604 delegate(const SymbolNameSet &Symbols); 605 606 void addDependencies(const SymbolStringPtr &Name, 607 const SymbolDependenceMap &Dependencies); 608 609 /// Add dependencies that apply to all symbols covered by this instance. 610 void addDependenciesForAll(const SymbolDependenceMap &Dependencies); 611 612 private: 613 /// Create a MaterializationResponsibility for the given JITDylib and 614 /// initial symbols. 615 MaterializationResponsibility(JITDylibSP JD, SymbolFlagsMap SymbolFlags, 616 SymbolStringPtr InitSymbol) 617 : JD(std::move(JD)), SymbolFlags(std::move(SymbolFlags)), 618 InitSymbol(std::move(InitSymbol)) { 619 assert(this->JD && "Cannot initialize with null JITDylib"); 620 assert(!this->SymbolFlags.empty() && "Materializing nothing?"); 621 } 622 623 JITDylibSP JD; 624 SymbolFlagsMap SymbolFlags; 625 SymbolStringPtr InitSymbol; 626 }; 627 628 /// A MaterializationUnit represents a set of symbol definitions that can 629 /// be materialized as a group, or individually discarded (when 630 /// overriding definitions are encountered). 631 /// 632 /// MaterializationUnits are used when providing lazy definitions of symbols to 633 /// JITDylibs. The JITDylib will call materialize when the address of a symbol 634 /// is requested via the lookup method. The JITDylib will call discard if a 635 /// stronger definition is added or already present. 636 class MaterializationUnit { 637 friend class ExecutionSession; 638 friend class JITDylib; 639 640 public: 641 static char ID; 642 643 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, 644 SymbolStringPtr InitSymbol) 645 : SymbolFlags(std::move(InitalSymbolFlags)), 646 InitSymbol(std::move(InitSymbol)) { 647 assert((!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) && 648 "If set, InitSymbol should appear in InitialSymbolFlags map"); 649 } 650 651 virtual ~MaterializationUnit() {} 652 653 /// Return the name of this materialization unit. Useful for debugging 654 /// output. 655 virtual StringRef getName() const = 0; 656 657 /// Return the set of symbols that this source provides. 658 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } 659 660 /// Returns the initialization symbol for this MaterializationUnit (if any). 661 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; } 662 663 /// Implementations of this method should materialize all symbols 664 /// in the materialzation unit, except for those that have been 665 /// previously discarded. 666 virtual void 667 materialize(std::unique_ptr<MaterializationResponsibility> R) = 0; 668 669 /// Called by JITDylibs to notify MaterializationUnits that the given symbol 670 /// has been overridden. 671 void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) { 672 SymbolFlags.erase(Name); 673 discard(JD, std::move(Name)); 674 } 675 676 protected: 677 SymbolFlagsMap SymbolFlags; 678 SymbolStringPtr InitSymbol; 679 680 private: 681 virtual void anchor(); 682 683 /// Implementations of this method should discard the given symbol 684 /// from the source (e.g. if the source is an LLVM IR Module and the 685 /// symbol is a function, delete the function body or mark it available 686 /// externally). 687 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0; 688 }; 689 690 /// A MaterializationUnit implementation for pre-existing absolute symbols. 691 /// 692 /// All symbols will be resolved and marked ready as soon as the unit is 693 /// materialized. 694 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { 695 public: 696 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols); 697 698 StringRef getName() const override; 699 700 private: 701 void materialize(std::unique_ptr<MaterializationResponsibility> R) override; 702 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; 703 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols); 704 705 SymbolMap Symbols; 706 }; 707 708 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols. 709 /// Useful for inserting absolute symbols into a JITDylib. E.g.: 710 /// \code{.cpp} 711 /// JITDylib &JD = ...; 712 /// SymbolStringPtr Foo = ...; 713 /// JITEvaluatedSymbol FooSym = ...; 714 /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}}))) 715 /// return Err; 716 /// \endcode 717 /// 718 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit> 719 absoluteSymbols(SymbolMap Symbols) { 720 return std::make_unique<AbsoluteSymbolsMaterializationUnit>( 721 std::move(Symbols)); 722 } 723 724 /// A materialization unit for symbol aliases. Allows existing symbols to be 725 /// aliased with alternate flags. 726 class ReExportsMaterializationUnit : public MaterializationUnit { 727 public: 728 /// SourceJD is allowed to be nullptr, in which case the source JITDylib is 729 /// taken to be whatever JITDylib these definitions are materialized in (and 730 /// MatchNonExported has no effect). This is useful for defining aliases 731 /// within a JITDylib. 732 /// 733 /// Note: Care must be taken that no sets of aliases form a cycle, as such 734 /// a cycle will result in a deadlock when any symbol in the cycle is 735 /// resolved. 736 ReExportsMaterializationUnit(JITDylib *SourceJD, 737 JITDylibLookupFlags SourceJDLookupFlags, 738 SymbolAliasMap Aliases); 739 740 StringRef getName() const override; 741 742 private: 743 void materialize(std::unique_ptr<MaterializationResponsibility> R) override; 744 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; 745 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases); 746 747 JITDylib *SourceJD = nullptr; 748 JITDylibLookupFlags SourceJDLookupFlags; 749 SymbolAliasMap Aliases; 750 }; 751 752 /// Create a ReExportsMaterializationUnit with the given aliases. 753 /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing 754 /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" 755 /// (for "bar") with: \code{.cpp} 756 /// SymbolStringPtr Baz = ...; 757 /// SymbolStringPtr Qux = ...; 758 /// if (auto Err = JD.define(symbolAliases({ 759 /// {Baz, { Foo, JITSymbolFlags::Exported }}, 760 /// {Qux, { Bar, JITSymbolFlags::Weak }}})) 761 /// return Err; 762 /// \endcode 763 inline std::unique_ptr<ReExportsMaterializationUnit> 764 symbolAliases(SymbolAliasMap Aliases) { 765 return std::make_unique<ReExportsMaterializationUnit>( 766 nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases)); 767 } 768 769 /// Create a materialization unit for re-exporting symbols from another JITDylib 770 /// with alternative names/flags. 771 /// SourceJD will be searched using the given JITDylibLookupFlags. 772 inline std::unique_ptr<ReExportsMaterializationUnit> 773 reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, 774 JITDylibLookupFlags SourceJDLookupFlags = 775 JITDylibLookupFlags::MatchExportedSymbolsOnly) { 776 return std::make_unique<ReExportsMaterializationUnit>( 777 &SourceJD, SourceJDLookupFlags, std::move(Aliases)); 778 } 779 780 /// Build a SymbolAliasMap for the common case where you want to re-export 781 /// symbols from another JITDylib with the same linkage/flags. 782 Expected<SymbolAliasMap> 783 buildSimpleReexportsAAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols); 784 785 /// Represents the state that a symbol has reached during materialization. 786 enum class SymbolState : uint8_t { 787 Invalid, /// No symbol should be in this state. 788 NeverSearched, /// Added to the symbol table, never queried. 789 Materializing, /// Queried, materialization begun. 790 Resolved, /// Assigned address, still materializing. 791 Emitted, /// Emitted to memory, but waiting on transitive dependencies. 792 Ready = 0x3f /// Ready and safe for clients to access. 793 }; 794 795 /// A symbol query that returns results via a callback when results are 796 /// ready. 797 /// 798 /// makes a callback when all symbols are available. 799 class AsynchronousSymbolQuery { 800 friend class ExecutionSession; 801 friend class InProgressFullLookupState; 802 friend class JITDylib; 803 friend class JITSymbolResolverAdapter; 804 friend class MaterializationResponsibility; 805 806 public: 807 /// Create a query for the given symbols. The NotifyComplete 808 /// callback will be called once all queried symbols reach the given 809 /// minimum state. 810 AsynchronousSymbolQuery(const SymbolLookupSet &Symbols, 811 SymbolState RequiredState, 812 SymbolsResolvedCallback NotifyComplete); 813 814 /// Notify the query that a requested symbol has reached the required state. 815 void notifySymbolMetRequiredState(const SymbolStringPtr &Name, 816 JITEvaluatedSymbol Sym); 817 818 /// Returns true if all symbols covered by this query have been 819 /// resolved. 820 bool isComplete() const { return OutstandingSymbolsCount == 0; } 821 822 823 private: 824 void handleComplete(ExecutionSession &ES); 825 826 SymbolState getRequiredState() { return RequiredState; } 827 828 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name); 829 830 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name); 831 832 void dropSymbol(const SymbolStringPtr &Name); 833 834 void handleFailed(Error Err); 835 836 void detach(); 837 838 SymbolsResolvedCallback NotifyComplete; 839 SymbolDependenceMap QueryRegistrations; 840 SymbolMap ResolvedSymbols; 841 size_t OutstandingSymbolsCount; 842 SymbolState RequiredState; 843 }; 844 845 /// Wraps state for a lookup-in-progress. 846 /// DefinitionGenerators can optionally take ownership of a LookupState object 847 /// to suspend a lookup-in-progress while they search for definitions. 848 class LookupState { 849 friend class OrcV2CAPIHelper; 850 friend class ExecutionSession; 851 852 public: 853 LookupState(); 854 LookupState(LookupState &&); 855 LookupState &operator=(LookupState &&); 856 ~LookupState(); 857 858 /// Continue the lookup. This can be called by DefinitionGenerators 859 /// to re-start a captured query-application operation. 860 void continueLookup(Error Err); 861 862 private: 863 LookupState(std::unique_ptr<InProgressLookupState> IPLS); 864 865 // For C API. 866 void reset(InProgressLookupState *IPLS); 867 868 std::unique_ptr<InProgressLookupState> IPLS; 869 }; 870 871 /// Definition generators can be attached to JITDylibs to generate new 872 /// definitions for otherwise unresolved symbols during lookup. 873 class DefinitionGenerator { 874 public: 875 virtual ~DefinitionGenerator(); 876 877 /// DefinitionGenerators should override this method to insert new 878 /// definitions into the parent JITDylib. K specifies the kind of this 879 /// lookup. JD specifies the target JITDylib being searched, and 880 /// JDLookupFlags specifies whether the search should match against 881 /// hidden symbols. Finally, Symbols describes the set of unresolved 882 /// symbols and their associated lookup flags. 883 virtual Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 884 JITDylibLookupFlags JDLookupFlags, 885 const SymbolLookupSet &LookupSet) = 0; 886 }; 887 888 /// A symbol table that supports asynchoronous symbol queries. 889 /// 890 /// Represents a virtual shared object. Instances can not be copied or moved, so 891 /// their addresses may be used as keys for resource management. 892 /// JITDylib state changes must be made via an ExecutionSession to guarantee 893 /// that they are synchronized with respect to other JITDylib operations. 894 class JITDylib : public ThreadSafeRefCountedBase<JITDylib>, 895 public jitlink::JITLinkDylib { 896 friend class AsynchronousSymbolQuery; 897 friend class ExecutionSession; 898 friend class Platform; 899 friend class MaterializationResponsibility; 900 public: 901 902 using AsynchronousSymbolQuerySet = 903 std::set<std::shared_ptr<AsynchronousSymbolQuery>>; 904 905 JITDylib(const JITDylib &) = delete; 906 JITDylib &operator=(const JITDylib &) = delete; 907 JITDylib(JITDylib &&) = delete; 908 JITDylib &operator=(JITDylib &&) = delete; 909 910 /// Get the name for this JITDylib. 911 const std::string &getName() const { return JITDylibName; } 912 913 /// Get a reference to the ExecutionSession for this JITDylib. 914 ExecutionSession &getExecutionSession() const { return ES; } 915 916 /// Calls remove on all trackers currently associated with this JITDylib. 917 /// Does not run static deinits. 918 /// 919 /// Note that removal happens outside the session lock, so new code may be 920 /// added concurrently while the clear is underway, and the newly added 921 /// code will *not* be cleared. Adding new code concurrently with a clear 922 /// is usually a bug and should be avoided. 923 Error clear(); 924 925 /// Get the default resource tracker for this JITDylib. 926 ResourceTrackerSP getDefaultResourceTracker(); 927 928 /// Create a resource tracker for this JITDylib. 929 ResourceTrackerSP createResourceTracker(); 930 931 /// Adds a definition generator to this JITDylib and returns a referenece to 932 /// it. 933 /// 934 /// When JITDylibs are searched during lookup, if no existing definition of 935 /// a symbol is found, then any generators that have been added are run (in 936 /// the order that they were added) to potentially generate a definition. 937 template <typename GeneratorT> 938 GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator); 939 940 /// Remove a definition generator from this JITDylib. 941 /// 942 /// The given generator must exist in this JITDylib's generators list (i.e. 943 /// have been added and not yet removed). 944 void removeGenerator(DefinitionGenerator &G); 945 946 /// Set the link order to be used when fixing up definitions in JITDylib. 947 /// This will replace the previous link order, and apply to any symbol 948 /// resolutions made for definitions in this JITDylib after the call to 949 /// setLinkOrder (even if the definition itself was added before the 950 /// call). 951 /// 952 /// If LinkAgainstThisJITDylibFirst is true (the default) then this JITDylib 953 /// will add itself to the beginning of the LinkOrder (Clients should not 954 /// put this JITDylib in the list in this case, to avoid redundant lookups). 955 /// 956 /// If LinkAgainstThisJITDylibFirst is false then the link order will be used 957 /// as-is. The primary motivation for this feature is to support deliberate 958 /// shadowing of symbols in this JITDylib by a facade JITDylib. For example, 959 /// the facade may resolve function names to stubs, and the stubs may compile 960 /// lazily by looking up symbols in this dylib. Adding the facade dylib 961 /// as the first in the link order (instead of this dylib) ensures that 962 /// definitions within this dylib resolve to the lazy-compiling stubs, 963 /// rather than immediately materializing the definitions in this dylib. 964 void setLinkOrder(JITDylibSearchOrder NewSearchOrder, 965 bool LinkAgainstThisJITDylibFirst = true); 966 967 /// Add the given JITDylib to the link order for definitions in this 968 /// JITDylib. 969 void addToLinkOrder(JITDylib &JD, 970 JITDylibLookupFlags JDLookupFlags = 971 JITDylibLookupFlags::MatchExportedSymbolsOnly); 972 973 /// Replace OldJD with NewJD in the link order if OldJD is present. 974 /// Otherwise this operation is a no-op. 975 void replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD, 976 JITDylibLookupFlags JDLookupFlags = 977 JITDylibLookupFlags::MatchExportedSymbolsOnly); 978 979 /// Remove the given JITDylib from the link order for this JITDylib if it is 980 /// present. Otherwise this operation is a no-op. 981 void removeFromLinkOrder(JITDylib &JD); 982 983 /// Do something with the link order (run under the session lock). 984 template <typename Func> 985 auto withLinkOrderDo(Func &&F) 986 -> decltype(F(std::declval<const JITDylibSearchOrder &>())); 987 988 /// Define all symbols provided by the materialization unit to be part of this 989 /// JITDylib. 990 /// 991 /// If RT is not specified then the default resource tracker will be used. 992 /// 993 /// This overload always takes ownership of the MaterializationUnit. If any 994 /// errors occur, the MaterializationUnit consumed. 995 template <typename MaterializationUnitType> 996 Error define(std::unique_ptr<MaterializationUnitType> &&MU, 997 ResourceTrackerSP RT = nullptr); 998 999 /// Define all symbols provided by the materialization unit to be part of this 1000 /// JITDylib. 1001 /// 1002 /// This overload only takes ownership of the MaterializationUnit no error is 1003 /// generated. If an error occurs, ownership remains with the caller. This 1004 /// may allow the caller to modify the MaterializationUnit to correct the 1005 /// issue, then re-call define. 1006 template <typename MaterializationUnitType> 1007 Error define(std::unique_ptr<MaterializationUnitType> &MU, 1008 ResourceTrackerSP RT = nullptr); 1009 1010 /// Tries to remove the given symbols. 1011 /// 1012 /// If any symbols are not defined in this JITDylib this method will return 1013 /// a SymbolsNotFound error covering the missing symbols. 1014 /// 1015 /// If all symbols are found but some symbols are in the process of being 1016 /// materialized this method will return a SymbolsCouldNotBeRemoved error. 1017 /// 1018 /// On success, all symbols are removed. On failure, the JITDylib state is 1019 /// left unmodified (no symbols are removed). 1020 Error remove(const SymbolNameSet &Names); 1021 1022 /// Dump current JITDylib state to OS. 1023 void dump(raw_ostream &OS); 1024 1025 /// Returns the given JITDylibs and all of their transitive dependencies in 1026 /// DFS order (based on linkage relationships). Each JITDylib will appear 1027 /// only once. 1028 static std::vector<JITDylibSP> getDFSLinkOrder(ArrayRef<JITDylibSP> JDs); 1029 1030 /// Returns the given JITDylibs and all of their transitive dependensies in 1031 /// reverse DFS order (based on linkage relationships). Each JITDylib will 1032 /// appear only once. 1033 static std::vector<JITDylibSP> 1034 getReverseDFSLinkOrder(ArrayRef<JITDylibSP> JDs); 1035 1036 /// Return this JITDylib and its transitive dependencies in DFS order 1037 /// based on linkage relationships. 1038 std::vector<JITDylibSP> getDFSLinkOrder(); 1039 1040 /// Rteurn this JITDylib and its transitive dependencies in reverse DFS order 1041 /// based on linkage relationships. 1042 std::vector<JITDylibSP> getReverseDFSLinkOrder(); 1043 1044 private: 1045 using AsynchronousSymbolQueryList = 1046 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>; 1047 1048 struct UnmaterializedInfo { 1049 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU, 1050 ResourceTracker *RT) 1051 : MU(std::move(MU)), RT(RT) {} 1052 1053 std::unique_ptr<MaterializationUnit> MU; 1054 ResourceTracker *RT; 1055 }; 1056 1057 using UnmaterializedInfosMap = 1058 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>; 1059 1060 using UnmaterializedInfosList = 1061 std::vector<std::shared_ptr<UnmaterializedInfo>>; 1062 1063 struct MaterializingInfo { 1064 SymbolDependenceMap Dependants; 1065 SymbolDependenceMap UnemittedDependencies; 1066 1067 void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q); 1068 void removeQuery(const AsynchronousSymbolQuery &Q); 1069 AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState); 1070 AsynchronousSymbolQueryList takeAllPendingQueries() { 1071 return std::move(PendingQueries); 1072 } 1073 bool hasQueriesPending() const { return !PendingQueries.empty(); } 1074 const AsynchronousSymbolQueryList &pendingQueries() const { 1075 return PendingQueries; 1076 } 1077 private: 1078 AsynchronousSymbolQueryList PendingQueries; 1079 }; 1080 1081 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>; 1082 1083 class SymbolTableEntry { 1084 public: 1085 SymbolTableEntry() = default; 1086 SymbolTableEntry(JITSymbolFlags Flags) 1087 : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)), 1088 MaterializerAttached(false), PendingRemoval(false) {} 1089 1090 JITTargetAddress getAddress() const { return Addr; } 1091 JITSymbolFlags getFlags() const { return Flags; } 1092 SymbolState getState() const { return static_cast<SymbolState>(State); } 1093 1094 bool hasMaterializerAttached() const { return MaterializerAttached; } 1095 bool isPendingRemoval() const { return PendingRemoval; } 1096 1097 void setAddress(JITTargetAddress Addr) { this->Addr = Addr; } 1098 void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; } 1099 void setState(SymbolState State) { 1100 assert(static_cast<uint8_t>(State) < (1 << 6) && 1101 "State does not fit in bitfield"); 1102 this->State = static_cast<uint8_t>(State); 1103 } 1104 1105 void setMaterializerAttached(bool MaterializerAttached) { 1106 this->MaterializerAttached = MaterializerAttached; 1107 } 1108 1109 void setPendingRemoval(bool PendingRemoval) { 1110 this->PendingRemoval = PendingRemoval; 1111 } 1112 1113 JITEvaluatedSymbol getSymbol() const { 1114 return JITEvaluatedSymbol(Addr, Flags); 1115 } 1116 1117 private: 1118 JITTargetAddress Addr = 0; 1119 JITSymbolFlags Flags; 1120 uint8_t State : 6; 1121 uint8_t MaterializerAttached : 1; 1122 uint8_t PendingRemoval : 1; 1123 }; 1124 1125 using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>; 1126 1127 JITDylib(ExecutionSession &ES, std::string Name); 1128 1129 ResourceTrackerSP getTracker(MaterializationResponsibility &MR); 1130 std::pair<AsynchronousSymbolQuerySet, std::shared_ptr<SymbolDependenceMap>> 1131 removeTracker(ResourceTracker &RT); 1132 1133 void transferTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); 1134 1135 Error defineImpl(MaterializationUnit &MU); 1136 1137 void installMaterializationUnit(std::unique_ptr<MaterializationUnit> MU, 1138 ResourceTracker &RT); 1139 1140 void detachQueryHelper(AsynchronousSymbolQuery &Q, 1141 const SymbolNameSet &QuerySymbols); 1142 1143 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI, 1144 const SymbolStringPtr &DependantName, 1145 MaterializingInfo &EmittedMI); 1146 1147 Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags); 1148 1149 Error replace(MaterializationResponsibility &FromMR, 1150 std::unique_ptr<MaterializationUnit> MU); 1151 1152 Expected<std::unique_ptr<MaterializationResponsibility>> 1153 delegate(MaterializationResponsibility &FromMR, SymbolFlagsMap SymbolFlags, 1154 SymbolStringPtr InitSymbol); 1155 1156 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const; 1157 1158 void addDependencies(const SymbolStringPtr &Name, 1159 const SymbolDependenceMap &Dependants); 1160 1161 Error resolve(MaterializationResponsibility &MR, const SymbolMap &Resolved); 1162 1163 Error emit(MaterializationResponsibility &MR, const SymbolFlagsMap &Emitted); 1164 1165 void unlinkMaterializationResponsibility(MaterializationResponsibility &MR); 1166 1167 using FailedSymbolsWorklist = 1168 std::vector<std::pair<JITDylib *, SymbolStringPtr>>; 1169 1170 static std::pair<AsynchronousSymbolQuerySet, 1171 std::shared_ptr<SymbolDependenceMap>> 1172 failSymbols(FailedSymbolsWorklist); 1173 1174 ExecutionSession &ES; 1175 std::string JITDylibName; 1176 std::mutex GeneratorsMutex; 1177 bool Open = true; 1178 SymbolTable Symbols; 1179 UnmaterializedInfosMap UnmaterializedInfos; 1180 MaterializingInfosMap MaterializingInfos; 1181 std::vector<std::shared_ptr<DefinitionGenerator>> DefGenerators; 1182 JITDylibSearchOrder LinkOrder; 1183 ResourceTrackerSP DefaultTracker; 1184 1185 // Map trackers to sets of symbols tracked. 1186 DenseMap<ResourceTracker *, SymbolNameVector> TrackerSymbols; 1187 DenseMap<MaterializationResponsibility *, ResourceTracker *> MRTrackers; 1188 }; 1189 1190 /// Platforms set up standard symbols and mediate interactions between dynamic 1191 /// initializers (e.g. C++ static constructors) and ExecutionSession state. 1192 /// Note that Platforms do not automatically run initializers: clients are still 1193 /// responsible for doing this. 1194 class Platform { 1195 public: 1196 virtual ~Platform(); 1197 1198 /// This method will be called outside the session lock each time a JITDylib 1199 /// is created (unless it is created with EmptyJITDylib set) to allow the 1200 /// Platform to install any JITDylib specific standard symbols (e.g 1201 /// __dso_handle). 1202 virtual Error setupJITDylib(JITDylib &JD) = 0; 1203 1204 /// This method will be called under the ExecutionSession lock each time a 1205 /// MaterializationUnit is added to a JITDylib. 1206 virtual Error notifyAdding(ResourceTracker &RT, 1207 const MaterializationUnit &MU) = 0; 1208 1209 /// This method will be called under the ExecutionSession lock when a 1210 /// ResourceTracker is removed. 1211 virtual Error notifyRemoving(ResourceTracker &RT) = 0; 1212 1213 /// A utility function for looking up initializer symbols. Performs a blocking 1214 /// lookup for the given symbols in each of the given JITDylibs. 1215 static Expected<DenseMap<JITDylib *, SymbolMap>> 1216 lookupInitSymbols(ExecutionSession &ES, 1217 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms); 1218 }; 1219 1220 /// Represents an abstract task for ORC to run. 1221 class Task : public RTTIExtends<Task, RTTIRoot> { 1222 public: 1223 static char ID; 1224 1225 /// Description of the task to be performed. Used for logging. 1226 virtual void printDescription(raw_ostream &OS) = 0; 1227 1228 /// Run the task. 1229 virtual void run() = 0; 1230 1231 private: 1232 void anchor() override; 1233 }; 1234 1235 /// A materialization task. 1236 class MaterializationTask : public RTTIExtends<MaterializationTask, Task> { 1237 public: 1238 static char ID; 1239 1240 MaterializationTask(std::unique_ptr<MaterializationUnit> MU, 1241 std::unique_ptr<MaterializationResponsibility> MR) 1242 : MU(std::move(MU)), MR(std::move(MR)) {} 1243 void printDescription(raw_ostream &OS) override; 1244 void run() override; 1245 1246 private: 1247 std::unique_ptr<MaterializationUnit> MU; 1248 std::unique_ptr<MaterializationResponsibility> MR; 1249 }; 1250 1251 /// An ExecutionSession represents a running JIT program. 1252 class ExecutionSession { 1253 friend class InProgressLookupFlagsState; 1254 friend class InProgressFullLookupState; 1255 friend class JITDylib; 1256 friend class LookupState; 1257 friend class MaterializationResponsibility; 1258 friend class ResourceTracker; 1259 1260 public: 1261 /// For reporting errors. 1262 using ErrorReporter = std::function<void(Error)>; 1263 1264 /// For dispatching ORC tasks (typically materialization tasks). 1265 using DispatchTaskFunction = unique_function<void(std::unique_ptr<Task> T)>; 1266 1267 /// Construct an ExecutionSession. 1268 /// 1269 /// SymbolStringPools may be shared between ExecutionSessions. 1270 ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr); 1271 1272 /// End the session. Closes all JITDylibs. 1273 Error endSession(); 1274 1275 /// Add a symbol name to the SymbolStringPool and return a pointer to it. 1276 SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); } 1277 1278 /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession. 1279 std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; } 1280 1281 /// Set the Platform for this ExecutionSession. 1282 void setPlatform(std::unique_ptr<Platform> P) { this->P = std::move(P); } 1283 1284 /// Get the Platform for this session. 1285 /// Will return null if no Platform has been set for this ExecutionSession. 1286 Platform *getPlatform() { return P.get(); } 1287 1288 /// Run the given lambda with the session mutex locked. 1289 template <typename Func> decltype(auto) runSessionLocked(Func &&F) { 1290 std::lock_guard<std::recursive_mutex> Lock(SessionMutex); 1291 return F(); 1292 } 1293 1294 /// Register the given ResourceManager with this ExecutionSession. 1295 /// Managers will be notified of events in reverse order of registration. 1296 void registerResourceManager(ResourceManager &RM); 1297 1298 /// Deregister the given ResourceManager with this ExecutionSession. 1299 /// Manager must have been previously registered. 1300 void deregisterResourceManager(ResourceManager &RM); 1301 1302 /// Return a pointer to the "name" JITDylib. 1303 /// Ownership of JITDylib remains within Execution Session 1304 JITDylib *getJITDylibByName(StringRef Name); 1305 1306 /// Add a new bare JITDylib to this ExecutionSession. 1307 /// 1308 /// The JITDylib Name is required to be unique. Clients should verify that 1309 /// names are not being re-used (E.g. by calling getJITDylibByName) if names 1310 /// are based on user input. 1311 /// 1312 /// This call does not install any library code or symbols into the newly 1313 /// created JITDylib. The client is responsible for all configuration. 1314 JITDylib &createBareJITDylib(std::string Name); 1315 1316 /// Add a new JITDylib to this ExecutionSession. 1317 /// 1318 /// The JITDylib Name is required to be unique. Clients should verify that 1319 /// names are not being re-used (e.g. by calling getJITDylibByName) if names 1320 /// are based on user input. 1321 /// 1322 /// If a Platform is attached then Platform::setupJITDylib will be called to 1323 /// install standard platform symbols (e.g. standard library interposes). 1324 /// If no Platform is attached this call is equivalent to createBareJITDylib. 1325 Expected<JITDylib &> createJITDylib(std::string Name); 1326 1327 /// Set the error reporter function. 1328 ExecutionSession &setErrorReporter(ErrorReporter ReportError) { 1329 this->ReportError = std::move(ReportError); 1330 return *this; 1331 } 1332 1333 /// Report a error for this execution session. 1334 /// 1335 /// Unhandled errors can be sent here to log them. 1336 void reportError(Error Err) { ReportError(std::move(Err)); } 1337 1338 /// Set the task dispatch function. 1339 ExecutionSession &setDispatchTask(DispatchTaskFunction DispatchTask) { 1340 this->DispatchTask = std::move(DispatchTask); 1341 return *this; 1342 } 1343 1344 /// Search the given JITDylibs to find the flags associated with each of the 1345 /// given symbols. 1346 void lookupFlags(LookupKind K, JITDylibSearchOrder SearchOrder, 1347 SymbolLookupSet Symbols, 1348 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete); 1349 1350 /// Blocking version of lookupFlags. 1351 Expected<SymbolFlagsMap> lookupFlags(LookupKind K, 1352 JITDylibSearchOrder SearchOrder, 1353 SymbolLookupSet Symbols); 1354 1355 /// Search the given JITDylibs for the given symbols. 1356 /// 1357 /// SearchOrder lists the JITDylibs to search. For each dylib, the associated 1358 /// boolean indicates whether the search should match against non-exported 1359 /// (hidden visibility) symbols in that dylib (true means match against 1360 /// non-exported symbols, false means do not match). 1361 /// 1362 /// The NotifyComplete callback will be called once all requested symbols 1363 /// reach the required state. 1364 /// 1365 /// If all symbols are found, the RegisterDependencies function will be called 1366 /// while the session lock is held. This gives clients a chance to register 1367 /// dependencies for on the queried symbols for any symbols they are 1368 /// materializing (if a MaterializationResponsibility instance is present, 1369 /// this can be implemented by calling 1370 /// MaterializationResponsibility::addDependencies). If there are no 1371 /// dependenant symbols for this query (e.g. it is being made by a top level 1372 /// client to get an address to call) then the value NoDependenciesToRegister 1373 /// can be used. 1374 void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, 1375 SymbolLookupSet Symbols, SymbolState RequiredState, 1376 SymbolsResolvedCallback NotifyComplete, 1377 RegisterDependenciesFunction RegisterDependencies); 1378 1379 /// Blocking version of lookup above. Returns the resolved symbol map. 1380 /// If WaitUntilReady is true (the default), will not return until all 1381 /// requested symbols are ready (or an error occurs). If WaitUntilReady is 1382 /// false, will return as soon as all requested symbols are resolved, 1383 /// or an error occurs. If WaitUntilReady is false and an error occurs 1384 /// after resolution, the function will return a success value, but the 1385 /// error will be reported via reportErrors. 1386 Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder, 1387 const SymbolLookupSet &Symbols, 1388 LookupKind K = LookupKind::Static, 1389 SymbolState RequiredState = SymbolState::Ready, 1390 RegisterDependenciesFunction RegisterDependencies = 1391 NoDependenciesToRegister); 1392 1393 /// Convenience version of blocking lookup. 1394 /// Searches each of the JITDylibs in the search order in turn for the given 1395 /// symbol. 1396 Expected<JITEvaluatedSymbol> 1397 lookup(const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Symbol, 1398 SymbolState RequiredState = SymbolState::Ready); 1399 1400 /// Convenience version of blocking lookup. 1401 /// Searches each of the JITDylibs in the search order in turn for the given 1402 /// symbol. The search will not find non-exported symbols. 1403 Expected<JITEvaluatedSymbol> 1404 lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Symbol, 1405 SymbolState RequiredState = SymbolState::Ready); 1406 1407 /// Convenience version of blocking lookup. 1408 /// Searches each of the JITDylibs in the search order in turn for the given 1409 /// symbol. The search will not find non-exported symbols. 1410 Expected<JITEvaluatedSymbol> 1411 lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Symbol, 1412 SymbolState RequiredState = SymbolState::Ready); 1413 1414 /// Materialize the given unit. 1415 void dispatchTask(std::unique_ptr<Task> T) { 1416 assert(T && "T must be non-null"); 1417 DEBUG_WITH_TYPE("orc", dumpDispatchInfo(*T)); 1418 DispatchTask(std::move(T)); 1419 } 1420 1421 /// Dump the state of all the JITDylibs in this session. 1422 void dump(raw_ostream &OS); 1423 1424 private: 1425 static void logErrorsToStdErr(Error Err) { 1426 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); 1427 } 1428 1429 static void runOnCurrentThread(std::unique_ptr<Task> T) { T->run(); } 1430 1431 void dispatchOutstandingMUs(); 1432 1433 static std::unique_ptr<MaterializationResponsibility> 1434 createMaterializationResponsibility(ResourceTracker &RT, 1435 SymbolFlagsMap Symbols, 1436 SymbolStringPtr InitSymbol) { 1437 auto &JD = RT.getJITDylib(); 1438 std::unique_ptr<MaterializationResponsibility> MR( 1439 new MaterializationResponsibility(&JD, std::move(Symbols), 1440 std::move(InitSymbol))); 1441 JD.MRTrackers[MR.get()] = &RT; 1442 return MR; 1443 } 1444 1445 Error removeResourceTracker(ResourceTracker &RT); 1446 void transferResourceTracker(ResourceTracker &DstRT, ResourceTracker &SrcRT); 1447 void destroyResourceTracker(ResourceTracker &RT); 1448 1449 // State machine functions for query application.. 1450 1451 /// IL_updateCandidatesFor is called to remove already-defined symbols that 1452 /// match a given query from the set of candidate symbols to generate 1453 /// definitions for (no need to generate a definition if one already exists). 1454 Error IL_updateCandidatesFor(JITDylib &JD, JITDylibLookupFlags JDLookupFlags, 1455 SymbolLookupSet &Candidates, 1456 SymbolLookupSet *NonCandidates); 1457 1458 /// OL_applyQueryPhase1 is an optionally re-startable loop for triggering 1459 /// definition generation. It is called when a lookup is performed, and again 1460 /// each time that LookupState::continueLookup is called. 1461 void OL_applyQueryPhase1(std::unique_ptr<InProgressLookupState> IPLS, 1462 Error Err); 1463 1464 /// OL_completeLookup is run once phase 1 successfully completes for a lookup 1465 /// call. It attempts to attach the symbol to all symbol table entries and 1466 /// collect all MaterializationUnits to dispatch. If this method fails then 1467 /// all MaterializationUnits will be left un-materialized. 1468 void OL_completeLookup(std::unique_ptr<InProgressLookupState> IPLS, 1469 std::shared_ptr<AsynchronousSymbolQuery> Q, 1470 RegisterDependenciesFunction RegisterDependencies); 1471 1472 /// OL_completeLookupFlags is run once phase 1 successfully completes for a 1473 /// lookupFlags call. 1474 void OL_completeLookupFlags( 1475 std::unique_ptr<InProgressLookupState> IPLS, 1476 unique_function<void(Expected<SymbolFlagsMap>)> OnComplete); 1477 1478 // State machine functions for MaterializationResponsibility. 1479 void OL_destroyMaterializationResponsibility( 1480 MaterializationResponsibility &MR); 1481 SymbolNameSet OL_getRequestedSymbols(const MaterializationResponsibility &MR); 1482 Error OL_notifyResolved(MaterializationResponsibility &MR, 1483 const SymbolMap &Symbols); 1484 Error OL_notifyEmitted(MaterializationResponsibility &MR); 1485 Error OL_defineMaterializing(MaterializationResponsibility &MR, 1486 SymbolFlagsMap SymbolFlags); 1487 void OL_notifyFailed(MaterializationResponsibility &MR); 1488 Error OL_replace(MaterializationResponsibility &MR, 1489 std::unique_ptr<MaterializationUnit> MU); 1490 Expected<std::unique_ptr<MaterializationResponsibility>> 1491 OL_delegate(MaterializationResponsibility &MR, const SymbolNameSet &Symbols); 1492 void OL_addDependencies(MaterializationResponsibility &MR, 1493 const SymbolStringPtr &Name, 1494 const SymbolDependenceMap &Dependencies); 1495 void OL_addDependenciesForAll(MaterializationResponsibility &MR, 1496 const SymbolDependenceMap &Dependencies); 1497 1498 #ifndef NDEBUG 1499 void dumpDispatchInfo(Task &T); 1500 #endif // NDEBUG 1501 1502 mutable std::recursive_mutex SessionMutex; 1503 bool SessionOpen = true; 1504 std::shared_ptr<SymbolStringPool> SSP; 1505 std::unique_ptr<Platform> P; 1506 ErrorReporter ReportError = logErrorsToStdErr; 1507 DispatchTaskFunction DispatchTask = runOnCurrentThread; 1508 1509 std::vector<ResourceManager *> ResourceManagers; 1510 1511 std::vector<JITDylibSP> JDs; 1512 1513 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works 1514 // with callbacks from asynchronous queries. 1515 mutable std::recursive_mutex OutstandingMUsMutex; 1516 std::vector<std::pair<std::unique_ptr<MaterializationUnit>, 1517 std::unique_ptr<MaterializationResponsibility>>> 1518 OutstandingMUs; 1519 }; 1520 1521 inline ExecutionSession &MaterializationResponsibility::getExecutionSession() { 1522 return JD->getExecutionSession(); 1523 } 1524 1525 template <typename Func> 1526 Error MaterializationResponsibility::withResourceKeyDo(Func &&F) const { 1527 return JD->getExecutionSession().runSessionLocked([&]() -> Error { 1528 auto I = JD->MRTrackers.find(this); 1529 assert(I != JD->MRTrackers.end() && "No tracker for this MR"); 1530 if (I->second->isDefunct()) 1531 return make_error<ResourceTrackerDefunct>(I->second); 1532 F(I->second->getKeyUnsafe()); 1533 return Error::success(); 1534 }); 1535 } 1536 1537 template <typename GeneratorT> 1538 GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) { 1539 auto &G = *DefGenerator; 1540 std::lock_guard<std::mutex> Lock(GeneratorsMutex); 1541 DefGenerators.push_back(std::move(DefGenerator)); 1542 return G; 1543 } 1544 1545 template <typename Func> 1546 auto JITDylib::withLinkOrderDo(Func &&F) 1547 -> decltype(F(std::declval<const JITDylibSearchOrder &>())) { 1548 return ES.runSessionLocked([&]() { return F(LinkOrder); }); 1549 } 1550 1551 template <typename MaterializationUnitType> 1552 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU, 1553 ResourceTrackerSP RT) { 1554 assert(MU && "Can not define with a null MU"); 1555 1556 if (MU->getSymbols().empty()) { 1557 // Empty MUs are allowable but pathological, so issue a warning. 1558 DEBUG_WITH_TYPE("orc", { 1559 dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for " 1560 << getName() << "\n"; 1561 }); 1562 return Error::success(); 1563 } else 1564 DEBUG_WITH_TYPE("orc", { 1565 dbgs() << "Defining MU " << MU->getName() << " for " << getName() 1566 << " (tracker: "; 1567 if (RT == getDefaultResourceTracker()) 1568 dbgs() << "default)"; 1569 else if (RT) 1570 dbgs() << RT.get() << ")\n"; 1571 else 1572 dbgs() << "0x0, default will be used)\n"; 1573 }); 1574 1575 return ES.runSessionLocked([&, this]() -> Error { 1576 if (auto Err = defineImpl(*MU)) 1577 return Err; 1578 1579 if (!RT) 1580 RT = getDefaultResourceTracker(); 1581 1582 if (auto *P = ES.getPlatform()) { 1583 if (auto Err = P->notifyAdding(*RT, *MU)) 1584 return Err; 1585 } 1586 1587 installMaterializationUnit(std::move(MU), *RT); 1588 return Error::success(); 1589 }); 1590 } 1591 1592 template <typename MaterializationUnitType> 1593 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU, 1594 ResourceTrackerSP RT) { 1595 assert(MU && "Can not define with a null MU"); 1596 1597 if (MU->getSymbols().empty()) { 1598 // Empty MUs are allowable but pathological, so issue a warning. 1599 DEBUG_WITH_TYPE("orc", { 1600 dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName() 1601 << "\n"; 1602 }); 1603 return Error::success(); 1604 } else 1605 DEBUG_WITH_TYPE("orc", { 1606 dbgs() << "Defining MU " << MU->getName() << " for " << getName() 1607 << " (tracker: "; 1608 if (RT == getDefaultResourceTracker()) 1609 dbgs() << "default)"; 1610 else if (RT) 1611 dbgs() << RT.get() << ")\n"; 1612 else 1613 dbgs() << "0x0, default will be used)\n"; 1614 }); 1615 1616 return ES.runSessionLocked([&, this]() -> Error { 1617 if (auto Err = defineImpl(*MU)) 1618 return Err; 1619 1620 if (!RT) 1621 RT = getDefaultResourceTracker(); 1622 1623 if (auto *P = ES.getPlatform()) { 1624 if (auto Err = P->notifyAdding(*RT, *MU)) 1625 return Err; 1626 } 1627 1628 installMaterializationUnit(std::move(MU), *RT); 1629 return Error::success(); 1630 }); 1631 } 1632 1633 /// ReexportsGenerator can be used with JITDylib::addGenerator to automatically 1634 /// re-export a subset of the source JITDylib's symbols in the target. 1635 class ReexportsGenerator : public DefinitionGenerator { 1636 public: 1637 using SymbolPredicate = std::function<bool(SymbolStringPtr)>; 1638 1639 /// Create a reexports generator. If an Allow predicate is passed, only 1640 /// symbols for which the predicate returns true will be reexported. If no 1641 /// Allow predicate is passed, all symbols will be exported. 1642 ReexportsGenerator(JITDylib &SourceJD, 1643 JITDylibLookupFlags SourceJDLookupFlags, 1644 SymbolPredicate Allow = SymbolPredicate()); 1645 1646 Error tryToGenerate(LookupState &LS, LookupKind K, JITDylib &JD, 1647 JITDylibLookupFlags JDLookupFlags, 1648 const SymbolLookupSet &LookupSet) override; 1649 1650 private: 1651 JITDylib &SourceJD; 1652 JITDylibLookupFlags SourceJDLookupFlags; 1653 SymbolPredicate Allow; 1654 }; 1655 1656 // --------------- IMPLEMENTATION -------------- 1657 // Implementations for inline functions/methods. 1658 // --------------------------------------------- 1659 1660 inline MaterializationResponsibility::~MaterializationResponsibility() { 1661 JD->getExecutionSession().OL_destroyMaterializationResponsibility(*this); 1662 } 1663 1664 inline SymbolNameSet MaterializationResponsibility::getRequestedSymbols() const { 1665 return JD->getExecutionSession().OL_getRequestedSymbols(*this); 1666 } 1667 1668 inline Error MaterializationResponsibility::notifyResolved( 1669 const SymbolMap &Symbols) { 1670 return JD->getExecutionSession().OL_notifyResolved(*this, Symbols); 1671 } 1672 1673 inline Error MaterializationResponsibility::notifyEmitted() { 1674 return JD->getExecutionSession().OL_notifyEmitted(*this); 1675 } 1676 1677 inline Error MaterializationResponsibility::defineMaterializing( 1678 SymbolFlagsMap SymbolFlags) { 1679 return JD->getExecutionSession().OL_defineMaterializing( 1680 *this, std::move(SymbolFlags)); 1681 } 1682 1683 inline void MaterializationResponsibility::failMaterialization() { 1684 JD->getExecutionSession().OL_notifyFailed(*this); 1685 } 1686 1687 inline Error MaterializationResponsibility::replace( 1688 std::unique_ptr<MaterializationUnit> MU) { 1689 return JD->getExecutionSession().OL_replace(*this, std::move(MU)); 1690 } 1691 1692 inline Expected<std::unique_ptr<MaterializationResponsibility>> 1693 MaterializationResponsibility::delegate(const SymbolNameSet &Symbols) { 1694 return JD->getExecutionSession().OL_delegate(*this, Symbols); 1695 } 1696 1697 inline void MaterializationResponsibility::addDependencies( 1698 const SymbolStringPtr &Name, const SymbolDependenceMap &Dependencies) { 1699 JD->getExecutionSession().OL_addDependencies(*this, Name, Dependencies); 1700 } 1701 1702 inline void MaterializationResponsibility::addDependenciesForAll( 1703 const SymbolDependenceMap &Dependencies) { 1704 JD->getExecutionSession().OL_addDependenciesForAll(*this, Dependencies); 1705 } 1706 1707 } // End namespace orc 1708 } // End namespace llvm 1709 1710 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H 1711