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

Generated by: LCOV version 1.13