blob: 8b875b7906e110e4d73318b8b32745c9ed628e5f [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- OrcRemoteTargetClient.h - Orc Remote-target Client -------*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the OrcRemoteTargetClient class and helpers. This class
10// can be used to communicate over an RawByteChannel with an
11// OrcRemoteTargetServer instance to support remote-JITing.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
16#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
17
18#include "llvm/ADT/Optional.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/StringMap.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/ExecutionEngine/JITSymbol.h"
23#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
24#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
25#include "llvm/ExecutionEngine/RuntimeDyld.h"
26#include "llvm/Support/Debug.h"
27#include "llvm/Support/Error.h"
28#include "llvm/Support/ErrorHandling.h"
29#include "llvm/Support/Format.h"
30#include "llvm/Support/MathExtras.h"
31#include "llvm/Support/Memory.h"
32#include "llvm/Support/raw_ostream.h"
33#include <algorithm>
34#include <cassert>
35#include <cstdint>
36#include <memory>
37#include <string>
38#include <tuple>
39#include <utility>
40#include <vector>
41
42#define DEBUG_TYPE "orc-remote"
43
44namespace llvm {
45namespace orc {
46namespace remote {
47
48/// This class provides utilities (including memory manager, indirect stubs
49/// manager, and compile callback manager types) that support remote JITing
50/// in ORC.
51///
52/// Each of the utility classes talks to a JIT server (an instance of the
53/// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
54/// its actions.
55class OrcRemoteTargetClient
56 : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
57public:
58 /// Remote-mapped RuntimeDyld-compatible memory manager.
59 class RemoteRTDyldMemoryManager : public RuntimeDyld::MemoryManager {
60 friend class OrcRemoteTargetClient;
61
62 public:
63 ~RemoteRTDyldMemoryManager() {
64 Client.destroyRemoteAllocator(Id);
Andrew Scullcdfcccc2018-10-05 20:58:37 +010065 LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010066 }
67
68 RemoteRTDyldMemoryManager(const RemoteRTDyldMemoryManager &) = delete;
69 RemoteRTDyldMemoryManager &
70 operator=(const RemoteRTDyldMemoryManager &) = delete;
71 RemoteRTDyldMemoryManager(RemoteRTDyldMemoryManager &&) = default;
Andrew Scull0372a572018-11-16 15:47:06 +000072 RemoteRTDyldMemoryManager &operator=(RemoteRTDyldMemoryManager &&) = delete;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010073
74 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
75 unsigned SectionID,
76 StringRef SectionName) override {
77 Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
78 uint8_t *Alloc = reinterpret_cast<uint8_t *>(
79 Unmapped.back().CodeAllocs.back().getLocalAddress());
Andrew Scullcdfcccc2018-10-05 20:58:37 +010080 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
81 << SectionName << ": " << Alloc << " (" << Size
82 << " bytes, alignment " << Alignment << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010083 return Alloc;
84 }
85
86 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
87 unsigned SectionID, StringRef SectionName,
88 bool IsReadOnly) override {
89 if (IsReadOnly) {
90 Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
91 uint8_t *Alloc = reinterpret_cast<uint8_t *>(
92 Unmapped.back().RODataAllocs.back().getLocalAddress());
Andrew Scullcdfcccc2018-10-05 20:58:37 +010093 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
94 << SectionName << ": " << Alloc << " (" << Size
95 << " bytes, alignment " << Alignment << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010096 return Alloc;
97 } // else...
98
99 Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
100 uint8_t *Alloc = reinterpret_cast<uint8_t *>(
101 Unmapped.back().RWDataAllocs.back().getLocalAddress());
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100102 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
103 << SectionName << ": " << Alloc << " (" << Size
104 << " bytes, alignment " << Alignment << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100105 return Alloc;
106 }
107
108 void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
109 uintptr_t RODataSize, uint32_t RODataAlign,
110 uintptr_t RWDataSize,
111 uint32_t RWDataAlign) override {
112 Unmapped.push_back(ObjectAllocs());
113
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100114 LLVM_DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100115
116 if (CodeSize != 0) {
117 Unmapped.back().RemoteCodeAddr =
118 Client.reserveMem(Id, CodeSize, CodeAlign);
119
Andrew Walbran16937d02019-10-22 13:54:20 +0100120 LLVM_DEBUG(
121 dbgs() << " code: "
122 << format("0x%016" PRIx64, Unmapped.back().RemoteCodeAddr)
123 << " (" << CodeSize << " bytes, alignment " << CodeAlign
124 << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100125 }
126
127 if (RODataSize != 0) {
128 Unmapped.back().RemoteRODataAddr =
129 Client.reserveMem(Id, RODataSize, RODataAlign);
130
Andrew Walbran16937d02019-10-22 13:54:20 +0100131 LLVM_DEBUG(
132 dbgs() << " ro-data: "
133 << format("0x%016" PRIx64, Unmapped.back().RemoteRODataAddr)
134 << " (" << RODataSize << " bytes, alignment " << RODataAlign
135 << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100136 }
137
138 if (RWDataSize != 0) {
139 Unmapped.back().RemoteRWDataAddr =
140 Client.reserveMem(Id, RWDataSize, RWDataAlign);
141
Andrew Walbran16937d02019-10-22 13:54:20 +0100142 LLVM_DEBUG(
143 dbgs() << " rw-data: "
144 << format("0x%016" PRIx64, Unmapped.back().RemoteRWDataAddr)
145 << " (" << RWDataSize << " bytes, alignment " << RWDataAlign
146 << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100147 }
148 }
149
150 bool needsToReserveAllocationSpace() override { return true; }
151
152 void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
153 size_t Size) override {
154 UnfinalizedEHFrames.push_back({LoadAddr, Size});
155 }
156
157 void deregisterEHFrames() override {
158 for (auto &Frame : RegisteredEHFrames) {
159 // FIXME: Add error poll.
160 Client.deregisterEHFrames(Frame.Addr, Frame.Size);
161 }
162 }
163
164 void notifyObjectLoaded(RuntimeDyld &Dyld,
165 const object::ObjectFile &Obj) override {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100166 LLVM_DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100167 for (auto &ObjAllocs : Unmapped) {
168 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
169 ObjAllocs.RemoteCodeAddr);
170 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
171 ObjAllocs.RemoteRODataAddr);
172 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
173 ObjAllocs.RemoteRWDataAddr);
174 Unfinalized.push_back(std::move(ObjAllocs));
175 }
176 Unmapped.clear();
177 }
178
179 bool finalizeMemory(std::string *ErrMsg = nullptr) override {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100180 LLVM_DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100181
182 for (auto &ObjAllocs : Unfinalized) {
183 if (copyAndProtect(ObjAllocs.CodeAllocs, ObjAllocs.RemoteCodeAddr,
184 sys::Memory::MF_READ | sys::Memory::MF_EXEC))
185 return true;
186
187 if (copyAndProtect(ObjAllocs.RODataAllocs, ObjAllocs.RemoteRODataAddr,
188 sys::Memory::MF_READ))
189 return true;
190
191 if (copyAndProtect(ObjAllocs.RWDataAllocs, ObjAllocs.RemoteRWDataAddr,
192 sys::Memory::MF_READ | sys::Memory::MF_WRITE))
193 return true;
194 }
195 Unfinalized.clear();
196
197 for (auto &EHFrame : UnfinalizedEHFrames) {
198 if (auto Err = Client.registerEHFrames(EHFrame.Addr, EHFrame.Size)) {
199 // FIXME: Replace this once finalizeMemory can return an Error.
200 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
201 if (ErrMsg) {
202 raw_string_ostream ErrOut(*ErrMsg);
203 EIB.log(ErrOut);
204 }
205 });
206 return false;
207 }
208 }
209 RegisteredEHFrames = std::move(UnfinalizedEHFrames);
210 UnfinalizedEHFrames = {};
211
212 return false;
213 }
214
215 private:
216 class Alloc {
217 public:
218 Alloc(uint64_t Size, unsigned Align)
219 : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
220
221 Alloc(const Alloc &) = delete;
222 Alloc &operator=(const Alloc &) = delete;
223 Alloc(Alloc &&) = default;
224 Alloc &operator=(Alloc &&) = default;
225
226 uint64_t getSize() const { return Size; }
227
228 unsigned getAlign() const { return Align; }
229
230 char *getLocalAddress() const {
231 uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
232 LocalAddr = alignTo(LocalAddr, Align);
233 return reinterpret_cast<char *>(LocalAddr);
234 }
235
236 void setRemoteAddress(JITTargetAddress RemoteAddr) {
237 this->RemoteAddr = RemoteAddr;
238 }
239
240 JITTargetAddress getRemoteAddress() const { return RemoteAddr; }
241
242 private:
243 uint64_t Size;
244 unsigned Align;
245 std::unique_ptr<char[]> Contents;
246 JITTargetAddress RemoteAddr = 0;
247 };
248
249 struct ObjectAllocs {
250 ObjectAllocs() = default;
251 ObjectAllocs(const ObjectAllocs &) = delete;
252 ObjectAllocs &operator=(const ObjectAllocs &) = delete;
253 ObjectAllocs(ObjectAllocs &&) = default;
254 ObjectAllocs &operator=(ObjectAllocs &&) = default;
255
256 JITTargetAddress RemoteCodeAddr = 0;
257 JITTargetAddress RemoteRODataAddr = 0;
258 JITTargetAddress RemoteRWDataAddr = 0;
259 std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
260 };
261
262 RemoteRTDyldMemoryManager(OrcRemoteTargetClient &Client,
263 ResourceIdMgr::ResourceId Id)
264 : Client(Client), Id(Id) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100265 LLVM_DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100266 }
267
268 // Maps all allocations in Allocs to aligned blocks
269 void mapAllocsToRemoteAddrs(RuntimeDyld &Dyld, std::vector<Alloc> &Allocs,
270 JITTargetAddress NextAddr) {
271 for (auto &Alloc : Allocs) {
272 NextAddr = alignTo(NextAddr, Alloc.getAlign());
273 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextAddr);
Andrew Walbran16937d02019-10-22 13:54:20 +0100274 LLVM_DEBUG(
275 dbgs() << " " << static_cast<void *>(Alloc.getLocalAddress())
276 << " -> " << format("0x%016" PRIx64, NextAddr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100277 Alloc.setRemoteAddress(NextAddr);
278
279 // Only advance NextAddr if it was non-null to begin with,
280 // otherwise leave it as null.
281 if (NextAddr)
282 NextAddr += Alloc.getSize();
283 }
284 }
285
286 // Copies data for each alloc in the list, then set permissions on the
287 // segment.
288 bool copyAndProtect(const std::vector<Alloc> &Allocs,
289 JITTargetAddress RemoteSegmentAddr,
290 unsigned Permissions) {
291 if (RemoteSegmentAddr) {
292 assert(!Allocs.empty() && "No sections in allocated segment");
293
294 for (auto &Alloc : Allocs) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100295 LLVM_DEBUG(dbgs() << " copying section: "
296 << static_cast<void *>(Alloc.getLocalAddress())
297 << " -> "
Andrew Walbran16937d02019-10-22 13:54:20 +0100298 << format("0x%016" PRIx64, Alloc.getRemoteAddress())
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100299 << " (" << Alloc.getSize() << " bytes)\n";);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100300
301 if (Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
302 Alloc.getSize()))
303 return true;
304 }
305
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100306 LLVM_DEBUG(dbgs() << " setting "
307 << (Permissions & sys::Memory::MF_READ ? 'R' : '-')
308 << (Permissions & sys::Memory::MF_WRITE ? 'W' : '-')
309 << (Permissions & sys::Memory::MF_EXEC ? 'X' : '-')
310 << " permissions on block: "
Andrew Walbran16937d02019-10-22 13:54:20 +0100311 << format("0x%016" PRIx64, RemoteSegmentAddr)
312 << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100313 if (Client.setProtections(Id, RemoteSegmentAddr, Permissions))
314 return true;
315 }
316 return false;
317 }
318
319 OrcRemoteTargetClient &Client;
320 ResourceIdMgr::ResourceId Id;
321 std::vector<ObjectAllocs> Unmapped;
322 std::vector<ObjectAllocs> Unfinalized;
323
324 struct EHFrame {
325 JITTargetAddress Addr;
326 uint64_t Size;
327 };
328 std::vector<EHFrame> UnfinalizedEHFrames;
329 std::vector<EHFrame> RegisteredEHFrames;
330 };
331
332 /// Remote indirect stubs manager.
333 class RemoteIndirectStubsManager : public IndirectStubsManager {
334 public:
335 RemoteIndirectStubsManager(OrcRemoteTargetClient &Client,
336 ResourceIdMgr::ResourceId Id)
337 : Client(Client), Id(Id) {}
338
339 ~RemoteIndirectStubsManager() override {
340 Client.destroyIndirectStubsManager(Id);
341 }
342
343 Error createStub(StringRef StubName, JITTargetAddress StubAddr,
344 JITSymbolFlags StubFlags) override {
345 if (auto Err = reserveStubs(1))
346 return Err;
347
348 return createStubInternal(StubName, StubAddr, StubFlags);
349 }
350
351 Error createStubs(const StubInitsMap &StubInits) override {
352 if (auto Err = reserveStubs(StubInits.size()))
353 return Err;
354
355 for (auto &Entry : StubInits)
356 if (auto Err = createStubInternal(Entry.first(), Entry.second.first,
357 Entry.second.second))
358 return Err;
359
360 return Error::success();
361 }
362
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100363 JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100364 auto I = StubIndexes.find(Name);
365 if (I == StubIndexes.end())
366 return nullptr;
367 auto Key = I->second.first;
368 auto Flags = I->second.second;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100369 auto StubSymbol = JITEvaluatedSymbol(getStubAddr(Key), Flags);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100370 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
371 return nullptr;
372 return StubSymbol;
373 }
374
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100375 JITEvaluatedSymbol findPointer(StringRef Name) override {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100376 auto I = StubIndexes.find(Name);
377 if (I == StubIndexes.end())
378 return nullptr;
379 auto Key = I->second.first;
380 auto Flags = I->second.second;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100381 return JITEvaluatedSymbol(getPtrAddr(Key), Flags);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100382 }
383
384 Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
385 auto I = StubIndexes.find(Name);
386 assert(I != StubIndexes.end() && "No stub pointer for symbol");
387 auto Key = I->second.first;
388 return Client.writePointer(getPtrAddr(Key), NewAddr);
389 }
390
391 private:
392 struct RemoteIndirectStubsInfo {
393 JITTargetAddress StubBase;
394 JITTargetAddress PtrBase;
395 unsigned NumStubs;
396 };
397
398 using StubKey = std::pair<uint16_t, uint16_t>;
399
400 Error reserveStubs(unsigned NumStubs) {
401 if (NumStubs <= FreeStubs.size())
402 return Error::success();
403
404 unsigned NewStubsRequired = NumStubs - FreeStubs.size();
405 JITTargetAddress StubBase;
406 JITTargetAddress PtrBase;
407 unsigned NumStubsEmitted;
408
409 if (auto StubInfoOrErr = Client.emitIndirectStubs(Id, NewStubsRequired))
410 std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
411 else
412 return StubInfoOrErr.takeError();
413
414 unsigned NewBlockId = RemoteIndirectStubsInfos.size();
415 RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
416
417 for (unsigned I = 0; I < NumStubsEmitted; ++I)
418 FreeStubs.push_back(std::make_pair(NewBlockId, I));
419
420 return Error::success();
421 }
422
423 Error createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
424 JITSymbolFlags StubFlags) {
425 auto Key = FreeStubs.back();
426 FreeStubs.pop_back();
427 StubIndexes[StubName] = std::make_pair(Key, StubFlags);
428 return Client.writePointer(getPtrAddr(Key), InitAddr);
429 }
430
431 JITTargetAddress getStubAddr(StubKey K) {
432 assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
433 "Missing stub address");
434 return RemoteIndirectStubsInfos[K.first].StubBase +
435 K.second * Client.getIndirectStubSize();
436 }
437
438 JITTargetAddress getPtrAddr(StubKey K) {
439 assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
440 "Missing pointer address");
441 return RemoteIndirectStubsInfos[K.first].PtrBase +
442 K.second * Client.getPointerSize();
443 }
444
445 OrcRemoteTargetClient &Client;
446 ResourceIdMgr::ResourceId Id;
447 std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
448 std::vector<StubKey> FreeStubs;
449 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
450 };
451
Andrew Scull0372a572018-11-16 15:47:06 +0000452 class RemoteTrampolinePool : public TrampolinePool {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100453 public:
Andrew Scull0372a572018-11-16 15:47:06 +0000454 RemoteTrampolinePool(OrcRemoteTargetClient &Client) : Client(Client) {}
455
456 Expected<JITTargetAddress> getTrampoline() override {
457 std::lock_guard<std::mutex> Lock(RTPMutex);
458 if (AvailableTrampolines.empty()) {
459 if (auto Err = grow())
460 return std::move(Err);
461 }
462 assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool");
463 auto TrampolineAddr = AvailableTrampolines.back();
464 AvailableTrampolines.pop_back();
465 return TrampolineAddr;
466 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100467
468 private:
Andrew Scull0372a572018-11-16 15:47:06 +0000469 Error grow() {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100470 JITTargetAddress BlockAddr = 0;
471 uint32_t NumTrampolines = 0;
472 if (auto TrampolineInfoOrErr = Client.emitTrampolineBlock())
473 std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
474 else
475 return TrampolineInfoOrErr.takeError();
476
477 uint32_t TrampolineSize = Client.getTrampolineSize();
478 for (unsigned I = 0; I < NumTrampolines; ++I)
479 this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
480
481 return Error::success();
482 }
483
Andrew Scull0372a572018-11-16 15:47:06 +0000484 std::mutex RTPMutex;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100485 OrcRemoteTargetClient &Client;
Andrew Scull0372a572018-11-16 15:47:06 +0000486 std::vector<JITTargetAddress> AvailableTrampolines;
487 };
488
489 /// Remote compile callback manager.
490 class RemoteCompileCallbackManager : public JITCompileCallbackManager {
491 public:
492 RemoteCompileCallbackManager(OrcRemoteTargetClient &Client,
493 ExecutionSession &ES,
494 JITTargetAddress ErrorHandlerAddress)
495 : JITCompileCallbackManager(
496 llvm::make_unique<RemoteTrampolinePool>(Client), ES,
497 ErrorHandlerAddress) {}
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100498 };
499
500 /// Create an OrcRemoteTargetClient.
501 /// Channel is the ChannelT instance to communicate on. It is assumed that
502 /// the channel is ready to be read from and written to.
503 static Expected<std::unique_ptr<OrcRemoteTargetClient>>
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100504 Create(rpc::RawByteChannel &Channel, ExecutionSession &ES) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100505 Error Err = Error::success();
506 auto Client = std::unique_ptr<OrcRemoteTargetClient>(
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100507 new OrcRemoteTargetClient(Channel, ES, Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100508 if (Err)
509 return std::move(Err);
510 return std::move(Client);
511 }
512
513 /// Call the int(void) function at the given address in the target and return
514 /// its result.
515 Expected<int> callIntVoid(JITTargetAddress Addr) {
Andrew Walbran16937d02019-10-22 13:54:20 +0100516 LLVM_DEBUG(dbgs() << "Calling int(*)(void) "
517 << format("0x%016" PRIx64, Addr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100518 return callB<exec::CallIntVoid>(Addr);
519 }
520
521 /// Call the int(int, char*[]) function at the given address in the target and
522 /// return its result.
523 Expected<int> callMain(JITTargetAddress Addr,
524 const std::vector<std::string> &Args) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100525 LLVM_DEBUG(dbgs() << "Calling int(*)(int, char*[]) "
Andrew Walbran16937d02019-10-22 13:54:20 +0100526 << format("0x%016" PRIx64, Addr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100527 return callB<exec::CallMain>(Addr, Args);
528 }
529
530 /// Call the void() function at the given address in the target and wait for
531 /// it to finish.
532 Error callVoidVoid(JITTargetAddress Addr) {
Andrew Walbran16937d02019-10-22 13:54:20 +0100533 LLVM_DEBUG(dbgs() << "Calling void(*)(void) "
534 << format("0x%016" PRIx64, Addr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100535 return callB<exec::CallVoidVoid>(Addr);
536 }
537
538 /// Create an RCMemoryManager which will allocate its memory on the remote
539 /// target.
540 Expected<std::unique_ptr<RemoteRTDyldMemoryManager>>
541 createRemoteMemoryManager() {
542 auto Id = AllocatorIds.getNext();
543 if (auto Err = callB<mem::CreateRemoteAllocator>(Id))
544 return std::move(Err);
545 return std::unique_ptr<RemoteRTDyldMemoryManager>(
546 new RemoteRTDyldMemoryManager(*this, Id));
547 }
548
549 /// Create an RCIndirectStubsManager that will allocate stubs on the remote
550 /// target.
551 Expected<std::unique_ptr<RemoteIndirectStubsManager>>
552 createIndirectStubsManager() {
553 auto Id = IndirectStubOwnerIds.getNext();
554 if (auto Err = callB<stubs::CreateIndirectStubsOwner>(Id))
555 return std::move(Err);
556 return llvm::make_unique<RemoteIndirectStubsManager>(*this, Id);
557 }
558
559 Expected<RemoteCompileCallbackManager &>
560 enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100561 assert(!CallbackManager && "CallbackManager already obtained");
562
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100563 // Emit the resolver block on the JIT server.
564 if (auto Err = callB<stubs::EmitResolverBlock>())
565 return std::move(Err);
566
567 // Create the callback manager.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100568 CallbackManager.emplace(*this, ES, ErrorHandlerAddress);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100569 RemoteCompileCallbackManager &Mgr = *CallbackManager;
570 return Mgr;
571 }
572
573 /// Search for symbols in the remote process. Note: This should be used by
574 /// symbol resolvers *after* they've searched the local symbol table in the
575 /// JIT stack.
576 Expected<JITTargetAddress> getSymbolAddress(StringRef Name) {
577 return callB<utils::GetSymbolAddress>(Name);
578 }
579
580 /// Get the triple for the remote target.
581 const std::string &getTargetTriple() const { return RemoteTargetTriple; }
582
583 Error terminateSession() { return callB<utils::TerminateSession>(); }
584
585private:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100586 OrcRemoteTargetClient(rpc::RawByteChannel &Channel, ExecutionSession &ES,
587 Error &Err)
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100588 : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true),
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100589 ES(ES) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100590 ErrorAsOutParameter EAO(&Err);
591
592 addHandler<utils::RequestCompile>(
593 [this](JITTargetAddress Addr) -> JITTargetAddress {
594 if (CallbackManager)
595 return CallbackManager->executeCompileCallback(Addr);
596 return 0;
597 });
598
599 if (auto RIOrErr = callB<utils::GetRemoteInfo>()) {
600 std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
601 RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
602 Err = Error::success();
603 } else
604 Err = RIOrErr.takeError();
605 }
606
607 void deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
608 if (auto Err = callB<eh::RegisterEHFrames>(Addr, Size))
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100609 ES.reportError(std::move(Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100610 }
611
612 void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
613 if (auto Err = callB<mem::DestroyRemoteAllocator>(Id)) {
614 // FIXME: This will be triggered by a removeModuleSet call: Propagate
615 // error return up through that.
616 llvm_unreachable("Failed to destroy remote allocator.");
617 AllocatorIds.release(Id);
618 }
619 }
620
621 void destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
622 IndirectStubOwnerIds.release(Id);
623 if (auto Err = callB<stubs::DestroyIndirectStubsOwner>(Id))
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100624 ES.reportError(std::move(Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100625 }
626
627 Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
628 emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
629 return callB<stubs::EmitIndirectStubs>(Id, NumStubsRequired);
630 }
631
632 Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() {
633 return callB<stubs::EmitTrampolineBlock>();
634 }
635
636 uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
637 uint32_t getPageSize() const { return RemotePageSize; }
638 uint32_t getPointerSize() const { return RemotePointerSize; }
639
640 uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
641
642 Expected<std::vector<uint8_t>> readMem(char *Dst, JITTargetAddress Src,
643 uint64_t Size) {
644 return callB<mem::ReadMem>(Src, Size);
645 }
646
647 Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
648 // FIXME: Duplicate error and report it via ReportError too?
649 return callB<eh::RegisterEHFrames>(RAddr, Size);
650 }
651
652 JITTargetAddress reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
653 uint32_t Align) {
654 if (auto AddrOrErr = callB<mem::ReserveMem>(Id, Size, Align))
655 return *AddrOrErr;
656 else {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100657 ES.reportError(AddrOrErr.takeError());
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100658 return 0;
659 }
660 }
661
662 bool setProtections(ResourceIdMgr::ResourceId Id,
663 JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
664 if (auto Err = callB<mem::SetProtections>(Id, RemoteSegAddr, ProtFlags)) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100665 ES.reportError(std::move(Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100666 return true;
667 } else
668 return false;
669 }
670
671 bool writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
672 if (auto Err = callB<mem::WriteMem>(DirectBufferWriter(Src, Addr, Size))) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100673 ES.reportError(std::move(Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100674 return true;
675 } else
676 return false;
677 }
678
679 Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
680 return callB<mem::WritePtr>(Addr, PtrVal);
681 }
682
683 static Error doNothing() { return Error::success(); }
684
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100685 ExecutionSession &ES;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100686 std::function<void(Error)> ReportError;
687 std::string RemoteTargetTriple;
688 uint32_t RemotePointerSize = 0;
689 uint32_t RemotePageSize = 0;
690 uint32_t RemoteTrampolineSize = 0;
691 uint32_t RemoteIndirectStubSize = 0;
692 ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
693 Optional<RemoteCompileCallbackManager> CallbackManager;
694};
695
696} // end namespace remote
697} // end namespace orc
698} // end namespace llvm
699
700#undef DEBUG_TYPE
701
702#endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H