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