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

Generated by: LCOV version 1.13