blob: e27f6e1e2cd6a545aefa10dbf40aa0274b975237 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- 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"
Andrew Scullcdfcccc2018-10-05 20:58:37 +010023#include "llvm/Support/DynamicLibrary.h"
24#include "llvm/Target/TargetOptions.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010025#include <algorithm>
26#include <cstdint>
27#include <string>
28#include <utility>
29#include <vector>
30
31namespace llvm {
32
33class ConstantArray;
34class GlobalVariable;
35class Function;
36class Module;
Andrew Scullcdfcccc2018-10-05 20:58:37 +010037class TargetMachine;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010038class Value;
39
40namespace orc {
41
Andrew Scullcdfcccc2018-10-05 20:58:37 +010042/// A utility class for building TargetMachines for JITs.
43class JITTargetMachineBuilder {
44public:
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
70private:
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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010082/// 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.
86class CtorDtorIterator {
87public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +010088 /// Accessor for an element of the global_ctors/global_dtors array.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010089 ///
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
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100101 /// Construct an iterator instance. If End is true then this iterator
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100102 /// acts as the end of the range, otherwise it is the beginning.
103 CtorDtorIterator(const GlobalVariable *GV, bool End);
104
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100105 /// Test iterators for equality.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100106 bool operator==(const CtorDtorIterator &Other) const;
107
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100108 /// Test iterators for inequality.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100109 bool operator!=(const CtorDtorIterator &Other) const;
110
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100111 /// Pre-increment iterator.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100112 CtorDtorIterator& operator++();
113
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100114 /// Post-increment iterator.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100115 CtorDtorIterator operator++(int);
116
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100117 /// Dereference iterator. The resulting value provides a read-only view
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100118 /// of this element of the global_ctors/global_dtors list.
119 Element operator*() const;
120
121private:
122 const ConstantArray *InitList;
123 unsigned I;
124};
125
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100126/// Create an iterator range over the entries of the llvm.global_ctors
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100127/// array.
128iterator_range<CtorDtorIterator> getConstructors(const Module &M);
129
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100130/// Create an iterator range over the entries of the llvm.global_ctors
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100131/// array.
132iterator_range<CtorDtorIterator> getDestructors(const Module &M);
133
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100134/// Convenience class for recording constructor/destructor names for
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100135/// later execution.
136template <typename JITLayerT>
137class CtorDtorRunner {
138public:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100139 /// Construct a CtorDtorRunner for the given range using the given
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100140 /// name mangling function.
141 CtorDtorRunner(std::vector<std::string> CtorDtorNames, VModuleKey K)
142 : CtorDtorNames(std::move(CtorDtorNames)), K(K) {}
143
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100144 /// Run the recorded constructors/destructors through the given JIT
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100145 /// 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
167private:
168 std::vector<std::string> CtorDtorNames;
169 orc::VModuleKey K;
170};
171
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100172class CtorDtorRunner2 {
173public:
174 CtorDtorRunner2(VSO &V) : V(V) {}
175 void add(iterator_range<CtorDtorIterator> CtorDtors);
176 Error run();
177
178private:
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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100187/// 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.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100201class LocalCXXRuntimeOverridesBase {
202public:
203 /// Run any destructors recorded by the overriden __cxa_atexit function
204 /// (CXAAtExitOverride).
205 void runDestructors();
206
207protected:
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
220class LocalCXXRuntimeOverrides : public LocalCXXRuntimeOverridesBase {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100221public:
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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100237private:
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100238 void addOverride(const std::string &Name, JITTargetAddress Addr) {
239 CXXRuntimeOverrides.insert(std::make_pair(Name, Addr));
240 }
241
242 StringMap<JITTargetAddress> CXXRuntimeOverrides;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100243};
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100244
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100245class LocalCXXRuntimeOverrides2 : public LocalCXXRuntimeOverridesBase {
246public:
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.
255class DynamicLibraryFallbackGenerator {
256public:
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
262private:
263 sys::DynamicLibrary Dylib;
264 SymbolPredicate Allow;
265 char GlobalPrefix;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100266};
267
268} // end namespace orc
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100269} // end namespace llvm
270
271#endif // LLVM_EXECUTIONENGINE_ORC_EXECUTIONUTILS_H