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