Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
numba
GitHub Repository: numba/llvmlite
Path: blob/main/ffi/orcjit.cpp
1154 views
1
#include "core.h"
2
#include "llvm-c/LLJIT.h"
3
#include "llvm-c/Orc.h"
4
#include <sstream>
5
6
#include "llvm/AsmParser/Parser.h"
7
#include "llvm/ExecutionEngine/Orc/Core.h"
8
#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupportPlugin.h"
9
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
10
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
11
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
12
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
13
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
14
#include "llvm/IRReader/IRReader.h"
15
#include "llvm/Support/MemoryBuffer.h"
16
#include "llvm/Support/SourceMgr.h"
17
18
using namespace llvm;
19
using namespace llvm::orc;
20
21
inline LLJIT *unwrap(LLVMOrcLLJITRef P) { return reinterpret_cast<LLJIT *>(P); }
22
23
inline TargetMachine *unwrap(LLVMTargetMachineRef TM) {
24
return reinterpret_cast<TargetMachine *>(TM);
25
}
26
27
inline LLVMOrcJITTargetMachineBuilderRef wrap(JITTargetMachineBuilder *JTMB) {
28
return reinterpret_cast<LLVMOrcJITTargetMachineBuilderRef>(JTMB);
29
}
30
31
static void destroyError(Error e) {
32
/* LLVM's Error type will abort if you don't read it. */
33
LLVMDisposeErrorMessage(LLVMGetErrorMessage(wrap(std::move(e))));
34
}
35
36
class JITDylibTracker {
37
public:
38
std::shared_ptr<LLJIT> lljit;
39
JITDylib &dylib;
40
IntrusiveRefCntPtr<llvm::orc::ResourceTracker> tracker;
41
JITDylibTracker(std::shared_ptr<LLJIT> &lljit_, JITDylib &dylib_,
42
IntrusiveRefCntPtr<llvm::orc::ResourceTracker> &&tracker_)
43
: lljit(lljit_), dylib(dylib_), tracker(tracker_) {}
44
};
45
46
typedef struct {
47
uint8_t element_kind;
48
char *value;
49
size_t value_len;
50
} LinkElement;
51
typedef struct {
52
char *name;
53
uint64_t address;
54
} SymbolAddress;
55
extern "C" {
56
57
API_EXPORT(std::shared_ptr<LLJIT> *)
58
LLVMPY_CreateLLJITCompiler(LLVMTargetMachineRef tm, bool suppressErrors,
59
bool useJitLink, const char **OutError) {
60
LLJITBuilder builder;
61
#ifdef _WIN32
62
if (useJitLink) {
63
*OutError = LLVMPY_CreateString(
64
"JITLink is not currently available on Windows");
65
return nullptr;
66
}
67
#endif
68
if (tm) {
69
// The following is based on
70
// LLVMOrcJITTargetMachineBuilderCreateFromTargetMachine. However,
71
// we can't use that directly because it destroys the target
72
// machine, but we need to keep it alive because it is referenced by
73
// / shared with other objects on the Python side.
74
auto *template_tm = unwrap(tm);
75
76
builder.setJITTargetMachineBuilder(
77
JITTargetMachineBuilder(template_tm->getTargetTriple())
78
.setCPU(template_tm->getTargetCPU().str())
79
.setRelocationModel(template_tm->getRelocationModel())
80
.setCodeModel(template_tm->getCodeModel())
81
.setCodeGenOptLevel(template_tm->getOptLevel())
82
.setFeatures(template_tm->getTargetFeatureString())
83
.setOptions(template_tm->Options));
84
}
85
builder.setObjectLinkingLayerCreator(
86
[=](llvm::orc::ExecutionSession &session, const llvm::Triple &triple)
87
-> std::unique_ptr<llvm::orc::ObjectLayer> {
88
if (useJitLink) {
89
auto linkingLayer =
90
std::make_unique<llvm::orc::ObjectLinkingLayer>(session);
91
92
/* FIXME(LLVM16): In newer LLVM versions, there is a simple
93
* EnableDebugSupport flag on the builder and we don't need to
94
* do any of this. */
95
// if (triple.getObjectFormat() == Triple::ELF ||
96
// triple.getObjectFormat() == Triple::MachO) {
97
// linkingLayer->addPlugin(
98
// std::make_unique<orc::GDBJITDebugInfoRegistrationPlugin>(
99
// ExecutorAddr::fromPtr(
100
// &llvm_orc_registerJITLoaderGDBWrapper)));
101
// }
102
if (triple.isOSBinFormatCOFF()) {
103
linkingLayer->setOverrideObjectFlagsWithResponsibilityFlags(
104
true);
105
linkingLayer->setAutoClaimResponsibilityForObjectSymbols(
106
true);
107
}
108
return linkingLayer;
109
} else {
110
auto linkingLayer = std::make_unique<
111
llvm::orc::RTDyldObjectLinkingLayer>(session, []() {
112
return std::make_unique<llvm::SectionMemoryManager>();
113
});
114
if (triple.isOSBinFormatCOFF()) {
115
linkingLayer->setOverrideObjectFlagsWithResponsibilityFlags(
116
true);
117
linkingLayer->setAutoClaimResponsibilityForObjectSymbols(
118
true);
119
}
120
linkingLayer->registerJITEventListener(
121
*llvm::JITEventListener::createGDBRegistrationListener());
122
123
return linkingLayer;
124
}
125
});
126
127
auto jit = builder.create();
128
129
if (!jit) {
130
char *message = LLVMGetErrorMessage(wrap(jit.takeError()));
131
*OutError = LLVMPY_CreateString(message);
132
LLVMDisposeErrorMessage(message);
133
return nullptr;
134
}
135
if (suppressErrors) {
136
(*jit)->getExecutionSession().setErrorReporter(destroyError);
137
}
138
return new std::shared_ptr<LLJIT>(std::move(*jit));
139
}
140
141
API_EXPORT(JITDylibTracker *)
142
LLVMPY_LLJITLookup(std::shared_ptr<LLJIT> *lljit, const char *dylib_name,
143
const char *name, uint64_t *addr, const char **OutError) {
144
145
auto dylib = (*lljit)->getJITDylibByName(dylib_name);
146
if (!dylib) {
147
*OutError = LLVMPY_CreateString("No such library");
148
return nullptr;
149
}
150
151
auto sym = (*lljit)->lookup(*dylib, name);
152
if (!sym) {
153
char *message = LLVMGetErrorMessage(wrap(sym.takeError()));
154
*OutError = LLVMPY_CreateString(message);
155
LLVMDisposeErrorMessage(message);
156
return nullptr;
157
}
158
159
*addr = sym->getValue();
160
return new JITDylibTracker(*lljit, *dylib,
161
std::move(dylib->createResourceTracker()));
162
}
163
164
API_EXPORT(LLVMTargetDataRef)
165
LLVMPY_LLJITGetDataLayout(std::shared_ptr<LLJIT> *lljit) {
166
return wrap(&(*lljit)->getDataLayout());
167
}
168
169
API_EXPORT(void)
170
LLVMPY_LLJITDispose(std::shared_ptr<LLJIT> *lljit) { delete lljit; }
171
172
API_EXPORT(JITDylibTracker *)
173
LLVMPY_LLJIT_Link(std::shared_ptr<LLJIT> *lljit, const char *libraryName,
174
LinkElement *elements, size_t elements_length,
175
SymbolAddress *imports, size_t imports_length,
176
SymbolAddress *exports, size_t exports_length,
177
const char **OutError) {
178
if ((*lljit)->getJITDylibByName(libraryName) != nullptr) {
179
std::stringstream err;
180
err << "Library name `" << libraryName << "' is already in use.";
181
*OutError = LLVMPY_CreateString(err.str().c_str());
182
return nullptr;
183
}
184
auto dylib = (*lljit)->createJITDylib(libraryName);
185
186
if (!dylib) {
187
char *message = LLVMGetErrorMessage(wrap(std::move(dylib.takeError())));
188
*OutError = LLVMPY_CreateString(message);
189
LLVMDisposeErrorMessage(message);
190
return nullptr;
191
}
192
193
for (size_t import_idx = 0; import_idx < imports_length; import_idx++) {
194
SymbolStringPtr mangled =
195
(*lljit)->mangleAndIntern(imports[import_idx].name);
196
ExecutorSymbolDef symbol(ExecutorAddr(imports[import_idx].address),
197
JITSymbolFlags::Exported);
198
199
auto error = dylib->define(absoluteSymbols({{mangled, symbol}}));
200
201
if (error) {
202
char *message = LLVMGetErrorMessage(wrap(std::move(error)));
203
*OutError = LLVMPY_CreateString(message);
204
LLVMDisposeErrorMessage(message);
205
return nullptr;
206
}
207
}
208
209
for (size_t element_idx = 0; element_idx < elements_length; element_idx++) {
210
switch (elements[element_idx].element_kind) {
211
case 0: // Adding IR
212
{
213
auto ctxt = std::make_unique<LLVMContext>();
214
SMDiagnostic error;
215
auto module =
216
parseIR(*MemoryBuffer::getMemBuffer(
217
StringRef(elements[element_idx].value,
218
elements[element_idx].value_len),
219
"ir", false),
220
error, *ctxt);
221
if (!module) {
222
std::string osbuf;
223
raw_string_ostream os(osbuf);
224
error.print("", os);
225
os.flush();
226
*OutError = LLVMPY_CreateString(os.str().c_str());
227
return nullptr;
228
}
229
auto addError = (*lljit)->addIRModule(
230
*dylib, ThreadSafeModule(std::move(module), std::move(ctxt)));
231
if (addError) {
232
char *message = LLVMGetErrorMessage(wrap(std::move(addError)));
233
*OutError = LLVMPY_CreateString(message);
234
LLVMDisposeErrorMessage(message);
235
return nullptr;
236
}
237
}; break;
238
case 1: // Adding native assembly
239
{
240
auto ctxt = std::make_unique<LLVMContext>();
241
SMDiagnostic error;
242
auto module =
243
parseAssembly(*MemoryBuffer::getMemBuffer(
244
StringRef(elements[element_idx].value,
245
elements[element_idx].value_len),
246
"asm", false),
247
error,
248
249
*ctxt);
250
if (!module) {
251
std::string osbuf;
252
raw_string_ostream os(osbuf);
253
error.print("", os);
254
os.flush();
255
*OutError = LLVMPY_CreateString(os.str().c_str());
256
return nullptr;
257
}
258
auto addError = (*lljit)->addIRModule(
259
*dylib, ThreadSafeModule(std::move(module), std::move(ctxt)));
260
if (addError) {
261
char *message = LLVMGetErrorMessage(wrap(std::move(addError)));
262
*OutError = LLVMPY_CreateString(message);
263
LLVMDisposeErrorMessage(message);
264
return nullptr;
265
}
266
}; break;
267
case 2: // Adding object code
268
{
269
auto addError = (*lljit)->addObjectFile(
270
*dylib, MemoryBuffer::getMemBufferCopy(
271
StringRef(elements[element_idx].value,
272
elements[element_idx].value_len)));
273
if (addError) {
274
char *message = LLVMGetErrorMessage(wrap(std::move(addError)));
275
*OutError = LLVMPY_CreateString(message);
276
LLVMDisposeErrorMessage(message);
277
return nullptr;
278
}
279
}; break;
280
case 3: // Adding existing library
281
// Take an empty name to be the current process
282
if (elements[element_idx].value_len) {
283
auto other = (*lljit)->getJITDylibByName(
284
StringRef(elements[element_idx].value,
285
elements[element_idx].value_len));
286
if (!other) {
287
std::string osbuf;
288
raw_string_ostream os(osbuf);
289
os << "Failed to find library `"
290
<< StringRef(elements[element_idx].value,
291
elements[element_idx].value_len)
292
<< "'.";
293
os.flush();
294
*OutError = LLVMPY_CreateString(osbuf.c_str());
295
return nullptr;
296
}
297
dylib->addToLinkOrder(*other);
298
} else {
299
auto prefix = (*lljit)->getDataLayout().getGlobalPrefix();
300
auto DLSGOrErr =
301
DynamicLibrarySearchGenerator::GetForCurrentProcess(prefix);
302
if (DLSGOrErr) {
303
dylib->addGenerator(std::move(*DLSGOrErr));
304
} else {
305
char *message =
306
LLVMGetErrorMessage(wrap(DLSGOrErr.takeError()));
307
*OutError = LLVMPY_CreateString(message);
308
LLVMDisposeErrorMessage(message);
309
return nullptr;
310
}
311
}
312
break;
313
314
default:
315
*OutError = LLVMPY_CreateString("Unknown element type");
316
return nullptr;
317
}
318
}
319
auto initError = (*lljit)->initialize(*dylib);
320
if (initError) {
321
char *message = LLVMGetErrorMessage(wrap(std::move(initError)));
322
*OutError = LLVMPY_CreateString(message);
323
LLVMDisposeErrorMessage(message);
324
325
return nullptr;
326
}
327
for (size_t export_idx = 0; export_idx < exports_length; export_idx++) {
328
auto lookup = (*lljit)->lookup(*dylib, exports[export_idx].name);
329
if (!lookup) {
330
char *message =
331
LLVMGetErrorMessage(wrap(std::move(lookup.takeError())));
332
*OutError = LLVMPY_CreateString(message);
333
LLVMDisposeErrorMessage(message);
334
return nullptr;
335
}
336
exports[export_idx].address = lookup->getValue();
337
}
338
return new JITDylibTracker(*lljit, *dylib,
339
std::move(dylib->getDefaultResourceTracker()));
340
}
341
342
API_EXPORT(bool)
343
LLVMPY_LLJIT_Dylib_Tracker_Dispose(JITDylibTracker *tracker,
344
const char **OutError) {
345
*OutError = nullptr;
346
auto result = false;
347
/* This is undoubtedly a really bad and fragile check. LLVM creates a bunch
348
* of platform support to know if there's deinitializers to run. If we try
349
* to run them when they aren't present, a bunch of junk will be printed to
350
* stderr. So, we're rummaging around for an internal symbol in its platform
351
* support library and skipping the deinitialization if we don't find. */
352
auto lookup = tracker->lljit->lookup(tracker->dylib,
353
"__lljit.platform_support_instance");
354
if (lookup) {
355
auto error = tracker->lljit->deinitialize(tracker->dylib);
356
if (error) {
357
char *message = LLVMGetErrorMessage(wrap(std::move(error)));
358
*OutError = LLVMPY_CreateString(message);
359
LLVMDisposeErrorMessage(message);
360
result = true;
361
}
362
} else {
363
destroyError(std::move(lookup.takeError()));
364
}
365
auto error = tracker->dylib.clear();
366
if (error && !result) {
367
char *message = LLVMGetErrorMessage(wrap(std::move(error)));
368
*OutError = LLVMPY_CreateString(message);
369
LLVMDisposeErrorMessage(message);
370
result = true;
371
}
372
delete tracker;
373
374
return result;
375
}
376
377
} // extern "C"
378
379