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/ExecutionEngine/JITSymbol.h" 20 #include "llvm/ExecutionEngine/Orc/SymbolStringPool.h" 21 #include "llvm/ExecutionEngine/OrcV1Deprecation.h" 22 #include "llvm/Support/Debug.h" 23 24 #include <memory> 25 #include <vector> 26 27 namespace llvm { 28 namespace orc { 29 30 // Forward declare some classes. 31 class AsynchronousSymbolQuery; 32 class ExecutionSession; 33 class MaterializationUnit; 34 class MaterializationResponsibility; 35 class JITDylib; 36 enum class SymbolState : uint8_t; 37 38 /// VModuleKey provides a unique identifier (allocated and managed by 39 /// ExecutionSessions) for a module added to the JIT. 40 using VModuleKey = uint64_t; 41 42 /// A set of symbol names (represented by SymbolStringPtrs for 43 // efficiency). 44 using SymbolNameSet = DenseSet<SymbolStringPtr>; 45 46 /// A vector of symbol names. 47 using SymbolNameVector = std::vector<SymbolStringPtr>; 48 49 /// A map from symbol names (as SymbolStringPtrs) to JITSymbols 50 /// (address/flags pairs). 51 using SymbolMap = DenseMap<SymbolStringPtr, JITEvaluatedSymbol>; 52 53 /// A map from symbol names (as SymbolStringPtrs) to JITSymbolFlags. 54 using SymbolFlagsMap = DenseMap<SymbolStringPtr, JITSymbolFlags>; 55 56 /// A map from JITDylibs to sets of symbols. 57 using SymbolDependenceMap = DenseMap<JITDylib *, SymbolNameSet>; 58 59 /// Lookup flags that apply to each dylib in the search order for a lookup. 60 /// 61 /// If MatchHiddenSymbolsOnly is used (the default) for a given dylib, then 62 /// only symbols in that Dylib's interface will be searched. If 63 /// MatchHiddenSymbols is used then symbols with hidden visibility will match 64 /// as well. 65 enum class JITDylibLookupFlags { MatchExportedSymbolsOnly, MatchAllSymbols }; 66 67 /// Lookup flags that apply to each symbol in a lookup. 68 /// 69 /// If RequiredSymbol is used (the default) for a given symbol then that symbol 70 /// must be found during the lookup or the lookup will fail returning a 71 /// SymbolNotFound error. If WeaklyReferencedSymbol is used and the given 72 /// symbol is not found then the query will continue, and no result for the 73 /// missing symbol will be present in the result (assuming the rest of the 74 /// lookup succeeds). 75 enum class SymbolLookupFlags { RequiredSymbol, WeaklyReferencedSymbol }; 76 77 /// Describes the kind of lookup being performed. The lookup kind is passed to 78 /// symbol generators (if they're invoked) to help them determine what 79 /// definitions to generate. 80 /// 81 /// Static -- Lookup is being performed as-if at static link time (e.g. 82 /// generators representing static archives should pull in new 83 /// definitions). 84 /// 85 /// DLSym -- Lookup is being performed as-if at runtime (e.g. generators 86 /// representing static archives should not pull in new definitions). 87 enum class LookupKind { Static, DLSym }; 88 89 /// A list of (JITDylib*, JITDylibLookupFlags) pairs to be used as a search 90 /// order during symbol lookup. 91 using JITDylibSearchOrder = 92 std::vector<std::pair<JITDylib *, JITDylibLookupFlags>>; 93 94 /// Convenience function for creating a search order from an ArrayRef of 95 /// JITDylib*, all with the same flags. 96 inline JITDylibSearchOrder makeJITDylibSearchOrder( 97 ArrayRef<JITDylib *> JDs, 98 JITDylibLookupFlags Flags = JITDylibLookupFlags::MatchExportedSymbolsOnly) { 99 JITDylibSearchOrder O; 100 O.reserve(JDs.size()); 101 for (auto *JD : JDs) 102 O.push_back(std::make_pair(JD, Flags)); 103 return O; 104 } 105 106 /// A set of symbols to look up, each associated with a SymbolLookupFlags 107 /// value. 108 /// 109 /// This class is backed by a vector and optimized for fast insertion, 110 /// deletion and iteration. It does not guarantee a stable order between 111 /// operations, and will not automatically detect duplicate elements (they 112 /// can be manually checked by calling the validate method). 113 class SymbolLookupSet { 114 public: 115 using value_type = std::pair<SymbolStringPtr, SymbolLookupFlags>; 116 using UnderlyingVector = std::vector<value_type>; 117 using iterator = UnderlyingVector::iterator; 118 using const_iterator = UnderlyingVector::const_iterator; 119 120 SymbolLookupSet() = default; 121 122 explicit SymbolLookupSet( 123 SymbolStringPtr Name, 124 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 125 add(std::move(Name), Flags); 126 } 127 128 /// Construct a SymbolLookupSet from an initializer list of SymbolStringPtrs. 129 explicit SymbolLookupSet( 130 std::initializer_list<SymbolStringPtr> Names, 131 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 132 Symbols.reserve(Names.size()); 133 for (auto &Name : Names) 134 add(std::move(Name), Flags); 135 } 136 137 /// Construct a SymbolLookupSet from a SymbolNameSet with the given 138 /// Flags used for each value. 139 explicit SymbolLookupSet( 140 const SymbolNameSet &Names, 141 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 142 Symbols.reserve(Names.size()); 143 for (const auto &Name : Names) 144 add(Name, Flags); 145 } 146 147 /// Construct a SymbolLookupSet from a vector of symbols with the given Flags 148 /// used for each value. 149 /// If the ArrayRef contains duplicates it is up to the client to remove these 150 /// before using this instance for lookup. 151 explicit SymbolLookupSet( 152 ArrayRef<SymbolStringPtr> Names, 153 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 154 Symbols.reserve(Names.size()); 155 for (const auto &Name : Names) 156 add(Name, Flags); 157 } 158 159 /// Add an element to the set. The client is responsible for checking that 160 /// duplicates are not added. 161 void add(SymbolStringPtr Name, 162 SymbolLookupFlags Flags = SymbolLookupFlags::RequiredSymbol) { 163 Symbols.push_back(std::make_pair(std::move(Name), Flags)); 164 } 165 166 bool empty() const { return Symbols.empty(); } 167 UnderlyingVector::size_type size() const { return Symbols.size(); } 168 iterator begin() { return Symbols.begin(); } 169 iterator end() { return Symbols.end(); } 170 const_iterator begin() const { return Symbols.begin(); } 171 const_iterator end() const { return Symbols.end(); } 172 173 /// Removes the Ith element of the vector, replacing it with the last element. 174 void remove(UnderlyingVector::size_type I) { 175 std::swap(Symbols[I], Symbols.back()); 176 Symbols.pop_back(); 177 } 178 179 /// Removes the element pointed to by the given iterator. This iterator and 180 /// all subsequent ones (including end()) are invalidated. 181 void remove(iterator I) { remove(I - begin()); } 182 183 /// Removes all elements matching the given predicate, which must be callable 184 /// as bool(const SymbolStringPtr &, SymbolLookupFlags Flags). 185 template <typename PredFn> void remove_if(PredFn &&Pred) { 186 UnderlyingVector::size_type I = 0; 187 while (I != Symbols.size()) { 188 const auto &Name = Symbols[I].first; 189 auto Flags = Symbols[I].second; 190 if (Pred(Name, Flags)) 191 remove(I); 192 else 193 ++I; 194 } 195 } 196 197 /// Loop over the elements of this SymbolLookupSet, applying the Body function 198 /// to each one. Body must be callable as 199 /// bool(const SymbolStringPtr &, SymbolLookupFlags). 200 /// If Body returns true then the element just passed in is removed from the 201 /// set. If Body returns false then the element is retained. 202 template <typename BodyFn> 203 auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t< 204 std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(), 205 std::declval<SymbolLookupFlags>())), 206 bool>::value> { 207 UnderlyingVector::size_type I = 0; 208 while (I != Symbols.size()) { 209 const auto &Name = Symbols[I].first; 210 auto Flags = Symbols[I].second; 211 if (Body(Name, Flags)) 212 remove(I); 213 else 214 ++I; 215 } 216 } 217 218 /// Loop over the elements of this SymbolLookupSet, applying the Body function 219 /// to each one. Body must be callable as 220 /// Expected<bool>(const SymbolStringPtr &, SymbolLookupFlags). 221 /// If Body returns a failure value, the loop exits immediately. If Body 222 /// returns true then the element just passed in is removed from the set. If 223 /// Body returns false then the element is retained. 224 template <typename BodyFn> 225 auto forEachWithRemoval(BodyFn &&Body) -> std::enable_if_t< 226 std::is_same<decltype(Body(std::declval<const SymbolStringPtr &>(), 227 std::declval<SymbolLookupFlags>())), 228 Expected<bool>>::value, 229 Error> { 230 UnderlyingVector::size_type I = 0; 231 while (I != Symbols.size()) { 232 const auto &Name = Symbols[I].first; 233 auto Flags = Symbols[I].second; 234 auto Remove = Body(Name, Flags); 235 if (!Remove) 236 return Remove.takeError(); 237 if (*Remove) 238 remove(I); 239 else 240 ++I; 241 } 242 return Error::success(); 243 } 244 245 /// Construct a SymbolNameVector from this instance by dropping the Flags 246 /// values. 247 SymbolNameVector getSymbolNames() const { 248 SymbolNameVector Names; 249 Names.reserve(Symbols.size()); 250 for (auto &KV : Symbols) 251 Names.push_back(KV.first); 252 return Names; 253 } 254 255 /// Sort the lookup set by pointer value. This sort is fast but sensitive to 256 /// allocation order and so should not be used where a consistent order is 257 /// required. 258 void sortByAddress() { 259 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) { 260 return LHS.first < RHS.first; 261 }); 262 } 263 264 /// Sort the lookup set lexicographically. This sort is slow but the order 265 /// is unaffected by allocation order. 266 void sortByName() { 267 llvm::sort(Symbols, [](const value_type &LHS, const value_type &RHS) { 268 return *LHS.first < *RHS.first; 269 }); 270 } 271 272 /// Remove any duplicate elements. If a SymbolLookupSet is not duplicate-free 273 /// by construction, this method can be used to turn it into a proper set. 274 void removeDuplicates() { 275 sortByAddress(); 276 auto LastI = std::unique(Symbols.begin(), Symbols.end()); 277 Symbols.erase(LastI, Symbols.end()); 278 } 279 280 #ifndef NDEBUG 281 /// Returns true if this set contains any duplicates. This should only be used 282 /// in assertions. 283 bool containsDuplicates() { 284 if (Symbols.size() < 2) 285 return false; 286 sortByAddress(); 287 for (UnderlyingVector::size_type I = 1; I != Symbols.size(); ++I) 288 if (Symbols[I].first == Symbols[I - 1].first) 289 return true; 290 return true; 291 } 292 #endif 293 294 private: 295 UnderlyingVector Symbols; 296 }; 297 298 struct SymbolAliasMapEntry { 299 SymbolAliasMapEntry() = default; 300 SymbolAliasMapEntry(SymbolStringPtr Aliasee, JITSymbolFlags AliasFlags) 301 : Aliasee(std::move(Aliasee)), AliasFlags(AliasFlags) {} 302 303 SymbolStringPtr Aliasee; 304 JITSymbolFlags AliasFlags; 305 }; 306 307 /// A map of Symbols to (Symbol, Flags) pairs. 308 using SymbolAliasMap = DenseMap<SymbolStringPtr, SymbolAliasMapEntry>; 309 310 /// Callback to notify client that symbols have been resolved. 311 using SymbolsResolvedCallback = unique_function<void(Expected<SymbolMap>)>; 312 313 /// Callback to register the dependencies for a given query. 314 using RegisterDependenciesFunction = 315 std::function<void(const SymbolDependenceMap &)>; 316 317 /// This can be used as the value for a RegisterDependenciesFunction if there 318 /// are no dependants to register with. 319 extern RegisterDependenciesFunction NoDependenciesToRegister; 320 321 /// Used to notify a JITDylib that the given set of symbols failed to 322 /// materialize. 323 class FailedToMaterialize : public ErrorInfo<FailedToMaterialize> { 324 public: 325 static char ID; 326 327 FailedToMaterialize(std::shared_ptr<SymbolDependenceMap> Symbols); 328 std::error_code convertToErrorCode() const override; 329 void log(raw_ostream &OS) const override; 330 const SymbolDependenceMap &getSymbols() const { return *Symbols; } 331 332 private: 333 std::shared_ptr<SymbolDependenceMap> Symbols; 334 }; 335 336 /// Used to notify clients when symbols can not be found during a lookup. 337 class SymbolsNotFound : public ErrorInfo<SymbolsNotFound> { 338 public: 339 static char ID; 340 341 SymbolsNotFound(SymbolNameSet Symbols); 342 SymbolsNotFound(SymbolNameVector Symbols); 343 std::error_code convertToErrorCode() const override; 344 void log(raw_ostream &OS) const override; 345 const SymbolNameVector &getSymbols() const { return Symbols; } 346 347 private: 348 SymbolNameVector Symbols; 349 }; 350 351 /// Used to notify clients that a set of symbols could not be removed. 352 class SymbolsCouldNotBeRemoved : public ErrorInfo<SymbolsCouldNotBeRemoved> { 353 public: 354 static char ID; 355 356 SymbolsCouldNotBeRemoved(SymbolNameSet Symbols); 357 std::error_code convertToErrorCode() const override; 358 void log(raw_ostream &OS) const override; 359 const SymbolNameSet &getSymbols() const { return Symbols; } 360 361 private: 362 SymbolNameSet Symbols; 363 }; 364 365 /// Errors of this type should be returned if a module fails to include 366 /// definitions that are claimed by the module's associated 367 /// MaterializationResponsibility. If this error is returned it is indicative of 368 /// a broken transformation / compiler / object cache. 369 class MissingSymbolDefinitions : public ErrorInfo<MissingSymbolDefinitions> { 370 public: 371 static char ID; 372 373 MissingSymbolDefinitions(std::string ModuleName, SymbolNameVector Symbols) 374 : ModuleName(std::move(ModuleName)), Symbols(std::move(Symbols)) {} 375 std::error_code convertToErrorCode() const override; 376 void log(raw_ostream &OS) const override; 377 const std::string &getModuleName() const { return ModuleName; } 378 const SymbolNameVector &getSymbols() const { return Symbols; } 379 private: 380 std::string ModuleName; 381 SymbolNameVector Symbols; 382 }; 383 384 /// Errors of this type should be returned if a module contains definitions for 385 /// symbols that are not claimed by the module's associated 386 /// MaterializationResponsibility. If this error is returned it is indicative of 387 /// a broken transformation / compiler / object cache. 388 class UnexpectedSymbolDefinitions : public ErrorInfo<UnexpectedSymbolDefinitions> { 389 public: 390 static char ID; 391 392 UnexpectedSymbolDefinitions(std::string ModuleName, SymbolNameVector Symbols) 393 : ModuleName(std::move(ModuleName)), Symbols(std::move(Symbols)) {} 394 std::error_code convertToErrorCode() const override; 395 void log(raw_ostream &OS) const override; 396 const std::string &getModuleName() const { return ModuleName; } 397 const SymbolNameVector &getSymbols() const { return Symbols; } 398 private: 399 std::string ModuleName; 400 SymbolNameVector Symbols; 401 }; 402 403 /// Tracks responsibility for materialization, and mediates interactions between 404 /// MaterializationUnits and JDs. 405 /// 406 /// An instance of this class is passed to MaterializationUnits when their 407 /// materialize method is called. It allows MaterializationUnits to resolve and 408 /// emit symbols, or abandon materialization by notifying any unmaterialized 409 /// symbols of an error. 410 class MaterializationResponsibility { 411 friend class MaterializationUnit; 412 public: 413 MaterializationResponsibility(MaterializationResponsibility &&) = default; 414 MaterializationResponsibility & 415 operator=(MaterializationResponsibility &&) = delete; 416 417 /// Destruct a MaterializationResponsibility instance. In debug mode 418 /// this asserts that all symbols being tracked have been either 419 /// emitted or notified of an error. 420 ~MaterializationResponsibility(); 421 422 /// Returns the target JITDylib that these symbols are being materialized 423 /// into. 424 JITDylib &getTargetJITDylib() const { return *JD; } 425 426 /// Returns the VModuleKey for this instance. 427 VModuleKey getVModuleKey() const { return K; } 428 429 /// Returns the symbol flags map for this responsibility instance. 430 /// Note: The returned flags may have transient flags (Lazy, Materializing) 431 /// set. These should be stripped with JITSymbolFlags::stripTransientFlags 432 /// before using. 433 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } 434 435 /// Returns the initialization pseudo-symbol, if any. This symbol will also 436 /// be present in the SymbolFlagsMap for this MaterializationResponsibility 437 /// object. 438 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; } 439 440 /// Returns the names of any symbols covered by this 441 /// MaterializationResponsibility object that have queries pending. This 442 /// information can be used to return responsibility for unrequested symbols 443 /// back to the JITDylib via the delegate method. 444 SymbolNameSet getRequestedSymbols() const; 445 446 /// Notifies the target JITDylib that the given symbols have been resolved. 447 /// This will update the given symbols' addresses in the JITDylib, and notify 448 /// any pending queries on the given symbols of their resolution. The given 449 /// symbols must be ones covered by this MaterializationResponsibility 450 /// instance. Individual calls to this method may resolve a subset of the 451 /// symbols, but all symbols must have been resolved prior to calling emit. 452 /// 453 /// This method will return an error if any symbols being resolved have been 454 /// moved to the error state due to the failure of a dependency. If this 455 /// method returns an error then clients should log it and call 456 /// failMaterialize. If no dependencies have been registered for the 457 /// symbols covered by this MaterializationResponsibiility then this method 458 /// is guaranteed to return Error::success() and can be wrapped with cantFail. 459 Error notifyResolved(const SymbolMap &Symbols); 460 461 /// Notifies the target JITDylib (and any pending queries on that JITDylib) 462 /// that all symbols covered by this MaterializationResponsibility instance 463 /// have been emitted. 464 /// 465 /// This method will return an error if any symbols being resolved have been 466 /// moved to the error state due to the failure of a dependency. If this 467 /// method returns an error then clients should log it and call 468 /// failMaterialize. If no dependencies have been registered for the 469 /// symbols covered by this MaterializationResponsibiility then this method 470 /// is guaranteed to return Error::success() and can be wrapped with cantFail. 471 Error notifyEmitted(); 472 473 /// Attempt to claim responsibility for new definitions. This method can be 474 /// used to claim responsibility for symbols that are added to a 475 /// materialization unit during the compilation process (e.g. literal pool 476 /// symbols). Symbol linkage rules are the same as for symbols that are 477 /// defined up front: duplicate strong definitions will result in errors. 478 /// Duplicate weak definitions will be discarded (in which case they will 479 /// not be added to this responsibility instance). 480 /// 481 /// This method can be used by materialization units that want to add 482 /// additional symbols at materialization time (e.g. stubs, compile 483 /// callbacks, metadata). 484 Error defineMaterializing(SymbolFlagsMap SymbolFlags); 485 486 /// Define the given symbols as non-existent, removing it from the symbol 487 /// table and notifying any pending queries. Queries that lookup up the 488 /// symbol using the SymbolLookupFlags::WeaklyReferencedSymbol flag will 489 /// behave as if the symbol had not been matched in the first place. Queries 490 /// that required this symbol will fail with a missing symbol definition 491 /// error. 492 /// 493 /// This method is intended to support cleanup of special symbols like 494 /// initializer symbols: Queries using 495 /// SymbolLookupFlags::WeaklyReferencedSymbol can be used to trigger their 496 /// emission, and this method can be used to remove them from the JITDylib 497 /// once materialization is complete. 498 void defineNonExistent(ArrayRef<SymbolStringPtr> Symbols); 499 500 /// Notify all not-yet-emitted covered by this MaterializationResponsibility 501 /// instance that an error has occurred. 502 /// This will remove all symbols covered by this MaterializationResponsibilty 503 /// from the target JITDylib, and send an error to any queries waiting on 504 /// these symbols. 505 void failMaterialization(); 506 507 /// Transfers responsibility to the given MaterializationUnit for all 508 /// symbols defined by that MaterializationUnit. This allows 509 /// materializers to break up work based on run-time information (e.g. 510 /// by introspecting which symbols have actually been looked up and 511 /// materializing only those). 512 void replace(std::unique_ptr<MaterializationUnit> MU); 513 514 /// Delegates responsibility for the given symbols to the returned 515 /// materialization responsibility. Useful for breaking up work between 516 /// threads, or different kinds of materialization processes. 517 MaterializationResponsibility delegate(const SymbolNameSet &Symbols, 518 VModuleKey NewKey = VModuleKey()); 519 520 void addDependencies(const SymbolStringPtr &Name, 521 const SymbolDependenceMap &Dependencies); 522 523 /// Add dependencies that apply to all symbols covered by this instance. 524 void addDependenciesForAll(const SymbolDependenceMap &Dependencies); 525 526 private: 527 /// Create a MaterializationResponsibility for the given JITDylib and 528 /// initial symbols. 529 MaterializationResponsibility(std::shared_ptr<JITDylib> JD, 530 SymbolFlagsMap SymbolFlags, 531 SymbolStringPtr InitSymbol, VModuleKey K) 532 : JD(std::move(JD)), SymbolFlags(std::move(SymbolFlags)), 533 InitSymbol(std::move(InitSymbol)), K(std::move(K)) { 534 assert(this->JD && "Cannot initialize with null JD"); 535 assert(!this->SymbolFlags.empty() && "Materializing nothing?"); 536 } 537 538 std::shared_ptr<JITDylib> JD; 539 SymbolFlagsMap SymbolFlags; 540 SymbolStringPtr InitSymbol; 541 VModuleKey K; 542 }; 543 544 /// A MaterializationUnit represents a set of symbol definitions that can 545 /// be materialized as a group, or individually discarded (when 546 /// overriding definitions are encountered). 547 /// 548 /// MaterializationUnits are used when providing lazy definitions of symbols to 549 /// JITDylibs. The JITDylib will call materialize when the address of a symbol 550 /// is requested via the lookup method. The JITDylib will call discard if a 551 /// stronger definition is added or already present. 552 class MaterializationUnit { 553 friend class ExecutionSession; 554 friend class JITDylib; 555 556 public: 557 MaterializationUnit(SymbolFlagsMap InitalSymbolFlags, 558 SymbolStringPtr InitSymbol, VModuleKey K) 559 : SymbolFlags(std::move(InitalSymbolFlags)), 560 InitSymbol(std::move(InitSymbol)), K(std::move(K)) { 561 assert((!this->InitSymbol || this->SymbolFlags.count(this->InitSymbol)) && 562 "If set, InitSymbol should appear in InitialSymbolFlags map"); 563 } 564 565 virtual ~MaterializationUnit() {} 566 567 /// Return the name of this materialization unit. Useful for debugging 568 /// output. 569 virtual StringRef getName() const = 0; 570 571 /// Return the set of symbols that this source provides. 572 const SymbolFlagsMap &getSymbols() const { return SymbolFlags; } 573 574 /// Returns the initialization symbol for this MaterializationUnit (if any). 575 const SymbolStringPtr &getInitializerSymbol() const { return InitSymbol; } 576 577 /// Implementations of this method should materialize all symbols 578 /// in the materialzation unit, except for those that have been 579 /// previously discarded. 580 virtual void materialize(MaterializationResponsibility R) = 0; 581 582 /// Called by JITDylibs to notify MaterializationUnits that the given symbol 583 /// has been overridden. 584 void doDiscard(const JITDylib &JD, const SymbolStringPtr &Name) { 585 SymbolFlags.erase(Name); 586 discard(JD, std::move(Name)); 587 } 588 589 protected: 590 SymbolFlagsMap SymbolFlags; 591 SymbolStringPtr InitSymbol; 592 VModuleKey K; 593 594 private: 595 virtual void anchor(); 596 597 MaterializationResponsibility 598 createMaterializationResponsibility(std::shared_ptr<JITDylib> JD) { 599 return MaterializationResponsibility(std::move(JD), std::move(SymbolFlags), 600 std::move(InitSymbol), K); 601 } 602 603 /// Implementations of this method should discard the given symbol 604 /// from the source (e.g. if the source is an LLVM IR Module and the 605 /// symbol is a function, delete the function body or mark it available 606 /// externally). 607 virtual void discard(const JITDylib &JD, const SymbolStringPtr &Name) = 0; 608 }; 609 610 using MaterializationUnitList = 611 std::vector<std::unique_ptr<MaterializationUnit>>; 612 613 /// A MaterializationUnit implementation for pre-existing absolute symbols. 614 /// 615 /// All symbols will be resolved and marked ready as soon as the unit is 616 /// materialized. 617 class AbsoluteSymbolsMaterializationUnit : public MaterializationUnit { 618 public: 619 AbsoluteSymbolsMaterializationUnit(SymbolMap Symbols, VModuleKey K); 620 621 StringRef getName() const override; 622 623 private: 624 void materialize(MaterializationResponsibility R) override; 625 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; 626 static SymbolFlagsMap extractFlags(const SymbolMap &Symbols); 627 628 SymbolMap Symbols; 629 }; 630 631 /// Create an AbsoluteSymbolsMaterializationUnit with the given symbols. 632 /// Useful for inserting absolute symbols into a JITDylib. E.g.: 633 /// \code{.cpp} 634 /// JITDylib &JD = ...; 635 /// SymbolStringPtr Foo = ...; 636 /// JITEvaluatedSymbol FooSym = ...; 637 /// if (auto Err = JD.define(absoluteSymbols({{Foo, FooSym}}))) 638 /// return Err; 639 /// \endcode 640 /// 641 inline std::unique_ptr<AbsoluteSymbolsMaterializationUnit> 642 absoluteSymbols(SymbolMap Symbols, VModuleKey K = VModuleKey()) { 643 return std::make_unique<AbsoluteSymbolsMaterializationUnit>( 644 std::move(Symbols), std::move(K)); 645 } 646 647 /// A materialization unit for symbol aliases. Allows existing symbols to be 648 /// aliased with alternate flags. 649 class ReExportsMaterializationUnit : public MaterializationUnit { 650 public: 651 /// SourceJD is allowed to be nullptr, in which case the source JITDylib is 652 /// taken to be whatever JITDylib these definitions are materialized in (and 653 /// MatchNonExported has no effect). This is useful for defining aliases 654 /// within a JITDylib. 655 /// 656 /// Note: Care must be taken that no sets of aliases form a cycle, as such 657 /// a cycle will result in a deadlock when any symbol in the cycle is 658 /// resolved. 659 ReExportsMaterializationUnit(JITDylib *SourceJD, 660 JITDylibLookupFlags SourceJDLookupFlags, 661 SymbolAliasMap Aliases, VModuleKey K); 662 663 StringRef getName() const override; 664 665 private: 666 void materialize(MaterializationResponsibility R) override; 667 void discard(const JITDylib &JD, const SymbolStringPtr &Name) override; 668 static SymbolFlagsMap extractFlags(const SymbolAliasMap &Aliases); 669 670 JITDylib *SourceJD = nullptr; 671 JITDylibLookupFlags SourceJDLookupFlags; 672 SymbolAliasMap Aliases; 673 }; 674 675 /// Create a ReExportsMaterializationUnit with the given aliases. 676 /// Useful for defining symbol aliases.: E.g., given a JITDylib JD containing 677 /// symbols "foo" and "bar", we can define aliases "baz" (for "foo") and "qux" 678 /// (for "bar") with: \code{.cpp} 679 /// SymbolStringPtr Baz = ...; 680 /// SymbolStringPtr Qux = ...; 681 /// if (auto Err = JD.define(symbolAliases({ 682 /// {Baz, { Foo, JITSymbolFlags::Exported }}, 683 /// {Qux, { Bar, JITSymbolFlags::Weak }}})) 684 /// return Err; 685 /// \endcode 686 inline std::unique_ptr<ReExportsMaterializationUnit> 687 symbolAliases(SymbolAliasMap Aliases, VModuleKey K = VModuleKey()) { 688 return std::make_unique<ReExportsMaterializationUnit>( 689 nullptr, JITDylibLookupFlags::MatchAllSymbols, std::move(Aliases), 690 std::move(K)); 691 } 692 693 /// Create a materialization unit for re-exporting symbols from another JITDylib 694 /// with alternative names/flags. 695 /// SourceJD will be searched using the given JITDylibLookupFlags. 696 inline std::unique_ptr<ReExportsMaterializationUnit> 697 reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, 698 JITDylibLookupFlags SourceJDLookupFlags = 699 JITDylibLookupFlags::MatchExportedSymbolsOnly, 700 VModuleKey K = VModuleKey()) { 701 return std::make_unique<ReExportsMaterializationUnit>( 702 &SourceJD, SourceJDLookupFlags, std::move(Aliases), std::move(K)); 703 } 704 705 /// Build a SymbolAliasMap for the common case where you want to re-export 706 /// symbols from another JITDylib with the same linkage/flags. 707 Expected<SymbolAliasMap> 708 buildSimpleReexportsAAliasMap(JITDylib &SourceJD, const SymbolNameSet &Symbols); 709 710 /// Represents the state that a symbol has reached during materialization. 711 enum class SymbolState : uint8_t { 712 Invalid, /// No symbol should be in this state. 713 NeverSearched, /// Added to the symbol table, never queried. 714 Materializing, /// Queried, materialization begun. 715 Resolved, /// Assigned address, still materializing. 716 Emitted, /// Emitted to memory, but waiting on transitive dependencies. 717 Ready = 0x3f /// Ready and safe for clients to access. 718 }; 719 720 /// A symbol query that returns results via a callback when results are 721 /// ready. 722 /// 723 /// makes a callback when all symbols are available. 724 class AsynchronousSymbolQuery { 725 friend class ExecutionSession; 726 friend class JITDylib; 727 friend class JITSymbolResolverAdapter; 728 729 public: 730 /// Create a query for the given symbols. The NotifyComplete 731 /// callback will be called once all queried symbols reach the given 732 /// minimum state. 733 AsynchronousSymbolQuery(const SymbolLookupSet &Symbols, 734 SymbolState RequiredState, 735 SymbolsResolvedCallback NotifyComplete); 736 737 /// Notify the query that a requested symbol has reached the required state. 738 void notifySymbolMetRequiredState(const SymbolStringPtr &Name, 739 JITEvaluatedSymbol Sym); 740 741 /// Returns true if all symbols covered by this query have been 742 /// resolved. 743 bool isComplete() const { return OutstandingSymbolsCount == 0; } 744 745 /// Call the NotifyComplete callback. 746 /// 747 /// This should only be called if all symbols covered by the query have 748 /// reached the specified state. 749 void handleComplete(); 750 751 private: 752 SymbolState getRequiredState() { return RequiredState; } 753 754 void addQueryDependence(JITDylib &JD, SymbolStringPtr Name); 755 756 void removeQueryDependence(JITDylib &JD, const SymbolStringPtr &Name); 757 758 void dropSymbol(const SymbolStringPtr &Name); 759 760 bool canStillFail(); 761 762 void handleFailed(Error Err); 763 764 void detach(); 765 766 SymbolsResolvedCallback NotifyComplete; 767 SymbolDependenceMap QueryRegistrations; 768 SymbolMap ResolvedSymbols; 769 size_t OutstandingSymbolsCount; 770 SymbolState RequiredState; 771 }; 772 773 /// A symbol table that supports asynchoronous symbol queries. 774 /// 775 /// Represents a virtual shared object. Instances can not be copied or moved, so 776 /// their addresses may be used as keys for resource management. 777 /// JITDylib state changes must be made via an ExecutionSession to guarantee 778 /// that they are synchronized with respect to other JITDylib operations. 779 class JITDylib : public std::enable_shared_from_this<JITDylib> { 780 friend class AsynchronousSymbolQuery; 781 friend class ExecutionSession; 782 friend class Platform; 783 friend class MaterializationResponsibility; 784 public: 785 /// Definition generators can be attached to JITDylibs to generate new 786 /// definitions for otherwise unresolved symbols during lookup. 787 class DefinitionGenerator { 788 public: 789 virtual ~DefinitionGenerator(); 790 791 /// DefinitionGenerators should override this method to insert new 792 /// definitions into the parent JITDylib. K specifies the kind of this 793 /// lookup. JD specifies the target JITDylib being searched, and 794 /// JDLookupFlags specifies whether the search should match against 795 /// hidden symbols. Finally, Symbols describes the set of unresolved 796 /// symbols and their associated lookup flags. 797 virtual Error tryToGenerate(LookupKind K, JITDylib &JD, 798 JITDylibLookupFlags JDLookupFlags, 799 const SymbolLookupSet &LookupSet) = 0; 800 }; 801 802 using AsynchronousSymbolQuerySet = 803 std::set<std::shared_ptr<AsynchronousSymbolQuery>>; 804 805 JITDylib(const JITDylib &) = delete; 806 JITDylib &operator=(const JITDylib &) = delete; 807 JITDylib(JITDylib &&) = delete; 808 JITDylib &operator=(JITDylib &&) = delete; 809 810 /// Get the name for this JITDylib. 811 const std::string &getName() const { return JITDylibName; } 812 813 /// Get a reference to the ExecutionSession for this JITDylib. 814 ExecutionSession &getExecutionSession() const { return ES; } 815 816 /// Adds a definition generator to this JITDylib and returns a referenece to 817 /// it. 818 /// 819 /// When JITDylibs are searched during lookup, if no existing definition of 820 /// a symbol is found, then any generators that have been added are run (in 821 /// the order that they were added) to potentially generate a definition. 822 template <typename GeneratorT> 823 GeneratorT &addGenerator(std::unique_ptr<GeneratorT> DefGenerator); 824 825 /// Remove a definition generator from this JITDylib. 826 /// 827 /// The given generator must exist in this JITDylib's generators list (i.e. 828 /// have been added and not yet removed). 829 void removeGenerator(DefinitionGenerator &G); 830 831 /// Set the link order to be used when fixing up definitions in JITDylib. 832 /// This will replace the previous link order, and apply to any symbol 833 /// resolutions made for definitions in this JITDylib after the call to 834 /// setLinkOrder (even if the definition itself was added before the 835 /// call). 836 /// 837 /// If LinkAgainstThisJITDylibFirst is true (the default) then this JITDylib 838 /// will add itself to the beginning of the LinkOrder (Clients should not 839 /// put this JITDylib in the list in this case, to avoid redundant lookups). 840 /// 841 /// If LinkAgainstThisJITDylibFirst is false then the link order will be used 842 /// as-is. The primary motivation for this feature is to support deliberate 843 /// shadowing of symbols in this JITDylib by a facade JITDylib. For example, 844 /// the facade may resolve function names to stubs, and the stubs may compile 845 /// lazily by looking up symbols in this dylib. Adding the facade dylib 846 /// as the first in the link order (instead of this dylib) ensures that 847 /// definitions within this dylib resolve to the lazy-compiling stubs, 848 /// rather than immediately materializing the definitions in this dylib. 849 void setLinkOrder(JITDylibSearchOrder NewSearchOrder, 850 bool LinkAgainstThisJITDylibFirst = true); 851 852 /// Add the given JITDylib to the link order for definitions in this 853 /// JITDylib. 854 void addToLinkOrder(JITDylib &JD, 855 JITDylibLookupFlags JDLookupFlags = 856 JITDylibLookupFlags::MatchExportedSymbolsOnly); 857 858 /// Replace OldJD with NewJD in the link order if OldJD is present. 859 /// Otherwise this operation is a no-op. 860 void replaceInLinkOrder(JITDylib &OldJD, JITDylib &NewJD, 861 JITDylibLookupFlags JDLookupFlags = 862 JITDylibLookupFlags::MatchExportedSymbolsOnly); 863 864 /// Remove the given JITDylib from the link order for this JITDylib if it is 865 /// present. Otherwise this operation is a no-op. 866 void removeFromLinkOrder(JITDylib &JD); 867 868 /// Do something with the link order (run under the session lock). 869 template <typename Func> 870 auto withLinkOrderDo(Func &&F) 871 -> decltype(F(std::declval<const JITDylibSearchOrder &>())); 872 873 /// Define all symbols provided by the materialization unit to be part of this 874 /// JITDylib. 875 /// 876 /// This overload always takes ownership of the MaterializationUnit. If any 877 /// errors occur, the MaterializationUnit consumed. 878 template <typename MaterializationUnitType> 879 Error define(std::unique_ptr<MaterializationUnitType> &&MU); 880 881 /// Define all symbols provided by the materialization unit to be part of this 882 /// JITDylib. 883 /// 884 /// This overload only takes ownership of the MaterializationUnit no error is 885 /// generated. If an error occurs, ownership remains with the caller. This 886 /// may allow the caller to modify the MaterializationUnit to correct the 887 /// issue, then re-call define. 888 template <typename MaterializationUnitType> 889 Error define(std::unique_ptr<MaterializationUnitType> &MU); 890 891 /// Tries to remove the given symbols. 892 /// 893 /// If any symbols are not defined in this JITDylib this method will return 894 /// a SymbolsNotFound error covering the missing symbols. 895 /// 896 /// If all symbols are found but some symbols are in the process of being 897 /// materialized this method will return a SymbolsCouldNotBeRemoved error. 898 /// 899 /// On success, all symbols are removed. On failure, the JITDylib state is 900 /// left unmodified (no symbols are removed). 901 Error remove(const SymbolNameSet &Names); 902 903 /// Search the given JITDylib for the symbols in Symbols. If found, store 904 /// the flags for each symbol in Flags. If any required symbols are not found 905 /// then an error will be returned. 906 Expected<SymbolFlagsMap> lookupFlags(LookupKind K, 907 JITDylibLookupFlags JDLookupFlags, 908 SymbolLookupSet LookupSet); 909 910 /// Dump current JITDylib state to OS. 911 void dump(raw_ostream &OS); 912 913 /// FIXME: Remove this when we remove the old ORC layers. 914 /// Search the given JITDylibs in order for the symbols in Symbols. Results 915 /// (once they become available) will be returned via the given Query. 916 /// 917 /// If any symbol is not found then the unresolved symbols will be returned, 918 /// and the query will not be applied. The Query is not failed and can be 919 /// re-used in a subsequent lookup once the symbols have been added, or 920 /// manually failed. 921 Expected<SymbolNameSet> 922 legacyLookup(std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names); 923 924 private: 925 using AsynchronousSymbolQueryList = 926 std::vector<std::shared_ptr<AsynchronousSymbolQuery>>; 927 928 struct UnmaterializedInfo { 929 UnmaterializedInfo(std::unique_ptr<MaterializationUnit> MU) 930 : MU(std::move(MU)) {} 931 932 std::unique_ptr<MaterializationUnit> MU; 933 }; 934 935 using UnmaterializedInfosMap = 936 DenseMap<SymbolStringPtr, std::shared_ptr<UnmaterializedInfo>>; 937 938 struct MaterializingInfo { 939 SymbolDependenceMap Dependants; 940 SymbolDependenceMap UnemittedDependencies; 941 942 void addQuery(std::shared_ptr<AsynchronousSymbolQuery> Q); 943 void removeQuery(const AsynchronousSymbolQuery &Q); 944 AsynchronousSymbolQueryList takeQueriesMeeting(SymbolState RequiredState); 945 AsynchronousSymbolQueryList takeAllPendingQueries() { 946 return std::move(PendingQueries); 947 } 948 bool hasQueriesPending() const { return !PendingQueries.empty(); } 949 const AsynchronousSymbolQueryList &pendingQueries() const { 950 return PendingQueries; 951 } 952 private: 953 AsynchronousSymbolQueryList PendingQueries; 954 }; 955 956 using MaterializingInfosMap = DenseMap<SymbolStringPtr, MaterializingInfo>; 957 958 class SymbolTableEntry { 959 public: 960 SymbolTableEntry() = default; 961 SymbolTableEntry(JITSymbolFlags Flags) 962 : Flags(Flags), State(static_cast<uint8_t>(SymbolState::NeverSearched)), 963 MaterializerAttached(false), PendingRemoval(false) {} 964 965 JITTargetAddress getAddress() const { return Addr; } 966 JITSymbolFlags getFlags() const { return Flags; } 967 SymbolState getState() const { return static_cast<SymbolState>(State); } 968 969 bool hasMaterializerAttached() const { return MaterializerAttached; } 970 bool isPendingRemoval() const { return PendingRemoval; } 971 972 void setAddress(JITTargetAddress Addr) { this->Addr = Addr; } 973 void setFlags(JITSymbolFlags Flags) { this->Flags = Flags; } 974 void setState(SymbolState State) { 975 assert(static_cast<uint8_t>(State) < (1 << 6) && 976 "State does not fit in bitfield"); 977 this->State = static_cast<uint8_t>(State); 978 } 979 980 void setMaterializerAttached(bool MaterializerAttached) { 981 this->MaterializerAttached = MaterializerAttached; 982 } 983 984 void setPendingRemoval(bool PendingRemoval) { 985 this->PendingRemoval = PendingRemoval; 986 } 987 988 JITEvaluatedSymbol getSymbol() const { 989 return JITEvaluatedSymbol(Addr, Flags); 990 } 991 992 private: 993 JITTargetAddress Addr = 0; 994 JITSymbolFlags Flags; 995 uint8_t State : 6; 996 uint8_t MaterializerAttached : 1; 997 uint8_t PendingRemoval : 1; 998 }; 999 1000 using SymbolTable = DenseMap<SymbolStringPtr, SymbolTableEntry>; 1001 1002 JITDylib(ExecutionSession &ES, std::string Name); 1003 1004 Error defineImpl(MaterializationUnit &MU); 1005 1006 void lookupFlagsImpl(SymbolFlagsMap &Result, LookupKind K, 1007 JITDylibLookupFlags JDLookupFlags, 1008 SymbolLookupSet &Unresolved); 1009 1010 Error lodgeQuery(MaterializationUnitList &MUs, 1011 std::shared_ptr<AsynchronousSymbolQuery> &Q, LookupKind K, 1012 JITDylibLookupFlags JDLookupFlags, 1013 SymbolLookupSet &Unresolved); 1014 1015 Error lodgeQueryImpl(MaterializationUnitList &MUs, 1016 std::shared_ptr<AsynchronousSymbolQuery> &Q, 1017 LookupKind K, JITDylibLookupFlags JDLookupFlags, 1018 SymbolLookupSet &Unresolved); 1019 1020 bool lookupImpl(std::shared_ptr<AsynchronousSymbolQuery> &Q, 1021 std::vector<std::unique_ptr<MaterializationUnit>> &MUs, 1022 SymbolLookupSet &Unresolved); 1023 1024 void detachQueryHelper(AsynchronousSymbolQuery &Q, 1025 const SymbolNameSet &QuerySymbols); 1026 1027 void transferEmittedNodeDependencies(MaterializingInfo &DependantMI, 1028 const SymbolStringPtr &DependantName, 1029 MaterializingInfo &EmittedMI); 1030 1031 Expected<SymbolFlagsMap> defineMaterializing(SymbolFlagsMap SymbolFlags); 1032 1033 void replace(std::unique_ptr<MaterializationUnit> MU); 1034 1035 SymbolNameSet getRequestedSymbols(const SymbolFlagsMap &SymbolFlags) const; 1036 1037 void addDependencies(const SymbolStringPtr &Name, 1038 const SymbolDependenceMap &Dependants); 1039 1040 Error resolve(const SymbolMap &Resolved); 1041 1042 Error emit(const SymbolFlagsMap &Emitted); 1043 1044 using FailedSymbolsWorklist = 1045 std::vector<std::pair<JITDylib *, SymbolStringPtr>>; 1046 static void notifyFailed(FailedSymbolsWorklist FailedSymbols); 1047 1048 ExecutionSession &ES; 1049 std::string JITDylibName; 1050 bool Open = true; 1051 SymbolTable Symbols; 1052 UnmaterializedInfosMap UnmaterializedInfos; 1053 MaterializingInfosMap MaterializingInfos; 1054 std::vector<std::unique_ptr<DefinitionGenerator>> DefGenerators; 1055 JITDylibSearchOrder LinkOrder; 1056 }; 1057 1058 /// Platforms set up standard symbols and mediate interactions between dynamic 1059 /// initializers (e.g. C++ static constructors) and ExecutionSession state. 1060 /// Note that Platforms do not automatically run initializers: clients are still 1061 /// responsible for doing this. 1062 class Platform { 1063 public: 1064 virtual ~Platform(); 1065 1066 /// This method will be called outside the session lock each time a JITDylib 1067 /// is created (unless it is created with EmptyJITDylib set) to allow the 1068 /// Platform to install any JITDylib specific standard symbols (e.g 1069 /// __dso_handle). 1070 virtual Error setupJITDylib(JITDylib &JD) = 0; 1071 1072 /// This method will be called under the ExecutionSession lock each time a 1073 /// MaterializationUnit is added to a JITDylib. 1074 virtual Error notifyAdding(JITDylib &JD, const MaterializationUnit &MU) = 0; 1075 1076 /// This method will be called under the ExecutionSession lock when a 1077 /// VModuleKey is removed. 1078 virtual Error notifyRemoving(JITDylib &JD, VModuleKey K) = 0; 1079 1080 /// A utility function for looking up initializer symbols. Performs a blocking 1081 /// lookup for the given symbols in each of the given JITDylibs. 1082 static Expected<DenseMap<JITDylib *, SymbolMap>> 1083 lookupInitSymbols(ExecutionSession &ES, 1084 const DenseMap<JITDylib *, SymbolLookupSet> &InitSyms); 1085 }; 1086 1087 /// An ExecutionSession represents a running JIT program. 1088 class ExecutionSession { 1089 // FIXME: Remove this when we remove the old ORC layers. 1090 friend class JITDylib; 1091 1092 public: 1093 /// For reporting errors. 1094 using ErrorReporter = std::function<void(Error)>; 1095 1096 /// For dispatching MaterializationUnit::materialize calls. 1097 using DispatchMaterializationFunction = 1098 std::function<void(std::unique_ptr<MaterializationUnit> MU, 1099 MaterializationResponsibility MR)>; 1100 1101 /// Construct an ExecutionSession. 1102 /// 1103 /// SymbolStringPools may be shared between ExecutionSessions. 1104 ExecutionSession(std::shared_ptr<SymbolStringPool> SSP = nullptr); 1105 1106 /// Add a symbol name to the SymbolStringPool and return a pointer to it. 1107 SymbolStringPtr intern(StringRef SymName) { return SSP->intern(SymName); } 1108 1109 /// Returns a shared_ptr to the SymbolStringPool for this ExecutionSession. 1110 std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; } 1111 1112 /// Set the Platform for this ExecutionSession. 1113 void setPlatform(std::unique_ptr<Platform> P) { this->P = std::move(P); } 1114 1115 /// Get the Platform for this session. 1116 /// Will return null if no Platform has been set for this ExecutionSession. 1117 Platform *getPlatform() { return P.get(); } 1118 1119 /// Run the given lambda with the session mutex locked. 1120 template <typename Func> decltype(auto) runSessionLocked(Func &&F) { 1121 std::lock_guard<std::recursive_mutex> Lock(SessionMutex); 1122 return F(); 1123 } 1124 1125 /// Return a pointer to the "name" JITDylib. 1126 /// Ownership of JITDylib remains within Execution Session 1127 JITDylib *getJITDylibByName(StringRef Name); 1128 1129 /// Add a new bare JITDylib to this ExecutionSession. 1130 /// 1131 /// The JITDylib Name is required to be unique. Clients should verify that 1132 /// names are not being re-used (E.g. by calling getJITDylibByName) if names 1133 /// are based on user input. 1134 /// 1135 /// This call does not install any library code or symbols into the newly 1136 /// created JITDylib. The client is responsible for all configuration. 1137 JITDylib &createBareJITDylib(std::string Name); 1138 1139 /// Add a new JITDylib to this ExecutionSession. 1140 /// 1141 /// The JITDylib Name is required to be unique. Clients should verify that 1142 /// names are not being re-used (e.g. by calling getJITDylibByName) if names 1143 /// are based on user input. 1144 /// 1145 /// If a Platform is attached then Platform::setupJITDylib will be called to 1146 /// install standard platform symbols (e.g. standard library interposes). 1147 /// If no Platform is attached this call is equivalent to createBareJITDylib. 1148 Expected<JITDylib &> createJITDylib(std::string Name); 1149 1150 /// Allocate a module key for a new module to add to the JIT. 1151 VModuleKey allocateVModule() { 1152 return runSessionLocked([this]() { return ++LastKey; }); 1153 } 1154 1155 /// Return a module key to the ExecutionSession so that it can be 1156 /// re-used. This should only be done once all resources associated 1157 /// with the original key have been released. 1158 void releaseVModule(VModuleKey Key) { /* FIXME: Recycle keys */ 1159 } 1160 1161 /// Set the error reporter function. 1162 ExecutionSession &setErrorReporter(ErrorReporter ReportError) { 1163 this->ReportError = std::move(ReportError); 1164 return *this; 1165 } 1166 1167 /// Report a error for this execution session. 1168 /// 1169 /// Unhandled errors can be sent here to log them. 1170 void reportError(Error Err) { ReportError(std::move(Err)); } 1171 1172 /// Set the materialization dispatch function. 1173 ExecutionSession &setDispatchMaterialization( 1174 DispatchMaterializationFunction DispatchMaterialization) { 1175 this->DispatchMaterialization = std::move(DispatchMaterialization); 1176 return *this; 1177 } 1178 1179 void legacyFailQuery(AsynchronousSymbolQuery &Q, Error Err); 1180 1181 using LegacyAsyncLookupFunction = std::function<SymbolNameSet( 1182 std::shared_ptr<AsynchronousSymbolQuery> Q, SymbolNameSet Names)>; 1183 1184 /// A legacy lookup function for JITSymbolResolverAdapter. 1185 /// Do not use -- this will be removed soon. 1186 Expected<SymbolMap> 1187 legacyLookup(LegacyAsyncLookupFunction AsyncLookup, SymbolNameSet Names, 1188 SymbolState RequiredState, 1189 RegisterDependenciesFunction RegisterDependencies); 1190 1191 /// Search the given JITDylib list for the given symbols. 1192 /// 1193 /// SearchOrder lists the JITDylibs to search. For each dylib, the associated 1194 /// boolean indicates whether the search should match against non-exported 1195 /// (hidden visibility) symbols in that dylib (true means match against 1196 /// non-exported symbols, false means do not match). 1197 /// 1198 /// The NotifyComplete callback will be called once all requested symbols 1199 /// reach the required state. 1200 /// 1201 /// If all symbols are found, the RegisterDependencies function will be called 1202 /// while the session lock is held. This gives clients a chance to register 1203 /// dependencies for on the queried symbols for any symbols they are 1204 /// materializing (if a MaterializationResponsibility instance is present, 1205 /// this can be implemented by calling 1206 /// MaterializationResponsibility::addDependencies). If there are no 1207 /// dependenant symbols for this query (e.g. it is being made by a top level 1208 /// client to get an address to call) then the value NoDependenciesToRegister 1209 /// can be used. 1210 void lookup(LookupKind K, const JITDylibSearchOrder &SearchOrder, 1211 SymbolLookupSet Symbols, SymbolState RequiredState, 1212 SymbolsResolvedCallback NotifyComplete, 1213 RegisterDependenciesFunction RegisterDependencies); 1214 1215 /// Blocking version of lookup above. Returns the resolved symbol map. 1216 /// If WaitUntilReady is true (the default), will not return until all 1217 /// requested symbols are ready (or an error occurs). If WaitUntilReady is 1218 /// false, will return as soon as all requested symbols are resolved, 1219 /// or an error occurs. If WaitUntilReady is false and an error occurs 1220 /// after resolution, the function will return a success value, but the 1221 /// error will be reported via reportErrors. 1222 Expected<SymbolMap> lookup(const JITDylibSearchOrder &SearchOrder, 1223 const SymbolLookupSet &Symbols, 1224 LookupKind K = LookupKind::Static, 1225 SymbolState RequiredState = SymbolState::Ready, 1226 RegisterDependenciesFunction RegisterDependencies = 1227 NoDependenciesToRegister); 1228 1229 /// Convenience version of blocking lookup. 1230 /// Searches each of the JITDylibs in the search order in turn for the given 1231 /// symbol. 1232 Expected<JITEvaluatedSymbol> 1233 lookup(const JITDylibSearchOrder &SearchOrder, SymbolStringPtr Symbol, 1234 SymbolState RequiredState = SymbolState::Ready); 1235 1236 /// Convenience version of blocking lookup. 1237 /// Searches each of the JITDylibs in the search order in turn for the given 1238 /// symbol. The search will not find non-exported symbols. 1239 Expected<JITEvaluatedSymbol> 1240 lookup(ArrayRef<JITDylib *> SearchOrder, SymbolStringPtr Symbol, 1241 SymbolState RequiredState = SymbolState::Ready); 1242 1243 /// Convenience version of blocking lookup. 1244 /// Searches each of the JITDylibs in the search order in turn for the given 1245 /// symbol. The search will not find non-exported symbols. 1246 Expected<JITEvaluatedSymbol> 1247 lookup(ArrayRef<JITDylib *> SearchOrder, StringRef Symbol, 1248 SymbolState RequiredState = SymbolState::Ready); 1249 1250 /// Materialize the given unit. 1251 void dispatchMaterialization(std::unique_ptr<MaterializationUnit> MU, 1252 MaterializationResponsibility MR) { 1253 assert(MU && "MU must be non-null"); 1254 DEBUG_WITH_TYPE("orc", dumpDispatchInfo(MR.getTargetJITDylib(), *MU)); 1255 DispatchMaterialization(std::move(MU), std::move(MR)); 1256 } 1257 1258 /// Dump the state of all the JITDylibs in this session. 1259 void dump(raw_ostream &OS); 1260 1261 private: 1262 static void logErrorsToStdErr(Error Err) { 1263 logAllUnhandledErrors(std::move(Err), errs(), "JIT session error: "); 1264 } 1265 1266 static void 1267 materializeOnCurrentThread(std::unique_ptr<MaterializationUnit> MU, 1268 MaterializationResponsibility MR) { 1269 MU->materialize(std::move(MR)); 1270 } 1271 1272 void runOutstandingMUs(); 1273 1274 #ifndef NDEBUG 1275 void dumpDispatchInfo(JITDylib &JD, MaterializationUnit &MU); 1276 #endif // NDEBUG 1277 1278 mutable std::recursive_mutex SessionMutex; 1279 std::shared_ptr<SymbolStringPool> SSP; 1280 std::unique_ptr<Platform> P; 1281 VModuleKey LastKey = 0; 1282 ErrorReporter ReportError = logErrorsToStdErr; 1283 DispatchMaterializationFunction DispatchMaterialization = 1284 materializeOnCurrentThread; 1285 1286 std::vector<std::shared_ptr<JITDylib>> JDs; 1287 1288 // FIXME: Remove this (and runOutstandingMUs) once the linking layer works 1289 // with callbacks from asynchronous queries. 1290 mutable std::recursive_mutex OutstandingMUsMutex; 1291 std::vector<std::pair<std::unique_ptr<MaterializationUnit>, 1292 MaterializationResponsibility>> 1293 OutstandingMUs; 1294 }; 1295 1296 template <typename GeneratorT> 1297 GeneratorT &JITDylib::addGenerator(std::unique_ptr<GeneratorT> DefGenerator) { 1298 auto &G = *DefGenerator; 1299 ES.runSessionLocked( 1300 [&]() { DefGenerators.push_back(std::move(DefGenerator)); }); 1301 return G; 1302 } 1303 1304 template <typename Func> 1305 auto JITDylib::withLinkOrderDo(Func &&F) 1306 -> decltype(F(std::declval<const JITDylibSearchOrder &>())) { 1307 return ES.runSessionLocked([&]() { return F(LinkOrder); }); 1308 } 1309 1310 template <typename MaterializationUnitType> 1311 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &&MU) { 1312 assert(MU && "Can not define with a null MU"); 1313 1314 if (MU->getSymbols().empty()) { 1315 // Empty MUs are allowable but pathological, so issue a warning. 1316 DEBUG_WITH_TYPE("orc", { 1317 dbgs() << "Warning: Discarding empty MU " << MU->getName() << " for " 1318 << getName() << "\n"; 1319 }); 1320 return Error::success(); 1321 } else 1322 DEBUG_WITH_TYPE("orc", { 1323 dbgs() << "Defining MU " << MU->getName() << " for " << getName() << "\n"; 1324 }); 1325 1326 return ES.runSessionLocked([&, this]() -> Error { 1327 if (auto Err = defineImpl(*MU)) 1328 return Err; 1329 1330 if (auto *P = ES.getPlatform()) { 1331 if (auto Err = P->notifyAdding(*this, *MU)) 1332 return Err; 1333 } 1334 1335 /// defineImpl succeeded. 1336 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); 1337 for (auto &KV : UMI->MU->getSymbols()) 1338 UnmaterializedInfos[KV.first] = UMI; 1339 1340 return Error::success(); 1341 }); 1342 } 1343 1344 template <typename MaterializationUnitType> 1345 Error JITDylib::define(std::unique_ptr<MaterializationUnitType> &MU) { 1346 assert(MU && "Can not define with a null MU"); 1347 1348 if (MU->getSymbols().empty()) { 1349 // Empty MUs are allowable but pathological, so issue a warning. 1350 DEBUG_WITH_TYPE("orc", { 1351 dbgs() << "Warning: Discarding empty MU " << MU->getName() << getName() 1352 << "\n"; 1353 }); 1354 return Error::success(); 1355 } else 1356 DEBUG_WITH_TYPE("orc", { 1357 dbgs() << "Defining MU " << MU->getName() << " for " << getName() << "\n"; 1358 }); 1359 1360 return ES.runSessionLocked([&, this]() -> Error { 1361 if (auto Err = defineImpl(*MU)) 1362 return Err; 1363 1364 if (auto *P = ES.getPlatform()) { 1365 if (auto Err = P->notifyAdding(*this, *MU)) 1366 return Err; 1367 } 1368 1369 /// defineImpl succeeded. 1370 auto UMI = std::make_shared<UnmaterializedInfo>(std::move(MU)); 1371 for (auto &KV : UMI->MU->getSymbols()) 1372 UnmaterializedInfos[KV.first] = UMI; 1373 1374 return Error::success(); 1375 }); 1376 } 1377 1378 /// ReexportsGenerator can be used with JITDylib::addGenerator to automatically 1379 /// re-export a subset of the source JITDylib's symbols in the target. 1380 class ReexportsGenerator : public JITDylib::DefinitionGenerator { 1381 public: 1382 using SymbolPredicate = std::function<bool(SymbolStringPtr)>; 1383 1384 /// Create a reexports generator. If an Allow predicate is passed, only 1385 /// symbols for which the predicate returns true will be reexported. If no 1386 /// Allow predicate is passed, all symbols will be exported. 1387 ReexportsGenerator(JITDylib &SourceJD, 1388 JITDylibLookupFlags SourceJDLookupFlags, 1389 SymbolPredicate Allow = SymbolPredicate()); 1390 1391 Error tryToGenerate(LookupKind K, JITDylib &JD, 1392 JITDylibLookupFlags JDLookupFlags, 1393 const SymbolLookupSet &LookupSet) override; 1394 1395 private: 1396 JITDylib &SourceJD; 1397 JITDylibLookupFlags SourceJDLookupFlags; 1398 SymbolPredicate Allow; 1399 }; 1400 1401 } // End namespace orc 1402 } // End namespace llvm 1403 1404 #endif // LLVM_EXECUTIONENGINE_ORC_CORE_H 1405