1/**
2 * Copyright (c) Glow Contributors. See CONTRIBUTORS file.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "glow/LLVMIRCodeGen/CommandLine.h"
18
19#include "glow/LLVMIRCodeGen/GlowJIT.h"
20#include "glow/Support/Debug.h"
21
22#include "llvm/ExecutionEngine/JITEventListener.h"
23#include "llvm/Object/SymbolSize.h"
24
25#define DEBUG_TYPE "jit-engine"
26
27namespace {
28/// An option to enabling the dump of the symbol information for the JITted
29/// functions. It dumps e.g. the names of the functions, their start addresses
30/// and their end addresses.
31static llvm::cl::opt<bool> dumpJITSymbolInfo(
32 "dump-jit-symbol-info",
33 llvm::cl::desc("Dump the load addresses and sizes of JITted symbols"),
34 llvm::cl::init(false), llvm::cl::cat(getLLVMBackendCat()));
35
36/// This is a callback that is invoked when an LLVM module is compiled and
37/// loaded by the JIT for execution.
38class NotifyLoadedFunctorBase {
39protected:
40 /// The listener for debugger events. It is used to provide debuggers with the
41 /// information about JITted code.
42 llvm::JITEventListener *dbgRegistrationListener_;
43 /// Dump symbol information for symbols defined by the object file.
44 void dumpSymbolInfo(const llvm::object::ObjectFile &loadedObj,
45 const llvm::RuntimeDyld::LoadedObjectInfo &objInfo) {
46 if (!dumpJITSymbolInfo)
47 return;
48 // Dump information about symbols.
49 for (auto symSizePair : llvm::object::computeSymbolSizes(loadedObj)) {
50 auto sym = symSizePair.first;
51 auto size = symSizePair.second;
52 auto symName = sym.getName();
53 // Skip any unnamed symbols.
54 if (!symName || symName->empty())
55 continue;
56 // The relative address of the symbol inside its section.
57 auto symAddr = sym.getAddress();
58 if (!symAddr)
59 continue;
60 // The address the functions was loaded at.
61 auto loadedSymAddress = *symAddr;
62 auto symbolSection = sym.getSection();
63 if (symbolSection) {
64 // Compute the load address of the symbol by adding the section load
65 // address.
66 loadedSymAddress += objInfo.getSectionLoadAddress(*symbolSection.get());
67 }
68 llvm::outs() << llvm::format("Address range: [%12p, %12p]",
69 loadedSymAddress, loadedSymAddress + size)
70 << "\tSymbol: " << *symName << "\n";
71 }
72 }
73
74 NotifyLoadedFunctorBase()
75 : dbgRegistrationListener_(
76 llvm::JITEventListener::createGDBRegistrationListener()) {}
77};
78
79} // namespace
80
81//##############################################################################
82#if GLOW_JIT_ORC_VERSION == 1
83//##############################################################################
84using GlowJIT = llvm::orc::GlowJIT;
85
86class NotifyLoadedFunctor : public NotifyLoadedFunctorBase {
87public:
88 void operator()(llvm::orc::VModuleKey key,
89 const llvm::object::ObjectFile &obj,
90 const llvm::RuntimeDyld::LoadedObjectInfo &objInfo) {
91 auto &loadedObj = obj;
92 // Inform the debugger about the loaded object file. This should allow for
93 // more complete stack traces under debugger. And even it should even enable
94 // the stepping functionality on platforms supporting it.
95#if LLVM_VERSION_MAJOR == 7 || LLVM_VERSION_MAJOR == 10 || \
96 (LLVM_VERSION_MAJOR <= 8 && FACEBOOK_INTERNAL)
97 // This fails sometimes with the following assertion:
98 // lib/ExecutionEngine/GDBRegistrationListener.cpp:168: virtual void
99 // {anonymous}::GDBJITRegistrationListener::NotifyObjectEmitted(const
100 // llvm::object::ObjectFile&, const llvm::RuntimeDyld::LoadedObjectInfo&):
101 // Assertion `ObjectBufferMap.find(Key) == ObjectBufferMap.end() && "Second
102 // attempt to perform debug registration."' failed.
103 // dbgRegistrationListener_->NotifyObjectEmitted(loadedObj, objInfo);
104#else
105 dbgRegistrationListener_->notifyObjectLoaded(
106 (llvm::JITEventListener::ObjectKey)&loadedObj, loadedObj, objInfo);
107#endif
108
109 // Dump symbol information for the JITed symbols.
110 dumpSymbolInfo(loadedObj, objInfo);
111 }
112};
113
114//==============================================================================
115#if LLVM_VERSION_MAJOR < 8 && FACEBOOK_INTERNAL
116//==============================================================================
117llvm::JITSymbol GlowJIT::resolveSymbol(const std::string &name) {
118 // Search for symbols which may not be exported. On PE/COFF targets
119 // (i.e. Windows), not all symbols are implicitly exported. If the
120 // symbols is not marked as DLLExport, it is not considered
121 // exported, and the symbol lookup may fail. This may also occur on
122 // ELF/MachO targets if built with hidden visibility. The JIT
123 // however maintains a list of all symbols and can find unexported
124 // symbols as well.
125 if (auto Sym = compileLayer_.findSymbol(Name, /*ExportedSymbolsOnly=*/false))
126 return Sym;
127 else if (auto Err = Sym.takeError())
128 return std::move(Err);
129 if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name))
130 return JITSymbol(SymAddr, JITSymbolFlags::Exported);
131 return nullptr;
132}
133
134template <typename LegacyLookupFn>
135static std::shared_ptr<llvm::orc::LegacyLookupFnResolver<LegacyLookupFn>>
136createLookupResolver(llvm::orc::ExecutionSession &, LegacyLookupFn LegacyLookup,
137 std::function<void(llvm::Error)> ErrorReporter) {
138 return createLegacyLookupResolver(std::move(LegacyLookup),
139 std::move(ErrorReporter));
140}
141
142//==============================================================================
143#elif LLVM_VERSION_MAJOR < 8
144//==============================================================================
145llvm::JITSymbol GlowJIT::resolveSymbol(const std::string &name) {
146 if (auto localSym = compileLayer_.findSymbol(name, false)) {
147 return localSym;
148 } else if (auto Err = localSym.takeError()) {
149 return std::move(Err);
150 }
151 // Some symbols are overridden, in particular __dso_handle and
152 // __cxa_atexit .
153 if (auto overriddenSym = cxxSymbolOverride_.searchOverrides(name)) {
154 return overriddenSym;
155 }
156 // FIXME: looking for symbols external to libjit in the process is
157 // dangerous because it can be environment dependent. For example,
158 // we get cases where a symbol is found in the Linux environment,
159 // but not in the Windows environment.
160 if (auto processSymAddr =
161 RTDyldMemoryManager::getSymbolAddressInProcess(name)) {
162 return JITSymbol(processSymAddr, JITSymbolFlags::Exported);
163 }
164 // The symbol was not resolved. This will make the retreival of
165 // 'main' function symbol fail later without much information about
166 // the source of the problem. Then, we dump an error message now to
167 // ease debugging.
168 DEBUG_GLOW(llvm::dbgs() << "JIT: Error resolving symbol '" << name << "'\n");
169 // Return a 'symbol not found' JITSymbol object (nullptr).
170 return nullptr;
171}
172
173template <typename LegacyLookupFn>
174static std::shared_ptr<llvm::orc::LegacyLookupFnResolver<LegacyLookupFn>>
175createLookupResolver(llvm::orc::ExecutionSession &ES,
176 LegacyLookupFn LegacyLookup,
177 std::function<void(llvm::Error)> ErrorReporter) {
178 return createLegacyLookupResolver(ES, std::move(LegacyLookup),
179 std::move(ErrorReporter));
180}
181
182//==============================================================================
183#else // 8 <= LLVM_VERSION_MAJOR
184//==============================================================================
185static bool symbolFound(llvm::JITSymbol &s) {
186 const llvm::JITSymbolFlags flags = s.getFlags();
187 if (flags.getRawFlagsValue() || flags.getTargetFlags()) {
188 return true;
189 }
190
191 llvm::Expected<llvm::JITTargetAddress> expAddr = s.getAddress();
192 if (!expAddr) {
193 return false; // should never get here since no flags are set
194 }
195
196 return expAddr.get() != 0;
197}
198
199llvm::JITSymbol GlowJIT::resolveSymbol(const std::string &name) {
200
201 // Search accross all modules for a strong symbol. If no strong symbol is
202 // found, return the first matching weak symbol found if any.
203 bool weakFound = false;
204 JITSymbol firstWeak(nullptr);
205 for (auto k : vModKeys_) {
206 JITSymbol localSym = compileLayer_.findSymbolIn(k, name, false);
207 if (auto Err = localSym.takeError()) {
208 return std::move(Err);
209 }
210
211 if (!symbolFound(localSym)) {
212 continue;
213 }
214
215 JITSymbolFlags flags = localSym.getFlags();
216 if (flags.isStrong()) {
217 return localSym;
218 }
219
220 // This is a matching weak or common symbol. Remember the first one we find
221 // in case we don't find a subsequent strong one.
222 if (!weakFound) {
223 firstWeak = std::move(localSym);
224 weakFound = true;
225 }
226 }
227
228#if !FACEBOOK_INTERNAL
229 // Some symbols are overridden, in particular __dso_handle and
230 // __cxa_atexit .
231 if (auto overriddenSym = cxxSymbolOverride_.searchOverrides(name)) {
232 return overriddenSym;
233 }
234#endif
235 // FIXME: looking for symbols external to libjit in the process is
236 // dangerous because it can be environment dependent. For example,
237 // we get cases where a symbol is found in the Linux environment,
238 // but not in the Windows environment.
239 if (auto processSymAddr =
240 RTDyldMemoryManager::getSymbolAddressInProcess(name)) {
241 return JITSymbol(processSymAddr, JITSymbolFlags::Exported);
242 }
243
244 // No strong symbol found. Return a weak symbol if we found one.
245 if (weakFound) {
246 return firstWeak;
247 }
248
249 // The symbol was not resolved. This will make the retreival of
250 // 'main' function symbol fail later without much information about
251 // the source of the problem. Then, we dump an error message now to
252 // ease debugging.
253 DEBUG_GLOW(llvm::dbgs() << "JIT: Error resolving symbol '" << name << "'\n");
254 // Return a 'symbol not found' JITSymbol object (nullptr).
255 return nullptr;
256}
257
258namespace {
259// In order to work around a bug in the llvm-provided
260// 'getResponsibilitySetWithLegacyFn' involving the handling of weak symbols, we
261// provide our own implementation, called indirectly through this implementation
262// of the 'llvm::orc::SymbolResolver' interface.
263template <typename LegacyLookupFn>
264class LookupFnResolver final : public llvm::orc::SymbolResolver {
265private:
266 using Error = llvm::Error;
267 using ErrorReporter = std::function<void(Error)>;
268 using SymbolNameSet = llvm::orc::SymbolNameSet;
269 using AsynchronousSymbolQuery = llvm::orc::AsynchronousSymbolQuery;
270 using ExecutionSession = llvm::orc::ExecutionSession;
271 using JITSymbol = llvm::JITSymbol;
272 using JITSymbolFlags = llvm::JITSymbolFlags;
273 using JITTargetAddress = llvm::JITTargetAddress;
274
275 ExecutionSession &ES;
276 LegacyLookupFn LegacyLookup;
277 ErrorReporter ReportError;
278
279 llvm::Expected<SymbolNameSet>
280 getResponsibilitySetWithLegacyFn(const SymbolNameSet &Symbols) {
281 SymbolNameSet Result;
282
283 for (auto &S : Symbols) {
284 // Note that we don't use Sym's operator bool() here since that returns
285 // false for symbols with no address (which includes weak symbols).
286 JITSymbol Sym = LegacyLookup(std::string(*S));
287 if (auto Err = Sym.takeError()) {
288 return std::move(Err);
289 }
290 if (!Sym.getFlags().isStrong()) {
291 Result.insert(S);
292 }
293 }
294
295 return Result;
296 }
297
298public:
299 LookupFnResolver(ExecutionSession &ES, LegacyLookupFn LegacyLookup,
300 ErrorReporter ReportError)
301 : ES(ES), LegacyLookup(std::move(LegacyLookup)),
302 ReportError(std::move(ReportError)) {}
303
304 SymbolNameSet lookup(std::shared_ptr<AsynchronousSymbolQuery> Query,
305 SymbolNameSet Symbols) final {
306 return llvm::orc::lookupWithLegacyFn(ES, *Query, Symbols, LegacyLookup);
307 }
308
309 SymbolNameSet getResponsibilitySet(const SymbolNameSet &Symbols) final {
310 auto ResponsibilitySet = getResponsibilitySetWithLegacyFn(Symbols);
311
312 if (ResponsibilitySet) {
313 return std::move(*ResponsibilitySet);
314 }
315
316 ReportError(ResponsibilitySet.takeError());
317 return SymbolNameSet();
318 }
319};
320} // namespace
321
322template <typename LegacyLookupFn>
323static std::shared_ptr<LookupFnResolver<LegacyLookupFn>>
324createLookupResolver(llvm::orc::ExecutionSession &ES,
325 LegacyLookupFn LegacyLookup,
326 std::function<void(llvm::Error)> ErrorReporter) {
327 return std::make_shared<LookupFnResolver<LegacyLookupFn>>(
328 ES, std::move(LegacyLookup), std::move(ErrorReporter));
329}
330#endif
331
332GlowJIT::GlowJIT(std::unique_ptr<llvm::TargetMachine> TM)
333 : TM_(std::move(TM)), DL_(TM_->createDataLayout()),
334#if FACEBOOK_INTERNAL && LLVM_VERSION_MAJOR < 8
335 ES_(SSP_),
336 resolver_(createLookupResolver(
337 ES_,
338 [this](const std::string &Name) -> JITSymbol {
339 return this->resolveSymbol(Name);
340 },
341 [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })),
342 objectLayer_(ES_,
343 [this](llvm::orc::VModuleKey) {
344 return RTDyldObjectLinkingLayer::Resources{
345 std::make_shared<SectionMemoryManager>(), resolver_};
346 }),
347#else
348 SSP_(std::make_shared<SymbolStringPool>()), ES_(SSP_),
349#if !FACEBOOK_INTERNAL
350 cxxSymbolOverride_(
351 [this](const std::string &name) { return mangle(name); }),
352#endif
353 resolver_(createLookupResolver(
354 ES_,
355 [this](llvm::StringRef name) -> JITSymbol {
356 return this->resolveSymbol(std::string(name));
357 },
358 [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })),
359#if LLVM_VERSION_MAJOR == 7 || (LLVM_VERSION_MAJOR <= 8 && FACEBOOK_INTERNAL)
360 objectLayer_(
361 ES_,
362 [this](llvm::orc::VModuleKey) {
363 return RTDyldObjectLinkingLayer::Resources{
364 std::make_shared<SectionMemoryManager>(), resolver_};
365 },
366 NotifyLoadedFunctor()),
367#else
368 objectLayer_(
369 ES_,
370 [this](llvm::orc::VModuleKey) {
371 return LegacyRTDyldObjectLinkingLayer::Resources{
372 std::make_shared<SectionMemoryManager>(), resolver_};
373 },
374 NotifyLoadedFunctor()),
375#endif
376#endif
377 compileLayer_(objectLayer_, SimpleCompiler(*TM_)) {
378 // When passing a null pointer to LoadLibraryPermanently, we request to
379 // 'load' the host process itself, making its exported symbols available for
380 // execution.
381 llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
382}
383
384GlowJIT::~GlowJIT() {
385#if !FACEBOOK_INTERNAL
386 // Run any destructor registered with __cxa_atexit.
387 cxxSymbolOverride_.runDestructors();
388#endif
389 // Run any destructor discovered in the LLVM IR of the JIT modules.
390 for (auto &dtorRunner : irStaticDestructorRunners_) {
391 cantFail(dtorRunner.runViaLayer(compileLayer_));
392 }
393}
394
395GlowJIT::ModuleHandle GlowJIT::addModule(std::unique_ptr<llvm::Module> M) {
396 // Add the set to the JIT with the resolver and a newly created
397 // SectionMemoryManager.
398
399 auto K = ES_.allocateVModule();
400
401 // Record the static constructors and destructors. We have to do this before
402 // we hand over ownership of the module to the JIT.
403 // Note: This code is based on the LLI/OrcLazyJIT LLVM tool code that is based
404 // on the ORCv1 API (see
405 // https://github.com/llvm-mirror/llvm/blob/release_60/tools/lli/OrcLazyJIT.cpp)
406 // In recent LLVM versions (7+), LLJIT uses the newer ORCv2 API (see
407 // https://github.com/llvm-mirror/llvm/blob/release_70/lib/ExecutionEngine/Orc/LLJIT.cpp).
408 std::vector<std::string> ctorNames, dtorNames;
409 for (auto ctor : orc::getConstructors(*M))
410 ctorNames.push_back(mangle(ctor.Func->getName().str()));
411 for (auto dtor : orc::getDestructors(*M))
412 dtorNames.push_back(mangle(dtor.Func->getName().str()));
413
414 cantFail(compileLayer_.addModule(K, std::move(M)));
415 vModKeys_.insert(K);
416
417#if LLVM_VERSION_MAJOR == 7 || (LLVM_VERSION_MAJOR <= 8 && FACEBOOK_INTERNAL)
418 CtorDtorRunner<decltype(compileLayer_)> ctorRunner(std::move(ctorNames), K);
419#else
420 LegacyCtorDtorRunner<decltype(compileLayer_)> ctorRunner(std::move(ctorNames),
421 K);
422#endif
423
424 // Run the static constructors and register static destructors.
425 consumeError(ctorRunner.runViaLayer(compileLayer_));
426 irStaticDestructorRunners_.emplace_back(std::move(dtorNames), K);
427
428 return K;
429}
430
431void GlowJIT::removeModule(GlowJIT::ModuleHandle H) {
432 vModKeys_.erase(H);
433 cantFail(compileLayer_.removeModule(H));
434}
435
436std::string GlowJIT::mangle(const std::string &name) {
437 std::string mangledName;
438 raw_string_ostream MangledNameStream(mangledName);
439 Mangler::getNameWithPrefix(MangledNameStream, name, DL_);
440 return MangledNameStream.str();
441}
442
443llvm::JITSymbol GlowJIT::findSymbol(const std::string &name) {
444 return compileLayer_.findSymbol(mangle(name), false);
445}
446
447void GlowJIT::setContext(std::unique_ptr<llvm::LLVMContext> ctx) {
448 ctx_ = std::move(ctx);
449}
450
451//##############################################################################
452#elif GLOW_JIT_ORC_VERSION == 2
453//##############################################################################
454
455namespace glow {
456
457class NotifyLoadedFunctorOrcV2Base : public NotifyLoadedFunctorBase {
458protected:
459 void notify(const llvm::object::ObjectFile &obj,
460 const llvm::RuntimeDyld::LoadedObjectInfo &objInfo) {
461 auto &loadedObj = obj;
462 // Inform the debugger about the loaded object file. This should allow for
463 // more complete stack traces under debugger. And even it should even enable
464 // the stepping functionality on platforms supporting it.
465 dbgRegistrationListener_->notifyObjectLoaded(
466 (llvm::JITEventListener::ObjectKey)&loadedObj, loadedObj, objInfo);
467
468 // Dump symbol information for the JITed symbols.
469 dumpSymbolInfo(loadedObj, objInfo);
470 }
471};
472
473//******************************************************************************
474#if LLVM_VERSION_MAJOR >= 12
475//******************************************************************************
476class NotifyLoadedFunctor : public NotifyLoadedFunctorOrcV2Base {
477public:
478 void operator()(llvm::orc::MaterializationResponsibility &R,
479 const llvm::object::ObjectFile &obj,
480 const llvm::RuntimeDyld::LoadedObjectInfo &objInfo) {
481 notify(obj, objInfo);
482 }
483};
484
485class GlowJITDefGenerator : public llvm::orc::DefinitionGenerator {
486 GlowJIT *gj_;
487
488public:
489 GlowJITDefGenerator(GlowJIT *gj) : gj_(gj) {}
490 virtual ~GlowJITDefGenerator() {}
491
492 llvm::Error
493 tryToGenerate(llvm::orc::LookupState &ls, llvm::orc::LookupKind k,
494 llvm::orc::JITDylib &jd,
495 llvm::orc::JITDylibLookupFlags jdLookupFlags,
496 const llvm::orc::SymbolLookupSet &lookupSet) override {
497 return gj_->tryToGenerate(k, jd, jdLookupFlags, lookupSet);
498 }
499};
500
501void endSession(llvm::orc::ExecutionSession &es) {
502 if (auto err = es.endSession()) {
503 llvm::errs() << "Error ending session: " << err << "\n";
504 }
505}
506
507//==============================================================================
508#else // LLVM_VERSION_MAJOR: 10, 11
509//==============================================================================
510class NotifyLoadedFunctor : public NotifyLoadedFunctorOrcV2Base {
511public:
512 void operator()(llvm::orc::VModuleKey key,
513 const llvm::object::ObjectFile &obj,
514 const llvm::RuntimeDyld::LoadedObjectInfo &objInfo) {
515 notify(obj, objInfo);
516 }
517};
518
519class GlowJITDefGenerator : public llvm::orc::JITDylib::DefinitionGenerator {
520 GlowJIT *gj_;
521
522public:
523 GlowJITDefGenerator(GlowJIT *gj) : gj_(gj) {}
524 virtual ~GlowJITDefGenerator() {}
525
526 llvm::Error
527 tryToGenerate(llvm::orc::LookupKind k, llvm::orc::JITDylib &jd,
528 llvm::orc::JITDylibLookupFlags jdLookupFlags,
529 const llvm::orc::SymbolLookupSet &lookupSet) override {
530 return gj_->tryToGenerate(k, jd, jdLookupFlags, lookupSet);
531 }
532};
533
534void endSession(llvm::orc::ExecutionSession &es) {}
535#endif
536
537//******************************************************************************
538#if LLVM_VERSION_MAJOR >= 11
539//******************************************************************************
540llvm::orc::JITDylib &createJITDylib(llvm::orc::ExecutionSession &es) {
541 return cantFail(es.createJITDylib(std::string("libGlowJIT.dylib")));
542}
543#else // LLVM_VERSION_MAJOR: 10
544llvm::orc::JITDylib &createJITDylib(llvm::orc::ExecutionSession &es) {
545 return es.createJITDylib(std::string("libGlowJIT.dylib"));
546}
547#endif
548
549//******************************************************************************
550// GlowJITOrcV2
551//******************************************************************************
552GlowJITOrcV2::GlowJITOrcV2(std::unique_ptr<llvm::TargetMachine> tm)
553 : tm_(std::move(tm)), dl_(tm_->createDataLayout()),
554 ssp_(std::make_shared<llvm::orc::SymbolStringPool>()), es_(ssp_),
555 jd_(createJITDylib(es_)),
556 objectLayer_(
557 es_, []() { return std::make_unique<llvm::SectionMemoryManager>(); }),
558 compileLayer_(es_, objectLayer_,
559 std::make_unique<llvm::orc::SimpleCompiler>(*tm_)),
560 mangler_(es_, dl_) {
561
562 cantFail(cxxSymbolOverride_.enable(jd_, mangler_));
563 objectLayer_.setNotifyLoaded(NotifyLoadedFunctor());
564 if (tm_->getTargetTriple().isOSBinFormatCOFF()) {
565 objectLayer_.setOverrideObjectFlagsWithResponsibilityFlags(true);
566 objectLayer_.setAutoClaimResponsibilityForObjectSymbols(true);
567 }
568 jd_.addGenerator(std::make_unique<GlowJITDefGenerator>(this));
569
570 // When passing a null pointer to LoadLibraryPermanently, we request to
571 // 'load' the host process itself, making its exported symbols available for
572 // execution.
573 llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
574}
575
576GlowJITOrcV2::~GlowJITOrcV2() {
577 // Run any destructor discovered in the LLVM IR of the JIT modules.
578 for (auto i = irStaticDestructorRunners_.rbegin();
579 i != irStaticDestructorRunners_.rend(); ++i) {
580 cantFail(i->run());
581 }
582
583 // Run any destructor registered with __cxa_atexit.
584 cxxSymbolOverride_.runDestructors();
585
586 endSession(es_);
587}
588
589llvm::Error
590GlowJITOrcV2::tryToGenerate(llvm::orc::LookupKind K, llvm::orc::JITDylib &JD,
591 llvm::orc::JITDylibLookupFlags JDLookupFlags,
592 const llvm::orc::SymbolLookupSet &LookupSet) {
593 llvm::orc::SymbolMap newSymbols;
594
595 for (const auto &i : LookupSet) {
596 const llvm::orc::SymbolStringPtr &ssp = i.first;
597 llvm::StringRef name = *ssp;
598
599 // FIXME: looking for symbols external to libjit in the process is
600 // dangerous because it can be environment dependent. For example,
601 // we get cases where a symbol is found in the Linux environment,
602 // but not in the Windows environment.
603 if (auto processSymAddr =
604 llvm::RTDyldMemoryManager::getSymbolAddressInProcess(name.str())) {
605 newSymbols[ssp] = llvm::JITEvaluatedSymbol(
606 processSymAddr, llvm::JITSymbolFlags::Exported);
607 continue;
608 }
609
610 // The symbol was not resolved. This will make the retreival of
611 // 'main' function symbol fail later without much information about
612 // the source of the problem. Then, we dump an error message now to
613 // ease debugging.
614 DEBUG_GLOW(llvm::dbgs()
615 << "JIT: Error resolving symbol '" << name << "'\n");
616 // Return a 'symbol not found' JITSymbol object (nullptr).
617 }
618
619 if (newSymbols.empty())
620 return llvm::Error::success();
621
622 return JD.define(absoluteSymbols(std::move(newSymbols)));
623}
624
625llvm::JITSymbol GlowJITOrcV2::findSymbol(const std::string &name) {
626 auto s = es_.lookup({&jd_}, name);
627 return s ? llvm::JITSymbol(s.get()) : llvm::JITSymbol(s.takeError());
628}
629
630void GlowJITOrcV2::setContext(std::unique_ptr<llvm::LLVMContext> ctx) {
631 ctx_ = llvm::orc::ThreadSafeContext(std::move(ctx));
632}
633
634void GlowJITOrcV2::addModule(std::unique_ptr<llvm::Module> m) {
635 auto ctors = llvm::orc::getConstructors(*m.get());
636 llvm::orc::CtorDtorRunner ctorRunner(jd_);
637 ctorRunner.add(ctors);
638
639 auto dtors = llvm::orc::getDestructors(*m.get());
640 irStaticDestructorRunners_.emplace_back(jd_);
641 irStaticDestructorRunners_.back().add(dtors);
642
643 cantFail(
644 compileLayer_.add(jd_, llvm::orc::ThreadSafeModule(std::move(m), ctx_)));
645
646 // Run the static constructors
647 if (auto err = ctorRunner.run()) {
648 LOG(WARNING) << "Error while running static constructors for "
649 << m->getName().str() << ": "
650 << llvm::toString(std::move(err));
651 }
652}
653
654} // namespace glow
655#else
656#error Unsupported GLOW_JIT_ORC_VERSION
657#endif
658