[llvm] [cmake] Add possibility to use ChooseMSVCCRT.cmake when include LLVM library
[llvm-core.git] / include / llvm / ExecutionEngine / Orc / OrcRemoteTargetServer.h
blob4c8e2ea1a7be6bd8064ab34afa794cd9fc594b44
1 //===- OrcRemoteTargetServer.h - Orc Remote-target Server -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the OrcRemoteTargetServer class. It can be used to build a
10 // JIT server that can execute code sent from an OrcRemoteTargetClient.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
15 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
17 #include "llvm/ExecutionEngine/JITSymbol.h"
18 #include "llvm/ExecutionEngine/Orc/OrcError.h"
19 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
20 #include "llvm/Support/Debug.h"
21 #include "llvm/Support/Error.h"
22 #include "llvm/Support/Format.h"
23 #include "llvm/Support/Host.h"
24 #include "llvm/Support/Memory.h"
25 #include "llvm/Support/Process.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <algorithm>
28 #include <cassert>
29 #include <cstddef>
30 #include <cstdint>
31 #include <functional>
32 #include <map>
33 #include <memory>
34 #include <string>
35 #include <system_error>
36 #include <tuple>
37 #include <type_traits>
38 #include <vector>
40 #define DEBUG_TYPE "orc-remote"
42 namespace llvm {
43 namespace orc {
44 namespace remote {
46 template <typename ChannelT, typename TargetT>
47 class OrcRemoteTargetServer
48 : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
49 public:
50 using SymbolLookupFtor =
51 std::function<JITTargetAddress(const std::string &Name)>;
53 using EHFrameRegistrationFtor =
54 std::function<void(uint8_t *Addr, uint32_t Size)>;
56 OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup,
57 EHFrameRegistrationFtor EHFramesRegister,
58 EHFrameRegistrationFtor EHFramesDeregister)
59 : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true),
60 SymbolLookup(std::move(SymbolLookup)),
61 EHFramesRegister(std::move(EHFramesRegister)),
62 EHFramesDeregister(std::move(EHFramesDeregister)) {
63 using ThisT = typename std::remove_reference<decltype(*this)>::type;
64 addHandler<exec::CallIntVoid>(*this, &ThisT::handleCallIntVoid);
65 addHandler<exec::CallMain>(*this, &ThisT::handleCallMain);
66 addHandler<exec::CallVoidVoid>(*this, &ThisT::handleCallVoidVoid);
67 addHandler<mem::CreateRemoteAllocator>(*this,
68 &ThisT::handleCreateRemoteAllocator);
69 addHandler<mem::DestroyRemoteAllocator>(
70 *this, &ThisT::handleDestroyRemoteAllocator);
71 addHandler<mem::ReadMem>(*this, &ThisT::handleReadMem);
72 addHandler<mem::ReserveMem>(*this, &ThisT::handleReserveMem);
73 addHandler<mem::SetProtections>(*this, &ThisT::handleSetProtections);
74 addHandler<mem::WriteMem>(*this, &ThisT::handleWriteMem);
75 addHandler<mem::WritePtr>(*this, &ThisT::handleWritePtr);
76 addHandler<eh::RegisterEHFrames>(*this, &ThisT::handleRegisterEHFrames);
77 addHandler<eh::DeregisterEHFrames>(*this, &ThisT::handleDeregisterEHFrames);
78 addHandler<stubs::CreateIndirectStubsOwner>(
79 *this, &ThisT::handleCreateIndirectStubsOwner);
80 addHandler<stubs::DestroyIndirectStubsOwner>(
81 *this, &ThisT::handleDestroyIndirectStubsOwner);
82 addHandler<stubs::EmitIndirectStubs>(*this,
83 &ThisT::handleEmitIndirectStubs);
84 addHandler<stubs::EmitResolverBlock>(*this,
85 &ThisT::handleEmitResolverBlock);
86 addHandler<stubs::EmitTrampolineBlock>(*this,
87 &ThisT::handleEmitTrampolineBlock);
88 addHandler<utils::GetSymbolAddress>(*this, &ThisT::handleGetSymbolAddress);
89 addHandler<utils::GetRemoteInfo>(*this, &ThisT::handleGetRemoteInfo);
90 addHandler<utils::TerminateSession>(*this, &ThisT::handleTerminateSession);
93 // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
94 OrcRemoteTargetServer(const OrcRemoteTargetServer &) = delete;
95 OrcRemoteTargetServer &operator=(const OrcRemoteTargetServer &) = delete;
97 OrcRemoteTargetServer(OrcRemoteTargetServer &&Other) = default;
98 OrcRemoteTargetServer &operator=(OrcRemoteTargetServer &&) = delete;
100 Expected<JITTargetAddress> requestCompile(JITTargetAddress TrampolineAddr) {
101 return callB<utils::RequestCompile>(TrampolineAddr);
104 bool receivedTerminate() const { return TerminateFlag; }
106 private:
107 struct Allocator {
108 Allocator() = default;
109 Allocator(Allocator &&Other) : Allocs(std::move(Other.Allocs)) {}
111 Allocator &operator=(Allocator &&Other) {
112 Allocs = std::move(Other.Allocs);
113 return *this;
116 ~Allocator() {
117 for (auto &Alloc : Allocs)
118 sys::Memory::releaseMappedMemory(Alloc.second);
121 Error allocate(void *&Addr, size_t Size, uint32_t Align) {
122 std::error_code EC;
123 sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(
124 Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
125 if (EC)
126 return errorCodeToError(EC);
128 Addr = MB.base();
129 assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc");
130 Allocs[MB.base()] = std::move(MB);
131 return Error::success();
134 Error setProtections(void *block, unsigned Flags) {
135 auto I = Allocs.find(block);
136 if (I == Allocs.end())
137 return errorCodeToError(orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized));
138 return errorCodeToError(
139 sys::Memory::protectMappedMemory(I->second, Flags));
142 private:
143 std::map<void *, sys::MemoryBlock> Allocs;
146 static Error doNothing() { return Error::success(); }
148 static JITTargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
149 auto T = static_cast<OrcRemoteTargetServer *>(JITTargetAddr);
150 auto AddrOrErr = T->requestCompile(static_cast<JITTargetAddress>(
151 reinterpret_cast<uintptr_t>(TrampolineAddr)));
152 // FIXME: Allow customizable failure substitution functions.
153 assert(AddrOrErr && "Compile request failed");
154 return *AddrOrErr;
157 Expected<int32_t> handleCallIntVoid(JITTargetAddress Addr) {
158 using IntVoidFnTy = int (*)();
160 IntVoidFnTy Fn =
161 reinterpret_cast<IntVoidFnTy>(static_cast<uintptr_t>(Addr));
163 LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
164 int Result = Fn();
165 LLVM_DEBUG(dbgs() << " Result = " << Result << "\n");
167 return Result;
170 Expected<int32_t> handleCallMain(JITTargetAddress Addr,
171 std::vector<std::string> Args) {
172 using MainFnTy = int (*)(int, const char *[]);
174 MainFnTy Fn = reinterpret_cast<MainFnTy>(static_cast<uintptr_t>(Addr));
175 int ArgC = Args.size() + 1;
176 int Idx = 1;
177 std::unique_ptr<const char *[]> ArgV(new const char *[ArgC + 1]);
178 ArgV[0] = "<jit process>";
179 for (auto &Arg : Args)
180 ArgV[Idx++] = Arg.c_str();
181 ArgV[ArgC] = 0;
182 LLVM_DEBUG(for (int Idx = 0; Idx < ArgC; ++Idx) {
183 llvm::dbgs() << "Arg " << Idx << ": " << ArgV[Idx] << "\n";
186 LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
187 int Result = Fn(ArgC, ArgV.get());
188 LLVM_DEBUG(dbgs() << " Result = " << Result << "\n");
190 return Result;
193 Error handleCallVoidVoid(JITTargetAddress Addr) {
194 using VoidVoidFnTy = void (*)();
196 VoidVoidFnTy Fn =
197 reinterpret_cast<VoidVoidFnTy>(static_cast<uintptr_t>(Addr));
199 LLVM_DEBUG(dbgs() << " Calling " << format("0x%016x", Addr) << "\n");
200 Fn();
201 LLVM_DEBUG(dbgs() << " Complete.\n");
203 return Error::success();
206 Error handleCreateRemoteAllocator(ResourceIdMgr::ResourceId Id) {
207 auto I = Allocators.find(Id);
208 if (I != Allocators.end())
209 return errorCodeToError(
210 orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse));
211 LLVM_DEBUG(dbgs() << " Created allocator " << Id << "\n");
212 Allocators[Id] = Allocator();
213 return Error::success();
216 Error handleCreateIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
217 auto I = IndirectStubsOwners.find(Id);
218 if (I != IndirectStubsOwners.end())
219 return errorCodeToError(
220 orcError(OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse));
221 LLVM_DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
222 IndirectStubsOwners[Id] = ISBlockOwnerList();
223 return Error::success();
226 Error handleDeregisterEHFrames(JITTargetAddress TAddr, uint32_t Size) {
227 uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
228 LLVM_DEBUG(dbgs() << " Registering EH frames at "
229 << format("0x%016x", TAddr) << ", Size = " << Size
230 << " bytes\n");
231 EHFramesDeregister(Addr, Size);
232 return Error::success();
235 Error handleDestroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
236 auto I = Allocators.find(Id);
237 if (I == Allocators.end())
238 return errorCodeToError(
239 orcError(OrcErrorCode::RemoteAllocatorDoesNotExist));
240 Allocators.erase(I);
241 LLVM_DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
242 return Error::success();
245 Error handleDestroyIndirectStubsOwner(ResourceIdMgr::ResourceId Id) {
246 auto I = IndirectStubsOwners.find(Id);
247 if (I == IndirectStubsOwners.end())
248 return errorCodeToError(
249 orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist));
250 IndirectStubsOwners.erase(I);
251 return Error::success();
254 Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
255 handleEmitIndirectStubs(ResourceIdMgr::ResourceId Id,
256 uint32_t NumStubsRequired) {
257 LLVM_DEBUG(dbgs() << " ISMgr " << Id << " request " << NumStubsRequired
258 << " stubs.\n");
260 auto StubOwnerItr = IndirectStubsOwners.find(Id);
261 if (StubOwnerItr == IndirectStubsOwners.end())
262 return errorCodeToError(
263 orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist));
265 typename TargetT::IndirectStubsInfo IS;
266 if (auto Err =
267 TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
268 return std::move(Err);
270 JITTargetAddress StubsBase = static_cast<JITTargetAddress>(
271 reinterpret_cast<uintptr_t>(IS.getStub(0)));
272 JITTargetAddress PtrsBase = static_cast<JITTargetAddress>(
273 reinterpret_cast<uintptr_t>(IS.getPtr(0)));
274 uint32_t NumStubsEmitted = IS.getNumStubs();
276 auto &BlockList = StubOwnerItr->second;
277 BlockList.push_back(std::move(IS));
279 return std::make_tuple(StubsBase, PtrsBase, NumStubsEmitted);
282 Error handleEmitResolverBlock() {
283 std::error_code EC;
284 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
285 TargetT::ResolverCodeSize, nullptr,
286 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
287 if (EC)
288 return errorCodeToError(EC);
290 TargetT::writeResolverCode(static_cast<uint8_t *>(ResolverBlock.base()),
291 &reenter, this);
293 return errorCodeToError(sys::Memory::protectMappedMemory(
294 ResolverBlock.getMemoryBlock(),
295 sys::Memory::MF_READ | sys::Memory::MF_EXEC));
298 Expected<std::tuple<JITTargetAddress, uint32_t>> handleEmitTrampolineBlock() {
299 std::error_code EC;
300 auto TrampolineBlock =
301 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
302 sys::Process::getPageSizeEstimate(), nullptr,
303 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
304 if (EC)
305 return errorCodeToError(EC);
307 uint32_t NumTrampolines =
308 (sys::Process::getPageSizeEstimate() - TargetT::PointerSize) /
309 TargetT::TrampolineSize;
311 uint8_t *TrampolineMem = static_cast<uint8_t *>(TrampolineBlock.base());
312 TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
313 NumTrampolines);
315 EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
316 sys::Memory::MF_READ |
317 sys::Memory::MF_EXEC);
319 TrampolineBlocks.push_back(std::move(TrampolineBlock));
321 auto TrampolineBaseAddr = static_cast<JITTargetAddress>(
322 reinterpret_cast<uintptr_t>(TrampolineMem));
324 return std::make_tuple(TrampolineBaseAddr, NumTrampolines);
327 Expected<JITTargetAddress> handleGetSymbolAddress(const std::string &Name) {
328 JITTargetAddress Addr = SymbolLookup(Name);
329 LLVM_DEBUG(dbgs() << " Symbol '" << Name
330 << "' = " << format("0x%016x", Addr) << "\n");
331 return Addr;
334 Expected<std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>>
335 handleGetRemoteInfo() {
336 std::string ProcessTriple = sys::getProcessTriple();
337 uint32_t PointerSize = TargetT::PointerSize;
338 uint32_t PageSize = sys::Process::getPageSizeEstimate();
339 uint32_t TrampolineSize = TargetT::TrampolineSize;
340 uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize;
341 LLVM_DEBUG(dbgs() << " Remote info:\n"
342 << " triple = '" << ProcessTriple << "'\n"
343 << " pointer size = " << PointerSize << "\n"
344 << " page size = " << PageSize << "\n"
345 << " trampoline size = " << TrampolineSize << "\n"
346 << " indirect stub size = " << IndirectStubSize
347 << "\n");
348 return std::make_tuple(ProcessTriple, PointerSize, PageSize, TrampolineSize,
349 IndirectStubSize);
352 Expected<std::vector<uint8_t>> handleReadMem(JITTargetAddress RSrc,
353 uint64_t Size) {
354 uint8_t *Src = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(RSrc));
356 LLVM_DEBUG(dbgs() << " Reading " << Size << " bytes from "
357 << format("0x%016x", RSrc) << "\n");
359 std::vector<uint8_t> Buffer;
360 Buffer.resize(Size);
361 for (uint8_t *P = Src; Size != 0; --Size)
362 Buffer.push_back(*P++);
364 return Buffer;
367 Error handleRegisterEHFrames(JITTargetAddress TAddr, uint32_t Size) {
368 uint8_t *Addr = reinterpret_cast<uint8_t *>(static_cast<uintptr_t>(TAddr));
369 LLVM_DEBUG(dbgs() << " Registering EH frames at "
370 << format("0x%016x", TAddr) << ", Size = " << Size
371 << " bytes\n");
372 EHFramesRegister(Addr, Size);
373 return Error::success();
376 Expected<JITTargetAddress> handleReserveMem(ResourceIdMgr::ResourceId Id,
377 uint64_t Size, uint32_t Align) {
378 auto I = Allocators.find(Id);
379 if (I == Allocators.end())
380 return errorCodeToError(
381 orcError(OrcErrorCode::RemoteAllocatorDoesNotExist));
382 auto &Allocator = I->second;
383 void *LocalAllocAddr = nullptr;
384 if (auto Err = Allocator.allocate(LocalAllocAddr, Size, Align))
385 return std::move(Err);
387 LLVM_DEBUG(dbgs() << " Allocator " << Id << " reserved " << LocalAllocAddr
388 << " (" << Size << " bytes, alignment " << Align
389 << ")\n");
391 JITTargetAddress AllocAddr = static_cast<JITTargetAddress>(
392 reinterpret_cast<uintptr_t>(LocalAllocAddr));
394 return AllocAddr;
397 Error handleSetProtections(ResourceIdMgr::ResourceId Id,
398 JITTargetAddress Addr, uint32_t Flags) {
399 auto I = Allocators.find(Id);
400 if (I == Allocators.end())
401 return errorCodeToError(
402 orcError(OrcErrorCode::RemoteAllocatorDoesNotExist));
403 auto &Allocator = I->second;
404 void *LocalAddr = reinterpret_cast<void *>(static_cast<uintptr_t>(Addr));
405 LLVM_DEBUG(dbgs() << " Allocator " << Id << " set permissions on "
406 << LocalAddr << " to "
407 << (Flags & sys::Memory::MF_READ ? 'R' : '-')
408 << (Flags & sys::Memory::MF_WRITE ? 'W' : '-')
409 << (Flags & sys::Memory::MF_EXEC ? 'X' : '-') << "\n");
410 return Allocator.setProtections(LocalAddr, Flags);
413 Error handleTerminateSession() {
414 TerminateFlag = true;
415 return Error::success();
418 Error handleWriteMem(DirectBufferWriter DBW) {
419 LLVM_DEBUG(dbgs() << " Writing " << DBW.getSize() << " bytes to "
420 << format("0x%016x", DBW.getDst()) << "\n");
421 return Error::success();
424 Error handleWritePtr(JITTargetAddress Addr, JITTargetAddress PtrVal) {
425 LLVM_DEBUG(dbgs() << " Writing pointer *" << format("0x%016x", Addr)
426 << " = " << format("0x%016x", PtrVal) << "\n");
427 uintptr_t *Ptr =
428 reinterpret_cast<uintptr_t *>(static_cast<uintptr_t>(Addr));
429 *Ptr = static_cast<uintptr_t>(PtrVal);
430 return Error::success();
433 SymbolLookupFtor SymbolLookup;
434 EHFrameRegistrationFtor EHFramesRegister, EHFramesDeregister;
435 std::map<ResourceIdMgr::ResourceId, Allocator> Allocators;
436 using ISBlockOwnerList = std::vector<typename TargetT::IndirectStubsInfo>;
437 std::map<ResourceIdMgr::ResourceId, ISBlockOwnerList> IndirectStubsOwners;
438 sys::OwningMemoryBlock ResolverBlock;
439 std::vector<sys::OwningMemoryBlock> TrampolineBlocks;
440 bool TerminateFlag = false;
443 } // end namespace remote
444 } // end namespace orc
445 } // end namespace llvm
447 #undef DEBUG_TYPE
449 #endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H