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