Re-apply "[ORC] LLJIT updates: ExecutorNativePlatform, default ..." with fixes.

This reapplies 371cb1af61, which was reverted in 0b2240eda0 due to bot
failures.

The clang-repl test failure is fixed by dropping the process symbols definition
generator that was manually attached to the main JITDylib, since LLJIT now
exposes process symbols by default. (The bug was triggered when JIT'd code used
the process atexit provided by the generator, rather than the JIT atexit which
has been moved into the platform JITDylib).

Any LLJIT clients that see crashes in static destructors should likewise remove
any process symbol generators attached to their main JITDylib.
This commit is contained in:
Lang Hames
2023-04-07 17:06:20 +00:00
parent 7fff3bfe78
commit 231107a8b5
13 changed files with 388 additions and 417 deletions

View File

@@ -43,15 +43,6 @@ IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
Err = JitOrErr.takeError();
return;
}
const char Pref = Jit->getDataLayout().getGlobalPrefix();
// Discover symbols from the process as a fallback.
if (auto PSGOrErr = DynamicLibrarySearchGenerator::GetForCurrentProcess(Pref))
Jit->getMainJITDylib().addGenerator(std::move(*PSGOrErr));
else {
Err = PSGOrErr.takeError();
return;
}
}
IncrementalExecutor::~IncrementalExecutor() {}

View File

@@ -14,7 +14,6 @@ add_subdirectory(OrcV2CBindingsBasicUsage)
add_subdirectory(OrcV2CBindingsDumpObjects)
add_subdirectory(OrcV2CBindingsIRTransforms)
add_subdirectory(OrcV2CBindingsMCJITLikeMemoryManager)
add_subdirectory(OrcV2CBindingsReflectProcessSymbols)
add_subdirectory(OrcV2CBindingsRemovableCode)
add_subdirectory(OrcV2CBindingsLazy)
add_subdirectory(OrcV2CBindingsVeryLazy)

View File

