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