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