Home | History | Annotate | Download | only in Orc
      1 //===- ExecutionUtils.h - Utilities for executing code in Orc ---*- 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 // Contains utilities for executing code in Orc.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
     15 #define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
     16 
     17 #include "llvm/ADT/StringMap.h"
     18 #include "llvm/ADT/iterator_range.h"
     19 #include "llvm/ExecutionEngine/JITSymbol.h"
     20 #include "llvm/ExecutionEngine/RuntimeDyld.h"
     21 #include "llvm/ExecutionEngine/Orc/OrcError.h"
     22 #include <algorithm>
     23 #include <cstdint>
     24 #include <string>
     25 #include <vector>
     26 #include <utility>
     27 
     28 namespace llvm {
     29 
     30 class ConstantArray;
     31 class GlobalVariable;
     32 class Function;
     33 class Module;
     34 class Value;
     35 
     36 namespace orc {
     37 
     38 /// @brief This iterator provides a convenient way to iterate over the elements
     39 ///        of an llvm.global_ctors/llvm.global_dtors instance.
     40 ///
     41 ///   The easiest way to get hold of instances of this class is to use the
     42 /// getConstructors/getDestructors functions.
     43 class CtorDtorIterator {
     44 public:
     45   /// @brief Accessor for an element of the global_ctors/global_dtors array.
     46   ///
     47   ///   This class provides a read-only view of the element with any casts on
     48   /// the function stripped away.
     49   struct Element {
     50     Element(unsigned Priority, Function *Func, Value *Data)
     51       : Priority(Priority), Func(Func), Data(Data) {}
     52 
     53     unsigned Priority;
     54     Function *Func;
     55     Value *Data;
     56   };
     57 
     58   /// @brief Construct an iterator instance. If End is true then this iterator
     59   ///        acts as the end of the range, otherwise it is the beginning.
     60   CtorDtorIterator(const GlobalVariable *GV, bool End);
     61 
     62   /// @brief Test iterators for equality.
     63   bool operator==(const CtorDtorIterator &Other) const;
     64 
     65   /// @brief Test iterators for inequality.
     66   bool operator!=(const CtorDtorIterator &Other) const;
     67 
     68   /// @brief Pre-increment iterator.
     69   CtorDtorIterator& operator++();
     70 
     71   /// @brief Post-increment iterator.
     72   CtorDtorIterator operator++(int);
     73 
     74   /// @brief Dereference iterator. The resulting value provides a read-only view
     75   ///        of this element of the global_ctors/global_dtors list.
     76   Element operator*() const;
     77 
     78 private:
     79   const ConstantArray *InitList;
     80   unsigned I;
     81 };
     82 
     83 /// @brief Create an iterator range over the entries of the llvm.global_ctors
     84 ///        array.
     85 iterator_range<CtorDtorIterator> getConstructors(const Module &M);
     86 
     87 /// @brief Create an iterator range over the entries of the llvm.global_ctors
     88 ///        array.
     89 iterator_range<CtorDtorIterator> getDestructors(const Module &M);
     90 
     91 /// @brief Convenience class for recording constructor/destructor names for
     92 ///        later execution.
     93 template <typename JITLayerT>
     94 class CtorDtorRunner {
     95 public:
     96   /// @brief Construct a CtorDtorRunner for the given range using the given
     97   ///        name mangling function.
     98   CtorDtorRunner(std::vector<std::string> CtorDtorNames,
     99                  typename JITLayerT::ModuleHandleT H)
    100       : CtorDtorNames(std::move(CtorDtorNames)), H(H) {}
    101 
    102   /// @brief Run the recorded constructors/destructors through the given JIT
    103   ///        layer.
    104   Error runViaLayer(JITLayerT &JITLayer) const {
    105     using CtorDtorTy = void (*)();
    106 
    107     for (const auto &CtorDtorName : CtorDtorNames)
    108       if (auto CtorDtorSym = JITLayer.findSymbolIn(H, CtorDtorName, false)) {
    109         if (auto AddrOrErr = CtorDtorSym.getAddress()) {
    110           CtorDtorTy CtorDtor =
    111             reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr));
    112           CtorDtor();
    113         } else
    114           return AddrOrErr.takeError();
    115       } else {
    116         if (auto Err = CtorDtorSym.takeError())
    117           return Err;
    118         else
    119           return make_error<JITSymbolNotFound>(CtorDtorName);
    120       }
    121     return Error::success();
    122   }
    123 
    124 private:
    125   std::vector<std::string> CtorDtorNames;
    126   typename JITLayerT::ModuleHandleT H;
    127 };
    128 
    129 /// @brief Support class for static dtor execution. For hosted (in-process) JITs
    130 ///        only!
    131 ///
    132 ///   If a __cxa_atexit function isn't found C++ programs that use static
    133 /// destructors will fail to link. However, we don't want to use the host
    134 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run
    135 /// after the JIT has been torn down, which is no good. This class makes it easy
    136 /// to override __cxa_atexit (and the related __dso_handle).
    137 ///
    138 ///   To use, clients should manually call searchOverrides from their symbol
    139 /// resolver. This should generally be done after attempting symbol resolution
    140 /// inside the JIT, but before searching the host process's symbol table. When
    141 /// the client determines that destructors should be run (generally at JIT
    142 /// teardown or after a return from main), the runDestructors method should be
    143 /// called.
    144 class LocalCXXRuntimeOverrides {
    145 public:
    146   /// Create a runtime-overrides class.
    147   template <typename MangleFtorT>
    148   LocalCXXRuntimeOverrides(const MangleFtorT &Mangle) {
    149     addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
    150     addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
    151   }
    152 
    153   /// Search overrided symbols.
    154   JITEvaluatedSymbol searchOverrides(const std::string &Name) {
    155     auto I = CXXRuntimeOverrides.find(Name);
    156     if (I != CXXRuntimeOverrides.end())
    157       return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported);
    158     return nullptr;
    159   }
    160 
    161   /// Run any destructors recorded by the overriden __cxa_atexit function
    162   /// (CXAAtExitOverride).
    163   void runDestructors();
    164 
    165 private:
    166   template <typename PtrTy>
    167   JITTargetAddress toTargetAddress(PtrTy* P) {
    168     return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P));
    169   }
    170 
    171   void addOverride(const std::string &Name, JITTargetAddress Addr) {
    172     CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
    173   }
    174 
    175   StringMap<JITTargetAddress> CXXRuntimeOverrides;
    176 
    177   using DestructorPtr = void (*)(void *);
    178   using CXXDestructorDataPair = std::pair<DestructorPtr, void *>;
    179   using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>;
    180   CXXDestructorDataPairList DSOHandleOverride;
    181   static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg,
    182                                void *DSOHandle);
    183 };
    184 
    185 } // end namespace orc
    186 
    187 } // end namespace llvm
    188 
    189 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
    190