LCOV - code coverage report
Current view: top level - include/llvm/ExecutionEngine - JITSymbol.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 31 31 100.0 %
Date: 2018-05-20 00:06:23 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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        1172 :   JITSymbolFlags() = default;
      65             : 
      66             :   /// Construct a JITSymbolFlags instance from the given flags.
      67         894 :   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          10 :     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           3 :   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         196 :   JITEvaluatedSymbol(std::nullptr_t) {}
     163             : 
     164             :   /// Create a symbol for the given address and flags.
     165             :   JITEvaluatedSymbol(JITTargetAddress Address, JITSymbolFlags Flags)
     166         911 :       : 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          13 :   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         985 :       : 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         398 :       : CachedAddr(Addr), Flags(Flags) {}
     203             : 
     204             :   /// Construct a JITSymbol from a JITEvaluatedSymbol.
     205             :   JITSymbol(JITEvaluatedSymbol Sym)
     206         471 :       : 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         212 :       : GetAddress(std::move(GetAddress)), CachedAddr(0), Flags(Flags) {}
     219             : 
     220             :   JITSymbol(const JITSymbol&) = delete;
     221             :   JITSymbol& operator=(const JITSymbol&) = delete;
     222             : 
     223         607 :   JITSymbol(JITSymbol &&Other)
     224        1214 :     : GetAddress(std::move(Other.GetAddress)), Flags(std::move(Other.Flags)) {
     225         607 :     if (Flags.hasError())
     226             :       Err = std::move(Other.Err);
     227             :     else
     228         607 :       CachedAddr = std::move(Other.CachedAddr);
     229         607 :   }
     230             : 
     231          10 :   JITSymbol& operator=(JITSymbol &&Other) {
     232          10 :     GetAddress = std::move(Other.GetAddress);
     233          10 :     Flags = std::move(Other.Flags);
     234          10 :     if (Flags.hasError())
     235             :       Err = std::move(Other.Err);
     236             :     else
     237          10 :       CachedAddr = std::move(Other.CachedAddr);
     238          10 :     return *this;
     239             :   }
     240             : 
     241        5286 :   ~JITSymbol() {
     242        2643 :     if (Flags.hasError())
     243             :       Err.~Error();
     244             :     else
     245             :       CachedAddr.~JITTargetAddress();
     246        2643 :   }
     247             : 
     248             :   /// Returns true if the symbol exists, false otherwise.
     249             :   explicit operator bool() const {
     250        3865 :     return !Flags.hasError() && (CachedAddr || GetAddress);
     251             :   }
     252             : 
     253             :   /// Move the error field value out of this JITSymbol.
     254             :   Error takeError() {
     255         408 :     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         758 :   Expected<JITTargetAddress> getAddress() {
     263             :     assert(!Flags.hasError() && "getAddress called on error value");
     264         758 :     if (GetAddress) {
     265         208 :       if (auto CachedAddrOrErr = GetAddress()) {
     266             :         GetAddress = nullptr;
     267         208 :         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

Generated by: LCOV version 1.13