1 //===- ExecutionUtils.h - Utilities for executing code in Orc ---*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Contains utilities for executing code in Orc.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H
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"
42 /// A utility class for building TargetMachines for JITs.
43 class JITTargetMachineBuilder {
45 JITTargetMachineBuilder(Triple TT);
46 static Expected<JITTargetMachineBuilder> detectHost();
47 Expected<std::unique_ptr<TargetMachine>> createTargetMachine();
49 JITTargetMachineBuilder &setArch(std::string Arch) {
50 this->Arch = std::move(Arch);
53 JITTargetMachineBuilder &setCPU(std::string CPU) {
54 this->CPU = std::move(CPU);
57 JITTargetMachineBuilder &setRelocationModel(Optional<Reloc::Model> RM) {
58 this->RM = std::move(RM);
61 JITTargetMachineBuilder &setCodeModel(Optional<CodeModel::Model> CM) {
62 this->CM = std::move(CM);
65 JITTargetMachineBuilder &
66 addFeatures(const std::vector<std::string> &FeatureVec);
67 SubtargetFeatures &getFeatures() { return Features; }
68 TargetOptions &getOptions() { return Options; }
74 SubtargetFeatures Features;
75 TargetOptions Options;
76 Optional<Reloc::Model> RM;
77 Optional<CodeModel::Model> CM;
78 CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
81 /// This iterator provides a convenient way to iterate over the elements
82 /// of an llvm.global_ctors/llvm.global_dtors instance.
84 /// The easiest way to get hold of instances of this class is to use the
85 /// getConstructors/getDestructors functions.
86 class CtorDtorIterator {
88 /// Accessor for an element of the global_ctors/global_dtors array.
90 /// This class provides a read-only view of the element with any casts on
91 /// the function stripped away.
93 Element(unsigned Priority, Function *Func, Value *Data)
94 : Priority(Priority), Func(Func), Data(Data) {}
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);
105 /// Test iterators for equality.
106 bool operator==(const CtorDtorIterator &Other) const;
108 /// Test iterators for inequality.
109 bool operator!=(const CtorDtorIterator &Other) const;
111 /// Pre-increment iterator.
112 CtorDtorIterator& operator++();
114 /// Post-increment iterator.
115 CtorDtorIterator operator++(int);
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;
122 const ConstantArray *InitList;
126 /// Create an iterator range over the entries of the llvm.global_ctors
128 iterator_range<CtorDtorIterator> getConstructors(const Module &M);
130 /// Create an iterator range over the entries of the llvm.global_ctors
132 iterator_range<CtorDtorIterator> getDestructors(const Module &M);
134 /// Convenience class for recording constructor/destructor names for
136 template <typename JITLayerT>
137 class CtorDtorRunner {
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) {}
144 /// Run the recorded constructors/destructors through the given JIT
146 Error runViaLayer(JITLayerT &JITLayer) const {
147 using CtorDtorTy = void (*)();
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));
156 return AddrOrErr.takeError();
158 if (auto Err = CtorDtorSym.takeError())
161 return make_error<JITSymbolNotFound>(CtorDtorName);
164 return Error::success();
168 std::vector<std::string> CtorDtorNames;
172 class CtorDtorRunner2 {
174 CtorDtorRunner2(VSO &V) : V(V) {}
175 void add(iterator_range<CtorDtorIterator> CtorDtors);
179 using CtorDtorList = std::vector<SymbolStringPtr>;
180 using CtorDtorPriorityMap = std::map<unsigned, CtorDtorList>;
183 CtorDtorPriorityMap CtorDtorsByPriority;
186 /// Support class for static dtor execution. For hosted (in-process) JITs
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).
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
201 class LocalCXXRuntimeOverridesBase {
203 /// Run any destructors recorded by the overriden __cxa_atexit function
204 /// (CXAAtExitOverride).
205 void runDestructors();
208 template <typename PtrTy> JITTargetAddress toTargetAddress(PtrTy *P) {
209 return static_cast<JITTargetAddress>(reinterpret_cast<uintptr_t>(P));
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,
220 class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
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));
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);
238 void addOverride(const std::string &Name, JITTargetAddress Addr) {
239 CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
242 StringMap<JITTargetAddress> CXXRuntimeOverrides;
245 class LocalCXXRuntimeOverrides2 : public LocalCXXRuntimeOverridesBase {
247 Error enable(VSO &V, MangleAndInterner &Mangler);
250 /// A utility class to expose symbols found via dlsym to the JIT.
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 {
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);
263 sys::DynamicLibrary Dylib;
264 SymbolPredicate Allow;
268 } // end namespace orc
269 } // end namespace llvm
271 #endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H