1//===- JITSymbol.h - JIT symbol abstraction ---------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Abstraction for target process addresses.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_EXECUTIONENGINE_JITSYMBOL_H
15#define LLVM_EXECUTIONENGINE_JITSYMBOL_H
16
17#include <algorithm>
18#include <cassert>
19#include <cstddef>
20#include <cstdint>
21#include <functional>
22#include <string>
23
24#include "llvm/Support/Error.h"
25
26namespace llvm {
27
28class GlobalValue;
29
30namespace object {
31
32class BasicSymbolRef;
33
34} // end namespace object
35
36/// @brief Represents an address in the target process's address space.
37using JITTargetAddress = uint64_t;
38
39/// @brief Flags for symbols in the JIT.
40class JITSymbolFlags {
41public:
42  using UnderlyingType = uint8_t;
43  using TargetFlagsType = uint64_t;
44
45  enum FlagNames : UnderlyingType {
46    None = 0,
47    HasError = 1U << 0,
48    Weak = 1U << 1,
49    Common = 1U << 2,
50    Absolute = 1U << 3,
51    Exported = 1U << 4
52  };
53
54  /// @brief Default-construct a JITSymbolFlags instance.
55  JITSymbolFlags() = default;
56
57  /// @brief Construct a JITSymbolFlags instance from the given flags.
58  JITSymbolFlags(FlagNames Flags) : Flags(Flags) {}
59
60  /// @brief Construct a JITSymbolFlags instance from the given flags and target
61  ///        flags.
62  JITSymbolFlags(FlagNames Flags, TargetFlagsType TargetFlags)
63    : Flags(Flags), TargetFlags(TargetFlags) {}
64
65  /// @brief Return true if there was an error retrieving this symbol.
66  bool hasError() const {
67    return (Flags & HasError) == HasError;
68  }
69
70  /// @brief Returns true if the Weak flag is set.
71  bool isWeak() const {
72    return (Flags & Weak) == Weak;
73  }
74
75  /// @brief Returns true if the Common flag is set.
76  bool isCommon() const {
77    return (Flags & Common) == Common;
78  }
79
80  /// @brief Returns true if the symbol isn't weak or common.
81  bool isStrongDefinition() const {
82    return !isWeak() && !isCommon();
83  }
84
85  /// @brief Returns true if the Exported flag is set.
86  bool isExported() const {
87    return (Flags & Exported) == Exported;
88  }
89
90  /// @brief Implicitly convert to the underlying flags type.
91  operator UnderlyingType&() { return Flags; }
92
93  /// @brief Implicitly convert to the underlying flags type.
94  operator const UnderlyingType&() const { return Flags; }
95
96  /// @brief Return a reference to the target-specific flags.
97  TargetFlagsType& getTargetFlags() { return TargetFlags; }
98
99  /// @brief Return a reference to the target-specific flags.
100  const TargetFlagsType& getTargetFlags() const { return TargetFlags; }
101
102  /// Construct a JITSymbolFlags value based on the flags of the given global
103  /// value.
104  static JITSymbolFlags fromGlobalValue(const GlobalValue &GV);
105
106  /// Construct a JITSymbolFlags value based on the flags of the given libobject
107  /// symbol.
108  static JITSymbolFlags fromObjectSymbol(const object::BasicSymbolRef &Symbol);
109
110private:
111  UnderlyingType Flags = None;
112  TargetFlagsType TargetFlags = 0;
113};
114
115/// @brief ARM-specific JIT symbol flags.
116/// FIXME: This should be moved into a target-specific header.
117class ARMJITSymbolFlags {
118public:
119  ARMJITSymbolFlags() = default;
120
121  enum FlagNames {
122    None = 0,
123    Thumb = 1 << 0
124  };
125
126  operator JITSymbolFlags::TargetFlagsType&() { return Flags; }
127
128  static ARMJITSymbolFlags fromObjectSymbol(
129                                           const object::BasicSymbolRef &Symbol);
130private:
131  JITSymbolFlags::TargetFlagsType Flags = 0;
132};
133
134/// @brief Represents a symbol that has been evaluated to an address already.
135class JITEvaluatedSymbol {
136public:
137  /// @brief Create a 'null' symbol.
138  JITEvaluatedSymbol(std::nullptr_t) {}
139
140  /// @brief Create a symbol for the given address and flags.
141  JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags)
142      : Address(Address), Flags(Flags) {}
143
144  /// @brief An evaluated symbol converts to 'true' if its address is non-zero.
145  explicit operator bool() const { return Address != 0; }
146
147  /// @brief Return the address of this symbol.
148  JITTargetAddress getAddress() const { return Address; }
149
150  /// @brief Return the flags for this symbol.
151  JITSymbolFlags getFlags() const { return Flags; }
152
153private:
154  JITTargetAddress Address = 0;
155  JITSymbolFlags Flags;
156};
157
158/// @brief Represents a symbol in the JIT.
159class JITSymbol {
160public:
161  using GetAddressFtor = std::function<Expected<JITTargetAddress>()>;
162
163  /// @brief Create a 'null' symbol, used to represent a "symbol not found"
164  ///        result from a successful (non-erroneous) lookup.
165  JITSymbol(std::nullptr_t)
166      : CachedAddr(0) {}
167
168  /// @brief Create a JITSymbol representing an error in the symbol lookup
169  ///        process (e.g. a network failure during a remote lookup).
170  JITSymbol(Error Err)
171    : Err(std::move(Err)), Flags(JITSymbolFlags::HasError) {}
172
173  /// @brief Create a symbol for a definition with a known address.
174  JITSymbol(JITTargetAddress Addr, JITSymbolFlags Flags)
175      : CachedAddr(Addr), Flags(Flags) {}
176
177  /// @brief Construct a JITSymbol from a JITEvaluatedSymbol.
178  JITSymbol(JITEvaluatedSymbol Sym)
179      : CachedAddr(Sym.getAddress()), Flags(Sym.getFlags()) {}
180
181  /// @brief Create a symbol for a definition that doesn't have a known address
182  ///        yet.
183  /// @param GetAddress A functor to materialize a definition (fixing the
184  ///        address) on demand.
185  ///
186  ///   This constructor allows a JIT layer to provide a reference to a symbol
187  /// definition without actually materializing the definition up front. The
188  /// user can materialize the definition at any time by calling the getAddress
189  /// method.
190  JITSymbol(GetAddressFtor GetAddress, JITSymbolFlags Flags)
191      : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
192
193  JITSymbol(const JITSymbol&) = delete;
194  JITSymbol& operator=(const JITSymbol&) = delete;
195
196  JITSymbol(JITSymbol &&Other)
197    : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
198    if (Flags.hasError())
199      Err = std::move(Other.Err);
200    else
201      CachedAddr = std::move(Other.CachedAddr);
202  }
203
204  JITSymbol& operator=(JITSymbol &&Other) {
205    GetAddress = std::move(Other.GetAddress);
206    Flags = std::move(Other.Flags);
207    if (Flags.hasError())
208      Err = std::move(Other.Err);
209    else
210      CachedAddr = std::move(Other.CachedAddr);
211    return *this;
212  }
213
214  ~JITSymbol() {
215    if (Flags.hasError())
216      Err.~Error();
217    else
218      CachedAddr.~JITTargetAddress();
219  }
220
221  /// @brief Returns true if the symbol exists, false otherwise.
222  explicit operator bool() const {
223    return !Flags.hasError() && (CachedAddr || GetAddress);
224  }
225
226  /// @brief Move the error field value out of this JITSymbol.
227  Error takeError() {
228    if (Flags.hasError())
229      return std::move(Err);
230    return Error::success();
231  }
232
233  /// @brief Get the address of the symbol in the target address space. Returns
234  ///        '0' if the symbol does not exist.
235  Expected<JITTargetAddress> getAddress() {
236    assert(!Flags.hasError() && "getAddress called on error value");
237    if (GetAddress) {
238      if (auto CachedAddrOrErr = GetAddress()) {
239        GetAddress = nullptr;
240        CachedAddr = *CachedAddrOrErr;
241        assert(CachedAddr && "Symbol could not be materialized.");
242      } else
243        return CachedAddrOrErr.takeError();
244    }
245    return CachedAddr;
246  }
247
248  JITSymbolFlags getFlags() const { return Flags; }
249
250private:
251  GetAddressFtor GetAddress;
252  union {
253    JITTargetAddress CachedAddr;
254    Error Err;
255  };
256  JITSymbolFlags Flags;
257};
258
259/// \brief Symbol resolution.
260class JITSymbolResolver {
261public:
262  virtual ~JITSymbolResolver() = default;
263
264  /// This method returns the address of the specified symbol if it exists
265  /// within the logical dynamic library represented by this JITSymbolResolver.
266  /// Unlike findSymbol, queries through this interface should return addresses
267  /// for hidden symbols.
268  ///
269  /// This is of particular importance for the Orc JIT APIs, which support lazy
270  /// compilation by breaking up modules: Each of those broken out modules
271  /// must be able to resolve hidden symbols provided by the others. Clients
272  /// writing memory managers for MCJIT can usually ignore this method.
273  ///
274  /// This method will be queried by RuntimeDyld when checking for previous
275  /// definitions of common symbols.
276  virtual JITSymbol findSymbolInLogicalDylib(const std::string &Name) = 0;
277
278  /// This method returns the address of the specified function or variable.
279  /// It is used to resolve symbols during module linking.
280  ///
281  /// If the returned symbol's address is equal to ~0ULL then RuntimeDyld will
282  /// skip all relocations for that symbol, and the client will be responsible
283  /// for handling them manually.
284  virtual JITSymbol findSymbol(const std::string &Name) = 0;
285
286private:
287  virtual void anchor();
288};
289
290} // end namespace llvm
291
292#endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H
293