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