Go to the documentation of this file.
13 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
14 #define LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
27 template <
typename OrcRPCTPCImplT>
31 std::unique_ptr<char[]> Mem;
37 uint64_t AllocatedSize = 0;
48 : Parent(Parent), HostAllocs(
std::
move(HostAllocs)),
49 TargetAllocs(
std::
move(TargetAllocs)) {
51 "HostAllocs size should match TargetAllocs");
55 assert(TargetAllocs.
empty() &&
"failed to deallocate");
59 auto I = HostAllocs.
find(Seg);
60 assert(
I != HostAllocs.
end() &&
"No host allocation for segment");
62 return {HA.Mem.get(),
static_cast<size_t>(HA.Size)};
66 auto I = TargetAllocs.
find(Seg);
67 assert(
I != TargetAllocs.
end() &&
"No target allocation for segment");
68 return I->second.Address;
73 std::vector<tpctypes::BufferWrite> BufferWrites;
76 for (
auto &KV : HostAllocs) {
78 "No target allocation for buffer");
80 auto &
TA = TargetAllocs[KV.first];
81 BufferWrites.push_back({
TA.Address,
StringRef(HA.Mem.get(), HA.Size)});
84 TA.Address,
TA.AllocatedSize});
88 dbgs() <<
"finalizeAsync " << (
void *)
this <<
":\n";
89 auto FMRI = FMR.begin();
90 for (
auto &
B : BufferWrites) {
91 auto Prot = FMRI->Prot;
93 dbgs() <<
" Writing " <<
formatv(
"{0:x16}",
B.Buffer.size())
97 <<
" segment: local " << (
const void *)
B.Buffer.data()
98 <<
" -> target " <<
formatv(
"{0:x16}",
B.Address) <<
"\n";
102 Parent.Parent.getMemoryAccess().writeBuffers(BufferWrites)) {
109 Parent.getEndpoint().template callAsync<orcrpctpc::FinalizeMem>(
112 std::thread([OF = std::move(OF),
113 Err3 = std::move(Err2)]() mutable {
115 "orc", { dbgs() <<
" finalizeAsync complete\n"; });
122 Parent.getEndpoint().abandonPendingResponses();
126 dbgs() <<
"Leaving finalizeAsync (finalization may continue in "
133 for (
auto &KV : TargetAllocs)
136 KV.second.Address, KV.second.AllocatedSize});
137 TargetAllocs.clear();
139 return Parent.getEndpoint().template callB<orcrpctpc::ReleaseMem>(RMR);
156 for (
auto &KV : Request) {
158 "Content size is out-of-range for host");
162 KV.second.getContentSize() + KV.second.getZeroFillSize(),
163 KV.second.getAlignment()});
164 HostAllocs[KV.first] = {
165 std::make_unique<char[]>(KV.second.getContentSize()),
166 KV.second.getContentSize()};
170 dbgs() <<
"Orc remote memmgr got request:\n";
171 for (
auto &KV : Request)
172 dbgs() <<
" permissions: "
176 <<
", content size: "
177 <<
formatv(
"{0:x16}", KV.second.getContentSize())
178 <<
" + zero-fill-size: "
179 <<
formatv(
"{0:x16}", KV.second.getZeroFillSize())
180 <<
", align: " << KV.second.getAlignment() <<
"\n";
186 auto TmpTargetAllocs =
187 Parent.getEndpoint().template callB<orcrpctpc::ReserveMem>(RMR);
188 if (!TmpTargetAllocs)
189 return TmpTargetAllocs.takeError();
191 if (TmpTargetAllocs->size() != RMR.size())
192 return make_error<StringError>(
193 "Number of target allocations does not match request",
197 for (
auto &
E : *TmpTargetAllocs)
199 E.Address,
E.AllocatedSize};
202 auto HAI = HostAllocs.
begin();
203 for (
auto &KV : TargetAllocs)
204 dbgs() <<
" permissions: "
208 <<
" assigned local " << (
void *)HAI->second.Mem.get()
209 <<
", target " <<
formatv(
"{0:x16}", KV.second.Address) <<
"\n";
212 return std::make_unique<OrcRPCAllocation>(*
this,
std::move(HostAllocs),
219 decltype(std::declval<OrcRPCTPCImplT>().getEndpoint()) getEndpoint() {
220 return Parent.getEndpoint();
223 OrcRPCTPCImplT &Parent;
228 template <
typename OrcRPCTPCImplT>
235 writeViaRPC<orcrpctpc::WriteUInt8s>(Ws,
std::move(OnWriteComplete));
240 writeViaRPC<orcrpctpc::WriteUInt16s>(Ws,
std::move(OnWriteComplete));
245 writeViaRPC<orcrpctpc::WriteUInt32s>(Ws,
std::move(OnWriteComplete));
250 writeViaRPC<orcrpctpc::WriteUInt64s>(Ws,
std::move(OnWriteComplete));
255 writeViaRPC<orcrpctpc::WriteBuffers>(Ws,
std::move(OnWriteComplete));
259 template <
typename WriteRPCFunction,
typename WriteElementT>
261 if (
auto Err = Parent.getEndpoint().template callAsync<WriteRPCFunction>(
263 OWC(std::move(Err2));
264 return Error::success();
268 Parent.getEndpoint().abandonPendingResponses();
272 OrcRPCTPCImplT &Parent;
276 template <
typename RPCEndpo
intT>
286 ReportError(
std::
move(ReportError)), EP(EP) {}
294 dbgs() <<
"Loading dylib \"" << (DylibPath ? DylibPath :
"") <<
"\" ";
296 dbgs() <<
"(process symbols)";
301 auto H = EP.template callB<orcrpctpc::LoadDylib>(DylibPath);
304 dbgs() <<
" got handle " <<
formatv(
"{0:x16}", *
H) <<
"\n";
306 dbgs() <<
" error, unable to load\n";
313 std::vector<orcrpctpc::RemoteLookupRequest> RR;
314 for (
auto &
E : Request) {
316 RR.back().first =
E.Handle;
317 for (
auto &KV :
E.Symbols)
318 RR.back().second.push_back(
320 KV.second == SymbolLookupFlags::WeaklyReferencedSymbol});
323 dbgs() <<
"Compound lookup:\n";
324 for (
auto &R : Request) {
325 dbgs() <<
" In " <<
formatv(
"{0:x16}", R.Handle) <<
": {";
327 for (
auto &KV : R.Symbols) {
328 dbgs() << (
First ?
"" :
",") <<
" " << *KV.first;
334 return EP.template callB<orcrpctpc::LookupSymbols>(RR);
340 dbgs() <<
"Running as main: " <<
formatv(
"{0:x16}", MainFnAddr)
342 for (
unsigned I = 0;
I !=
Args.size(); ++
I)
343 dbgs() << (
I ?
"," :
"") <<
" \"" <<
Args[
I] <<
"\"";
346 auto Result = EP.template callB<orcrpctpc::RunMain>(MainFnAddr,
Args);
348 dbgs() <<
" call to " <<
formatv(
"{0:x16}", MainFnAddr);
350 dbgs() <<
" returned result " << *Result <<
"\n";
352 dbgs() <<
" failed\n";
361 dbgs() <<
"Running as wrapper function "
362 <<
formatv(
"{0:x16}", WrapperFnAddr) <<
" with "
363 <<
formatv(
"{0:x16}", ArgBuffer.
size()) <<
" argument buffer\n";
366 EP.template callB<orcrpctpc::RunWrapper>(WrapperFnAddr, ArgBuffer);
373 return EP.template callAsync<orcrpctpc::CloseConnection>(
378 std::promise<MSVCPError>
P;
379 auto F =
P.get_future();
380 if (
auto Err = closeConnection([&](
Error Err2) ->
Error {
384 EP.abandonAllPendingResponses();
394 if (
auto TripleOrErr = EP.template callB<orcrpctpc::GetTargetTriple>())
395 TargetTriple =
Triple(*TripleOrErr);
397 return TripleOrErr.takeError();
399 if (
auto PageSizeOrErr = EP.template callB<orcrpctpc::GetPageSize>())
402 return PageSizeOrErr.takeError();
408 ErrorReporter ReportError;
415 #endif // LLVM_EXECUTIONENGINE_ORC_ORCRPCTARGETPROCESSCONTROL_H
Expected< std::unique_ptr< Allocation > > allocate(const jitlink::JITLinkDylib *JD, const SegmentsRequestMap &Request) override
Create an Allocation object.
This class represents lattice values for constants.
OrcRPCTPCMemoryAccess(OrcRPCTPCImplT &Parent)
This currently compiles esp xmm0 movsd esp eax eax esp ret We should use not the dag combiner This is because dagcombine2 needs to be able to see through the X86ISD::Wrapper which DAGCombine can t really do The code for turning x load into a single vector load is target independent and should be moved to the dag combiner The code for turning x load into a vector load can only handle a direct load from a global or a direct load from the stack It should be generalized to handle any load from P
APIs for manipulating memory in the target process.
std::vector< ReleaseOrFinalizeMemRequestElement > ReleaseOrFinalizeMemRequest
static ErrorSuccess success()
Create a success value.
Triple - Helper class for working with autoconf configuration names.
Expected< std::vector< tpctypes::LookupResult > > lookupSymbols(ArrayRef< LookupRequest > Request) override
Search for symbols in the target process.
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Manages allocations of JIT memory.
Tagged union holding either a T or a Error.
void writeUInt16s(ArrayRef< tpctypes::UInt16Write > Ws, WriteResultFn OnWriteComplete) override
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
#define DEBUG_WITH_TYPE(TYPE, X)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
void writeUInt8s(ArrayRef< tpctypes::UInt8Write > Ws, WriteResultFn OnWriteComplete) override
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static Error reportError(StringRef Message)
~OrcRPCAllocation() override
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
into llvm powi allowing the code generator to produce balanced multiplication trees First
void finalizeAsync(FinalizeContinuation OnFinalize) override
TargetProcessControl supports interaction with a JIT target process.
Expected< tpctypes::WrapperFunctionResult > runWrapper(JITTargetAddress WrapperFnAddr, ArrayRef< uint8_t > ArgBuffer) override
Run a wrapper function with signature:
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
void writeBuffers(ArrayRef< tpctypes::BufferWrite > Ws, WriteResultFn OnWriteComplete) override
Error joinErrors(Error E1, Error E2)
Concatenate errors.
OrcRPCAllocation(OrcRPCTPCJITLinkMemoryManager< OrcRPCTPCImplT > &Parent, HostAllocMap HostAllocs, TargetAllocMap TargetAllocs)
iterator find(const_arg_type_t< KeyT > Val)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
OrcRPCTPCJITLinkMemoryManager(OrcRPCTPCImplT &Parent)
std::vector< ReserveMemRequestElement > ReserveMemRequest
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
StringRef - Represent a constant reference to a string, i.e.
Expected< int32_t > runAsMain(JITTargetAddress MainFnAddr, ArrayRef< std::string > Args) override
Run function with a main-like signature.
LLVM_NODISCARD bool empty() const
void reportError(Error Err)
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Lightweight error class with error context and mandatory checking.
MutableArrayRef< char > getWorkingMemory(ProtectionFlags Seg) override
Error closeConnection(OnCloseConnectionFunction OnCloseConnection)
void writeUInt32s(ArrayRef< tpctypes::UInt32Write > Ws, WriteResultFn OnWriteComplete) override
uint64_t JITTargetAddress
Represents an address in the target process's address space.
TargetProcessControl::MemoryAccess implementation for a process connected via an ORC RPC endpoint.
sys::Memory::ProtectionFlags fromWireProtectionFlags(WireProtectionFlags WPF)
Error closeConnectionAndWait()
size_t size() const
size - Get the array size.
Align max(MaybeAlign Lhs, Align Rhs)
RPCEndpointT & getEndpoint()
WireProtectionFlags toWireProtectionFlags(sys::Memory::ProtectionFlags PF)
Convert from sys::Memory::ProtectionFlags.
void writeUInt64s(ArrayRef< tpctypes::UInt64Write > Ws, WriteResultFn OnWriteComplete) override
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
JITLinkMemoryManager implementation for a process connected via an ORC RPC endpoint.
Error initializeORCRPCTPCBase()
Subclasses must call this during construction to initialize the TargetTriple and PageSize members.
JITTargetAddress getTargetMemory(ProtectionFlags Seg) override
Error deallocate() override
OrcRPCTargetProcessControlBase(std::shared_ptr< SymbolStringPool > SSP, RPCEndpointT &EP, ErrorReporter ReportError)
Expected< tpctypes::DylibHandle > loadDylib(const char *DylibPath) override
Load the dynamic library at the given path and return a handle to it.