blob: 99468e269d31537a924152913bf682364301d7fc [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- OrcRemoteTargetClient.h - Orc Remote-target Client -------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the OrcRemoteTargetClient class and helpers. This class
11// can be used to communicate over an RawByteChannel with an
12// OrcRemoteTargetServer instance to support remote-JITing.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
17#define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
18
19#include "llvm/ADT/Optional.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/StringMap.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/ExecutionEngine/JITSymbol.h"
24#include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
25#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
26#include "llvm/ExecutionEngine/RuntimeDyld.h"
27#include "llvm/Support/Debug.h"
28#include "llvm/Support/Error.h"
29#include "llvm/Support/ErrorHandling.h"
30#include "llvm/Support/Format.h"
31#include "llvm/Support/MathExtras.h"
32#include "llvm/Support/Memory.h"
33#include "llvm/Support/raw_ostream.h"
34#include <algorithm>
35#include <cassert>
36#include <cstdint>
37#include <memory>
38#include <string>
39#include <tuple>
40#include <utility>
41#include <vector>
42
43#define DEBUG_TYPE "orc-remote"
44
45namespace llvm {
46namespace orc {
47namespace remote {
48
49/// This class provides utilities (including memory manager, indirect stubs
50/// manager, and compile callback manager types) that support remote JITing
51/// in ORC.
52///
53/// Each of the utility classes talks to a JIT server (an instance of the
54/// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
55/// its actions.
56class OrcRemoteTargetClient
57 : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
58public:
59 /// Remote-mapped RuntimeDyld-compatible memory manager.
60 class RemoteRTDyldMemoryManager : public RuntimeDyld::MemoryManager {
61 friend class OrcRemoteTargetClient;
62
63 public:
64 ~RemoteRTDyldMemoryManager() {
65 Client.destroyRemoteAllocator(Id);
Andrew Scullcdfcccc2018-10-05 20:58:37 +010066 LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010067 }
68
69 RemoteRTDyldMemoryManager(const RemoteRTDyldMemoryManager &) = delete;
70 RemoteRTDyldMemoryManager &
71 operator=(const RemoteRTDyldMemoryManager &) = delete;
72 RemoteRTDyldMemoryManager(RemoteRTDyldMemoryManager &&) = default;
Andrew Scull0372a572018-11-16 15:47:06 +000073 RemoteRTDyldMemoryManager &operator=(RemoteRTDyldMemoryManager &&) = delete;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010074
75 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
76 unsigned SectionID,
77 StringRef SectionName) override {
78 Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
79 uint8_t *Alloc = reinterpret_cast<uint8_t *>(
80 Unmapped.back().CodeAllocs.back().getLocalAddress());
Andrew Scullcdfcccc2018-10-05 20:58:37 +010081 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
82 << SectionName << ": " << Alloc << " (" << Size
83 << " bytes, alignment " << Alignment << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010084 return Alloc;
85 }
86
87 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
88 unsigned SectionID, StringRef SectionName,
89 bool IsReadOnly) override {
90 if (IsReadOnly) {
91 Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
92 uint8_t *Alloc = reinterpret_cast<uint8_t *>(
93 Unmapped.back().RODataAllocs.back().getLocalAddress());
Andrew Scullcdfcccc2018-10-05 20:58:37 +010094 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
95 << SectionName << ": " << Alloc << " (" << Size
96 << " bytes, alignment " << Alignment << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010097 return Alloc;
98 } // else...
99
100 Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
101 uint8_t *Alloc = reinterpret_cast<uint8_t *>(
102 Unmapped.back().RWDataAllocs.back().getLocalAddress());
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100103 LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
104 << SectionName << ": " << Alloc << " (" << Size
105 << " bytes, alignment " << Alignment << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100106 return Alloc;
107 }
108
109 void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
110 uintptr_t RODataSize, uint32_t RODataAlign,
111 uintptr_t RWDataSize,
112 uint32_t RWDataAlign) override {
113 Unmapped.push_back(ObjectAllocs());
114
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100115 LLVM_DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100116
117 if (CodeSize != 0) {
118 Unmapped.back().RemoteCodeAddr =
119 Client.reserveMem(Id, CodeSize, CodeAlign);
120
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100121 LLVM_DEBUG(dbgs() << " code: "
122 << format("0x%016x", Unmapped.back().RemoteCodeAddr)
123 << " (" << CodeSize << " bytes, alignment "
124 << CodeAlign << ")\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 Scullcdfcccc2018-10-05 20:58:37 +0100131 LLVM_DEBUG(dbgs() << " ro-data: "
132 << format("0x%016x", Unmapped.back().RemoteRODataAddr)
133 << " (" << RODataSize << " bytes, alignment "
134 << RODataAlign << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100135 }
136
137 if (RWDataSize != 0) {
138 Unmapped.back().RemoteRWDataAddr =
139 Client.reserveMem(Id, RWDataSize, RWDataAlign);
140
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100141 LLVM_DEBUG(dbgs() << " rw-data: "
142 << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
143 << " (" << RWDataSize << " bytes, alignment "
144 << RWDataAlign << ")\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100145 }
146 }
147
148 bool needsToReserveAllocationSpace() override { return true; }
149
150 void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
151 size_t Size) override {
152 UnfinalizedEHFrames.push_back({LoadAddr, Size});
153 }
154
155 void deregisterEHFrames() override {
156 for (auto &Frame : RegisteredEHFrames) {
157 // FIXME: Add error poll.
158 Client.deregisterEHFrames(Frame.Addr, Frame.Size);
159 }
160 }
161
162 void notifyObjectLoaded(RuntimeDyld &Dyld,
163 const object::ObjectFile &Obj) override {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100164 LLVM_DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100165 for (auto &ObjAllocs : Unmapped) {
166 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
167 ObjAllocs.RemoteCodeAddr);
168 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
169 ObjAllocs.RemoteRODataAddr);
170 mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
171 ObjAllocs.RemoteRWDataAddr);
172 Unfinalized.push_back(std::move(ObjAllocs));
173 }
174 Unmapped.clear();
175 }
176
177 bool finalizeMemory(std::string *ErrMsg = nullptr) override {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100178 LLVM_DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100179
180 for (auto &ObjAllocs : Unfinalized) {
181 if (copyAndProtect(ObjAllocs.CodeAllocs, ObjAllocs.RemoteCodeAddr,
182 sys::Memory::MF_READ | sys::Memory::MF_EXEC))
183 return true;
184
185 if (copyAndProtect(ObjAllocs.RODataAllocs, ObjAllocs.RemoteRODataAddr,
186 sys::Memory::MF_READ))
187 return true;
188
189 if (copyAndProtect(ObjAllocs.RWDataAllocs, ObjAllocs.RemoteRWDataAddr,
190 sys::Memory::MF_READ | sys::Memory::MF_WRITE))
191 return true;
192 }
193 Unfinalized.clear();
194
195 for (auto &EHFrame : UnfinalizedEHFrames) {
196 if (auto Err = Client.registerEHFrames(EHFrame.Addr, EHFrame.Size)) {
197 // FIXME: Replace this once finalizeMemory can return an Error.
198 handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
199 if (ErrMsg) {
200 raw_string_ostream ErrOut(*ErrMsg);
201 EIB.log(ErrOut);
202 }
203 });
204 return false;
205 }
206 }
207 RegisteredEHFrames = std::move(UnfinalizedEHFrames);
208 UnfinalizedEHFrames = {};
209
210 return false;
211 }
212
213 private:
214 class Alloc {
215 public:
216 Alloc(uint64_t Size, unsigned Align)
217 : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
218
219 Alloc(const Alloc &) = delete;
220 Alloc &operator=(const Alloc &) = delete;
221 Alloc(Alloc &&) = default;
222 Alloc &operator=(Alloc &&) = default;
223
224 uint64_t getSize() const { return Size; }
225
226 unsigned getAlign() const { return Align; }
227
228 char *getLocalAddress() const {
229 uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
230 LocalAddr = alignTo(LocalAddr, Align);
231 return reinterpret_cast<char *>(LocalAddr);
232 }
233
234 void setRemoteAddress(JITTargetAddress RemoteAddr) {
235 this->RemoteAddr = RemoteAddr;
236 }
237
238 JITTargetAddress getRemoteAddress() const { return RemoteAddr; }
239
240 private:
241 uint64_t Size;
242 unsigned Align;
243 std::unique_ptr<char[]> Contents;
244 JITTargetAddress RemoteAddr = 0;
245 };
246
247 struct ObjectAllocs {
248 ObjectAllocs() = default;
249 ObjectAllocs(const ObjectAllocs &) = delete;
250 ObjectAllocs &operator=(const ObjectAllocs &) = delete;
251 ObjectAllocs(ObjectAllocs &&) = default;
252 ObjectAllocs &operator=(ObjectAllocs &&) = default;
253
254 JITTargetAddress RemoteCodeAddr = 0;
255 JITTargetAddress RemoteRODataAddr = 0;
256 JITTargetAddress RemoteRWDataAddr = 0;
257 std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
258 };
259
260 RemoteRTDyldMemoryManager(OrcRemoteTargetClient &Client,
261 ResourceIdMgr::ResourceId Id)
262 : Client(Client), Id(Id) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100263 LLVM_DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100264 }
265
266 // Maps all allocations in Allocs to aligned blocks
267 void mapAllocsToRemoteAddrs(RuntimeDyld &Dyld, std::vector<Alloc> &Allocs,
268 JITTargetAddress NextAddr) {
269 for (auto &Alloc : Allocs) {
270 NextAddr = alignTo(NextAddr, Alloc.getAlign());
271 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextAddr);
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100272 LLVM_DEBUG(dbgs() << " "
273 << static_cast<void *>(Alloc.getLocalAddress())
274 << " -> " << format("0x%016x", NextAddr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100275 Alloc.setRemoteAddress(NextAddr);
276
277 // Only advance NextAddr if it was non-null to begin with,
278 // otherwise leave it as null.
279 if (NextAddr)
280 NextAddr += Alloc.getSize();
281 }
282 }
283
284 // Copies data for each alloc in the list, then set permissions on the
285 // segment.
286 bool copyAndProtect(const std::vector<Alloc> &Allocs,
287 JITTargetAddress RemoteSegmentAddr,
288 unsigned Permissions) {
289 if (RemoteSegmentAddr) {
290 assert(!Allocs.empty() && "No sections in allocated segment");
291
292 for (auto &Alloc : Allocs) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100293 LLVM_DEBUG(dbgs() << " copying section: "
294 << static_cast<void *>(Alloc.getLocalAddress())
295 << " -> "
296 << format("0x%016x", Alloc.getRemoteAddress())
297 << " (" << Alloc.getSize() << " bytes)\n";);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100298
299 if (Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
300 Alloc.getSize()))
301 return true;
302 }
303
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100304 LLVM_DEBUG(dbgs() << " setting "
305 << (Permissions & sys::Memory::MF_READ ? 'R' : '-')
306 << (Permissions & sys::Memory::MF_WRITE ? 'W' : '-')
307 << (Permissions & sys::Memory::MF_EXEC ? 'X' : '-')
308 << " permissions on block: "
309 << format("0x%016x", RemoteSegmentAddr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100310 if (Client.setProtections(Id, RemoteSegmentAddr, Permissions))
311 return true;
312 }
313 return false;
314 }
315
316 OrcRemoteTargetClient &Client;
317 ResourceIdMgr::ResourceId Id;
318 std::vector<ObjectAllocs> Unmapped;
319 std::vector<ObjectAllocs> Unfinalized;
320
321 struct EHFrame {
322 JITTargetAddress Addr;
323 uint64_t Size;
324 };
325 std::vector<EHFrame> UnfinalizedEHFrames;
326 std::vector<EHFrame> RegisteredEHFrames;
327 };
328
329 /// Remote indirect stubs manager.
330 class RemoteIndirectStubsManager : public IndirectStubsManager {
331 public:
332 RemoteIndirectStubsManager(OrcRemoteTargetClient &Client,
333 ResourceIdMgr::ResourceId Id)
334 : Client(Client), Id(Id) {}
335
336 ~RemoteIndirectStubsManager() override {
337 Client.destroyIndirectStubsManager(Id);
338 }
339
340 Error createStub(StringRef StubName, JITTargetAddress StubAddr,
341 JITSymbolFlags StubFlags) override {
342 if (auto Err = reserveStubs(1))
343 return Err;
344
345 return createStubInternal(StubName, StubAddr, StubFlags);
346 }
347
348 Error createStubs(const StubInitsMap &StubInits) override {
349 if (auto Err = reserveStubs(StubInits.size()))
350 return Err;
351
352 for (auto &Entry : StubInits)
353 if (auto Err = createStubInternal(Entry.first(), Entry.second.first,
354 Entry.second.second))
355 return Err;
356
357 return Error::success();
358 }
359
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100360 JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100361 auto I = StubIndexes.find(Name);
362 if (I == StubIndexes.end())
363 return nullptr;
364 auto Key = I->second.first;
365 auto Flags = I->second.second;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100366 auto StubSymbol = JITEvaluatedSymbol(getStubAddr(Key), Flags);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100367 if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
368 return nullptr;
369 return StubSymbol;
370 }
371
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100372 JITEvaluatedSymbol findPointer(StringRef Name) override {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100373 auto I = StubIndexes.find(Name);
374 if (I == StubIndexes.end())
375 return nullptr;
376 auto Key = I->second.first;
377 auto Flags = I->second.second;
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100378 return JITEvaluatedSymbol(getPtrAddr(Key), Flags);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100379 }
380
381 Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
382 auto I = StubIndexes.find(Name);
383 assert(I != StubIndexes.end() && "No stub pointer for symbol");
384 auto Key = I->second.first;
385 return Client.writePointer(getPtrAddr(Key), NewAddr);
386 }
387
388 private:
389 struct RemoteIndirectStubsInfo {
390 JITTargetAddress StubBase;
391 JITTargetAddress PtrBase;
392 unsigned NumStubs;
393 };
394
395 using StubKey = std::pair<uint16_t, uint16_t>;
396
397 Error reserveStubs(unsigned NumStubs) {
398 if (NumStubs <= FreeStubs.size())
399 return Error::success();
400
401 unsigned NewStubsRequired = NumStubs - FreeStubs.size();
402 JITTargetAddress StubBase;
403 JITTargetAddress PtrBase;
404 unsigned NumStubsEmitted;
405
406 if (auto StubInfoOrErr = Client.emitIndirectStubs(Id, NewStubsRequired))
407 std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
408 else
409 return StubInfoOrErr.takeError();
410
411 unsigned NewBlockId = RemoteIndirectStubsInfos.size();
412 RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
413
414 for (unsigned I = 0; I < NumStubsEmitted; ++I)
415 FreeStubs.push_back(std::make_pair(NewBlockId, I));
416
417 return Error::success();
418 }
419
420 Error createStubInternal(StringRef StubName, JITTargetAddress InitAddr,
421 JITSymbolFlags StubFlags) {
422 auto Key = FreeStubs.back();
423 FreeStubs.pop_back();
424 StubIndexes[StubName] = std::make_pair(Key, StubFlags);
425 return Client.writePointer(getPtrAddr(Key), InitAddr);
426 }
427
428 JITTargetAddress getStubAddr(StubKey K) {
429 assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
430 "Missing stub address");
431 return RemoteIndirectStubsInfos[K.first].StubBase +
432 K.second * Client.getIndirectStubSize();
433 }
434
435 JITTargetAddress getPtrAddr(StubKey K) {
436 assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
437 "Missing pointer address");
438 return RemoteIndirectStubsInfos[K.first].PtrBase +
439 K.second * Client.getPointerSize();
440 }
441
442 OrcRemoteTargetClient &Client;
443 ResourceIdMgr::ResourceId Id;
444 std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
445 std::vector<StubKey> FreeStubs;
446 StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
447 };
448
Andrew Scull0372a572018-11-16 15:47:06 +0000449 class RemoteTrampolinePool : public TrampolinePool {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100450 public:
Andrew Scull0372a572018-11-16 15:47:06 +0000451 RemoteTrampolinePool(OrcRemoteTargetClient &Client) : Client(Client) {}
452
453 Expected<JITTargetAddress> getTrampoline() override {
454 std::lock_guard<std::mutex> Lock(RTPMutex);
455 if (AvailableTrampolines.empty()) {
456 if (auto Err = grow())
457 return std::move(Err);
458 }
459 assert(!AvailableTrampolines.empty() && "Failed to grow trampoline pool");
460 auto TrampolineAddr = AvailableTrampolines.back();
461 AvailableTrampolines.pop_back();
462 return TrampolineAddr;
463 }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100464
465 private:
Andrew Scull0372a572018-11-16 15:47:06 +0000466 Error grow() {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100467 JITTargetAddress BlockAddr = 0;
468 uint32_t NumTrampolines = 0;
469 if (auto TrampolineInfoOrErr = Client.emitTrampolineBlock())
470 std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
471 else
472 return TrampolineInfoOrErr.takeError();
473
474 uint32_t TrampolineSize = Client.getTrampolineSize();
475 for (unsigned I = 0; I < NumTrampolines; ++I)
476 this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
477
478 return Error::success();
479 }
480
Andrew Scull0372a572018-11-16 15:47:06 +0000481 std::mutex RTPMutex;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100482 OrcRemoteTargetClient &Client;
Andrew Scull0372a572018-11-16 15:47:06 +0000483 std::vector<JITTargetAddress> AvailableTrampolines;
484 };
485
486 /// Remote compile callback manager.
487 class RemoteCompileCallbackManager : public JITCompileCallbackManager {
488 public:
489 RemoteCompileCallbackManager(OrcRemoteTargetClient &Client,
490 ExecutionSession &ES,
491 JITTargetAddress ErrorHandlerAddress)
492 : JITCompileCallbackManager(
493 llvm::make_unique<RemoteTrampolinePool>(Client), ES,
494 ErrorHandlerAddress) {}
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100495 };
496
497 /// Create an OrcRemoteTargetClient.
498 /// Channel is the ChannelT instance to communicate on. It is assumed that
499 /// the channel is ready to be read from and written to.
500 static Expected<std::unique_ptr<OrcRemoteTargetClient>>
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100501 Create(rpc::RawByteChannel &Channel, ExecutionSession &ES) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100502 Error Err = Error::success();
503 auto Client = std::unique_ptr<OrcRemoteTargetClient>(
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100504 new OrcRemoteTargetClient(Channel, ES, Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100505 if (Err)
506 return std::move(Err);
507 return std::move(Client);
508 }
509
510 /// Call the int(void) function at the given address in the target and return
511 /// its result.
512 Expected<int> callIntVoid(JITTargetAddress Addr) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100513 LLVM_DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr)
514 << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100515 return callB<exec::CallIntVoid>(Addr);
516 }
517
518 /// Call the int(int, char*[]) function at the given address in the target and
519 /// return its result.
520 Expected<int> callMain(JITTargetAddress Addr,
521 const std::vector<std::string> &Args) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100522 LLVM_DEBUG(dbgs() << "Calling int(*)(int, char*[]) "
523 << format("0x%016x", Addr) << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100524 return callB<exec::CallMain>(Addr, Args);
525 }
526
527 /// Call the void() function at the given address in the target and wait for
528 /// it to finish.
529 Error callVoidVoid(JITTargetAddress Addr) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100530 LLVM_DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
531 << "\n");
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100532 return callB<exec::CallVoidVoid>(Addr);
533 }
534
535 /// Create an RCMemoryManager which will allocate its memory on the remote
536 /// target.
537 Expected<std::unique_ptr<RemoteRTDyldMemoryManager>>
538 createRemoteMemoryManager() {
539 auto Id = AllocatorIds.getNext();
540 if (auto Err = callB<mem::CreateRemoteAllocator>(Id))
541 return std::move(Err);
542 return std::unique_ptr<RemoteRTDyldMemoryManager>(
543 new RemoteRTDyldMemoryManager(*this, Id));
544 }
545
546 /// Create an RCIndirectStubsManager that will allocate stubs on the remote
547 /// target.
548 Expected<std::unique_ptr<RemoteIndirectStubsManager>>
549 createIndirectStubsManager() {
550 auto Id = IndirectStubOwnerIds.getNext();
551 if (auto Err = callB<stubs::CreateIndirectStubsOwner>(Id))
552 return std::move(Err);
553 return llvm::make_unique<RemoteIndirectStubsManager>(*this, Id);
554 }
555
556 Expected<RemoteCompileCallbackManager &>
557 enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100558 assert(!CallbackManager && "CallbackManager already obtained");
559
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100560 // Emit the resolver block on the JIT server.
561 if (auto Err = callB<stubs::EmitResolverBlock>())
562 return std::move(Err);
563
564 // Create the callback manager.
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100565 CallbackManager.emplace(*this, ES, ErrorHandlerAddress);
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100566 RemoteCompileCallbackManager &Mgr = *CallbackManager;
567 return Mgr;
568 }
569
570 /// Search for symbols in the remote process. Note: This should be used by
571 /// symbol resolvers *after* they've searched the local symbol table in the
572 /// JIT stack.
573 Expected<JITTargetAddress> getSymbolAddress(StringRef Name) {
574 return callB<utils::GetSymbolAddress>(Name);
575 }
576
577 /// Get the triple for the remote target.
578 const std::string &getTargetTriple() const { return RemoteTargetTriple; }
579
580 Error terminateSession() { return callB<utils::TerminateSession>(); }
581
582private:
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100583 OrcRemoteTargetClient(rpc::RawByteChannel &Channel, ExecutionSession &ES,
584 Error &Err)
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100585 : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true),
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100586 ES(ES) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100587 ErrorAsOutParameter EAO(&Err);
588
589 addHandler<utils::RequestCompile>(
590 [this](JITTargetAddress Addr) -> JITTargetAddress {
591 if (CallbackManager)
592 return CallbackManager->executeCompileCallback(Addr);
593 return 0;
594 });
595
596 if (auto RIOrErr = callB<utils::GetRemoteInfo>()) {
597 std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
598 RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
599 Err = Error::success();
600 } else
601 Err = RIOrErr.takeError();
602 }
603
604 void deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
605 if (auto Err = callB<eh::RegisterEHFrames>(Addr, Size))
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100606 ES.reportError(std::move(Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100607 }
608
609 void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
610 if (auto Err = callB<mem::DestroyRemoteAllocator>(Id)) {
611 // FIXME: This will be triggered by a removeModuleSet call: Propagate
612 // error return up through that.
613 llvm_unreachable("Failed to destroy remote allocator.");
614 AllocatorIds.release(Id);
615 }
616 }
617
618 void destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
619 IndirectStubOwnerIds.release(Id);
620 if (auto Err = callB<stubs::DestroyIndirectStubsOwner>(Id))
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100621 ES.reportError(std::move(Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100622 }
623
624 Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
625 emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
626 return callB<stubs::EmitIndirectStubs>(Id, NumStubsRequired);
627 }
628
629 Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() {
630 return callB<stubs::EmitTrampolineBlock>();
631 }
632
633 uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
634 uint32_t getPageSize() const { return RemotePageSize; }
635 uint32_t getPointerSize() const { return RemotePointerSize; }
636
637 uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
638
639 Expected<std::vector<uint8_t>> readMem(char *Dst, JITTargetAddress Src,
640 uint64_t Size) {
641 return callB<mem::ReadMem>(Src, Size);
642 }
643
644 Error registerEHFrames(JITTargetAddress &RAddr, uint32_t Size) {
645 // FIXME: Duplicate error and report it via ReportError too?
646 return callB<eh::RegisterEHFrames>(RAddr, Size);
647 }
648
649 JITTargetAddress reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
650 uint32_t Align) {
651 if (auto AddrOrErr = callB<mem::ReserveMem>(Id, Size, Align))
652 return *AddrOrErr;
653 else {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100654 ES.reportError(AddrOrErr.takeError());
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100655 return 0;
656 }
657 }
658
659 bool setProtections(ResourceIdMgr::ResourceId Id,
660 JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
661 if (auto Err = callB<mem::SetProtections>(Id, RemoteSegAddr, ProtFlags)) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100662 ES.reportError(std::move(Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100663 return true;
664 } else
665 return false;
666 }
667
668 bool writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
669 if (auto Err = callB<mem::WriteMem>(DirectBufferWriter(Src, Addr, Size))) {
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100670 ES.reportError(std::move(Err));
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100671 return true;
672 } else
673 return false;
674 }
675
676 Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
677 return callB<mem::WritePtr>(Addr, PtrVal);
678 }
679
680 static Error doNothing() { return Error::success(); }
681
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100682 ExecutionSession &ES;
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100683 std::function<void(Error)> ReportError;
684 std::string RemoteTargetTriple;
685 uint32_t RemotePointerSize = 0;
686 uint32_t RemotePageSize = 0;
687 uint32_t RemoteTrampolineSize = 0;
688 uint32_t RemoteIndirectStubSize = 0;
689 ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
690 Optional<RemoteCompileCallbackManager> CallbackManager;
691};
692
693} // end namespace remote
694} // end namespace orc
695} // end namespace llvm
696
697#undef DEBUG_TYPE
698
699#endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H