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