@@ -22,7 +22,6 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
#include "llvm/ExecutionEngine/Orc/EPCIndirectionUtils.h"
#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
@@ -152,9 +151,6 @@ int main(int argc, char *argv[]) {
EPCIU->createLazyCallThroughManager(
J->getExecutionSession(), ExecutorAddr::fromPtr(&reportErrorAndExit));
auto ISM = EPCIU->createIndirectStubsManager();
J->getMainJITDylib().addGenerator(
ExitOnErr(EPCDynamicLibrarySearchGenerator::GetForTargetProcess(
J->getExecutionSession())));
// (4) Add modules.
ExitOnErr(J->addIRModule(ExitOnErr(parseExampleModule(FooMod, "foo-mod"))));

View File

@@ -82,17 +82,6 @@ int main(int argc, char *argv[]) {
})
.create());
// Make sure that our process symbols are visible to JIT'd code.
{
MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout());
J->getMainJITDylib().addGenerator(
ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
J->getDataLayout().getGlobalPrefix(),
[MainName = Mangle("main")](const orc::SymbolStringPtr &Name) {
return Name != MainName;
})));
}
// Load the input modules.
for (auto &InputFile : InputFiles) {
auto Ctx = std::make_unique<LLVMContext>();

View File

@@ -218,13 +218,6 @@ int main(int argc, char *argv[]) {
.create());
if (!InputObjects.empty()) {
// If we have input objects then reflect process symbols so the input
// objects can do interesting things, like call printf.
J->getMainJITDylib().addGenerator(
ExitOnErr(DynamicLibrarySearchGenerator::GetForCurrentProcess(
J->getDataLayout().getGlobalPrefix())));
// Load the input objects.
for (auto InputObject : InputObjects) {
auto ObjBuffer =

View File

@@ -1,17 +0,0 @@
set(LLVM_LINK_COMPONENTS
Core
ExecutionEngine
IRReader
JITLink
MC
OrcJIT
Support
Target
nativecodegen
)
add_llvm_example(OrcV2CBindingsReflectProcessSymbols
OrcV2CBindingsReflectProcessSymbols.c
)
export_executable_symbols(OrcV2CBindingsReflectProcessSymbols)

View File

@@ -1,221 +0,0 @@
//===-------- BasicOrcV2CBindings.c - Basic OrcV2 C Bindings Demo ---------===//
//
// 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-c/Core.h"
#include "llvm-c/Error.h"
#include "llvm-c/LLJIT.h"
#include "llvm-c/Support.h"
#include "llvm-c/Target.h"
#include <assert.h>
#include <stdio.h>
int handleError(LLVMErrorRef Err) {
char *ErrMsg = LLVMGetErrorMessage(Err);
fprintf(stderr, "Error: %s\n", ErrMsg);
LLVMDisposeErrorMessage(ErrMsg);
return 1;
}
int32_t add(int32_t X, int32_t Y) { return X + Y; }
int32_t mul(int32_t X, int32_t Y) { return X * Y; }
int allowedSymbols(void *Ctx, LLVMOrcSymbolStringPoolEntryRef Sym) {
assert(Ctx && "Cannot call allowedSymbols with a null context");
LLVMOrcSymbolStringPoolEntryRef *AllowList =
(LLVMOrcSymbolStringPoolEntryRef *)Ctx;
// If Sym appears in the allowed list then return true.
LLVMOrcSymbolStringPoolEntryRef *P = AllowList;
while (*P) {
if (Sym == *P)
return 1;
++P;
}
// otherwise return false.
return 0;
}
LLVMOrcThreadSafeModuleRef createDemoModule(void) {
// Create a new ThreadSafeContext and underlying LLVMContext.
LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();
// Get a reference to the underlying LLVMContext.
LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);
// Create a new LLVM module.
LLVMModuleRef M = LLVMModuleCreateWithNameInContext("demo", Ctx);
// Add a "sum" function":
// - Create the function type and function instance.
LLVMTypeRef I32BinOpParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()};
LLVMTypeRef I32BinOpFunctionType =
LLVMFunctionType(LLVMInt32Type(), I32BinOpParamTypes, 2, 0);
LLVMValueRef AddI32Function = LLVMAddFunction(M, "add", I32BinOpFunctionType);
LLVMValueRef MulI32Function = LLVMAddFunction(M, "mul", I32BinOpFunctionType);
LLVMTypeRef MulAddParamTypes[] = {LLVMInt32Type(), LLVMInt32Type(),
LLVMInt32Type()};
LLVMTypeRef MulAddFunctionType =
LLVMFunctionType(LLVMInt32Type(), MulAddParamTypes, 3, 0);
LLVMValueRef MulAddFunction =
LLVMAddFunction(M, "mul_add", MulAddFunctionType);
// - Add a basic block to the function.
LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(MulAddFunction, "entry");
// - Add an IR builder and point it at the end of the basic block.
LLVMBuilderRef Builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(Builder, EntryBB);
// - Get the three function arguments and use them co construct calls to
// 'mul' and 'add':
//
// i32 mul_add(i32 %0, i32 %1, i32 %2) {
// %t = call i32 @mul(i32 %0, i32 %1)
// %r = call i32 @add(i32 %t, i32 %2)
// ret i32 %r
// }
LLVMValueRef SumArg0 = LLVMGetParam(MulAddFunction, 0);
LLVMValueRef SumArg1 = LLVMGetParam(MulAddFunction, 1);
LLVMValueRef SumArg2 = LLVMGetParam(MulAddFunction, 2);
LLVMValueRef MulArgs[] = {SumArg0, SumArg1};
LLVMValueRef MulResult = LLVMBuildCall2(Builder, I32BinOpFunctionType,
MulI32Function, MulArgs, 2, "t");
LLVMValueRef AddArgs[] = {MulResult, SumArg2};
LLVMValueRef AddResult = LLVMBuildCall2(Builder, I32BinOpFunctionType,
AddI32Function, AddArgs, 2, "r");
// - Build the return instruction.
LLVMBuildRet(Builder, AddResult);
// - Free the builder.
LLVMDisposeBuilder(Builder);
// Our demo module is now complete. Wrap it and our ThreadSafeContext in a
// ThreadSafeModule.
LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);
// Dispose of our local ThreadSafeContext value. The underlying LLVMContext
// will be kept alive by our ThreadSafeModule, TSM.
LLVMOrcDisposeThreadSafeContext(TSCtx);
// Return the result.
return TSM;
}
int main(int argc, char *argv[]) {
int MainResult = 0;
// Parse command line arguments and initialize LLVM Core.
LLVMParseCommandLineOptions(argc, (const char **)argv, "");
// Initialize native target codegen and asm printer.
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
// Create the JIT instance.
LLVMOrcLLJITRef J;
{
LLVMErrorRef Err;
if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
MainResult = handleError(Err);
goto llvm_shutdown;
}
}
// Build a filter to allow JIT'd code to only access allowed symbols.
// This filter is optional: If a null value is suppled for the Filter
// argument to LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess then
// all process symbols will be reflected.
LLVMOrcSymbolStringPoolEntryRef AllowList[] = {
LLVMOrcLLJITMangleAndIntern(J, "mul"),
LLVMOrcLLJITMangleAndIntern(J, "add"), 0};
{
LLVMOrcDefinitionGeneratorRef ProcessSymbolsGenerator = 0;
LLVMErrorRef Err;
if ((Err = LLVMOrcCreateDynamicLibrarySearchGeneratorForProcess(
&ProcessSymbolsGenerator, LLVMOrcLLJITGetGlobalPrefix(J),
allowedSymbols, AllowList))) {
MainResult = handleError(Err);
goto jit_cleanup;
}
LLVMOrcJITDylibAddGenerator(LLVMOrcLLJITGetMainJITDylib(J),
ProcessSymbolsGenerator);
}
// Create our demo module.
LLVMOrcThreadSafeModuleRef TSM = createDemoModule();
// Add our demo module to the JIT.
{
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
LLVMErrorRef Err;
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, TSM))) {
// If adding the ThreadSafeModule fails then we need to clean it up
// ourselves. If adding it succeeds the JIT will manage the memory.
LLVMOrcDisposeThreadSafeModule(TSM);
MainResult = handleError(Err);
goto jit_cleanup;
}
}
// Look up the address of our demo entry point.
LLVMOrcJITTargetAddress MulAddAddr;
{
LLVMErrorRef Err;
if ((Err = LLVMOrcLLJITLookup(J, &MulAddAddr, "mul_add"))) {
MainResult = handleError(Err);
goto jit_cleanup;
}
}
// If we made it here then everything succeeded. Execute our JIT'd code.
int32_t (*MulAdd)(int32_t, int32_t, int32_t) =
(int32_t(*)(int32_t, int32_t, int32_t))MulAddAddr;
int32_t Result = MulAdd(3, 4, 5);
// Print the result.
printf("3 * 4 + 5 = %i\n", Result);
jit_cleanup:
// Release all symbol string pool entries that we have allocated. In this
// example that's just our allowed entries.
{
LLVMOrcSymbolStringPoolEntryRef *P = AllowList;
while (*P)
LLVMOrcReleaseSymbolStringPoolEntry(*P++);
}
// Destroy our JIT instance. This will clean up any memory that the JIT has
// taken ownership of. This operation is non-trivial (e.g. it may need to
// JIT static destructors) and may also fail. In that case we want to render
// the error to stderr, but not overwrite any existing return value.
{
LLVMErrorRef Err;
if ((Err = LLVMOrcDisposeLLJIT(J))) {
int NewFailureResult = handleError(Err);
if (MainResult == 0)
MainResult = NewFailureResult;
}
}
llvm_shutdown:
// Shut down LLVM.
LLVMShutdown();
return MainResult;
}

