Files
clang-p2996/llvm/lib/ExecutionEngine/Orc/ExecutorProcessControl.cpp
Sunho Kim 7260cdd2e1 [ORC][COFF] Introduce COFFVCRuntimeBootstrapper.
Introduces COFFVCRuntimeBootstrapper that loads/initialize vc runtime libraries. In COFF, we *must* jit-link vc runtime libraries as COFF relocation types have no proper way to deal with out-of-reach data symbols ragardless of linking mode. (even dynamic version msvcrt.lib have tons of static data symbols that must be jit-linked) This class tries to load vc runtime library files from msvc installations with an option to override the path.

There are some complications when dealing with static version of vc runtimes. First, they need static initializers to be ran that requires COFFPlatform support but orc runtime will not be usable before vc runtimes are fully initialized. (as orc runtime will use msvc stl libraries) COFFPlatform that will be introduced in a following up patch will collect static initializers and run them manually in host before boostrapping itself. So, the user will have to do the following.
1. Create COFFPlatform that addes static initializer collecting passes.
2. LoadVCRuntime
3. InitializeVCRuntime
4. COFFPlatform.bootstrap()
Second, the internal crt initialization function had to be reimplemented in orc side. There are other ways of doing this, but this is the simplest implementation that makes platform fully responsible for static initializer. The complication comes from the fact that crt initialization functions (such as acrt_initialize or dllmain_crt_process_attach) actually run all static initializers by traversing from `__xi_a` symbol to `__xi_z`. This requires symbols to be contiguously allocated in sections alphabetically sorted in memory, which is not possible right now and not practical in jit setting. We might ignore emission of `__xi_a` and `__xi_z` symbol and allocate them ourselves, but we have to take extra care after orc runtime boostrap has been done -- as that point orc runtime should be the one running the static initializers.

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D130456
2022-08-11 15:27:47 +09:00

210 lines
7.0 KiB
C++

