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