View File

@@ -39,6 +39,14 @@ public:
/// Try to create a COFFPlatform instance, adding the ORC runtime to the
/// given JITDylib.
static Expected<std::unique_ptr<COFFPlatform>>
Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD,
std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime = false,
const char *VCRuntimePath = nullptr,
std::optional<SymbolAliasMap> RuntimeAliases = std::nullopt);
static Expected<std::unique_ptr<COFFPlatform>>
Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
@@ -136,10 +144,14 @@ private:
static bool supportedTarget(const Triple &TT);
COFFPlatform(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
LoadDynamicLibrary LoadDynamicLibrary, bool StaticVCRuntime,
const char *VCRuntimePath, Error &Err);
COFFPlatform(
ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD,
std::unique_ptr<StaticLibraryDefinitionGenerator> OrcRuntimeGenerator,
std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
std::unique_ptr<object::Archive> OrcRuntimeArchive,
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
const char *VCRuntimePath, Error &Err);
// Associate COFFPlatform JIT-side runtime support functions with handlers.
Error associateRuntimeSupportFunctions(JITDylib &PlatformJD);

View File

@@ -37,7 +37,7 @@ class ExecutorProcessControl;
class LLJIT {
template <typename, typename, typename> friend class LLJITBuilderSetters;
friend void setUpGenericLLVMIRPlatform(LLJIT &J);
friend Expected<JITDylibSP> setUpGenericLLVMIRPlatform(LLJIT &J);
public:
/// Initializer support for LLJIT.
@@ -70,6 +70,20 @@ public:
/// Returns a reference to the JITDylib representing the JIT'd main program.
JITDylib &getMainJITDylib() { return *Main; }
/// Returns the ProcessSymbols JITDylib, which by default reflects non-JIT'd
/// symbols in the host process.
///
/// Note: JIT'd code should not be added to the ProcessSymbols JITDylib. Use
/// the main JITDylib or a custom JITDylib instead.
JITDylibSP getProcessSymbolsJITDylib();
/// Returns the Platform JITDylib, which will contain the ORC runtime (if
/// given) and any platform symbols.
///
/// Note: JIT'd code should not be added to the Platform JITDylib. Use the
/// main JITDylib or a custom JITDylib instead.
JITDylibSP getPlatformJITDylib();
/// Returns the JITDylib with the given name, or nullptr if no JITDylib with
/// that name exists.
JITDylib *getJITDylibByName(StringRef Name) {
@@ -108,9 +122,12 @@ public:
/// input or elsewhere in the environment then the client should check
/// (e.g. by calling getJITDylibByName) that the given name is not already in
/// use.
Expected<JITDylib &> createJITDylib(std::string Name) {
return ES->createJITDylib(std::move(Name));
}
Expected<JITDylib &> createJITDylib(std::string Name);
/// Returns the default link order for this LLJIT instance. This link order
/// will be appended to the link order of JITDylibs created by LLJIT's
/// createJITDylib method.
JITDylibSearchOrder defaultLinkOrder() { return DefaultLinks; }
/// Adds an IR module with the given ResourceTracker.
Error addIRModule(ResourceTrackerSP RT, ThreadSafeModule TSM);
@@ -228,8 +245,12 @@ protected:
std::unique_ptr<ExecutionSession> ES;
std::unique_ptr<PlatformSupport> PS;
JITDylib *ProcessSymbols = nullptr;
JITDylib *Platform = nullptr;
JITDylib *Main = nullptr;
JITDylibSearchOrder DefaultLinks;
DataLayout DL;
Triple TT;
std::unique_ptr<ThreadPool> CompileThreads;
@@ -284,12 +305,17 @@ public:
std::function<Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>(
JITTargetMachineBuilder JTMB)>;
using PlatformSetupFunction = std::function<Error(LLJIT &J)>;
using ProcessSymbolsJITDylibSetupFunction =
std::function<Error(JITDylib &JD)>;
using PlatformSetupFunction = unique_function<Expected<JITDylibSP>(LLJIT &J)>;
std::unique_ptr<ExecutorProcessControl> EPC;
std::unique_ptr<ExecutionSession> ES;
std::optional<JITTargetMachineBuilder> JTMB;
std::optional<DataLayout> DL;
bool LinkProcessSymbolsByDefault = true;
ProcessSymbolsJITDylibSetupFunction SetupProcessSymbolsJITDylib;
ObjectLinkingLayerCreator CreateObjectLinkingLayer;
CompileFunctionCreator CreateCompileFunction;
PlatformSetupFunction SetUpPlatform;
@@ -342,6 +368,28 @@ public:
return impl();
}
/// The LinkProcessSymbolsDyDefault flag determines whether the "Process"
/// JITDylib will be added to the default link order at LLJIT construction
/// time. If true, the Process JITDylib will be added as the last item in the
/// default link order. If false (or if the Process JITDylib is disabled via
/// setProcessSymbolsJITDylibSetup) then the Process JITDylib will not appear
/// in the default link order.
SetterImpl &setLinkProcessSymbolsByDefault(bool LinkProcessSymbolsByDefault) {
impl().LinkProcessSymbolsByDefault = LinkProcessSymbolsByDefault;
return impl();
}
/// Set a setup function for the process symbols dylib. If not provided,
/// but LinkProcessSymbolsJITDylibByDefault is true, then the process-symbols
/// JITDylib will be configured with a DynamicLibrarySearchGenerator with a
/// default symbol filter.
SetterImpl &setProcessSymbolsJITDylibSetup(
LLJITBuilderState::ProcessSymbolsJITDylibSetupFunction
SetupProcessSymbolsJITDylib) {
impl().SetupProcessSymbolsJITDylib = std::move(SetupProcessSymbolsJITDylib);
return impl();
}
/// Set an ObjectLinkingLayer creation function.
///
/// If this method is not called, a default creation function will be used
@@ -473,20 +521,49 @@ class LLLazyJITBuilder
public LLLazyJITBuilderSetters<LLLazyJIT, LLLazyJITBuilder,
LLLazyJITBuilderState> {};
/// Configure the LLJIT instance to use orc runtime support.
Error setUpOrcPlatform(LLJIT& J);
/// Configure the LLJIT instance to use orc runtime support. This overload
/// assumes that the client has manually configured a Platform object.
Error setUpOrcPlatformManually(LLJIT &J);
/// Configure the LLJIT instance to use the ORC runtime and the detected
/// native target for the executor.
class ExecutorNativePlatform {
public:
/// Set up using path to Orc runtime.
ExecutorNativePlatform(std::string OrcRuntimePath)
: OrcRuntime(std::move(OrcRuntimePath)) {}
/// Set up using the given memory buffer.
ExecutorNativePlatform(std::unique_ptr<MemoryBuffer> OrcRuntimeMB)
: OrcRuntime(std::move(OrcRuntimeMB)) {}
// TODO: add compiler-rt.
/// Add a path to the VC runtime.
ExecutorNativePlatform &addVCRuntime(std::string VCRuntimePath,
bool StaticVCRuntime) {
VCRuntime = {std::move(VCRuntimePath), StaticVCRuntime};
return *this;
}
Expected<JITDylibSP> operator()(LLJIT &J);
private:
std::variant<std::string, std::unique_ptr<MemoryBuffer>> OrcRuntime;
std::optional<std::pair<std::string, bool>> VCRuntime;
};
/// Configure the LLJIT instance to scrape modules for llvm.global_ctors and
/// llvm.global_dtors variables and (if present) build initialization and
/// deinitialization functions. Platform specific initialization configurations
/// should be preferred where available.
void setUpGenericLLVMIRPlatform(LLJIT &J);
Expected<JITDylibSP> setUpGenericLLVMIRPlatform(LLJIT &J);
/// Configure the LLJIT instance to disable platform support explicitly. This is
/// useful in two cases: for platforms that don't have such requirements and for
/// platforms, that we have no explicit support yet and that don't work well
/// with the generic IR platform.
Error setUpInactivePlatform(LLJIT &J);
Expected<JITDylibSP> setUpInactivePlatform(LLJIT &J);
} // End namespace orc
} // End namespace llvm

