Line data Source code
1 : //===- 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 :
45 : namespace llvm {
46 : namespace orc {
47 : namespace 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.
56 : class OrcRemoteTargetClient
57 : : public rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel> {
58 : public:
59 : /// Remote-mapped RuntimeDyld-compatible memory manager.
60 : class RemoteRTDyldMemoryManager : public RuntimeDyld::MemoryManager {
61 : friend class OrcRemoteTargetClient;
62 :
63 : public:
64 48 : ~RemoteRTDyldMemoryManager() {
65 24 : Client.destroyRemoteAllocator(Id);
66 : LLVM_DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
67 48 : }
68 24 :
69 : RemoteRTDyldMemoryManager(const RemoteRTDyldMemoryManager &) = delete;
70 : RemoteRTDyldMemoryManager &
71 24 : operator=(const RemoteRTDyldMemoryManager &) = delete;
72 24 : RemoteRTDyldMemoryManager(RemoteRTDyldMemoryManager &&) = default;
73 24 : RemoteRTDyldMemoryManager &operator=(RemoteRTDyldMemoryManager &&) = delete;
74 :
75 24 : 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());
81 : LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
82 : << SectionName << ": " << Alloc << " (" << Size
83 30 : << " bytes, alignment " << Alignment << ")\n");
84 : return Alloc;
85 : }
86 30 :
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 30 : uint8_t *Alloc = reinterpret_cast<uint8_t *>(
93 : Unmapped.back().RODataAllocs.back().getLocalAddress());
94 : LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
95 34 : << SectionName << ": " << Alloc << " (" << Size
96 : << " bytes, alignment " << Alignment << ")\n");
97 : return Alloc;
98 34 : } // else...
99 16 :
100 : Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
101 : uint8_t *Alloc = reinterpret_cast<uint8_t *>(
102 : Unmapped.back().RWDataAllocs.back().getLocalAddress());
103 : LLVM_DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
104 : << SectionName << ": " << Alloc << " (" << Size
105 16 : << " bytes, alignment " << Alignment << ")\n");
106 : return Alloc;
107 : }
108 18 :
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 18 :
115 : LLVM_DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
116 :
117 30 : if (CodeSize != 0) {
118 : Unmapped.back().RemoteCodeAddr =
119 : Client.reserveMem(Id, CodeSize, CodeAlign);
120 :
121 30 : LLVM_DEBUG(dbgs() << " code: "
122 : << format("0x%016x", Unmapped.back().RemoteCodeAddr)
123 : << " (" << CodeSize << " bytes, alignment "
124 : << CodeAlign << ")\n");
125 30 : }
126 30 :
127 60 : if (RODataSize != 0) {
128 : Unmapped.back().RemoteRODataAddr =
129 : Client.reserveMem(Id, RODataSize, RODataAlign);
130 :
131 : LLVM_DEBUG(dbgs() << " ro-data: "
132 : << format("0x%016x", Unmapped.back().RemoteRODataAddr)
133 : << " (" << RODataSize << " bytes, alignment "
134 : << RODataAlign << ")\n");
135 30 : }
136 14 :
137 28 : if (RWDataSize != 0) {
138 : Unmapped.back().RemoteRWDataAddr =
139 : Client.reserveMem(Id, RWDataSize, RWDataAlign);
140 :
141 : LLVM_DEBUG(dbgs() << " rw-data: "
142 : << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
143 : << " (" << RWDataSize << " bytes, alignment "
144 : << RWDataAlign << ")\n");
145 30 : }
146 14 : }
147 28 :
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 30 :
155 : void deregisterEHFrames() override {
156 30 : for (auto &Frame : RegisteredEHFrames) {
157 : // FIXME: Add error poll.
158 4 : Client.deregisterEHFrames(Frame.Addr, Frame.Size);
159 : }
160 4 : }
161 4 :
162 : void notifyObjectLoaded(RuntimeDyld &Dyld,
163 27 : const object::ObjectFile &Obj) override {
164 28 : LLVM_DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
165 : for (auto &ObjAllocs : Unmapped) {
166 1 : mapAllocsToRemoteAddrs(Dyld, ObjAllocs.CodeAllocs,
167 : ObjAllocs.RemoteCodeAddr);
168 27 : mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RODataAllocs,
169 : ObjAllocs.RemoteRODataAddr);
170 30 : mapAllocsToRemoteAddrs(Dyld, ObjAllocs.RWDataAllocs,
171 : ObjAllocs.RemoteRWDataAddr);
172 : Unfinalized.push_back(std::move(ObjAllocs));
173 60 : }
174 30 : Unmapped.clear();
175 : }
176 30 :
177 : bool finalizeMemory(std::string *ErrMsg = nullptr) override {
178 30 : LLVM_DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
179 :
180 30 : for (auto &ObjAllocs : Unfinalized) {
181 : if (copyAndProtect(ObjAllocs.CodeAllocs, ObjAllocs.RemoteCodeAddr,
182 : sys::Memory::MF_READ | sys::Memory::MF_EXEC))
183 30 : return true;
184 :
185 37 : if (copyAndProtect(ObjAllocs.RODataAllocs, ObjAllocs.RemoteRODataAddr,
186 : sys::Memory::MF_READ))
187 : return true;
188 67 :
189 30 : if (copyAndProtect(ObjAllocs.RWDataAllocs, ObjAllocs.RemoteRWDataAddr,
190 : sys::Memory::MF_READ | sys::Memory::MF_WRITE))
191 : return true;
192 : }
193 30 : Unfinalized.clear();
194 :
195 : for (auto &EHFrame : UnfinalizedEHFrames) {
196 : if (auto Err = Client.registerEHFrames(EHFrame.Addr, EHFrame.Size)) {
197 30 : // 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 41 : });
204 4 : return false;
205 : }
206 0 : }
207 : RegisteredEHFrames = std::move(UnfinalizedEHFrames);
208 : UnfinalizedEHFrames = {};
209 :
210 : return false;
211 : }
212 :
213 : private:
214 : class Alloc {
215 37 : public:
216 : Alloc(uint64_t Size, unsigned Align)
217 : : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
218 37 :
219 : Alloc(const Alloc &) = delete;
220 : Alloc &operator=(const Alloc &) = delete;
221 : Alloc(Alloc &&) = default;
222 70 : Alloc &operator=(Alloc &&) = default;
223 :
224 : uint64_t getSize() const { return Size; }
225 64 :
226 : unsigned getAlign() const { return Align; }
227 :
228 : char *getLocalAddress() const {
229 12 : uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
230 : LocalAddr = alignTo(LocalAddr, Align);
231 : return reinterpret_cast<char *>(LocalAddr);
232 0 : }
233 :
234 0 : void setRemoteAddress(JITTargetAddress RemoteAddr) {
235 : this->RemoteAddr = RemoteAddr;
236 : }
237 64 :
238 98 : JITTargetAddress getRemoteAddress() const { return RemoteAddr; }
239 34 :
240 : private:
241 : uint64_t Size;
242 0 : unsigned Align;
243 64 : std::unique_ptr<char[]> Contents;
244 0 : JITTargetAddress RemoteAddr = 0;
245 : };
246 0 :
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 136 :
260 : RemoteRTDyldMemoryManager(OrcRemoteTargetClient &Client,
261 : ResourceIdMgr::ResourceId Id)
262 : : Client(Client), Id(Id) {
263 : LLVM_DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
264 : }
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 24 : NextAddr = alignTo(NextAddr, Alloc.getAlign());
271 : Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextAddr);
272 : LLVM_DEBUG(dbgs() << " "
273 : << static_cast<void *>(Alloc.getLocalAddress())
274 : << " -> " << format("0x%016x", NextAddr) << "\n");
275 90 : Alloc.setRemoteAddress(NextAddr);
276 :
277 154 : // Only advance NextAddr if it was non-null to begin with,
278 64 : // otherwise leave it as null.
279 64 : 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 64 : JITTargetAddress RemoteSegmentAddr,
288 64 : unsigned Permissions) {
289 : if (RemoteSegmentAddr) {
290 90 : assert(!Allocs.empty() && "No sections in allocated segment");
291 :
292 : for (auto &Alloc : Allocs) {
293 : LLVM_DEBUG(dbgs() << " copying section: "
294 90 : << static_cast<void *>(Alloc.getLocalAddress())
295 : << " -> "
296 : << format("0x%016x", Alloc.getRemoteAddress())
297 90 : << " (" << Alloc.getSize() << " bytes)\n";);
298 :
299 : if (Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
300 122 : Alloc.getSize()))
301 : return true;
302 : }
303 :
304 : LLVM_DEBUG(dbgs() << " setting "
305 : << (Permissions & sys::Memory::MF_READ ? 'R' : '-')
306 : << (Permissions & sys::Memory::MF_WRITE ? 'W' : '-')
307 128 : << (Permissions & sys::Memory::MF_EXEC ? 'X' : '-')
308 : << " permissions on block: "
309 : << format("0x%016x", RemoteSegmentAddr) << "\n");
310 : if (Client.setProtections(Id, RemoteSegmentAddr, Permissions))
311 : return true;
312 : }
313 : return false;
314 : }
315 :
316 : OrcRemoteTargetClient &Client;
317 : ResourceIdMgr::ResourceId Id;
318 58 : std::vector<ObjectAllocs> Unmapped;
319 0 : 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 0 :
345 0 : return createStubInternal(StubName, StubAddr, StubFlags);
346 0 : }
347 0 :
348 : Error createStubs(const StubInitsMap &StubInits) override {
349 0 : if (auto Err = reserveStubs(StubInits.size()))
350 0 : return Err;
351 0 :
352 0 : for (auto &Entry : StubInits)
353 : if (auto Err = createStubInternal(Entry.first(), Entry.second.first,
354 0 : Entry.second.second))
355 : return Err;
356 0 :
357 : return Error::success();
358 : }
359 0 :
360 : JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
361 : auto I = StubIndexes.find(Name);
362 0 : if (I == StubIndexes.end())
363 0 : return nullptr;
364 : auto Key = I->second.first;
365 : auto Flags = I->second.second;
366 0 : auto StubSymbol = JITEvaluatedSymbol(getStubAddr(Key), Flags);
367 0 : if (ExportedStubsOnly && !StubSymbol.getFlags().isExported())
368 0 : return nullptr;
369 : return StubSymbol;
370 : }
371 :
372 : JITEvaluatedSymbol findPointer(StringRef Name) override {
373 : auto I = StubIndexes.find(Name);
374 0 : if (I == StubIndexes.end())
375 0 : return nullptr;
376 0 : auto Key = I->second.first;
377 : auto Flags = I->second.second;
378 0 : return JITEvaluatedSymbol(getPtrAddr(Key), Flags);
379 0 : }
380 :
381 0 : Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override {
382 : auto I = StubIndexes.find(Name);
383 0 : assert(I != StubIndexes.end() && "No stub pointer for symbol");
384 : auto Key = I->second.first;
385 : return Client.writePointer(getPtrAddr(Key), NewAddr);
386 0 : }
387 0 :
388 0 : private:
389 : struct RemoteIndirectStubsInfo {
390 0 : JITTargetAddress StubBase;
391 0 : JITTargetAddress PtrBase;
392 0 : unsigned NumStubs;
393 : };
394 :
395 0 : using StubKey = std::pair<uint16_t, uint16_t>;
396 0 :
397 : Error reserveStubs(unsigned NumStubs) {
398 0 : if (NumStubs <= FreeStubs.size())
399 0 : 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 0 : unsigned NewBlockId = RemoteIndirectStubsInfos.size();
412 0 : RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
413 :
414 : for (unsigned I = 0; I < NumStubsEmitted; ++I)
415 0 : FreeStubs.push_back(std::make_pair(NewBlockId, I));
416 :
417 : return Error::success();
418 : }
419 :
420 0 : 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 0 : return Client.writePointer(getPtrAddr(Key), InitAddr);
426 0 : }
427 :
428 0 : JITTargetAddress getStubAddr(StubKey K) {
429 0 : assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
430 : "Missing stub address");
431 : return RemoteIndirectStubsInfos[K.first].StubBase +
432 : K.second * Client.getIndirectStubSize();
433 : }
434 0 :
435 : JITTargetAddress getPtrAddr(StubKey K) {
436 0 : assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
437 : "Missing pointer address");
438 0 : return RemoteIndirectStubsInfos[K.first].PtrBase +
439 0 : K.second * Client.getPointerSize();
440 : }
441 :
442 : OrcRemoteTargetClient &Client;
443 : ResourceIdMgr::ResourceId Id;
444 : std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
445 0 : std::vector<StubKey> FreeStubs;
446 0 : StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
447 : };
448 :
449 : class RemoteTrampolinePool : public TrampolinePool {
450 : public:
451 : RemoteTrampolinePool(OrcRemoteTargetClient &Client) : Client(Client) {}
452 0 :
453 0 : 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 : }
464 :
465 : private:
466 : Error grow() {
467 0 : JITTargetAddress BlockAddr = 0;
468 0 : uint32_t NumTrampolines = 0;
469 0 : if (auto TrampolineInfoOrErr = Client.emitTrampolineBlock())
470 0 : std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
471 : else
472 : return TrampolineInfoOrErr.takeError();
473 :
474 0 : 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 0 :
481 0 : std::mutex RTPMutex;
482 0 : OrcRemoteTargetClient &Client;
483 0 : std::vector<JITTargetAddress> AvailableTrampolines;
484 : };
485 :
486 : /// Remote compile callback manager.
487 : class RemoteCompileCallbackManager : public JITCompileCallbackManager {
488 0 : public:
489 0 : RemoteCompileCallbackManager(OrcRemoteTargetClient &Client,
490 0 : ExecutionSession &ES,
491 : JITTargetAddress ErrorHandlerAddress)
492 : : JITCompileCallbackManager(
493 : llvm::make_unique<RemoteTrampolinePool>(Client), ES,
494 : ErrorHandlerAddress) {}
495 : };
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>>
501 : Create(rpc::RawByteChannel &Channel, ExecutionSession &ES) {
502 : Error Err = Error::success();
503 : auto Client = std::unique_ptr<OrcRemoteTargetClient>(
504 : new OrcRemoteTargetClient(Channel, ES, Err));
505 : 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) {
513 : LLVM_DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr)
514 : << "\n");
515 24 : return callB<exec::CallIntVoid>(Addr);
516 : }
517 :
518 48 : /// Call the int(int, char*[]) function at the given address in the target and
519 24 : /// return its result.
520 : Expected<int> callMain(JITTargetAddress Addr,
521 : const std::vector<std::string> &Args) {
522 : LLVM_DEBUG(dbgs() << "Calling int(*)(int, char*[]) "
523 : << format("0x%016x", Addr) << "\n");
524 : 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 24 : Error callVoidVoid(JITTargetAddress Addr) {
530 : LLVM_DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
531 : << "\n");
532 : 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 24 : return std::move(Err);
553 24 : return llvm::make_unique<RemoteIndirectStubsManager>(*this, Id);
554 48 : }
555 :
556 : Expected<RemoteCompileCallbackManager &>
557 24 : enableCompileCallbacks(JITTargetAddress ErrorHandlerAddress) {
558 : assert(!CallbackManager && "CallbackManager already obtained");
559 :
560 : // 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.
565 : CallbackManager.emplace(*this, ES, ErrorHandlerAddress);
566 : 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 :
582 : private:
583 : OrcRemoteTargetClient(rpc::RawByteChannel &Channel, ExecutionSession &ES,
584 : Error &Err)
585 : : rpc::SingleThreadedRPCEndpoint<rpc::RawByteChannel>(Channel, true),
586 : ES(ES) {
587 : 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 24 : });
595 :
596 : if (auto RIOrErr = callB<utils::GetRemoteInfo>()) {
597 24 : std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
598 : RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
599 24 : Err = Error::success();
600 24 : } else
601 : Err = RIOrErr.takeError();
602 : }
603 24 :
604 : void deregisterEHFrames(JITTargetAddress Addr, uint32_t Size) {
605 0 : if (auto Err = callB<eh::RegisterEHFrames>(Addr, Size))
606 0 : ES.reportError(std::move(Err));
607 : }
608 :
609 : void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
610 48 : if (auto Err = callB<mem::DestroyRemoteAllocator>(Id)) {
611 24 : // FIXME: This will be triggered by a removeModuleSet call: Propagate
612 24 : // error return up through that.
613 : llvm_unreachable("Failed to destroy remote allocator.");
614 : AllocatorIds.release(Id);
615 : }
616 24 : }
617 :
618 1 : void destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
619 2 : IndirectStubOwnerIds.release(Id);
620 0 : if (auto Err = callB<stubs::DestroyIndirectStubsOwner>(Id))
621 1 : ES.reportError(std::move(Err));
622 : }
623 24 :
624 48 : Expected<std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>>
625 : emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
626 : return callB<stubs::EmitIndirectStubs>(Id, NumStubsRequired);
627 0 : }
628 :
629 : Expected<std::tuple<JITTargetAddress, uint32_t>> emitTrampolineBlock() {
630 24 : return callB<stubs::EmitTrampolineBlock>();
631 : }
632 0 :
633 0 : uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
634 0 : uint32_t getPageSize() const { return RemotePageSize; }
635 0 : uint32_t getPointerSize() const { return RemotePointerSize; }
636 0 :
637 : uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
638 :
639 : Expected<std::vector<uint8_t>> readMem(char *Dst, JITTargetAddress Src,
640 0 : uint64_t Size) {
641 : return callB<mem::ReadMem>(Src, Size);
642 : }
643 :
644 0 : 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 0 : }
648 :
649 0 : JITTargetAddress reserveMem(ResourceIdMgr::ResourceId Id, uint64_t Size,
650 : uint32_t Align) {
651 0 : if (auto AddrOrErr = callB<mem::ReserveMem>(Id, Size, Align))
652 : return *AddrOrErr;
653 : else {
654 : ES.reportError(AddrOrErr.takeError());
655 : return 0;
656 : }
657 : }
658 :
659 : bool setProtections(ResourceIdMgr::ResourceId Id,
660 4 : JITTargetAddress RemoteSegAddr, unsigned ProtFlags) {
661 : if (auto Err = callB<mem::SetProtections>(Id, RemoteSegAddr, ProtFlags)) {
662 : ES.reportError(std::move(Err));
663 58 : return true;
664 : } else
665 58 : return false;
666 58 : }
667 :
668 0 : bool writeMem(JITTargetAddress Addr, const char *Src, uint64_t Size) {
669 0 : if (auto Err = callB<mem::WriteMem>(DirectBufferWriter(Src, Addr, Size))) {
670 : ES.reportError(std::move(Err));
671 : return true;
672 : } else
673 58 : return false;
674 : }
675 116 :
676 0 : Error writePointer(JITTargetAddress Addr, JITTargetAddress PtrVal) {
677 0 : return callB<mem::WritePtr>(Addr, PtrVal);
678 : }
679 :
680 : static Error doNothing() { return Error::success(); }
681 :
682 64 : ExecutionSession &ES;
683 128 : std::function<void(Error)> ReportError;
684 0 : std::string RemoteTargetTriple;
685 0 : 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 0 : };
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
|