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/Orc/Core.h"
     21 #include "llvm/ExecutionEngine/Orc/OrcError.h"
     22 #include "llvm/ExecutionEngine/RuntimeDyld.h"
     23 #include "llvm/Support/DynamicLibrary.h"
     24 #include "llvm/Target/TargetOptions.h"
     25 #include <algorithm>
     26 #include <cstdint>
     27 #include <string>
     28 #include <utility>
     29 #include <vector>
     30 
     31 namespace llvm {
     32 
     33 class ConstantArray;
     34 class GlobalVariable;
     35 class Function;
     36 class Module;
     37 class TargetMachine;
     38 class Value;
     39 
     40 namespace orc {
     41 
     42 /// A utility class for building TargetMachines for JITs.
     43 class JITTargetMachineBuilder {
     44 public:
     45   JITTargetMachineBuilder(Triple TT);
     46   static Expected<JITTargetMachineBuilder> detectHost();
     47   Expected<std::unique_ptr<TargetMachine>> createTargetMachine();
     48 
     49   JITTargetMachineBuilder &setArch(std::string Arch) {
     50     this->Arch = std::move(Arch);
     51     return *this;
     52   }
     53   JITTargetMachineBuilder &setCPU(std::string CPU) {
     54     this->CPU = std::move(CPU);
     55     return *this;
     56   }
     57   JITTargetMachineBuilder &setRelocationModel(Optional<Reloc::Model> RM) {
     58     this->RM = std::move(RM);
     59     return *this;
     60   }
     61   JITTargetMachineBuilder &setCodeModel(Optional<CodeModel::Model> CM) {
     62     this->CM = std::move(CM);
     63     return *this;
     64   }
     65   JITTargetMachineBuilder &
     66   addFeatures(const std::vector<std::string> &FeatureVec);
     67   SubtargetFeatures &getFeatures() { return Features; }
     68   TargetOptions &getOptions() { return Options; }
     69 
     70 private:
     71   Triple TT;
     72   std::string Arch;
     73   std::string CPU;
     74   SubtargetFeatures Features;
     75   TargetOptions Options;
     76   Optional<Reloc::Model> RM;
     77   Optional<CodeModel::Model> CM;
     78   CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
     79 };
     80 
     81 /// This iterator provides a convenient way to iterate over the elements
     82 ///        of an llvm.global_ctors/llvm.global_dtors instance.
     83 ///
     84 ///   The easiest way to get hold of instances of this class is to use the
     85 /// getConstructors/getDestructors functions.
     86 class CtorDtorIterator {
     87 public:
     88   /// Accessor for an element of the global_ctors/global_dtors array.
     89   ///
     90   ///   This class provides a read-only view of the element with any casts on
     91   /// the function stripped away.
     92   struct Element {
     93     Element(unsigned Priority, Function *Func, Value *Data)
     94       : Priority(Priority), Func(Func), Data(Data) {}
     95 
     96     unsigned Priority;
     97     Function *Func;
     98     Value *Data;
     99   };
    100 
    101   /// Construct an iterator instance. If End is true then this iterator
    102   ///        acts as the end of the range, otherwise it is the beginning.
    103   CtorDtorIterator(const GlobalVariable *GV, bool End);
    104 
    105   /// Test iterators for equality.
    106   bool operator==(const CtorDtorIterator &Other) const;
    107 
    108   /// Test iterators for inequality.
    109   bool operator!=(const CtorDtorIterator &Other) const;
    110 
    111   /// Pre-increment iterator.
    112   CtorDtorIterator& operator++();
    113 
    114   /// Post-increment iterator.
    115   CtorDtorIterator operator++(int);
    116 
    117   /// Dereference iterator. The resulting value provides a read-only view
    118   ///        of this element of the global_ctors/global_dtors list.
    119   Element operator*() const;
    120 
    121 private:
    122   const ConstantArray *InitList;
    123   unsigned I;
    124 };
    125 
    126 /// Create an iterator range over the entries of the llvm.global_ctors
    127 ///        array.
    128 iterator_range<CtorDtorIterator> getConstructors(const Module &M);
    129 
    130 /// Create an iterator range over the entries of the llvm.global_ctors
    131 ///        array.
    132 iterator_range<CtorDtorIterator> getDestructors(const Module &M);
    133 
    134 /// Convenience class for recording constructor/destructor names for
    135 ///        later execution.
    136 template <typename JITLayerT>
    137 class CtorDtorRunner {
    138 public:
    139   /// Construct a CtorDtorRunner for the given range using the given
    140   ///        name mangling function.
    141   CtorDtorRunner(std::vector<std::string> CtorDtorNames, VModuleKey K)
    142       : CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
    143 
    144   /// Run the recorded constructors/destructors through the given JIT
    145   ///        layer.
    146   Error runViaLayer(JITLayerT &JITLayer) const {
    147     using CtorDtorTy = void (*)();
    148 
    149     for (const auto &CtorDtorName : CtorDtorNames) {
    150       if (auto CtorDtorSym = JITLayer.findSymbolIn(K, CtorDtorName, false)) {
    151         if (auto AddrOrErr = CtorDtorSym.getAddress()) {
    152           CtorDtorTy CtorDtor =
    153             reinterpret_cast<CtorDtorTy>(static_cast<uintptr_t>(*AddrOrErr));
    154           CtorDtor();
    155         } else
    156           return AddrOrErr.takeError();
    157       } else {
    158         if (auto Err = CtorDtorSym.takeError())
    159           return Err;
    160         else
    161           return make_error<JITSymbolNotFound>(CtorDtorName);
    162       }
    163     }
    164     return Error::success();
    165   }
    166 
    167 private:
    168   std::vector<std::string> CtorDtorNames;
    169   orc::VModuleKey K;
    170 };
    171 
    172 class CtorDtorRunner2 {
    173 public:
    174   CtorDtorRunner2(VSO &V) : V(V) {}
    175   void add(iterator_range<CtorDtorIterator> CtorDtors);
    176   Error run();
    177 
    178 private:
    179   using CtorDtorList = std::vector<SymbolStringPtr>;
    180   using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>;
    181 
    182   VSO &V;
    183   CtorDtorPriorityMap CtorDtorsByPriority;
    184 };
    185 
    186 /// Support class for static dtor execution. For hosted (in-process) JITs
    187 ///        only!
    188 ///
    189 ///   If a __cxa_atexit function isn't found C++ programs that use static
    190 /// destructors will fail to link. However, we don't want to use the host
    191 /// process's __cxa_atexit, because it will schedule JIT'd destructors to run
    192 /// after the JIT has been torn down, which is no good. This class makes it easy
    193 /// to override __cxa_atexit (and the related __dso_handle).
    194 ///
    195 ///   To use, clients should manually call searchOverrides from their symbol
    196 /// resolver. This should generally be done after attempting symbol resolution
    197 /// inside the JIT, but before searching the host process's symbol table. When
    198 /// the client determines that destructors should be run (generally at JIT
    199 /// teardown or after a return from main), the runDestructors method should be
    200 /// called.
    201 class LocalCXXRuntimeOverridesBase {
    202 public:
    203   /// Run any destructors recorded by the overriden __cxa_atexit function
    204   /// (CXAAtExitOverride).
    205   void runDestructors();
    206 
    207 protected:
    208   template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) {
    209     return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P));
    210   }
    211 
    212   using DestructorPtr = void (*)(void *);
    213   using CXXDestructorDataPair = std::pair<DestructorPtr, void *>;
    214   using CXXDestructorDataPairList = std::vector<CXXDestructorDataPair>;
    215   CXXDestructorDataPairList DSOHandleOverride;
    216   static int CXAAtExitOverride(DestructorPtr Destructor, void *Arg,
    217                                void *DSOHandle);
    218 };
    219 
    220 class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
    221 public:
    222   /// Create a runtime-overrides class.
    223   template <typename MangleFtorT>
    224   LocalCXXRuntimeOverrides(const MangleFtorT &Mangle) {
    225     addOverride(Mangle("__dso_handle"), toTargetAddress(&DSOHandleOverride));
    226     addOverride(Mangle("__cxa_atexit"), toTargetAddress(&CXAAtExitOverride));
    227   }
    228 
    229   /// Search overrided symbols.
    230   JITEvaluatedSymbol searchOverrides(const std::string &Name) {
    231     auto I = CXXRuntimeOverrides.find(Name);
    232     if (I != CXXRuntimeOverrides.end())
    233       return JITEvaluatedSymbol(I->second, JITSymbolFlags::Exported);
    234     return nullptr;
    235   }
    236 
    237 private:
    238   void addOverride(const std::string &Name, JITTargetAddress Addr) {
    239     CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
    240   }
    241 
    242   StringMap<JITTargetAddress> CXXRuntimeOverrides;
    243 };
    244 
    245 class LocalCXXRuntimeOverrides2 : public LocalCXXRuntimeOverridesBase {
    246 public:
    247   Error enable(VSO &V, MangleAndInterner &Mangler);
    248 };
    249 
    250 /// A utility class to expose symbols found via dlsym to the JIT.
    251 ///
    252 /// If an instance of this class is attached to a VSO as a fallback definition
    253 /// generator, then any symbol found in the given DynamicLibrary that passes
    254 /// the 'Allow' predicate will be added to the VSO.
    255 class DynamicLibraryFallbackGenerator {
    256 public:
    257   using SymbolPredicate = std::function<bool(SymbolStringPtr)>;
    258   DynamicLibraryFallbackGenerator(sys::DynamicLibrary Dylib,
    259                                   const DataLayout &DL, SymbolPredicate Allow);
    260   SymbolNameSet operator()(VSO &V, const SymbolNameSet &Names);
    261 
    262 private:
    263   sys::DynamicLibrary Dylib;
    264   SymbolPredicate Allow;
    265   char GlobalPrefix;
    266 };
    267 
    268 } // end namespace orc
    269 } // end namespace llvm
    270 
    271 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
    272