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