JITSymbol.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- JITSymbol.h - JIT symbol abstraction ---------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // Abstraction for target process addresses.
  15. //
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_EXECUTIONENGINE_JITSYMBOL_H
  18. #define LLVM_EXECUTIONENGINE_JITSYMBOL_H
  19. #include <algorithm>
  20. #include <cassert>
  21. #include <cstddef>
  22. #include <cstdint>
  23. #include <functional>
  24. #include <map>
  25. #include <set>
  26. #include <string>
  27. #include "llvm/ADT/BitmaskEnum.h"
  28. #include "llvm/ADT/FunctionExtras.h"
  29. #include "llvm/ADT/StringRef.h"
  30. #include "llvm/Support/Error.h"
  31. namespace llvm {
  32. class GlobalValue;
  33. class GlobalValueSummary;
  34. namespace object {
  35. class SymbolRef;
  36. } // end namespace object
  37. /// Represents an address in the target process's address space.
  38. using JITTargetAddress = uint64_t;
  39. /// Convert a JITTargetAddress to a pointer.
  40. ///
  41. /// Note: This is a raw cast of the address bit pattern to the given pointer
  42. /// type. When casting to a function pointer in order to execute JIT'd code
  43. /// jitTargetAddressToFunction should be preferred, as it will also perform
  44. /// pointer signing on targets that require it.
  45. template <typename T> T jitTargetAddressToPointer(JITTargetAddress Addr) {
  46. static_assert(std::is_pointer<T>::value, "T must be a pointer type");
  47. uintptr_t IntPtr = static_cast<uintptr_t>(Addr);
  48. assert(IntPtr == Addr && "JITTargetAddress value out of range for uintptr_t");
  49. return reinterpret_cast<T>(IntPtr);
  50. }
  51. /// Convert a JITTargetAddress to a callable function pointer.
  52. ///
  53. /// Casts the given address to a callable function pointer. This operation
  54. /// will perform pointer signing for platforms that require it (e.g. arm64e).
  55. template <typename T> T jitTargetAddressToFunction(JITTargetAddress Addr) {
  56. static_assert(std::is_pointer<T>::value &&
  57. std::is_function<std::remove_pointer_t<T>>::value,
  58. "T must be a function pointer type");
  59. return jitTargetAddressToPointer<T>(Addr);
  60. }
  61. /// Convert a pointer to a JITTargetAddress.
  62. template <typename T> JITTargetAddress pointerToJITTargetAddress(T *Ptr) {
  63. return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(Ptr));
  64. }
  65. /// Flags for symbols in the JIT.
  66. class JITSymbolFlags {
  67. public:
  68. using UnderlyingType = uint8_t;
  69. using TargetFlagsType = uint8_t;
  70. enum FlagNames : UnderlyingType {
  71. None = 0,
  72. HasError = 1U << 0,
  73. Weak = 1U << 1,
  74. Common = 1U << 2,
  75. Absolute = 1U << 3,
  76. Exported = 1U << 4,
  77. Callable = 1U << 5,
  78. MaterializationSideEffectsOnly = 1U << 6,
  79. LLVM_MARK_AS_BITMASK_ENUM( // LargestValue =
  80. MaterializationSideEffectsOnly)
  81. };
  82. /// Default-construct a JITSymbolFlags instance.
  83. JITSymbolFlags() = default;
  84. /// Construct a JITSymbolFlags instance from the given flags.
  85. JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
  86. /// Construct a JITSymbolFlags instance from the given flags and target
  87. /// flags.
  88. JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
  89. : TargetFlags(TargetFlags), Flags(Flags) {}
  90. /// Implicitly convert to bool. Returs true if any flag is set.
  91. explicit operator bool() const { return Flags != None || TargetFlags != 0; }
  92. /// Compare for equality.
  93. bool operator==(const JITSymbolFlags &RHS) const {
  94. return Flags == RHS.Flags && TargetFlags == RHS.TargetFlags;
  95. }
  96. /// Bitwise AND-assignment for FlagNames.
  97. JITSymbolFlags &operator&=(const FlagNames &RHS) {
  98. Flags &= RHS;
  99. return *this;
  100. }
  101. /// Bitwise OR-assignment for FlagNames.
  102. JITSymbolFlags &operator|=(const FlagNames &RHS) {
  103. Flags |= RHS;
  104. return *this;
  105. }
  106. /// Return true if there was an error retrieving this symbol.
  107. bool hasError() const {
  108. return (Flags & HasError) == HasError;
  109. }
  110. /// Returns true if the Weak flag is set.
  111. bool isWeak() const {
  112. return (Flags & Weak) == Weak;
  113. }
  114. /// Returns true if the Common flag is set.
  115. bool isCommon() const {
  116. return (Flags & Common) == Common;
  117. }
  118. /// Returns true if the symbol isn't weak or common.
  119. bool isStrong() const {
  120. return !isWeak() && !isCommon();
  121. }
  122. /// Returns true if the Exported flag is set.
  123. bool isExported() const {
  124. return (Flags & Exported) == Exported;
  125. }
  126. /// Returns true if the given symbol is known to be callable.
  127. bool isCallable() const { return (Flags & Callable) == Callable; }
  128. /// Returns true if this symbol is a materialization-side-effects-only
  129. /// symbol. Such symbols do not have a real address. They exist to trigger
  130. /// and support synchronization of materialization side effects, e.g. for
  131. /// collecting initialization information. These symbols will vanish from
  132. /// the symbol table immediately upon reaching the ready state, and will
  133. /// appear to queries as if they were never defined (except that query
  134. /// callback execution will be delayed until they reach the ready state).
  135. /// MaterializationSideEffectOnly symbols should only be queried using the
  136. /// SymbolLookupFlags::WeaklyReferencedSymbol flag (see
  137. /// llvm/include/llvm/ExecutionEngine/Orc/Core.h).
  138. bool hasMaterializationSideEffectsOnly() const {
  139. return (Flags & MaterializationSideEffectsOnly) ==
  140. MaterializationSideEffectsOnly;
  141. }
  142. /// Get the underlying flags value as an integer.
  143. UnderlyingType getRawFlagsValue() const {
  144. return static_cast<UnderlyingType>(Flags);
  145. }
  146. /// Return a reference to the target-specific flags.
  147. TargetFlagsType& getTargetFlags() { return TargetFlags; }
  148. /// Return a reference to the target-specific flags.
  149. const TargetFlagsType& getTargetFlags() const { return TargetFlags; }
  150. /// Construct a JITSymbolFlags value based on the flags of the given global
  151. /// value.
  152. static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
  153. /// Construct a JITSymbolFlags value based on the flags of the given global
  154. /// value summary.
  155. static JITSymbolFlags fromSummary(GlobalValueSummary *S);
  156. /// Construct a JITSymbolFlags value based on the flags of the given libobject
  157. /// symbol.
  158. static Expected<JITSymbolFlags>
  159. fromObjectSymbol(const object::SymbolRef &Symbol);
  160. private:
  161. TargetFlagsType TargetFlags = 0;
  162. FlagNames Flags = None;
  163. };
  164. inline JITSymbolFlags operator&(const JITSymbolFlags &LHS,
  165. const JITSymbolFlags::FlagNames &RHS) {
  166. JITSymbolFlags Tmp = LHS;
  167. Tmp &= RHS;
  168. return Tmp;
  169. }
  170. inline JITSymbolFlags operator|(const JITSymbolFlags &LHS,
  171. const JITSymbolFlags::FlagNames &RHS) {
  172. JITSymbolFlags Tmp = LHS;
  173. Tmp |= RHS;
  174. return Tmp;
  175. }
  176. /// ARM-specific JIT symbol flags.
  177. /// FIXME: This should be moved into a target-specific header.
  178. class ARMJITSymbolFlags {
  179. public:
  180. ARMJITSymbolFlags() = default;
  181. enum FlagNames {
  182. None = 0,
  183. Thumb = 1 << 0
  184. };
  185. operator JITSymbolFlags::TargetFlagsType&() { return Flags; }
  186. static ARMJITSymbolFlags fromObjectSymbol(const object::SymbolRef &Symbol);
  187. private:
  188. JITSymbolFlags::TargetFlagsType Flags = 0;
  189. };
  190. /// Represents a symbol that has been evaluated to an address already.
  191. class JITEvaluatedSymbol {
  192. public:
  193. JITEvaluatedSymbol() = default;
  194. /// Create a 'null' symbol.
  195. JITEvaluatedSymbol(std::nullptr_t) {}
  196. /// Create a symbol for the given address and flags.
  197. JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags)
  198. : Address(Address), Flags(Flags) {}
  199. /// Create a symbol from the given pointer with the given flags.
  200. template <typename T>
  201. static JITEvaluatedSymbol
  202. fromPointer(T *P, JITSymbolFlags Flags = JITSymbolFlags::Exported) {
  203. return JITEvaluatedSymbol(pointerToJITTargetAddress(P), Flags);
  204. }
  205. /// An evaluated symbol converts to 'true' if its address is non-zero.
  206. explicit operator bool() const { return Address != 0; }
  207. /// Return the address of this symbol.
  208. JITTargetAddress getAddress() const { return Address; }
  209. /// Return the flags for this symbol.
  210. JITSymbolFlags getFlags() const { return Flags; }
  211. /// Set the flags for this symbol.
  212. void setFlags(JITSymbolFlags Flags) { this->Flags = std::move(Flags); }
  213. private:
  214. JITTargetAddress Address = 0;
  215. JITSymbolFlags Flags;
  216. };
  217. /// Represents a symbol in the JIT.
  218. class JITSymbol {
  219. public:
  220. using GetAddressFtor = unique_function<Expected<JITTargetAddress>()>;
  221. /// Create a 'null' symbol, used to represent a "symbol not found"
  222. /// result from a successful (non-erroneous) lookup.
  223. JITSymbol(std::nullptr_t)
  224. : CachedAddr(0) {}
  225. /// Create a JITSymbol representing an error in the symbol lookup
  226. /// process (e.g. a network failure during a remote lookup).
  227. JITSymbol(Error Err)
  228. : Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {}
  229. /// Create a symbol for a definition with a known address.
  230. JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags)
  231. : CachedAddr(Addr), Flags(Flags) {}
  232. /// Construct a JITSymbol from a JITEvaluatedSymbol.
  233. JITSymbol(JITEvaluatedSymbol Sym)
  234. : CachedAddr(Sym.getAddress()), Flags(Sym.getFlags()) {}
  235. /// Create a symbol for a definition that doesn't have a known address
  236. /// yet.
  237. /// @param GetAddress A functor to materialize a definition (fixing the
  238. /// address) on demand.
  239. ///
  240. /// This constructor allows a JIT layer to provide a reference to a symbol
  241. /// definition without actually materializing the definition up front. The
  242. /// user can materialize the definition at any time by calling the getAddress
  243. /// method.
  244. JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
  245. : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
  246. JITSymbol(const JITSymbol&) = delete;
  247. JITSymbol& operator=(const JITSymbol&) = delete;
  248. JITSymbol(JITSymbol &&Other)
  249. : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
  250. if (Flags.hasError())
  251. Err = std::move(Other.Err);
  252. else
  253. CachedAddr = std::move(Other.CachedAddr);
  254. }
  255. JITSymbol& operator=(JITSymbol &&Other) {
  256. GetAddress = std::move(Other.GetAddress);
  257. Flags = std::move(Other.Flags);
  258. if (Flags.hasError())
  259. Err = std::move(Other.Err);
  260. else
  261. CachedAddr = std::move(Other.CachedAddr);
  262. return *this;
  263. }
  264. ~JITSymbol() {
  265. if (Flags.hasError())
  266. Err.~Error();
  267. else
  268. CachedAddr.~JITTargetAddress();
  269. }
  270. /// Returns true if the symbol exists, false otherwise.
  271. explicit operator bool() const {
  272. return !Flags.hasError() && (CachedAddr || GetAddress);
  273. }
  274. /// Move the error field value out of this JITSymbol.
  275. Error takeError() {
  276. if (Flags.hasError())
  277. return std::move(Err);
  278. return Error::success();
  279. }
  280. /// Get the address of the symbol in the target address space. Returns
  281. /// '0' if the symbol does not exist.
  282. Expected<JITTargetAddress> getAddress() {
  283. assert(!Flags.hasError() && "getAddress called on error value");
  284. if (GetAddress) {
  285. if (auto CachedAddrOrErr = GetAddress()) {
  286. GetAddress = nullptr;
  287. CachedAddr = *CachedAddrOrErr;
  288. assert(CachedAddr && "Symbol could not be materialized.");
  289. } else
  290. return CachedAddrOrErr.takeError();
  291. }
  292. return CachedAddr;
  293. }
  294. JITSymbolFlags getFlags() const { return Flags; }
  295. private:
  296. GetAddressFtor GetAddress;
  297. union {
  298. JITTargetAddress CachedAddr;
  299. Error Err;
  300. };
  301. JITSymbolFlags Flags;
  302. };
  303. /// Symbol resolution interface.
  304. ///
  305. /// Allows symbol flags and addresses to be looked up by name.
  306. /// Symbol queries are done in bulk (i.e. you request resolution of a set of
  307. /// symbols, rather than a single one) to reduce IPC overhead in the case of
  308. /// remote JITing, and expose opportunities for parallel compilation.
  309. class JITSymbolResolver {
  310. public:
  311. using LookupSet = std::set<StringRef>;
  312. using LookupResult = std::map<StringRef, JITEvaluatedSymbol>;
  313. using OnResolvedFunction = unique_function<void(Expected<LookupResult>)>;
  314. virtual ~JITSymbolResolver() = default;
  315. /// Returns the fully resolved address and flags for each of the given
  316. /// symbols.
  317. ///
  318. /// This method will return an error if any of the given symbols can not be
  319. /// resolved, or if the resolution process itself triggers an error.
  320. virtual void lookup(const LookupSet &Symbols,
  321. OnResolvedFunction OnResolved) = 0;
  322. /// Returns the subset of the given symbols that should be materialized by
  323. /// the caller. Only weak/common symbols should be looked up, as strong
  324. /// definitions are implicitly always part of the caller's responsibility.
  325. virtual Expected<LookupSet>
  326. getResponsibilitySet(const LookupSet &Symbols) = 0;
  327. /// Specify if this resolver can return valid symbols with zero value.
  328. virtual bool allowsZeroSymbols() { return false; }
  329. private:
  330. virtual void anchor();
  331. };
  332. /// Legacy symbol resolution interface.
  333. class LegacyJITSymbolResolver : public JITSymbolResolver {
  334. public:
  335. /// Performs lookup by, for each symbol, first calling
  336. /// findSymbolInLogicalDylib and if that fails calling
  337. /// findSymbol.
  338. void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) final;
  339. /// Performs flags lookup by calling findSymbolInLogicalDylib and
  340. /// returning the flags value for that symbol.
  341. Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) final;
  342. /// This method returns the address of the specified symbol if it exists
  343. /// within the logical dynamic library represented by this JITSymbolResolver.
  344. /// Unlike findSymbol, queries through this interface should return addresses
  345. /// for hidden symbols.
  346. ///
  347. /// This is of particular importance for the Orc JIT APIs, which support lazy
  348. /// compilation by breaking up modules: Each of those broken out modules
  349. /// must be able to resolve hidden symbols provided by the others. Clients
  350. /// writing memory managers for MCJIT can usually ignore this method.
  351. ///
  352. /// This method will be queried by RuntimeDyld when checking for previous
  353. /// definitions of common symbols.
  354. virtual JITSymbol findSymbolInLogicalDylib(const std::string &Name) = 0;
  355. /// This method returns the address of the specified function or variable.
  356. /// It is used to resolve symbols during module linking.
  357. ///
  358. /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will
  359. /// skip all relocations for that symbol, and the client will be responsible
  360. /// for handling them manually.
  361. virtual JITSymbol findSymbol(const std::string &Name) = 0;
  362. private:
  363. void anchor() override;
  364. };
  365. } // end namespace llvm
  366. #endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H
  367. #ifdef __GNUC__
  368. #pragma GCC diagnostic pop
  369. #endif