//===---- ExecutorProcessControl.cpp -- Executor process control APIs -----===//
//
// 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/ExecutorProcessControl.h"
#include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Process.h"
#define DEBUG_TYPE "orc"
namespace llvm {
namespace orc {
ExecutorProcessControl::MemoryAccess::~MemoryAccess() = default;
ExecutorProcessControl::~ExecutorProcessControl() = default;
SelfExecutorProcessControl::SelfExecutorProcessControl(
std::shared_ptr<SymbolStringPool> SSP, std::unique_ptr<TaskDispatcher> D,
Triple TargetTriple, unsigned PageSize,
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr)
: ExecutorProcessControl(std::move(SSP), std::move(D)) {
OwnedMemMgr = std::move(MemMgr);
if (!OwnedMemMgr)
OwnedMemMgr = std::make_unique<jitlink::InProcessMemoryManager>(
sys::Process::getPageSizeEstimate());
this->TargetTriple = std::move(TargetTriple);
this->PageSize = PageSize;
this->MemMgr = OwnedMemMgr.get();
this->MemAccess = this;
this->JDI = {ExecutorAddr::fromPtr(jitDispatchViaWrapperFunctionManager),
ExecutorAddr::fromPtr(this)};
if (this->TargetTriple.isOSBinFormatMachO())
GlobalManglingPrefix = '_';
}
Expected<std::unique_ptr<SelfExecutorProcessControl>>
SelfExecutorProcessControl::Create(
std::shared_ptr<SymbolStringPool> SSP,
std::unique_ptr<TaskDispatcher> D,
std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr) {
if (!SSP)
SSP = std::make_shared<SymbolStringPool>();
if (!D) {
#if LLVM_ENABLE_THREADS
D = std::make_unique<DynamicThreadPoolTaskDispatcher>();
#else
D = std::make_unique<InPlaceTaskDispatcher>();
#endif
}
auto PageSize = sys::Process::getPageSize();
if (!PageSize)
return PageSize.takeError();
Triple TT(sys::getProcessTriple());
return std::make_unique<SelfExecutorProcessControl>(
std::move(SSP), std::move(D), std::move(TT), *PageSize,
std::move(MemMgr));
}
Expected<tpctypes::DylibHandle>
SelfExecutorProcessControl::loadDylib(const char *DylibPath) {
std::string ErrMsg;
auto Dylib = std::make_unique<sys::DynamicLibrary>(
sys::DynamicLibrary::getPermanentLibrary(DylibPath, &ErrMsg));
if (!Dylib->isValid())
return make_error<StringError>(std::move(ErrMsg), inconvertibleErrorCode());
DynamicLibraries.push_back(std::move(Dylib));
return pointerToJITTargetAddress(DynamicLibraries.back().get());
}
Expected<std::vector<tpctypes::LookupResult>>
SelfExecutorProcessControl::lookupSymbols(ArrayRef<LookupRequest> Request) {
std::vector<tpctypes::LookupResult> R;
for (auto &Elem : Request) {
auto *Dylib = jitTargetAddressToPointer<sys::DynamicLibrary *>(Elem.Handle);
assert(llvm::any_of(DynamicLibraries,
[=](const std::unique_ptr<sys::DynamicLibrary> &DL) {
return DL.get() == Dylib;
}) &&
"Invalid handle");
R.push_back(std::vector<JITTargetAddress>());
for (auto &KV : Elem.Symbols) {
auto &Sym = KV.first;
std::string Tmp((*Sym).data() + !!GlobalManglingPrefix,
(*Sym).size() - !!GlobalManglingPrefix);
void *Addr = Dylib->getAddressOfSymbol(Tmp.c_str());
if (!Addr && KV.second == SymbolLookupFlags::RequiredSymbol) {
// FIXME: Collect all failing symbols before erroring out.
SymbolNameVector MissingSymbols;
MissingSymbols.push_back(Sym);
return make_error<SymbolsNotFound>(SSP, std::move(MissingSymbols));
}
R.back().push_back(pointerToJITTargetAddress(Addr));
}
}
return R;
}
Expected<int32_t>
SelfExecutorProcessControl::runAsMain(ExecutorAddr MainFnAddr,
ArrayRef<std::string> Args) {
using MainTy = int (*)(int, char *[]);
return orc::runAsMain(MainFnAddr.toPtr<MainTy>(), Args);
}
Expected<int32_t>
SelfExecutorProcessControl::runAsVoidFunction(ExecutorAddr VoidFnAddr) {
using VoidTy = int (*)();
return orc::runAsVoidFunction(VoidFnAddr.toPtr<VoidTy>());
}
Expected<int32_t>
SelfExecutorProcessControl::runAsIntFunction(ExecutorAddr IntFnAddr, int Arg) {
using IntTy = int (*)(int);
return orc::runAsIntFunction(IntFnAddr.toPtr<IntTy>(), Arg);
}
void SelfExecutorProcessControl::callWrapperAsync(ExecutorAddr WrapperFnAddr,
IncomingWFRHandler SendResult,
ArrayRef<char> ArgBuffer) {
using WrapperFnTy =
shared::CWrapperFunctionResult (*)(const char *Data, size_t Size);
auto *WrapperFn = WrapperFnAddr.toPtr<WrapperFnTy>();
SendResult(WrapperFn(ArgBuffer.data(), ArgBuffer.size()));
}
Error SelfExecutorProcessControl::disconnect() {
D->shutdown();
return Error::success();
}
void SelfExecutorProcessControl::writeUInt8sAsync(
ArrayRef<tpctypes::UInt8Write> Ws, WriteResultFn OnWriteComplete) {
for (auto &W : Ws)
*W.Addr.toPtr<uint8_t *>() = W.Value;
OnWriteComplete(Error::success());
}
void SelfExecutorProcessControl::writeUInt16sAsync(
ArrayRef<tpctypes::UInt16Write> Ws, WriteResultFn OnWriteComplete) {
for (auto &W : Ws)
*W.Addr.toPtr<uint16_t *>() = W.Value;
OnWriteComplete(Error::success());
}
void SelfExecutorProcessControl::writeUInt32sAsync(
ArrayRef<tpctypes::UInt32Write> Ws, WriteResultFn OnWriteComplete) {
for (auto &W : Ws)
*W.Addr.toPtr<uint32_t *>() = W.Value;
OnWriteComplete(Error::success());
}
void SelfExecutorProcessControl::writeUInt64sAsync(
ArrayRef<tpctypes::UInt64Write> Ws, WriteResultFn OnWriteComplete) {
for (auto &W : Ws)
*W.Addr.toPtr<uint64_t *>() = W.Value;
OnWriteComplete(Error::success());
}
void SelfExecutorProcessControl::writeBuffersAsync(
ArrayRef<tpctypes::BufferWrite> Ws, WriteResultFn OnWriteComplete) {
for (auto &W : Ws)
memcpy(W.Addr.toPtr<char *>(), W.Buffer.data(), W.Buffer.size());
OnWriteComplete(Error::success());
}
shared::CWrapperFunctionResult
SelfExecutorProcessControl::jitDispatchViaWrapperFunctionManager(
void *Ctx, const void *FnTag, const char *Data, size_t Size) {
LLVM_DEBUG({
dbgs() << "jit-dispatch call with tag " << FnTag << " and " << Size
<< " byte payload.\n";
});
std::promise<shared::WrapperFunctionResult> ResultP;
auto ResultF = ResultP.get_future();
static_cast<SelfExecutorProcessControl *>(Ctx)
->getExecutionSession()
.runJITDispatchHandler(
[ResultP = std::move(ResultP)](
shared::WrapperFunctionResult Result) mutable {
ResultP.set_value(std::move(Result));
},
pointerToJITTargetAddress(FnTag), {Data, Size});
return ResultF.get().release();
}
} // end namespace orc
} // end namespace llvm