View File

@@ -159,12 +159,11 @@ private:
namespace llvm {
namespace orc {
Expected<std::unique_ptr<COFFPlatform>>
COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
const char *VCRuntimePath,
std::optional<SymbolAliasMap> RuntimeAliases) {
Expected<std::unique_ptr<COFFPlatform>> COFFPlatform::Create(
ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
const char *VCRuntimePath, std::optional<SymbolAliasMap> RuntimeAliases) {
// If the target is not supported then bail out immediately.
if (!supportedTarget(ES.getTargetTriple()))
@@ -174,6 +173,22 @@ COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
auto &EPC = ES.getExecutorProcessControl();
auto GeneratorArchive =
object::Archive::create(OrcRuntimeArchiveBuffer->getMemBufferRef());
if (!GeneratorArchive)
return GeneratorArchive.takeError();
auto OrcRuntimeArchiveGenerator = StaticLibraryDefinitionGenerator::Create(
ObjLinkingLayer, nullptr, std::move(*GeneratorArchive));
if (!OrcRuntimeArchiveGenerator)
return OrcRuntimeArchiveGenerator.takeError();
// We need a second instance of the archive (for now) for the Platform. We
// can `cantFail` this call, since if it were going to fail it would have
// failed above.
auto RuntimeArchive = cantFail(
object::Archive::create(OrcRuntimeArchiveBuffer->getMemBufferRef()));
// Create default aliases if the caller didn't supply any.
if (!RuntimeAliases)
RuntimeAliases = standardPlatformAliases(ES);
@@ -199,13 +214,30 @@ COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
// Create the instance.
Error Err = Error::success();
auto P = std::unique_ptr<COFFPlatform>(new COFFPlatform(
ES, ObjLinkingLayer, PlatformJD, OrcRuntimePath,
ES, ObjLinkingLayer, PlatformJD, std::move(*OrcRuntimeArchiveGenerator),
std::move(OrcRuntimeArchiveBuffer), std::move(RuntimeArchive),
std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath, Err));
if (Err)
return std::move(Err);
return std::move(P);
}
Expected<std::unique_ptr<COFFPlatform>>
COFFPlatform::Create(ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
const char *VCRuntimePath,
std::optional<SymbolAliasMap> RuntimeAliases) {
auto ArchiveBuffer = MemoryBuffer::getFile(OrcRuntimePath);
if (!ArchiveBuffer)
return createFileError(OrcRuntimePath, ArchiveBuffer.getError());
return Create(ES, ObjLinkingLayer, PlatformJD, std::move(*ArchiveBuffer),
std::move(LoadDynLibrary), StaticVCRuntime, VCRuntimePath,
std::move(RuntimeAliases));
}
Expected<MemoryBufferRef> COFFPlatform::getPerJDObjectFile() {
auto PerJDObj = OrcRuntimeArchive->findSym("__orc_rt_coff_per_jd_marker");
if (!PerJDObj)
@@ -349,37 +381,22 @@ bool COFFPlatform::supportedTarget(const Triple &TT) {
}
}
COFFPlatform::COFFPlatform(ExecutionSession &ES,
ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD, const char *OrcRuntimePath,
LoadDynamicLibrary LoadDynamicLibrary,
bool StaticVCRuntime, const char *VCRuntimePath,
Error &Err)
COFFPlatform::COFFPlatform(
ExecutionSession &ES, ObjectLinkingLayer &ObjLinkingLayer,
JITDylib &PlatformJD,
std::unique_ptr<StaticLibraryDefinitionGenerator> OrcRuntimeGenerator,
std::unique_ptr<MemoryBuffer> OrcRuntimeArchiveBuffer,
std::unique_ptr<object::Archive> OrcRuntimeArchive,
LoadDynamicLibrary LoadDynLibrary, bool StaticVCRuntime,
const char *VCRuntimePath, Error &Err)
: ES(ES), ObjLinkingLayer(ObjLinkingLayer),
LoadDynLibrary(std::move(LoadDynamicLibrary)),
LoadDynLibrary(std::move(LoadDynLibrary)),
OrcRuntimeArchiveBuffer(std::move(OrcRuntimeArchiveBuffer)),
OrcRuntimeArchive(std::move(OrcRuntimeArchive)),
StaticVCRuntime(StaticVCRuntime),
COFFHeaderStartSymbol(ES.intern("__ImageBase")) {
ErrorAsOutParameter _(&Err);
// Create a generator for the ORC runtime archive.
auto OrcRuntimeArchiveGenerator =
StaticLibraryDefinitionGenerator::Load(ObjLinkingLayer, OrcRuntimePath);
if (!OrcRuntimeArchiveGenerator) {
Err = OrcRuntimeArchiveGenerator.takeError();
return;
}
auto ArchiveBuffer = MemoryBuffer::getFile(OrcRuntimePath);
if (!ArchiveBuffer) {
Err = createFileError(OrcRuntimePath, ArchiveBuffer.getError());
return;
}
OrcRuntimeArchiveBuffer = std::move(*ArchiveBuffer);
OrcRuntimeArchive =
std::make_unique<object::Archive>(*OrcRuntimeArchiveBuffer, Err);
if (Err)
return;
Bootstrapping.store(true);
ObjLinkingLayer.addPlugin(std::make_unique<COFFPlatformPlugin>(*this));
@@ -392,7 +409,7 @@ COFFPlatform::COFFPlatform(ExecutionSession &ES,
}
VCRuntimeBootstrap = std::move(*VCRT);
for (auto &Lib : (*OrcRuntimeArchiveGenerator)->getImportedDynamicLibraries())
for (auto &Lib : OrcRuntimeGenerator->getImportedDynamicLibraries())
DylibsToPreload.insert(Lib);
auto ImportedLibs =
@@ -406,7 +423,7 @@ COFFPlatform::COFFPlatform(ExecutionSession &ES,
for (auto &Lib : *ImportedLibs)
DylibsToPreload.insert(Lib);
PlatformJD.addGenerator(std::move(*OrcRuntimeArchiveGenerator));
PlatformJD.addGenerator(std::move(OrcRuntimeGenerator));
// PlatformJD hasn't been set up by the platform yet (since we're creating
// the platform now), so set it up.
@@ -416,10 +433,10 @@ COFFPlatform::COFFPlatform(ExecutionSession &ES,
}
for (auto& Lib : DylibsToPreload)
if (auto E2 = LoadDynLibrary(PlatformJD, Lib)) {
Err = std::move(E2);
return;
}
if (auto E2 = this->LoadDynLibrary(PlatformJD, Lib)) {
Err = std::move(E2);
return;
}
if (StaticVCRuntime)
if (auto E2 = VCRuntimeBootstrap->initializeStaticVCRuntime(PlatformJD)) {

View File

@@ -9,6 +9,8 @@
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/COFFPlatform.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"
@@ -99,10 +101,16 @@ public:
ORC_RT_RTLD_GLOBAL = 0x8
};
if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlopen_wrapper")) {
return J.getExecutionSession().callSPSWrapper<SPSDLOpenSig>(
*WrapperAddr, DSOHandles[&JD], JD.getName(),
int32_t(ORC_RT_RTLD_LAZY));
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_dlopen_wrapper"))) {
return ES.callSPSWrapper<SPSDLOpenSig>(WrapperAddr->getAddress(),
DSOHandles[&JD], JD.getName(),
int32_t(ORC_RT_RTLD_LAZY));
} else
return WrapperAddr.takeError();
}
@@ -111,10 +119,16 @@ public:
using llvm::orc::shared::SPSExecutorAddr;
using SPSDLCloseSig = int32_t(SPSExecutorAddr);
if (auto WrapperAddr = J.lookup("__orc_rt_jit_dlclose_wrapper")) {
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, result, DSOHandles[&JD]);
WrapperAddr->getAddress(), result, DSOHandles[&JD]);
if (E)
return E;
else if (result)
@@ -177,7 +191,7 @@ private:
/// some runtime API, including __cxa_atexit, dlopen, and dlclose.
class GenericLLVMIRPlatformSupport : public LLJIT::PlatformSupport {
public:
GenericLLVMIRPlatformSupport(LLJIT &J)
GenericLLVMIRPlatformSupport(LLJIT &J, JITDylib &PlatformJD)
: J(J), InitFunctionPrefix(J.mangle("__orc_init_func.")),
DeInitFunctionPrefix(J.mangle("__orc_deinit_func.")) {
@@ -194,10 +208,9 @@ public:
StdInterposes[J.mangleAndIntern("__lljit.cxa_atexit_helper")] = {
ExecutorAddr::fromPtr(registerCxaAtExitHelper), JITSymbolFlags()};
cantFail(
J.getMainJITDylib().define(absoluteSymbols(std::move(StdInterposes))));
cantFail(setupJITDylib(J.getMainJITDylib()));
cantFail(J.addIRModule(J.getMainJITDylib(), createPlatformRuntimeModule()));
cantFail(PlatformJD.define(absoluteSymbols(std::move(StdInterposes))));
cantFail(setupJITDylib(PlatformJD));
cantFail(J.addIRModule(PlatformJD, createPlatformRuntimeModule()));
}
ExecutionSession &getExecutionSession() { return J.getExecutionSession(); }
@@ -754,6 +767,19 @@ LLJIT::~LLJIT() {
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)
@@ -893,13 +919,6 @@ LLJIT::LLJIT(LLJITBuilderState &S, Error &Err)
}
}
if (auto MainOrErr = this->ES->createJITDylib("main"))
Main = &*MainOrErr;
else {
Err = MainOrErr.takeError();
return;
}
if (S.DL)
DL = std::move(*S.DL);
else if (auto DLOrErr = S.JTMB->getDefaultDataLayoutForTarget())
@@ -947,10 +966,47 @@ LLJIT::LLJIT(LLJITBuilderState &S, Error &Err)
});
}
if (S.SetUpPlatform)
Err = S.SetUpPlatform(*this);
else
setUpGenericLLVMIRPlatform(*this);
if (S.LinkProcessSymbolsByDefault && !S.SetupProcessSymbolsJITDylib)
S.SetupProcessSymbolsJITDylib = [this](JITDylib &JD) -> Error {
auto G = orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
DL.getGlobalPrefix());
if (!G)
return G.takeError();
JD.addGenerator(std::move(*G));
return Error::success();
};
if (S.SetupProcessSymbolsJITDylib) {
ProcessSymbols = &ES->createBareJITDylib("<Process Symbols>");
if (auto Err2 = S.SetupProcessSymbolsJITDylib(*ProcessSymbols)) {
Err = std::move(Err2);
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 {
@@ -976,24 +1032,136 @@ Error LLJIT::applyDataLayout(Module &M) {
return Error::success();
}
Error setUpOrcPlatform(LLJIT& J) {
LLVM_DEBUG(
{ dbgs() << "Setting up orc platform support for LLJIT\n"; });
J.setPlatformSupport(std::make_unique<ORCPlatformSupport>(J));
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();
}
void setUpGenericLLVMIRPlatform(LLJIT &J) {
class LoadAndLinkDynLibrary {
public:
LoadAndLinkDynLibrary(LLJIT &J) : J(J) {}
Error operator()(JITDylib &JD, StringRef DLLName) {
if (!DLLName.endswith_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>(
"SetUpTargetPlatform 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(
ES, *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(ES, *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(ES, *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"; });
J.setPlatformSupport(std::make_unique<GenericLLVMIRPlatformSupport>(J));
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);
J.setPlatformSupport(
std::make_unique<GenericLLVMIRPlatformSupport>(J, PlatformJD));
return &PlatformJD;
}
Error setUpInactivePlatform(LLJIT &J) {
Expected<JITDylibSP> setUpInactivePlatform(LLJIT &J) {
LLVM_DEBUG(
{ dbgs() << "Explicitly deactivated platform support for LLJIT\n"; });
J.setPlatformSupport(std::make_unique<InactivePlatformSupport>());
return Error::success();
return nullptr;
}
Error LLLazyJITBuilderState::prepareForConstruction() {

View File

@@ -1,8 +1,8 @@
; LoongArch does not support emulated tls.
; UNSUPPORTED: target=loongarch{{.*}}
; RUN: not lli -no-process-syms -emulated-tls -jit-kind=orc-lazy %s 2>&1 \
; RUN: | FileCheck %s
; RUN: not lli -no-process-syms -lljit-platform=Inactive -emulated-tls \
; RUN: -jit-kind=orc-lazy %s 2>&1 | FileCheck %s
;
; Test that emulated-tls does not generate any unexpected errors.
;

View File

@@ -27,7 +27,6 @@
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
#include "llvm/ExecutionEngine/Orc/DebugUtils.h"
#include "llvm/ExecutionEngine/Orc/ELFNixPlatform.h"
#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"
#include "llvm/ExecutionEngine/Orc/EPCEHFrameRegistrar.h"
@@ -35,7 +34,6 @@
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/MachOPlatform.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/Orc/SimpleRemoteEPC.h"
#include "llvm/ExecutionEngine/Orc/SymbolStringPool.h"
@@ -236,20 +234,22 @@ namespace {
cl::desc("Do not resolve lli process symbols in JIT'd code"),
cl::init(false));
enum class LLJITPlatform { Inactive, DetectHost, ORC, GenericIR };
enum class LLJITPlatform { Inactive, Auto, ExecutorNative, GenericIR };
cl::opt<LLJITPlatform>
Platform("lljit-platform", cl::desc("Platform to use with LLJIT"),
cl::init(LLJITPlatform::DetectHost),
cl::values(clEnumValN(LLJITPlatform::DetectHost, "DetectHost",
"Select based on JIT target triple"),
clEnumValN(LLJITPlatform::ORC, "ORC",
"Use ORCPlatform with the ORC runtime"),
clEnumValN(LLJITPlatform::GenericIR, "GenericIR",
"Use LLJITGenericIRPlatform"),
clEnumValN(LLJITPlatform::Inactive, "Inactive",
"Disable platform support explicitly")),
cl::Hidden);
cl::opt<LLJITPlatform> Platform(
"lljit-platform", cl::desc("Platform to use with LLJIT"),
cl::init(LLJITPlatform::Auto),
cl::values(clEnumValN(LLJITPlatform::Auto, "Auto",
"Like 'ExecutorNative' if ORC runtime "
"provided, otherwise like 'GenericIR'"),
clEnumValN(LLJITPlatform::ExecutorNative, "ExecutorNative",
"Use the native platform for the executor."
"Requires -orc-runtime"),
clEnumValN(LLJITPlatform::GenericIR, "GenericIR",
"Use LLJITGenericIRPlatform"),
clEnumValN(LLJITPlatform::Inactive, "Inactive",
"Disable platform support explicitly")),
cl::Hidden);
enum class DumpKind {
NoDump,
@@ -864,6 +864,9 @@ int runOrcJIT(const char *ProgName) {
.setRelocationModel(codegen::getExplicitRelocModel())
.setCodeModel(codegen::getExplicitCodeModel());
// Link process symbols unless NoProcessSymbols is set.
Builder.setLinkProcessSymbolsByDefault(!NoProcessSymbols);
// FIXME: Setting a dummy call-through manager in non-lazy mode prevents the
// JIT builder to instantiate a default (which would fail with an error for
// unsupported architectures).
@@ -905,17 +908,15 @@ int runOrcJIT(const char *ProgName) {
// Set up LLJIT platform.
LLJITPlatform P = Platform;
if (P == LLJITPlatform::DetectHost) {
if (JITLinker == JITLinkerKind::JITLink && !OrcRuntime.empty() &&
(TT->isOSBinFormatMachO() || TT->isOSBinFormatELF()))
P = LLJITPlatform::ORC;
else
P = LLJITPlatform::GenericIR;
}
if (P == LLJITPlatform::Auto)
P = OrcRuntime.empty() ? LLJITPlatform::GenericIR
: LLJITPlatform::ExecutorNative;
switch (P) {
case LLJITPlatform::ORC:
Builder.setPlatformSetUp(orc::setUpOrcPlatform);
case LLJITPlatform::ExecutorNative: {
Builder.setPlatformSetUp(orc::ExecutorNativePlatform(OrcRuntime));
break;
}
case LLJITPlatform::GenericIR:
// Nothing to do: LLJITBuilder will use this by default.
break;
@@ -934,7 +935,7 @@ int runOrcJIT(const char *ProgName) {
Builder.setObjectLinkingLayerCreator([&EPC, &P](orc::ExecutionSession &ES,
const Triple &TT) {
auto L = std::make_unique<orc::ObjectLinkingLayer>(ES, EPC->getMemMgr());
if (P != LLJITPlatform::ORC) {
if (P != LLJITPlatform::ExecutorNative) {
L->addPlugin(std::make_unique<orc::EHFrameRegistrationPlugin>(
ES, ExitOnErr(orc::EPCEHFrameRegistrar::Create(ES))));
L->addPlugin(std::make_unique<orc::DebugObjectManagerPlugin>(
@@ -982,46 +983,12 @@ int runOrcJIT(const char *ProgName) {
return TSM;
});
orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout());
// Unless they've been explicitly disabled, make process symbols available to
// JIT'd code.
if (!NoProcessSymbols)
J->getMainJITDylib().addGenerator(
ExitOnErr(orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
J->getDataLayout().getGlobalPrefix(),
[MainName = Mangle("main")](const orc::SymbolStringPtr &Name) {
return Name != MainName;
})));
if (GenerateBuiltinFunctions.size() > 0)
if (GenerateBuiltinFunctions.size() > 0) {
// Add LLI builtins.
orc::MangleAndInterner Mangle(J->getExecutionSession(), J->getDataLayout());
J->getMainJITDylib().addGenerator(
std::make_unique<LLIBuiltinFunctionGenerator>(GenerateBuiltinFunctions,
Mangle));
if (P == LLJITPlatform::ORC) {
if (auto *OLL = llvm::dyn_cast<llvm::orc::ObjectLinkingLayer>(ObjLayer)) {
auto &ES = J->getExecutionSession();
if (TT->isOSBinFormatMachO()) {
if (auto P = llvm::orc::MachOPlatform::Create(
ES, *OLL, J->getMainJITDylib(), OrcRuntime.c_str()))
ES.setPlatform(std::move(*P));
else
ExitOnErr(P.takeError());
} else if (TT->isOSBinFormatELF()) {
if (auto P = llvm::orc::ELFNixPlatform::Create(
ES, *OLL, J->getMainJITDylib(), OrcRuntime.c_str()))
ES.setPlatform(std::move(*P));
else
ExitOnErr(P.takeError());
} else {
errs() << "No ORC platform support\n";
exit(1);
}
} else {
errs() << "ORC platform requires JITLink\n";
exit(1);
}
}
// Regular modules are greedy: They materialize as a whole and trigger