-
Notifications
You must be signed in to change notification settings - Fork 314
Expand file tree
/
Copy pathIncrementalExecutor.h
More file actions
290 lines (244 loc) · 10.2 KB
/
Copy pathIncrementalExecutor.h
File metadata and controls
290 lines (244 loc) · 10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#ifndef CLING_INCREMENTAL_EXECUTOR_H
#define CLING_INCREMENTAL_EXECUTOR_H
#include "IncrementalJIT.h"
#include "BackendPasses.h"
#include "cling/Interpreter/Transaction.h"
#include "cling/Interpreter/Value.h"
#include "cling/Utils/Casting.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringRef.h"
#include <vector>
#include <set>
#include <map>
#include <memory>
#include <atomic>
namespace clang {
class DiagnosticsEngine;
class CodeGenOptions;
class CompilerInstance;
}
namespace llvm {
class GlobalValue;
class Module;
class TargetMachine;
}
namespace cling {
class IncrementalJIT;
class Value;
class IncrementalExecutor {
public:
typedef void* (*LazyFunctionCreatorFunc_t)(const std::string&);
private:
///\brief Our JIT interface.
///
std::unique_ptr<IncrementalJIT> m_JIT;
// optimizer etc passes
std::unique_ptr<BackendPasses> m_BackendPasses;
///\brier A pointer to the IncrementalExecutor of the parent Interpreter.
///
IncrementalExecutor* m_externalIncrementalExecutor;
///\brief Helper that manages when the destructor of an object to be called.
///
/// The object is registered first as an CXAAtExitElement and then cling
/// takes the control of it's destruction.
///
struct CXAAtExitElement {
///\brief Constructs an element, whose destruction time will be managed by
/// the interpreter. (By registering a function to be called by exit
/// or when a shared library is unloaded.)
///
/// Registers destructors for objects with static storage duration with
/// the _cxa atexit function rather than the atexit function. This option
/// is required for fully standards-compliant handling of static
/// destructors(many of them created by cling), but will only work if
/// your C library supports __cxa_atexit (means we have our own work
/// around for Windows). More information about __cxa_atexit could be
/// found in the Itanium C++ ABI spec.
///
///\param [in] func - The function to be called on exit or unloading of
/// shared lib.(The destructor of the object.)
///\param [in] arg - The argument the func to be called with.
///\param [in] fromT - The unloading of this transaction will trigger the
/// atexit function.
///
CXAAtExitElement(void (*func) (void*), void* arg,
const llvm::Module* fromM):
m_Func(func), m_Arg(arg), m_FromM(fromM) {}
///\brief The function to be called.
///
void (*m_Func)(void*);
///\brief The single argument passed to the function.
///
void* m_Arg;
///\brief The module whose unloading will trigger the call to this atexit
/// function.
///
const llvm::Module* m_FromM;
};
///\brief Atomic used as a spin lock to protect the access to m_AtExitFuncs
///
/// AddAtExitFunc is used at the end of the 'interpreted' user code
/// and before the calling framework has any change of taking back/again
/// its lock protecting the access to cling, so we need to explicit protect
/// again multiple conccurent access.
std::atomic_flag m_AtExitFuncsSpinLock; // MSVC doesn't support = ATOMIC_FLAG_INIT;
typedef llvm::SmallVector<CXAAtExitElement, 128> AtExitFunctions;
///\brief Static object, which are bound to unloading of certain declaration
/// to be destructed.
///
AtExitFunctions m_AtExitFuncs;
///\brief Modules to emit upon the next call to the JIT.
///
std::vector<llvm::Module*> m_ModulesToJIT;
///\brief Lazy function creator, which is a final callback which the
/// JIT fires if there is unresolved symbol.
///
std::vector<LazyFunctionCreatorFunc_t> m_lazyFuncCreator;
///\brief Set of the symbols that the JIT couldn't resolve.
///
std::set<std::string> m_unresolvedSymbols;
#if 0 // See FIXME in IncrementalExecutor.cpp
///\brief The diagnostics engine, printing out issues coming from the
/// incremental executor.
clang::DiagnosticsEngine& m_Diags;
#endif
public:
enum ExecutionResult {
kExeSuccess,
kExeFunctionNotCompiled,
kExeUnresolvedSymbols,
kNumExeResults
};
IncrementalExecutor(clang::DiagnosticsEngine& diags,
const clang::CompilerInstance& CI);
~IncrementalExecutor();
void setExternalIncrementalExecutor(IncrementalExecutor *extIncrExec) {
m_externalIncrementalExecutor = extIncrExec;
}
void installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp);
///\brief Send all collected modules to the JIT, making their symbols
/// available to jitting (but not necessarily jitting them all).
Transaction::ExeUnloadHandle emitToJIT() {
size_t handle = m_JIT->addModules(std::move(m_ModulesToJIT));
m_ModulesToJIT.clear();
//m_JIT->finalizeMemory();
return Transaction::ExeUnloadHandle{(void*)handle};
}
///\brief Unload a set of JIT symbols.
bool unloadFromJIT(llvm::Module* M, Transaction::ExeUnloadHandle H) {
auto iMod = std::find(m_ModulesToJIT.begin(), m_ModulesToJIT.end(), M);
if (iMod != m_ModulesToJIT.end())
m_ModulesToJIT.erase(iMod);
else
m_JIT->removeModules((size_t)H.m_Opaque);
return true;
}
///\brief Run the static initializers of all modules collected to far.
ExecutionResult runStaticInitializersOnce(const Transaction& T);
///\brief Runs all destructors bound to the given transaction and removes
/// them from the list.
///\param[in] T - Transaction to which the dtors were bound.
///
void runAndRemoveStaticDestructors(Transaction* T);
///\brief Runs a wrapper function.
ExecutionResult executeWrapper(llvm::StringRef function,
Value* returnValue = 0) {
// Set the value to cling::invalid.
if (returnValue) {
*returnValue = Value();
}
typedef void (*InitFun_t)(void*);
InitFun_t fun;
ExecutionResult res = executeInitOrWrapper(function, fun);
if (res != kExeSuccess)
return res;
(*fun)(returnValue);
return kExeSuccess;
}
///\brief Adds a symbol (function) to the execution engine.
///
/// Allows runtime declaration of a function passing its pointer for being
/// used by JIT generated code.
///
/// @param[in] Name - The name of the symbol as required by the
/// linker (mangled if needed)
/// @param[in] Address - The function pointer to register
/// @param[in] JIT - Add to the JIT injected symbol table
/// @returns true if the symbol is successfully registered, false otherwise.
///
bool addSymbol(llvm::StringRef Name, void* Address, bool JIT = false);
///\brief Add a llvm::Module to the JIT.
///
/// @param[in] module - The module to pass to the execution engine.
/// @param[in] optLevel - The optimization level to be used.
void addModule(llvm::Module* module, int optLevel) {
if (m_BackendPasses)
m_BackendPasses->runOnModule(*module, optLevel);
m_ModulesToJIT.push_back(module);
}
///\brief Tells the execution context that we are shutting down the system.
///
/// This that notification is needed because the execution context needs to
/// perform extra actions like delete all managed by it symbols, which might
/// still require alive system.
///
void shuttingDown();
///\brief Gets the address of an existing global and whether it was JITted.
///
/// JIT symbols might not be immediately convertible to e.g. a function
/// pointer as their call setup is different.
///
///\param[in] mangledName - the globa's name
///\param[out] fromJIT - whether the symbol was JITted.
///
void* getAddressOfGlobal(llvm::StringRef mangledName, bool* fromJIT = 0);
///\brief Return the address of a global from the JIT (as
/// opposed to dynamic libraries). Forces the emission of the symbol if
/// it has not happened yet.
///
///param[in] GV - global value for which the address will be returned.
void* getPointerToGlobalFromJIT(const llvm::GlobalValue& GV);
///\brief Keep track of the entities whose dtor we need to call.
///
void AddAtExitFunc(void (*func) (void*), void* arg, llvm::Module* M);
///\brief Try to resolve a symbol through our LazyFunctionCreators;
/// print an error message if that fails.
void* NotifyLazyFunctionCreators(const std::string&);
private:
///\brief Report and empty m_unresolvedSymbols.
///\return true if m_unresolvedSymbols was non-empty.
bool diagnoseUnresolvedSymbols(llvm::StringRef trigger,
llvm::StringRef title = llvm::StringRef());
///\brief Remember that the symbol could not be resolved by the JIT.
void* HandleMissingFunction(const std::string& symbol);
///\brief Runs an initializer function.
ExecutionResult executeInit(llvm::StringRef function) {
typedef void (*InitFun_t)();
InitFun_t fun;
ExecutionResult res = executeInitOrWrapper(function, fun);
if (res != kExeSuccess)
return res;
(*fun)();
return kExeSuccess;
}
template <class T>
ExecutionResult executeInitOrWrapper(llvm::StringRef funcname, T& fun) {
fun = utils::UIntToFunctionPtr<T>(m_JIT->getSymbolAddress(funcname,
false /*dlsym*/));
// check if there is any unresolved symbol in the list
if (diagnoseUnresolvedSymbols(funcname, "function") || !fun)
return IncrementalExecutor::kExeUnresolvedSymbols;
return IncrementalExecutor::kExeSuccess;
}
};
} // end cling
#endif // CLING_INCREMENTAL_EXECUTOR_H