Home | History | Annotate | Download | only in ExecutionEngine
      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 
     26 namespace llvm {
     27 
     28 class GlobalValue;
     29 
     30 namespace object {
     31 
     32 class BasicSymbolRef;
     33 
     34 } // end namespace object
     35 
     36 /// @brief Represents an address in the target process's address space.
     37 using JITTargetAddress = uint64_t;
     38 
     39 /// @brief Flags for symbols in the JIT.
     40 class JITSymbolFlags {
     41 public:
     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 
    110 private:
    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.
    117 class ARMJITSymbolFlags {
    118 public:
    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);
    130 private:
    131   JITSymbolFlags::TargetFlagsType Flags = 0;
    132 };
    133 
    134 /// @brief Represents a symbol that has been evaluated to an address already.
    135 class JITEvaluatedSymbol {
    136 public:
    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 
    153 private:
    154   JITTargetAddress Address = 0;
    155   JITSymbolFlags Flags;
    156 };
    157 
    158 /// @brief Represents a symbol in the JIT.
    159 class JITSymbol {
    160 public:
    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 
    250 private:
    251   GetAddressFtor GetAddress;
    252   union {
    253     JITTargetAddress CachedAddr;
    254     Error Err;
    255   };
    256   JITSymbolFlags Flags;
    257 };
    258 
    259 /// \brief Symbol resolution.
    260 class JITSymbolResolver {
    261 public:
    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 
    286 private:
    287   virtual void anchor();
    288 };
    289 
    290 } // end namespace llvm
    291 
    292 #endif // LLVM_EXECUTIONENGINE_JITSYMBOL_H
    293