mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-29 19:56:05 +00:00

The find-dynamic-unwind-info callback registration APIs in libunwind limit the number of callbacks that can be registered. If we use multiple UnwindInfoManager instances, each with their own own callback function (as was the case prior to this patch) we can quickly exceed this limit (see https://github.com/llvm/llvm-project/issues/126611). This patch updates the UnwindInfoManager class to use a singleton pattern, with the single instance shared between all LLVM JITs in the process. This change does _not_ apply to compact unwind info registered through the ORC runtime (which currently installs its own callbacks). As a bonus this change eliminates the need to load an IR "bouncer" module to supply the unique callback for each instance, so support for compact-unwind can be extended to the llvm-jitlink tools (which does not support adding IR).
1352 lines
46 KiB
C++
1352 lines
46 KiB
C++
//===--------- LLJIT.cpp - An ORC-based JIT for compiling LLVM IR ---------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
|
|
|
|
#include "llvm/Analysis/TargetLibraryInfo.h"
|
|
#include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS
|
|
#include "llvm/ExecutionEngine/Orc/COFFPlatform.h"
|
|
#include "llvm/ExecutionEngine/Orc/EHFrameRegistrationPlugin.h"
|
|
#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
|
|
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
|
|
#include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h"
|
|
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
|
|
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
|
|
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
|
|
#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
|
|
#include "llvm/ExecutionEngine/Orc/UnwindInfoRegistrationPlugin.h"
|
|
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
|
|
#include "llvm/IR/GlobalVariable.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/Mangler.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/Support/DynamicLibrary.h"
|
|
|
|
#define DEBUG_TYPE "orc"
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::orc;
|
|
|
|
namespace {
|
|
|
|
/// Adds helper function decls and wrapper functions that call the helper with
|
|
/// some additional prefix arguments.
|
|
///
|
|
/// E.g. For wrapper "foo" with type i8(i8, i64), helper "bar", and prefix
|
|
/// args i32 4 and i16 12345, this function will add:
|
|
///
|
|
/// declare i8 @bar(i32, i16, i8, i64)
|
|
///
|
|
/// define i8 @foo(i8, i64) {
|
|
/// entry:
|
|
/// %2 = call i8 @bar(i32 4, i16 12345, i8 %0, i64 %1)
|
|
/// ret i8 %2
|
|
/// }
|
|
///
|
|
Function *addHelperAndWrapper(Module &M, StringRef WrapperName,
|
|
FunctionType *WrapperFnType,
|
|
GlobalValue::VisibilityTypes WrapperVisibility,
|
|
StringRef HelperName,
|
|
ArrayRef<Value *> HelperPrefixArgs) {
|
|
std::vector<Type *> HelperArgTypes;
|
|
for (auto *Arg : HelperPrefixArgs)
|
|
HelperArgTypes.push_back(Arg->getType());
|
|
for (auto *T : WrapperFnType->params())
|
|
HelperArgTypes.push_back(T);
|
|
auto *HelperFnType =
|
|
FunctionType::get(WrapperFnType->getReturnType(), HelperArgTypes, false);
|
|
auto *HelperFn = Function::Create(HelperFnType, GlobalValue::ExternalLinkage,
|
|
HelperName, M);
|
|
|
|
auto *WrapperFn = Function::Create(
|
|
WrapperFnType, GlobalValue::ExternalLinkage, WrapperName, M);
|
|
WrapperFn->setVisibility(WrapperVisibility);
|
|
|
|
auto *EntryBlock = BasicBlock::Create(M.getContext(), "entry", WrapperFn);
|
|
IRBuilder<> IB(EntryBlock);
|
|
|
|
std::vector<Value *> HelperArgs;
|
|
for (auto *Arg : HelperPrefixArgs)
|
|
HelperArgs.push_back(Arg);
|
|
for (auto &Arg : WrapperFn->args())
|
|
HelperArgs.push_back(&Arg);
|
|
auto *HelperResult = IB.CreateCall(HelperFn, HelperArgs);
|
|
if (HelperFn->getReturnType()->isVoidTy())
|
|
IB.CreateRetVoid();
|
|
else
|
|
IB.CreateRet(HelperResult);
|
|
|
|
return WrapperFn;
|
|
}
|
|
|
|
class GenericLLVMIRPlatformSupport;
|
|
|
|
/// orc::Platform component of Generic LLVM IR Platform support.
|
|
/// Just forwards calls to the GenericLLVMIRPlatformSupport class below.
|
|
class GenericLLVMIRPlatform : public Platform {
|
|
public:
|
|
GenericLLVMIRPlatform(GenericLLVMIRPlatformSupport &S) : S(S) {}
|
|
Error setupJITDylib(JITDylib &JD) override;
|
|
Error teardownJITDylib(JITDylib &JD) override;
|
|
Error notifyAdding(ResourceTracker &RT,
|
|
const MaterializationUnit &MU) override;
|
|
Error notifyRemoving(ResourceTracker &RT) override {
|
|
// Noop -- Nothing to do (yet).
|
|
return Error::success();
|
|
}
|
|
|
|
private:
|
|
GenericLLVMIRPlatformSupport &S;
|
|
};
|
|
|
|
/// This transform parses llvm.global_ctors to produce a single initialization
|
|
/// function for the module, records the function, then deletes
|
|
/// llvm.global_ctors.
|
|
class GlobalCtorDtorScraper {
|
|
public:
|
|
GlobalCtorDtorScraper(GenericLLVMIRPlatformSupport &PS,
|
|
StringRef InitFunctionPrefix,
|
|
StringRef DeInitFunctionPrefix)
|
|
: PS(PS), InitFunctionPrefix(InitFunctionPrefix),
|
|
DeInitFunctionPrefix(DeInitFunctionPrefix) {}
|
|
Expected<ThreadSafeModule> operator()(ThreadSafeModule TSM,
|
|
MaterializationResponsibility &R);
|
|
|
|
private:
|
|
GenericLLVMIRPlatformSupport &PS;
|
|
StringRef InitFunctionPrefix;
|
|
StringRef DeInitFunctionPrefix;
|
|
};
|
|
|
|
/// Generic IR Platform Support
|
|
///
|
|
/// Scrapes llvm.global_ctors and llvm.global_dtors and replaces them with
|
|
/// specially named 'init' and 'deinit'. Injects definitions / interposes for
|
|
/// some runtime API, including __cxa_atexit, dlopen, and dlclose.
|
|
class GenericLLVMIRPlatformSupport : public LLJIT::PlatformSupport {
|
|
public:
|
|
GenericLLVMIRPlatformSupport(LLJIT &J, JITDylib &PlatformJD)
|
|
: J(J), InitFunctionPrefix(J.mangle("__orc_init_func.")),
|
|
DeInitFunctionPrefix(J.mangle("__orc_deinit_func.")) {
|
|
|
|
getExecutionSession().setPlatform(
|
|
std::make_unique<GenericLLVMIRPlatform>(*this));
|
|
|
|
setInitTransform(J, GlobalCtorDtorScraper(*this, InitFunctionPrefix,
|
|
DeInitFunctionPrefix));
|
|
|
|
SymbolMap StdInterposes;
|
|
|
|
StdInterposes[J.mangleAndIntern("__lljit.platform_support_instance")] = {
|
|
ExecutorAddr::fromPtr(this), JITSymbolFlags::Exported};
|
|
StdInterposes[J.mangleAndIntern("__lljit.cxa_atexit_helper")] = {
|
|
ExecutorAddr::fromPtr(registerCxaAtExitHelper), JITSymbolFlags()};
|
|
|
|
cantFail(PlatformJD.define(absoluteSymbols(std::move(StdInterposes))));
|
|
cantFail(setupJITDylib(PlatformJD));
|
|
cantFail(J.addIRModule(PlatformJD, createPlatformRuntimeModule()));
|
|
}
|
|
|
|
ExecutionSession &getExecutionSession() { return J.getExecutionSession(); }
|
|
|
|
/// Adds a module that defines the __dso_handle global.
|
|
Error setupJITDylib(JITDylib &JD) {
|
|
|
|
// Add per-jitdylib standard interposes.
|
|
SymbolMap PerJDInterposes;
|
|
PerJDInterposes[J.mangleAndIntern("__lljit.run_atexits_helper")] = {
|
|
ExecutorAddr::fromPtr(runAtExitsHelper), JITSymbolFlags()};
|
|
PerJDInterposes[J.mangleAndIntern("__lljit.atexit_helper")] = {
|
|
ExecutorAddr::fromPtr(registerAtExitHelper), JITSymbolFlags()};
|
|
cantFail(JD.define(absoluteSymbols(std::move(PerJDInterposes))));
|
|
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
auto M = std::make_unique<Module>("__standard_lib", *Ctx);
|
|
M->setDataLayout(J.getDataLayout());
|
|
|
|
auto *Int64Ty = Type::getInt64Ty(*Ctx);
|
|
auto *DSOHandle = new GlobalVariable(
|
|
*M, Int64Ty, true, GlobalValue::ExternalLinkage,
|
|
ConstantInt::get(Int64Ty, reinterpret_cast<uintptr_t>(&JD)),
|
|
"__dso_handle");
|
|
DSOHandle->setVisibility(GlobalValue::DefaultVisibility);
|
|
DSOHandle->setInitializer(
|
|
ConstantInt::get(Int64Ty, ExecutorAddr::fromPtr(&JD).getValue()));
|
|
|
|
auto *GenericIRPlatformSupportTy =
|
|
StructType::create(*Ctx, "lljit.GenericLLJITIRPlatformSupport");
|
|
|
|
auto *PlatformInstanceDecl = new GlobalVariable(
|
|
*M, GenericIRPlatformSupportTy, true, GlobalValue::ExternalLinkage,
|
|
nullptr, "__lljit.platform_support_instance");
|
|
|
|
auto *VoidTy = Type::getVoidTy(*Ctx);
|
|
addHelperAndWrapper(
|
|
*M, "__lljit_run_atexits", FunctionType::get(VoidTy, {}, false),
|
|
GlobalValue::HiddenVisibility, "__lljit.run_atexits_helper",
|
|
{PlatformInstanceDecl, DSOHandle});
|
|
|
|
auto *IntTy = Type::getIntNTy(*Ctx, sizeof(int) * CHAR_BIT);
|
|
auto *AtExitCallbackPtrTy = PointerType::getUnqual(*Ctx);
|
|
auto *AtExit = addHelperAndWrapper(
|
|
*M, "atexit", FunctionType::get(IntTy, {AtExitCallbackPtrTy}, false),
|
|
GlobalValue::HiddenVisibility, "__lljit.atexit_helper",
|
|
{PlatformInstanceDecl, DSOHandle});
|
|
Attribute::AttrKind AtExitExtAttr =
|
|
TargetLibraryInfo::getExtAttrForI32Return(J.getTargetTriple());
|
|
if (AtExitExtAttr != Attribute::None)
|
|
AtExit->addRetAttr(AtExitExtAttr);
|
|
|
|
return J.addIRModule(JD, ThreadSafeModule(std::move(M), std::move(Ctx)));
|
|
}
|
|
|
|
Error notifyAdding(ResourceTracker &RT, const MaterializationUnit &MU) {
|
|
auto &JD = RT.getJITDylib();
|
|
if (auto &InitSym = MU.getInitializerSymbol())
|
|
InitSymbols[&JD].add(InitSym, SymbolLookupFlags::WeaklyReferencedSymbol);
|
|
else {
|
|
// If there's no identified init symbol attached, but there is a symbol
|
|
// with the GenericIRPlatform::InitFunctionPrefix, then treat that as
|
|
// an init function. Add the symbol to both the InitSymbols map (which
|
|
// will trigger a lookup to materialize the module) and the InitFunctions
|
|
// map (which holds the names of the symbols to execute).
|
|
for (auto &KV : MU.getSymbols())
|
|
if ((*KV.first).starts_with(InitFunctionPrefix)) {
|
|
InitSymbols[&JD].add(KV.first,
|
|
SymbolLookupFlags::WeaklyReferencedSymbol);
|
|
InitFunctions[&JD].add(KV.first);
|
|
} else if ((*KV.first).starts_with(DeInitFunctionPrefix)) {
|
|
DeInitFunctions[&JD].add(KV.first);
|
|
}
|
|
}
|
|
return Error::success();
|
|
}
|
|
|
|
Error initialize(JITDylib &JD) override {
|
|
LLVM_DEBUG({
|
|
dbgs() << "GenericLLVMIRPlatformSupport getting initializers to run\n";
|
|
});
|
|
if (auto Initializers = getInitializers(JD)) {
|
|
LLVM_DEBUG(
|
|
{ dbgs() << "GenericLLVMIRPlatformSupport running initializers\n"; });
|
|
for (auto InitFnAddr : *Initializers) {
|
|
LLVM_DEBUG({
|
|
dbgs() << " Running init " << formatv("{0:x16}", InitFnAddr)
|
|
<< "...\n";
|
|
});
|
|
auto *InitFn = InitFnAddr.toPtr<void (*)()>();
|
|
InitFn();
|
|
}
|
|
} else
|
|
return Initializers.takeError();
|
|
return Error::success();
|
|
}
|
|
|
|
Error deinitialize(JITDylib &JD) override {
|
|
LLVM_DEBUG({
|
|
dbgs() << "GenericLLVMIRPlatformSupport getting deinitializers to run\n";
|
|
});
|
|
if (auto Deinitializers = getDeinitializers(JD)) {
|
|
LLVM_DEBUG({
|
|
dbgs() << "GenericLLVMIRPlatformSupport running deinitializers\n";
|
|
});
|
|
for (auto DeinitFnAddr : *Deinitializers) {
|
|
LLVM_DEBUG({
|
|
dbgs() << " Running deinit " << formatv("{0:x16}", DeinitFnAddr)
|
|
<< "...\n";
|
|
});
|
|
auto *DeinitFn = DeinitFnAddr.toPtr<void (*)()>();
|
|
DeinitFn();
|
|
}
|
|
} else
|
|
return Deinitializers.takeError();
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
void registerInitFunc(JITDylib &JD, SymbolStringPtr InitName) {
|
|
getExecutionSession().runSessionLocked([&]() {
|
|
InitFunctions[&JD].add(InitName);
|
|
});
|
|
}
|
|
|
|
void registerDeInitFunc(JITDylib &JD, SymbolStringPtr DeInitName) {
|
|
getExecutionSession().runSessionLocked(
|
|
[&]() { DeInitFunctions[&JD].add(DeInitName); });
|
|
}
|
|
|
|
private:
|
|
Expected<std::vector<ExecutorAddr>> getInitializers(JITDylib &JD) {
|
|
if (auto Err = issueInitLookups(JD))
|
|
return std::move(Err);
|
|
|
|
DenseMap<JITDylib *, SymbolLookupSet> LookupSymbols;
|
|
std::vector<JITDylibSP> DFSLinkOrder;
|
|
|
|
if (auto Err = getExecutionSession().runSessionLocked([&]() -> Error {
|
|
if (auto DFSLinkOrderOrErr = JD.getDFSLinkOrder())
|
|
DFSLinkOrder = std::move(*DFSLinkOrderOrErr);
|
|
else
|
|
return DFSLinkOrderOrErr.takeError();
|
|
|
|
for (auto &NextJD : DFSLinkOrder) {
|
|
auto IFItr = InitFunctions.find(NextJD.get());
|
|
if (IFItr != InitFunctions.end()) {
|
|
LookupSymbols[NextJD.get()] = std::move(IFItr->second);
|
|
InitFunctions.erase(IFItr);
|
|
}
|
|
}
|
|
return Error::success();
|
|
}))
|
|
return std::move(Err);
|
|
|
|
LLVM_DEBUG({
|
|
dbgs() << "JITDylib init order is [ ";
|
|
for (auto &JD : llvm::reverse(DFSLinkOrder))
|
|
dbgs() << "\"" << JD->getName() << "\" ";
|
|
dbgs() << "]\n";
|
|
dbgs() << "Looking up init functions:\n";
|
|
for (auto &KV : LookupSymbols)
|
|
dbgs() << " \"" << KV.first->getName() << "\": " << KV.second << "\n";
|
|
});
|
|
|
|
auto &ES = getExecutionSession();
|
|
auto LookupResult = Platform::lookupInitSymbols(ES, LookupSymbols);
|
|
|
|
if (!LookupResult)
|
|
return LookupResult.takeError();
|
|
|
|
std::vector<ExecutorAddr> Initializers;
|
|
while (!DFSLinkOrder.empty()) {
|
|
auto &NextJD = *DFSLinkOrder.back();
|
|
DFSLinkOrder.pop_back();
|
|
auto InitsItr = LookupResult->find(&NextJD);
|
|
if (InitsItr == LookupResult->end())
|
|
continue;
|
|
for (auto &KV : InitsItr->second)
|
|
Initializers.push_back(KV.second.getAddress());
|
|
}
|
|
|
|
return Initializers;
|
|
}
|
|
|
|
Expected<std::vector<ExecutorAddr>> getDeinitializers(JITDylib &JD) {
|
|
auto &ES = getExecutionSession();
|
|
|
|
auto LLJITRunAtExits = J.mangleAndIntern("__lljit_run_atexits");
|
|
|
|
DenseMap<JITDylib *, SymbolLookupSet> LookupSymbols;
|
|
std::vector<JITDylibSP> DFSLinkOrder;
|
|
|
|
if (auto Err = ES.runSessionLocked([&]() -> Error {
|
|
if (auto DFSLinkOrderOrErr = JD.getDFSLinkOrder())
|
|
DFSLinkOrder = std::move(*DFSLinkOrderOrErr);
|
|
else
|
|
return DFSLinkOrderOrErr.takeError();
|
|
|
|
for (auto &NextJD : DFSLinkOrder) {
|
|
auto &JDLookupSymbols = LookupSymbols[NextJD.get()];
|
|
auto DIFItr = DeInitFunctions.find(NextJD.get());
|
|
if (DIFItr != DeInitFunctions.end()) {
|
|
LookupSymbols[NextJD.get()] = std::move(DIFItr->second);
|
|
DeInitFunctions.erase(DIFItr);
|
|
}
|
|
JDLookupSymbols.add(LLJITRunAtExits,
|
|
SymbolLookupFlags::WeaklyReferencedSymbol);
|
|
}
|
|
return Error::success();
|
|
}))
|
|
return std::move(Err);
|
|
|
|
LLVM_DEBUG({
|
|
dbgs() << "JITDylib deinit order is [ ";
|
|
for (auto &JD : DFSLinkOrder)
|
|
dbgs() << "\"" << JD->getName() << "\" ";
|
|
dbgs() << "]\n";
|
|
dbgs() << "Looking up deinit functions:\n";
|
|
for (auto &KV : LookupSymbols)
|
|
dbgs() << " \"" << KV.first->getName() << "\": " << KV.second << "\n";
|
|
});
|
|
|
|
auto LookupResult = Platform::lookupInitSymbols(ES, LookupSymbols);
|
|
|
|
if (!LookupResult)
|
|
return LookupResult.takeError();
|
|
|
|
std::vector<ExecutorAddr> DeInitializers;
|
|
for (auto &NextJD : DFSLinkOrder) {
|
|
auto DeInitsItr = LookupResult->find(NextJD.get());
|
|
assert(DeInitsItr != LookupResult->end() &&
|
|
"Every JD should have at least __lljit_run_atexits");
|
|
|
|
auto RunAtExitsItr = DeInitsItr->second.find(LLJITRunAtExits);
|
|
if (RunAtExitsItr != DeInitsItr->second.end())
|
|
DeInitializers.push_back(RunAtExitsItr->second.getAddress());
|
|
|
|
for (auto &KV : DeInitsItr->second)
|
|
if (KV.first != LLJITRunAtExits)
|
|
DeInitializers.push_back(KV.second.getAddress());
|
|
}
|
|
|
|
return DeInitializers;
|
|
}
|
|
|
|
/// Issue lookups for all init symbols required to initialize JD (and any
|
|
/// JITDylibs that it depends on).
|
|
Error issueInitLookups(JITDylib &JD) {
|
|
DenseMap<JITDylib *, SymbolLookupSet> RequiredInitSymbols;
|
|
std::vector<JITDylibSP> DFSLinkOrder;
|
|
|
|
if (auto Err = getExecutionSession().runSessionLocked([&]() -> Error {
|
|
if (auto DFSLinkOrderOrErr = JD.getDFSLinkOrder())
|
|
DFSLinkOrder = std::move(*DFSLinkOrderOrErr);
|
|
else
|
|
return DFSLinkOrderOrErr.takeError();
|
|
|
|
for (auto &NextJD : DFSLinkOrder) {
|
|
auto ISItr = InitSymbols.find(NextJD.get());
|
|
if (ISItr != InitSymbols.end()) {
|
|
RequiredInitSymbols[NextJD.get()] = std::move(ISItr->second);
|
|
InitSymbols.erase(ISItr);
|
|
}
|
|
}
|
|
return Error::success();
|
|
}))
|
|
return Err;
|
|
|
|
return Platform::lookupInitSymbols(getExecutionSession(),
|
|
RequiredInitSymbols)
|
|
.takeError();
|
|
}
|
|
|
|
static void registerCxaAtExitHelper(void *Self, void (*F)(void *), void *Ctx,
|
|
void *DSOHandle) {
|
|
LLVM_DEBUG({
|
|
dbgs() << "Registering cxa atexit function " << (void *)F << " for JD "
|
|
<< (*static_cast<JITDylib **>(DSOHandle))->getName() << "\n";
|
|
});
|
|
static_cast<GenericLLVMIRPlatformSupport *>(Self)->AtExitMgr.registerAtExit(
|
|
F, Ctx, DSOHandle);
|
|
}
|
|
|
|
static void registerAtExitHelper(void *Self, void *DSOHandle, void (*F)()) {
|
|
LLVM_DEBUG({
|
|
dbgs() << "Registering atexit function " << (void *)F << " for JD "
|
|
<< (*static_cast<JITDylib **>(DSOHandle))->getName() << "\n";
|
|
});
|
|
static_cast<GenericLLVMIRPlatformSupport *>(Self)->AtExitMgr.registerAtExit(
|
|
reinterpret_cast<void (*)(void *)>(F), nullptr, DSOHandle);
|
|
}
|
|
|
|
static void runAtExitsHelper(void *Self, void *DSOHandle) {
|
|
LLVM_DEBUG({
|
|
dbgs() << "Running atexit functions for JD "
|
|
<< (*static_cast<JITDylib **>(DSOHandle))->getName() << "\n";
|
|
});
|
|
static_cast<GenericLLVMIRPlatformSupport *>(Self)->AtExitMgr.runAtExits(
|
|
DSOHandle);
|
|
}
|
|
|
|
// Constructs an LLVM IR module containing platform runtime globals,
|
|
// functions, and interposes.
|
|
ThreadSafeModule createPlatformRuntimeModule() {
|
|
auto Ctx = std::make_unique<LLVMContext>();
|
|
auto M = std::make_unique<Module>("__standard_lib", *Ctx);
|
|
M->setDataLayout(J.getDataLayout());
|
|
|
|
auto *GenericIRPlatformSupportTy =
|
|
StructType::create(*Ctx, "lljit.GenericLLJITIRPlatformSupport");
|
|
|
|
auto *PlatformInstanceDecl = new GlobalVariable(
|
|
*M, GenericIRPlatformSupportTy, true, GlobalValue::ExternalLinkage,
|
|
nullptr, "__lljit.platform_support_instance");
|
|
|
|
auto *IntTy = Type::getIntNTy(*Ctx, sizeof(int) * CHAR_BIT);
|
|
auto *BytePtrTy = PointerType::getUnqual(*Ctx);
|
|
auto *CxaAtExitCallbackPtrTy = PointerType::getUnqual(*Ctx);
|
|
|
|
auto *CxaAtExit = addHelperAndWrapper(
|
|
*M, "__cxa_atexit",
|
|
FunctionType::get(IntTy, {CxaAtExitCallbackPtrTy, BytePtrTy, BytePtrTy},
|
|
false),
|
|
GlobalValue::DefaultVisibility, "__lljit.cxa_atexit_helper",
|
|
{PlatformInstanceDecl});
|
|
Attribute::AttrKind CxaAtExitExtAttr =
|
|
TargetLibraryInfo::getExtAttrForI32Return(J.getTargetTriple());
|
|
if (CxaAtExitExtAttr != Attribute::None)
|
|
CxaAtExit->addRetAttr(CxaAtExitExtAttr);
|
|
|
|
return ThreadSafeModule(std::move(M), std::move(Ctx));
|
|
}
|
|
|
|
LLJIT &J;
|
|
std::string InitFunctionPrefix;
|
|
std::string DeInitFunctionPrefix;
|
|
DenseMap<JITDylib *, SymbolLookupSet> InitSymbols;
|
|
DenseMap<JITDylib *, SymbolLookupSet> InitFunctions;
|
|
DenseMap<JITDylib *, SymbolLookupSet> DeInitFunctions;
|
|
ItaniumCXAAtExitSupport AtExitMgr;
|
|
};
|
|
|
|
Error GenericLLVMIRPlatform::setupJITDylib(JITDylib &JD) {
|
|
return S.setupJITDylib(JD);
|
|
}
|
|
|
|
Error GenericLLVMIRPlatform::teardownJITDylib(JITDylib &JD) {
|
|
return Error::success();
|
|
}
|
|
|
|
Error GenericLLVMIRPlatform::notifyAdding(ResourceTracker &RT,
|
|
const MaterializationUnit &MU) {
|
|
return S.notifyAdding(RT, MU);
|
|
}
|
|
|
|
Expected<ThreadSafeModule>
|
|
GlobalCtorDtorScraper::operator()(ThreadSafeModule TSM,
|
|
MaterializationResponsibility &R) {
|
|
auto Err = TSM.withModuleDo([&](Module &M) -> Error {
|
|
auto &Ctx = M.getContext();
|
|
auto *GlobalCtors = M.getNamedGlobal("llvm.global_ctors");
|
|
auto *GlobalDtors = M.getNamedGlobal("llvm.global_dtors");
|
|
|
|
auto RegisterCOrDtors = [&](GlobalVariable *GlobalCOrDtors,
|
|
bool isCtor) -> Error {
|
|
// If there's no llvm.global_c/dtor or it's just a decl then skip.
|
|
if (!GlobalCOrDtors || GlobalCOrDtors->isDeclaration())
|
|
return Error::success();
|
|
std::string InitOrDeInitFunctionName;
|
|
if (isCtor)
|
|
raw_string_ostream(InitOrDeInitFunctionName)
|
|
<< InitFunctionPrefix << M.getModuleIdentifier();
|
|
else
|
|
raw_string_ostream(InitOrDeInitFunctionName)
|
|
<< DeInitFunctionPrefix << M.getModuleIdentifier();
|
|
|
|
MangleAndInterner Mangle(PS.getExecutionSession(), M.getDataLayout());
|
|
auto InternedInitOrDeInitName = Mangle(InitOrDeInitFunctionName);
|
|
if (auto Err = R.defineMaterializing(
|
|
{{InternedInitOrDeInitName, JITSymbolFlags::Callable}}))
|
|
return Err;
|
|
|
|
auto *InitOrDeInitFunc = Function::Create(
|
|
FunctionType::get(Type::getVoidTy(Ctx), {}, false),
|
|
GlobalValue::ExternalLinkage, InitOrDeInitFunctionName, &M);
|
|
InitOrDeInitFunc->setVisibility(GlobalValue::HiddenVisibility);
|
|
std::vector<std::pair<Function *, unsigned>> InitsOrDeInits;
|
|
auto COrDtors = isCtor ? getConstructors(M) : getDestructors(M);
|
|
|
|
for (auto E : COrDtors)
|
|
InitsOrDeInits.push_back(std::make_pair(E.Func, E.Priority));
|
|
llvm::stable_sort(InitsOrDeInits, llvm::less_second());
|
|
|
|
auto *InitOrDeInitFuncEntryBlock =
|
|
BasicBlock::Create(Ctx, "entry", InitOrDeInitFunc);
|
|
IRBuilder<> IB(InitOrDeInitFuncEntryBlock);
|
|
for (auto &KV : InitsOrDeInits)
|
|
IB.CreateCall(KV.first);
|
|
IB.CreateRetVoid();
|
|
|
|
if (isCtor)
|
|
PS.registerInitFunc(R.getTargetJITDylib(), InternedInitOrDeInitName);
|
|
else
|
|
PS.registerDeInitFunc(R.getTargetJITDylib(), InternedInitOrDeInitName);
|
|
|
|
GlobalCOrDtors->eraseFromParent();
|
|
return Error::success();
|
|
};
|
|
|
|
if (auto Err = RegisterCOrDtors(GlobalCtors, true))
|
|
return Err;
|
|
if (auto Err = RegisterCOrDtors(GlobalDtors, false))
|
|
return Err;
|
|
|
|
return Error::success();
|
|
});
|
|
|
|
if (Err)
|
|
return std::move(Err);
|
|
|
|
return std::move(TSM);
|
|
}
|
|
|
|
/// Inactive Platform Support
|
|
///
|
|
/// Explicitly disables platform support. JITDylibs are not scanned for special
|
|
/// init/deinit symbols. No runtime API interposes are injected.
|
|
class InactivePlatformSupport : public LLJIT::PlatformSupport {
|
|
public:
|
|
InactivePlatformSupport() = default;
|
|
|
|
Error initialize(JITDylib &JD) override {
|
|
LLVM_DEBUG(dbgs() << "InactivePlatformSupport: no initializers running for "
|
|
<< JD.getName() << "\n");
|
|
return Error::success();
|
|
}
|
|
|
|
Error deinitialize(JITDylib &JD) override {
|
|
LLVM_DEBUG(
|
|
dbgs() << "InactivePlatformSupport: no deinitializers running for "
|
|
<< JD.getName() << "\n");
|
|
return Error::success();
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
namespace llvm {
|
|
namespace orc {
|
|
|
|
Error ORCPlatformSupport::initialize(orc::JITDylib &JD) {
|
|
using llvm::orc::shared::SPSExecutorAddr;
|
|
using llvm::orc::shared::SPSString;
|
|
using SPSDLOpenSig = SPSExecutorAddr(SPSString, int32_t);
|
|
using SPSDLUpdateSig = int32_t(SPSExecutorAddr);
|
|
enum dlopen_mode : int32_t {
|
|
ORC_RT_RTLD_LAZY = 0x1,
|
|
ORC_RT_RTLD_NOW = 0x2,
|
|
ORC_RT_RTLD_LOCAL = 0x4,
|
|
ORC_RT_RTLD_GLOBAL = 0x8
|
|
};
|
|
|
|
auto &ES = J.getExecutionSession();
|
|
auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo(
|
|
[](const JITDylibSearchOrder &SO) { return SO; });
|
|
StringRef WrapperToCall = "__orc_rt_jit_dlopen_wrapper";
|
|
bool dlupdate = false;
|
|
const Triple &TT = ES.getTargetTriple();
|
|
if (TT.isOSBinFormatMachO() || TT.isOSBinFormatELF()) {
|
|
if (InitializedDylib.contains(&JD)) {
|
|
WrapperToCall = "__orc_rt_jit_dlupdate_wrapper";
|
|
dlupdate = true;
|
|
} else
|
|
InitializedDylib.insert(&JD);
|
|
}
|
|
|
|
if (auto WrapperAddr =
|
|
ES.lookup(MainSearchOrder, J.mangleAndIntern(WrapperToCall))) {
|
|
if (dlupdate) {
|
|
int32_t result;
|
|
auto E = ES.callSPSWrapper<SPSDLUpdateSig>(WrapperAddr->getAddress(),
|
|
result, DSOHandles[&JD]);
|
|
if (result)
|
|
return make_error<StringError>("dlupdate failed",
|
|
inconvertibleErrorCode());
|
|
return E;
|
|
}
|
|
return ES.callSPSWrapper<SPSDLOpenSig>(WrapperAddr->getAddress(),
|
|
DSOHandles[&JD], JD.getName(),
|
|
int32_t(ORC_RT_RTLD_LAZY));
|
|
} else
|
|
return WrapperAddr.takeError();
|
|
}
|
|
|
|
Error ORCPlatformSupport::deinitialize(orc::JITDylib &JD) {
|
|
using llvm::orc::shared::SPSExecutorAddr;
|
|
using SPSDLCloseSig = int32_t(SPSExecutorAddr);
|
|
|
|
auto &ES = J.getExecutionSession();
|
|
auto MainSearchOrder = J.getMainJITDylib().withLinkOrderDo(
|
|
[](const JITDylibSearchOrder &SO) { return SO; });
|
|
|
|
if (auto WrapperAddr = ES.lookup(
|
|
MainSearchOrder, J.mangleAndIntern("__orc_rt_jit_dlclose_wrapper"))) {
|
|
int32_t result;
|
|
auto E = J.getExecutionSession().callSPSWrapper<SPSDLCloseSig>(
|
|
WrapperAddr->getAddress(), result, DSOHandles[&JD]);
|
|
if (E)
|
|
return E;
|
|
else if (result)
|
|
return make_error<StringError>("dlclose failed",
|
|
inconvertibleErrorCode());
|
|
DSOHandles.erase(&JD);
|
|
InitializedDylib.erase(&JD);
|
|
} else
|
|
return WrapperAddr.takeError();
|
|
return Error::success();
|
|
}
|
|
|
|
void LLJIT::PlatformSupport::setInitTransform(
|
|
LLJIT &J, IRTransformLayer::TransformFunction T) {
|
|
J.InitHelperTransformLayer->setTransform(std::move(T));
|
|
}
|
|
|
|
LLJIT::PlatformSupport::~PlatformSupport() = default;
|
|
|
|
Error LLJITBuilderState::prepareForConstruction() {
|
|
|
|
LLVM_DEBUG(dbgs() << "Preparing to create LLJIT instance...\n");
|
|
|
|
if (!JTMB) {
|
|
LLVM_DEBUG({
|
|
dbgs() << " No explicitly set JITTargetMachineBuilder. "
|
|
"Detecting host...\n";
|
|
});
|
|
if (auto JTMBOrErr = JITTargetMachineBuilder::detectHost())
|
|
JTMB = std::move(*JTMBOrErr);
|
|
else
|
|
return JTMBOrErr.takeError();
|
|
}
|
|
|
|
if ((ES || EPC) && NumCompileThreads)
|
|
return make_error<StringError>(
|
|
"NumCompileThreads cannot be used with a custom ExecutionSession or "
|
|
"ExecutorProcessControl",
|
|
inconvertibleErrorCode());
|
|
|
|
#if !LLVM_ENABLE_THREADS
|
|
if (NumCompileThreads)
|
|
return make_error<StringError>(
|
|
"LLJIT num-compile-threads is " + Twine(NumCompileThreads) +
|
|
" but LLVM was compiled with LLVM_ENABLE_THREADS=Off",
|
|
inconvertibleErrorCode());
|
|
#endif // !LLVM_ENABLE_THREADS
|
|
|
|
// Only used in debug builds.
|
|
[[maybe_unused]] bool ConcurrentCompilationSettingDefaulted =
|
|
!SupportConcurrentCompilation;
|
|
|
|
if (!SupportConcurrentCompilation) {
|
|
#if LLVM_ENABLE_THREADS
|
|
SupportConcurrentCompilation = NumCompileThreads || ES || EPC;
|
|
#else
|
|
SupportConcurrentCompilation = false;
|
|
#endif // LLVM_ENABLE_THREADS
|
|
} else {
|
|
#if !LLVM_ENABLE_THREADS
|
|
if (*SupportConcurrentCompilation)
|
|
return make_error<StringError>(
|
|
"LLJIT concurrent compilation support requested, but LLVM was built "
|
|
"with LLVM_ENABLE_THREADS=Off",
|
|
inconvertibleErrorCode());
|
|
#endif // !LLVM_ENABLE_THREADS
|
|
}
|
|
|
|
LLVM_DEBUG({
|
|
dbgs() << " JITTargetMachineBuilder is "
|
|
<< JITTargetMachineBuilderPrinter(*JTMB, " ")
|
|
<< " Pre-constructed ExecutionSession: " << (ES ? "Yes" : "No")
|
|
<< "\n"
|
|
<< " DataLayout: ";
|
|
if (DL)
|
|
dbgs() << DL->getStringRepresentation() << "\n";
|
|
else
|
|
dbgs() << "None (will be created by JITTargetMachineBuilder)\n";
|
|
|
|
dbgs() << " Custom object-linking-layer creator: "
|
|
<< (CreateObjectLinkingLayer ? "Yes" : "No") << "\n"
|
|
<< " Custom compile-function creator: "
|
|
<< (CreateCompileFunction ? "Yes" : "No") << "\n"
|
|
<< " Custom platform-setup function: "
|
|
<< (SetUpPlatform ? "Yes" : "No") << "\n"
|
|
<< " Support concurrent compilation: "
|
|
<< (*SupportConcurrentCompilation ? "Yes" : "No");
|
|
if (ConcurrentCompilationSettingDefaulted)
|
|
dbgs() << " (defaulted based on ES / EPC / NumCompileThreads)\n";
|
|
else
|
|
dbgs() << "\n";
|
|
dbgs() << " Number of compile threads: " << NumCompileThreads << "\n";
|
|
});
|
|
|
|
// Create DL if not specified.
|
|
if (!DL) {
|
|
if (auto DLOrErr = JTMB->getDefaultDataLayoutForTarget())
|
|
DL = std::move(*DLOrErr);
|
|
else
|
|
return DLOrErr.takeError();
|
|
}
|
|
|
|
// If neither ES nor EPC has been set then create an EPC instance.
|
|
if (!ES && !EPC) {
|
|
LLVM_DEBUG({
|
|
dbgs() << "ExecutorProcessControl not specified, "
|
|
"Creating SelfExecutorProcessControl instance\n";
|
|
});
|
|
|
|
std::unique_ptr<TaskDispatcher> D = nullptr;
|
|
#if LLVM_ENABLE_THREADS
|
|
if (*SupportConcurrentCompilation) {
|
|
std::optional<size_t> NumThreads = std ::nullopt;
|
|
if (NumCompileThreads)
|
|
NumThreads = NumCompileThreads;
|
|
D = std::make_unique<DynamicThreadPoolTaskDispatcher>(NumThreads);
|
|
} else
|
|
D = std::make_unique<InPlaceTaskDispatcher>();
|
|
#endif // LLVM_ENABLE_THREADS
|
|
if (auto EPCOrErr =
|
|
SelfExecutorProcessControl::Create(nullptr, std::move(D), nullptr))
|
|
EPC = std::move(*EPCOrErr);
|
|
else
|
|
return EPCOrErr.takeError();
|
|
} else if (EPC) {
|
|
LLVM_DEBUG({
|
|
dbgs() << "Using explicitly specified ExecutorProcessControl instance "
|
|
<< EPC.get() << "\n";
|
|
});
|
|
} else {
|
|
LLVM_DEBUG({
|
|
dbgs() << "Using explicitly specified ExecutionSession instance "
|
|
<< ES.get() << "\n";
|
|
});
|
|
}
|
|
|
|
// If the client didn't configure any linker options then auto-configure the
|
|
// JIT linker.
|
|
if (!CreateObjectLinkingLayer) {
|
|
auto &TT = JTMB->getTargetTriple();
|
|
bool UseJITLink = false;
|
|
switch (TT.getArch()) {
|
|
case Triple::riscv64:
|
|
case Triple::loongarch64:
|
|
UseJITLink = true;
|
|
break;
|
|
case Triple::aarch64:
|
|
UseJITLink = !TT.isOSBinFormatCOFF();
|
|
break;
|
|
case Triple::arm:
|
|
case Triple::armeb:
|
|
case Triple::thumb:
|
|
case Triple::thumbeb:
|
|
UseJITLink = TT.isOSBinFormatELF();
|
|
break;
|
|
case Triple::x86_64:
|
|
UseJITLink = !TT.isOSBinFormatCOFF();
|
|
break;
|
|
case Triple::ppc64:
|
|
UseJITLink = TT.isPPC64ELFv2ABI();
|
|
break;
|
|
case Triple::ppc64le:
|
|
UseJITLink = TT.isOSBinFormatELF();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (UseJITLink) {
|
|
if (!JTMB->getCodeModel())
|
|
JTMB->setCodeModel(CodeModel::Small);
|
|
JTMB->setRelocationModel(Reloc::PIC_);
|
|
CreateObjectLinkingLayer =
|
|
[](ExecutionSession &ES,
|
|
const Triple &) -> Expected<std::unique_ptr<ObjectLayer>> {
|
|
return std::make_unique<ObjectLinkingLayer>(ES);
|
|
};
|
|
}
|
|
}
|
|
|
|
// If we need a process JITDylib but no setup function has been given then
|
|
// create a default one.
|
|
if (!SetupProcessSymbolsJITDylib && LinkProcessSymbolsByDefault) {
|
|
LLVM_DEBUG(dbgs() << "Creating default Process JD setup function\n");
|
|
SetupProcessSymbolsJITDylib = [](LLJIT &J) -> Expected<JITDylibSP> {
|
|
auto &JD =
|
|
J.getExecutionSession().createBareJITDylib("<Process Symbols>");
|
|
auto G = EPCDynamicLibrarySearchGenerator::GetForTargetProcess(
|
|
J.getExecutionSession());
|
|
if (!G)
|
|
return G.takeError();
|
|
JD.addGenerator(std::move(*G));
|
|
return &JD;
|
|
};
|
|
}
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
LLJIT::~LLJIT() {
|
|
if (auto Err = ES->endSession())
|
|
ES->reportError(std::move(Err));
|
|
}
|
|
|
|
JITDylibSP LLJIT::getProcessSymbolsJITDylib() { return ProcessSymbols; }
|
|
|
|
JITDylibSP LLJIT::getPlatformJITDylib() { return Platform; }
|
|
|
|
Expected<JITDylib &> LLJIT::createJITDylib(std::string Name) {
|
|
auto JD = ES->createJITDylib(std::move(Name));
|
|
if (!JD)
|
|
return JD.takeError();
|
|
|
|
JD->addToLinkOrder(DefaultLinks);
|
|
return JD;
|
|
}
|
|
|
|
Expected<JITDylib &> LLJIT::loadPlatformDynamicLibrary(const char *Path) {
|
|
auto G = EPCDynamicLibrarySearchGenerator::Load(*ES, Path);
|
|
if (!G)
|
|
return G.takeError();
|
|
|
|
if (auto *ExistingJD = ES->getJITDylibByName(Path))
|
|
return *ExistingJD;
|
|
|
|
auto &JD = ES->createBareJITDylib(Path);
|
|
JD.addGenerator(std::move(*G));
|
|
return JD;
|
|
}
|
|
|
|
Error LLJIT::linkStaticLibraryInto(JITDylib &JD,
|
|
std::unique_ptr<MemoryBuffer> LibBuffer) {
|
|
auto G = StaticLibraryDefinitionGenerator::Create(*ObjLinkingLayer,
|
|
std::move(LibBuffer));
|
|
if (!G)
|
|
return G.takeError();
|
|
|
|
JD.addGenerator(std::move(*G));
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Error LLJIT::linkStaticLibraryInto(JITDylib &JD, const char *Path) {
|
|
auto G = StaticLibraryDefinitionGenerator::Load(*ObjLinkingLayer, Path);
|
|
if (!G)
|
|
return G.takeError();
|
|
|
|
JD.addGenerator(std::move(*G));
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Error LLJIT::addIRModule(ResourceTrackerSP RT, ThreadSafeModule TSM) {
|
|
assert(TSM && "Can not add null module");
|
|
|
|
if (auto Err =
|
|
TSM.withModuleDo([&](Module &M) { return applyDataLayout(M); }))
|
|
return Err;
|
|
|
|
return InitHelperTransformLayer->add(std::move(RT), std::move(TSM));
|
|
}
|
|
|
|
Error LLJIT::addIRModule(JITDylib &JD, ThreadSafeModule TSM) {
|
|
return addIRModule(JD.getDefaultResourceTracker(), std::move(TSM));
|
|
}
|
|
|
|
Error LLJIT::addObjectFile(ResourceTrackerSP RT,
|
|
std::unique_ptr<MemoryBuffer> Obj) {
|
|
assert(Obj && "Can not add null object");
|
|
|
|
return ObjTransformLayer->add(std::move(RT), std::move(Obj));
|
|
}
|
|
|
|
Error LLJIT::addObjectFile(JITDylib &JD, std::unique_ptr<MemoryBuffer> Obj) {
|
|
return addObjectFile(JD.getDefaultResourceTracker(), std::move(Obj));
|
|
}
|
|
|
|
Expected<ExecutorAddr> LLJIT::lookupLinkerMangled(JITDylib &JD,
|
|
SymbolStringPtr Name) {
|
|
if (auto Sym = ES->lookup(
|
|
makeJITDylibSearchOrder(&JD, JITDylibLookupFlags::MatchAllSymbols),
|
|
Name))
|
|
return Sym->getAddress();
|
|
else
|
|
return Sym.takeError();
|
|
}
|
|
|
|
Expected<std::unique_ptr<ObjectLayer>>
|
|
LLJIT::createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES) {
|
|
|
|
// If the config state provided an ObjectLinkingLayer factory then use it.
|
|
if (S.CreateObjectLinkingLayer)
|
|
return S.CreateObjectLinkingLayer(ES, S.JTMB->getTargetTriple());
|
|
|
|
// Otherwise default to creating an RTDyldObjectLinkingLayer that constructs
|
|
// a new SectionMemoryManager for each object.
|
|
auto GetMemMgr = []() { return std::make_unique<SectionMemoryManager>(); };
|
|
auto Layer =
|
|
std::make_unique<RTDyldObjectLinkingLayer>(ES, std::move(GetMemMgr));
|
|
|
|
if (S.JTMB->getTargetTriple().isOSBinFormatCOFF()) {
|
|
Layer->setOverrideObjectFlagsWithResponsibilityFlags(true);
|
|
Layer->setAutoClaimResponsibilityForObjectSymbols(true);
|
|
}
|
|
|
|
if (S.JTMB->getTargetTriple().isOSBinFormatELF() &&
|
|
(S.JTMB->getTargetTriple().getArch() == Triple::ArchType::ppc64 ||
|
|
S.JTMB->getTargetTriple().getArch() == Triple::ArchType::ppc64le))
|
|
Layer->setAutoClaimResponsibilityForObjectSymbols(true);
|
|
|
|
// FIXME: Explicit conversion to std::unique_ptr<ObjectLayer> added to silence
|
|
// errors from some GCC / libstdc++ bots. Remove this conversion (i.e.
|
|
// just return ObjLinkingLayer) once those bots are upgraded.
|
|
return std::unique_ptr<ObjectLayer>(std::move(Layer));
|
|
}
|
|
|
|
Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>
|
|
LLJIT::createCompileFunction(LLJITBuilderState &S,
|
|
JITTargetMachineBuilder JTMB) {
|
|
|
|
/// If there is a custom compile function creator set then use it.
|
|
if (S.CreateCompileFunction)
|
|
return S.CreateCompileFunction(std::move(JTMB));
|
|
|
|
// If using a custom EPC then use a ConcurrentIRCompiler by default.
|
|
if (*S.SupportConcurrentCompilation)
|
|
return std::make_unique<ConcurrentIRCompiler>(std::move(JTMB));
|
|
|
|
auto TM = JTMB.createTargetMachine();
|
|
if (!TM)
|
|
return TM.takeError();
|
|
|
|
return std::make_unique<TMOwningSimpleCompiler>(std::move(*TM));
|
|
}
|
|
|
|
LLJIT::LLJIT(LLJITBuilderState &S, Error &Err)
|
|
: DL(std::move(*S.DL)), TT(S.JTMB->getTargetTriple()) {
|
|
|
|
ErrorAsOutParameter _(Err);
|
|
|
|
assert(!(S.EPC && S.ES) && "EPC and ES should not both be set");
|
|
|
|
if (S.EPC) {
|
|
ES = std::make_unique<ExecutionSession>(std::move(S.EPC));
|
|
} else if (S.ES)
|
|
ES = std::move(S.ES);
|
|
else {
|
|
if (auto EPC = SelfExecutorProcessControl::Create()) {
|
|
ES = std::make_unique<ExecutionSession>(std::move(*EPC));
|
|
} else {
|
|
Err = EPC.takeError();
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto ObjLayer = createObjectLinkingLayer(S, *ES);
|
|
if (!ObjLayer) {
|
|
Err = ObjLayer.takeError();
|
|
return;
|
|
}
|
|
ObjLinkingLayer = std::move(*ObjLayer);
|
|
ObjTransformLayer =
|
|
std::make_unique<ObjectTransformLayer>(*ES, *ObjLinkingLayer);
|
|
|
|
{
|
|
auto CompileFunction = createCompileFunction(S, std::move(*S.JTMB));
|
|
if (!CompileFunction) {
|
|
Err = CompileFunction.takeError();
|
|
return;
|
|
}
|
|
CompileLayer = std::make_unique<IRCompileLayer>(
|
|
*ES, *ObjTransformLayer, std::move(*CompileFunction));
|
|
TransformLayer = std::make_unique<IRTransformLayer>(*ES, *CompileLayer);
|
|
InitHelperTransformLayer =
|
|
std::make_unique<IRTransformLayer>(*ES, *TransformLayer);
|
|
}
|
|
|
|
if (*S.SupportConcurrentCompilation)
|
|
InitHelperTransformLayer->setCloneToNewContextOnEmit(true);
|
|
|
|
if (S.SetupProcessSymbolsJITDylib) {
|
|
if (auto ProcSymsJD = S.SetupProcessSymbolsJITDylib(*this)) {
|
|
ProcessSymbols = ProcSymsJD->get();
|
|
} else {
|
|
Err = ProcSymsJD.takeError();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (S.PrePlatformSetup)
|
|
if ((Err = S.PrePlatformSetup(*this)))
|
|
return;
|
|
|
|
if (!S.SetUpPlatform)
|
|
S.SetUpPlatform = setUpGenericLLVMIRPlatform;
|
|
|
|
if (auto PlatformJDOrErr = S.SetUpPlatform(*this)) {
|
|
Platform = PlatformJDOrErr->get();
|
|
if (Platform)
|
|
DefaultLinks.push_back(
|
|
{Platform, JITDylibLookupFlags::MatchExportedSymbolsOnly});
|
|
} else {
|
|
Err = PlatformJDOrErr.takeError();
|
|
return;
|
|
}
|
|
|
|
if (S.LinkProcessSymbolsByDefault)
|
|
DefaultLinks.push_back(
|
|
{ProcessSymbols, JITDylibLookupFlags::MatchExportedSymbolsOnly});
|
|
|
|
if (auto MainOrErr = createJITDylib("main"))
|
|
Main = &*MainOrErr;
|
|
else {
|
|
Err = MainOrErr.takeError();
|
|
return;
|
|
}
|
|
}
|
|
|
|
std::string LLJIT::mangle(StringRef UnmangledName) const {
|
|
std::string MangledName;
|
|
{
|
|
raw_string_ostream MangledNameStream(MangledName);
|
|
Mangler::getNameWithPrefix(MangledNameStream, UnmangledName, DL);
|
|
}
|
|
return MangledName;
|
|
}
|
|
|
|
Error LLJIT::applyDataLayout(Module &M) {
|
|
if (M.getDataLayout().isDefault())
|
|
M.setDataLayout(DL);
|
|
|
|
if (M.getDataLayout() != DL)
|
|
return make_error<StringError>(
|
|
"Added modules have incompatible data layouts: " +
|
|
M.getDataLayout().getStringRepresentation() + " (module) vs " +
|
|
DL.getStringRepresentation() + " (jit)",
|
|
inconvertibleErrorCode());
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
Error setUpOrcPlatformManually(LLJIT &J) {
|
|
LLVM_DEBUG({ dbgs() << "Setting up orc platform support for LLJIT\n"; });
|
|
J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J));
|
|
return Error::success();
|
|
}
|
|
|
|
class LoadAndLinkDynLibrary {
|
|
public:
|
|
LoadAndLinkDynLibrary(LLJIT &J) : J(J) {}
|
|
Error operator()(JITDylib &JD, StringRef DLLName) {
|
|
if (!DLLName.ends_with_insensitive(".dll"))
|
|
return make_error<StringError>("DLLName not ending with .dll",
|
|
inconvertibleErrorCode());
|
|
auto DLLNameStr = DLLName.str(); // Guarantees null-termination.
|
|
auto DLLJD = J.loadPlatformDynamicLibrary(DLLNameStr.c_str());
|
|
if (!DLLJD)
|
|
return DLLJD.takeError();
|
|
JD.addToLinkOrder(*DLLJD);
|
|
return Error::success();
|
|
}
|
|
|
|
private:
|
|
LLJIT &J;
|
|
};
|
|
|
|
Expected<JITDylibSP> ExecutorNativePlatform::operator()(LLJIT &J) {
|
|
auto ProcessSymbolsJD = J.getProcessSymbolsJITDylib();
|
|
if (!ProcessSymbolsJD)
|
|
return make_error<StringError>(
|
|
"Native platforms require a process symbols JITDylib",
|
|
inconvertibleErrorCode());
|
|
|
|
const Triple &TT = J.getTargetTriple();
|
|
ObjectLinkingLayer *ObjLinkingLayer =
|
|
dyn_cast<ObjectLinkingLayer>(&J.getObjLinkingLayer());
|
|
|
|
if (!ObjLinkingLayer)
|
|
return make_error<StringError>(
|
|
"ExecutorNativePlatform requires ObjectLinkingLayer",
|
|
inconvertibleErrorCode());
|
|
|
|
std::unique_ptr<MemoryBuffer> RuntimeArchiveBuffer;
|
|
if (OrcRuntime.index() == 0) {
|
|
auto A = errorOrToExpected(MemoryBuffer::getFile(std::get<0>(OrcRuntime)));
|
|
if (!A)
|
|
return A.takeError();
|
|
RuntimeArchiveBuffer = std::move(*A);
|
|
} else
|
|
RuntimeArchiveBuffer = std::move(std::get<1>(OrcRuntime));
|
|
|
|
auto &ES = J.getExecutionSession();
|
|
auto &PlatformJD = ES.createBareJITDylib("<Platform>");
|
|
PlatformJD.addToLinkOrder(*ProcessSymbolsJD);
|
|
|
|
J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J));
|
|
|
|
switch (TT.getObjectFormat()) {
|
|
case Triple::COFF: {
|
|
const char *VCRuntimePath = nullptr;
|
|
bool StaticVCRuntime = false;
|
|
if (VCRuntime) {
|
|
VCRuntimePath = VCRuntime->first.c_str();
|
|
StaticVCRuntime = VCRuntime->second;
|
|
}
|
|
if (auto P = COFFPlatform::Create(
|
|
*ObjLinkingLayer, PlatformJD, std::move(RuntimeArchiveBuffer),
|
|
LoadAndLinkDynLibrary(J), StaticVCRuntime, VCRuntimePath))
|
|
J.getExecutionSession().setPlatform(std::move(*P));
|
|
else
|
|
return P.takeError();
|
|
break;
|
|
}
|
|
case Triple::ELF: {
|
|
auto G = StaticLibraryDefinitionGenerator::Create(
|
|
*ObjLinkingLayer, std::move(RuntimeArchiveBuffer));
|
|
if (!G)
|
|
return G.takeError();
|
|
|
|
if (auto P =
|
|
ELFNixPlatform::Create(*ObjLinkingLayer, PlatformJD, std::move(*G)))
|
|
J.getExecutionSession().setPlatform(std::move(*P));
|
|
else
|
|
return P.takeError();
|
|
break;
|
|
}
|
|
case Triple::MachO: {
|
|
auto G = StaticLibraryDefinitionGenerator::Create(
|
|
*ObjLinkingLayer, std::move(RuntimeArchiveBuffer));
|
|
if (!G)
|
|
return G.takeError();
|
|
|
|
if (auto P =
|
|
MachOPlatform::Create(*ObjLinkingLayer, PlatformJD, std::move(*G)))
|
|
ES.setPlatform(std::move(*P));
|
|
else
|
|
return P.takeError();
|
|
break;
|
|
}
|
|
default:
|
|
return make_error<StringError>("Unsupported object format in triple " +
|
|
TT.str(),
|
|
inconvertibleErrorCode());
|
|
}
|
|
|
|
return &PlatformJD;
|
|
}
|
|
|
|
Expected<JITDylibSP> setUpGenericLLVMIRPlatform(LLJIT &J) {
|
|
LLVM_DEBUG(
|
|
{ dbgs() << "Setting up GenericLLVMIRPlatform support for LLJIT\n"; });
|
|
auto ProcessSymbolsJD = J.getProcessSymbolsJITDylib();
|
|
if (!ProcessSymbolsJD)
|
|
return make_error<StringError>(
|
|
"Native platforms require a process symbols JITDylib",
|
|
inconvertibleErrorCode());
|
|
|
|
auto &PlatformJD = J.getExecutionSession().createBareJITDylib("<Platform>");
|
|
PlatformJD.addToLinkOrder(*ProcessSymbolsJD);
|
|
|
|
if (auto *OLL = dyn_cast<ObjectLinkingLayer>(&J.getObjLinkingLayer())) {
|
|
|
|
bool UseEHFrames = true;
|
|
|
|
// Enable compact-unwind support if possible.
|
|
if (J.getTargetTriple().isOSDarwin() ||
|
|
J.getTargetTriple().isOSBinFormatMachO()) {
|
|
|
|
// Check if the bootstrap map says that we should force eh-frames:
|
|
// Older libunwinds require this as they don't have a dynamic
|
|
// registration API for compact-unwind.
|
|
std::optional<bool> ForceEHFrames;
|
|
if (auto Err = J.getExecutionSession().getBootstrapMapValue<bool, bool>(
|
|
"darwin-use-ehframes-only", ForceEHFrames))
|
|
return Err;
|
|
if (ForceEHFrames.has_value())
|
|
UseEHFrames = *ForceEHFrames;
|
|
else
|
|
UseEHFrames = false;
|
|
|
|
// If UseEHFrames hasn't been set then we're good to use compact-unwind.
|
|
if (!UseEHFrames) {
|
|
if (auto UIRP =
|
|
UnwindInfoRegistrationPlugin::Create(J.getExecutionSession())) {
|
|
OLL->addPlugin(std::move(*UIRP));
|
|
LLVM_DEBUG(dbgs() << "Enabled compact-unwind support.\n");
|
|
} else
|
|
return UIRP.takeError();
|
|
}
|
|
}
|
|
|
|
// Otherwise fall back to standard unwind registration.
|
|
if (UseEHFrames) {
|
|
auto &ES = J.getExecutionSession();
|
|
if (auto EHFrameRegistrar = EPCEHFrameRegistrar::Create(ES)) {
|
|
OLL->addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
|
|
ES, std::move(*EHFrameRegistrar)));
|
|
LLVM_DEBUG(dbgs() << "Enabled eh-frame support.\n");
|
|
} else
|
|
return EHFrameRegistrar.takeError();
|
|
}
|
|
}
|
|
|
|
J.setPlatformSupport(
|
|
std::make_unique<GenericLLVMIRPlatformSupport>(J, PlatformJD));
|
|
|
|
return &PlatformJD;
|
|
}
|
|
|
|
Expected<JITDylibSP> setUpInactivePlatform(LLJIT &J) {
|
|
LLVM_DEBUG(
|
|
{ dbgs() << "Explicitly deactivated platform support for LLJIT\n"; });
|
|
J.setPlatformSupport(std::make_unique<InactivePlatformSupport>());
|
|
return nullptr;
|
|
}
|
|
|
|
Error LLLazyJITBuilderState::prepareForConstruction() {
|
|
if (auto Err = LLJITBuilderState::prepareForConstruction())
|
|
return Err;
|
|
TT = JTMB->getTargetTriple();
|
|
return Error::success();
|
|
}
|
|
|
|
Error LLLazyJIT::addLazyIRModule(JITDylib &JD, ThreadSafeModule TSM) {
|
|
assert(TSM && "Can not add null module");
|
|
|
|
if (auto Err = TSM.withModuleDo(
|
|
[&](Module &M) -> Error { return applyDataLayout(M); }))
|
|
return Err;
|
|
|
|
return CODLayer->add(JD, std::move(TSM));
|
|
}
|
|
|
|
LLLazyJIT::LLLazyJIT(LLLazyJITBuilderState &S, Error &Err) : LLJIT(S, Err) {
|
|
|
|
// If LLJIT construction failed then bail out.
|
|
if (Err)
|
|
return;
|
|
|
|
ErrorAsOutParameter _(&Err);
|
|
|
|
/// Take/Create the lazy-compile callthrough manager.
|
|
if (S.LCTMgr)
|
|
LCTMgr = std::move(S.LCTMgr);
|
|
else {
|
|
if (auto LCTMgrOrErr = createLocalLazyCallThroughManager(
|
|
S.TT, *ES, S.LazyCompileFailureAddr))
|
|
LCTMgr = std::move(*LCTMgrOrErr);
|
|
else {
|
|
Err = LCTMgrOrErr.takeError();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Take/Create the indirect stubs manager builder.
|
|
auto ISMBuilder = std::move(S.ISMBuilder);
|
|
|
|
// If none was provided, try to build one.
|
|
if (!ISMBuilder)
|
|
ISMBuilder = createLocalIndirectStubsManagerBuilder(S.TT);
|
|
|
|
// No luck. Bail out.
|
|
if (!ISMBuilder) {
|
|
Err = make_error<StringError>("Could not construct "
|
|
"IndirectStubsManagerBuilder for target " +
|
|
S.TT.str(),
|
|
inconvertibleErrorCode());
|
|
return;
|
|
}
|
|
|
|
// Create the IP Layer.
|
|
IPLayer = std::make_unique<IRPartitionLayer>(*ES, *InitHelperTransformLayer);
|
|
|
|
// Create the COD layer.
|
|
CODLayer = std::make_unique<CompileOnDemandLayer>(*ES, *IPLayer, *LCTMgr,
|
|
std::move(ISMBuilder));
|
|
|
|
if (*S.SupportConcurrentCompilation)
|
|
CODLayer->setCloneToNewContextOnEmit(true);
|
|
}
|
|
|
|
// In-process LLJIT uses eh-frame section wrappers via EPC, so we need to force
|
|
// them to be linked in.
|
|
LLVM_ATTRIBUTE_USED void linkComponents() {
|
|
errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
|
|
<< (void *)&llvm_orc_deregisterEHFrameSectionWrapper;
|
|
}
|
|
|
|
} // End namespace orc.
|
|
} // End namespace llvm.
|