• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
setArch(std::string Arch)49   JITTargetMachineBuilder &setArch(std::string Arch) {
50     this->Arch = std::move(Arch);
51     return *this;
52   }
setCPU(std::string CPU)53   JITTargetMachineBuilder &setCPU(std::string CPU) {
54     this->CPU = std::move(CPU);
55     return *this;
56   }
setRelocationModel(Optional<Reloc::Model> RM)57   JITTargetMachineBuilder &setRelocationModel(Optional<Reloc::Model> RM) {
58     this->RM = std::move(RM);
59     return *this;
60   }
setCodeModel(Optional<CodeModel::Model> CM)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);
getFeatures()67   SubtargetFeatures &getFeatures() { return Features; }
getOptions()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 {
ElementElement93     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.
CtorDtorRunner(std::vector<std::string> CtorDtorNames,VModuleKey K)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.
runViaLayer(JITLayerT & JITLayer)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:
CtorDtorRunner2(VSO & V)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:
toTargetAddress(PtrTy * P)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>
LocalCXXRuntimeOverrides(const MangleFtorT & Mangle)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.
searchOverrides(const std::string & Name)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:
addOverride(const std::string & Name,JITTargetAddress Addr)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