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