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