llvm.org GIT mirror llvm / 51c6025
[Orc] Add support for remote JITing to the ORC API. This patch adds utilities to ORC for managing a remote JIT target. It consists of: 1. A very primitive RPC system for making calls over a byte-stream. See RPCChannel.h, RPCUtils.h. 2. An RPC API defined in the above system for managing memory, looking up symbols, creating stubs, etc. on a remote target. See OrcRemoteTargetRPCAPI.h. 3. An interface for creating high-level JIT components (memory managers, callback managers, stub managers, etc.) that operate over the RPC API. See OrcRemoteTargetClient.h. 4. A helper class for building servers that can handle the RPC calls. See OrcRemoteTargetServer.h. The system is designed to work neatly with the existing ORC components and functionality. In particular, the ORC callback API (and consequently the CompileOnDemandLayer) is supported, enabling lazy compilation of remote code. Assuming this doesn't trigger any builder failures, a follow-up patch will be committed which tests these utilities by using them to replace LLI's existing remote-JITing demo code. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@257305 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 3 years ago
9 changed file(s) with 2068 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 //===---- OrcRemoteTargetClient.h - Orc Remote-target Client ----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the OrcRemoteTargetClient class and helpers. This class
10 // can be used to communicate over an RPCChannel with an OrcRemoteTargetServer
11 // 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 "OrcRemoteTargetRPCAPI.h"
19
20 #define DEBUG_TYPE "orc-remote"
21
22 namespace llvm {
23 namespace orc {
24 namespace remote {
25
26 /// This class provides utilities (including memory manager, indirect stubs
27 /// manager, and compile callback manager types) that support remote JITing
28 /// in ORC.
29 ///
30 /// Each of the utility classes talks to a JIT server (an instance of the
31 /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
32 /// its actions.
33 template
34 class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
35 public:
36 /// Remote memory manager.
37 class RCMemoryManager : public RuntimeDyld::MemoryManager {
38 public:
39 RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
40 : Client(Client), Id(Id) {
41 DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
42 }
43
44 ~RCMemoryManager() {
45 Client.destroyRemoteAllocator(Id);
46 DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
47 }
48
49 uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
50 unsigned SectionID,
51 StringRef SectionName) override {
52 Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
53 uint8_t *Alloc = reinterpret_cast(
54 Unmapped.back().CodeAllocs.back().getLocalAddress());
55 DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
56 << SectionName << ": " << Alloc << " (" << Size
57 << " bytes, alignment " << Alignment << ")\n");
58 return Alloc;
59 }
60
61 uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
62 unsigned SectionID, StringRef SectionName,
63 bool IsReadOnly) override {
64 if (IsReadOnly) {
65 Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
66 uint8_t *Alloc = reinterpret_cast(
67 Unmapped.back().RODataAllocs.back().getLocalAddress());
68 DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
69 << SectionName << ": " << Alloc << " (" << Size
70 << " bytes, alignment " << Alignment << ")\n");
71 return Alloc;
72 } // else...
73
74 Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
75 uint8_t *Alloc = reinterpret_cast(
76 Unmapped.back().RWDataAllocs.back().getLocalAddress());
77 DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
78 << SectionName << ": " << Alloc << " (" << Size
79 << " bytes, alignment " << Alignment << "\n");
80 return Alloc;
81 }
82
83 void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
84 uintptr_t RODataSize, uint32_t RODataAlign,
85 uintptr_t RWDataSize,
86 uint32_t RWDataAlign) override {
87 Unmapped.push_back(ObjectAllocs());
88
89 DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
90
91 if (CodeSize != 0) {
92 if (auto EC = Client.reserveMem(Unmapped.back().RemoteCodeAddr, Id,
93 CodeSize, CodeAlign)) {
94 // FIXME; Add error to poll.
95 llvm_unreachable("Failed reserving remote memory.");
96 }
97 DEBUG(dbgs() << " code: "
98 << format("0x%016x", Unmapped.back().RemoteCodeAddr)
99 << " (" << CodeSize << " bytes, alignment " << CodeAlign
100 << ")\n");
101 }
102
103 if (RODataSize != 0) {
104 if (auto EC = Client.reserveMem(Unmapped.back().RemoteRODataAddr, Id,
105 RODataSize, RODataAlign)) {
106 // FIXME; Add error to poll.
107 llvm_unreachable("Failed reserving remote memory.");
108 }
109 DEBUG(dbgs() << " ro-data: "
110 << format("0x%016x", Unmapped.back().RemoteRODataAddr)
111 << " (" << RODataSize << " bytes, alignment "
112 << RODataAlign << ")\n");
113 }
114
115 if (RWDataSize != 0) {
116 if (auto EC = Client.reserveMem(Unmapped.back().RemoteRWDataAddr, Id,
117 RWDataSize, RWDataAlign)) {
118 // FIXME; Add error to poll.
119 llvm_unreachable("Failed reserving remote memory.");
120 }
121 DEBUG(dbgs() << " rw-data: "
122 << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
123 << " (" << RWDataSize << " bytes, alignment "
124 << RWDataAlign << ")\n");
125 }
126 }
127
128 bool needsToReserveAllocationSpace() override { return true; }
129
130 void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
131 size_t Size) override {}
132
133 void deregisterEHFrames(uint8_t *addr, uint64_t LoadAddr,
134 size_t Size) override {}
135
136 void notifyObjectLoaded(RuntimeDyld &Dyld,
137 const object::ObjectFile &Obj) override {
138 DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
139 for (auto &ObjAllocs : Unmapped) {
140 {
141 TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr;
142 for (auto &Alloc : ObjAllocs.CodeAllocs) {
143 NextCodeAddr = RoundUpToAlignment(NextCodeAddr, Alloc.getAlign());
144 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr);
145 DEBUG(dbgs() << " code: "
146 << static_cast(Alloc.getLocalAddress())
147 << " -> " << format("0x%016x", NextCodeAddr) << "\n");
148 Alloc.setRemoteAddress(NextCodeAddr);
149 NextCodeAddr += Alloc.getSize();
150 }
151 }
152 {
153 TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr;
154 for (auto &Alloc : ObjAllocs.RODataAllocs) {
155 NextRODataAddr =
156 RoundUpToAlignment(NextRODataAddr, Alloc.getAlign());
157 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr);
158 DEBUG(dbgs() << " ro-data: "
159 << static_cast(Alloc.getLocalAddress())
160 << " -> " << format("0x%016x", NextRODataAddr)
161 << "\n");
162 Alloc.setRemoteAddress(NextRODataAddr);
163 NextRODataAddr += Alloc.getSize();
164 }
165 }
166 {
167 TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr;
168 for (auto &Alloc : ObjAllocs.RWDataAllocs) {
169 NextRWDataAddr =
170 RoundUpToAlignment(NextRWDataAddr, Alloc.getAlign());
171 Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr);
172 DEBUG(dbgs() << " rw-data: "
173 << static_cast(Alloc.getLocalAddress())
174 << " -> " << format("0x%016x", NextRWDataAddr)
175 << "\n");
176 Alloc.setRemoteAddress(NextRWDataAddr);
177 NextRWDataAddr += Alloc.getSize();
178 }
179 }
180 Unfinalized.push_back(std::move(ObjAllocs));
181 }
182 Unmapped.clear();
183 }
184
185 bool finalizeMemory(std::string *ErrMsg = nullptr) override {
186 DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
187
188 for (auto &ObjAllocs : Unfinalized) {
189
190 for (auto &Alloc : ObjAllocs.CodeAllocs) {
191 DEBUG(dbgs() << " copying code: "
192 << static_cast(Alloc.getLocalAddress()) << " -> "
193 << format("0x%016x", Alloc.getRemoteAddress()) << " ("
194 << Alloc.getSize() << " bytes)\n");
195 Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
196 Alloc.getSize());
197 }
198
199 if (ObjAllocs.RemoteCodeAddr) {
200 DEBUG(dbgs() << " setting R-X permissions on code block: "
201 << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n");
202 Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
203 sys::Memory::MF_READ | sys::Memory::MF_EXEC);
204 }
205
206 for (auto &Alloc : ObjAllocs.RODataAllocs) {
207 DEBUG(dbgs() << " copying ro-data: "
208 << static_cast(Alloc.getLocalAddress()) << " -> "
209 << format("0x%016x", Alloc.getRemoteAddress()) << " ("
210 << Alloc.getSize() << " bytes)\n");
211 Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
212 Alloc.getSize());
213 }
214
215 if (ObjAllocs.RemoteRODataAddr) {
216 DEBUG(dbgs() << " setting R-- permissions on ro-data block: "
217 << format("0x%016x", ObjAllocs.RemoteRODataAddr)
218 << "\n");
219 Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
220 sys::Memory::MF_READ);
221 }
222
223 for (auto &Alloc : ObjAllocs.RWDataAllocs) {
224 DEBUG(dbgs() << " copying rw-data: "
225 << static_cast(Alloc.getLocalAddress()) << " -> "
226 << format("0x%016x", Alloc.getRemoteAddress()) << " ("
227 << Alloc.getSize() << " bytes)\n");
228 Client.writeMem(Alloc.getRemoteAddress(), Alloc.getLocalAddress(),
229 Alloc.getSize());
230 }
231
232 if (ObjAllocs.RemoteRWDataAddr) {
233 DEBUG(dbgs() << " setting RW- permissions on rw-data block: "
234 << format("0x%016x", ObjAllocs.RemoteRWDataAddr)
235 << "\n");
236 Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
237 sys::Memory::MF_READ | sys::Memory::MF_WRITE);
238 }
239 }
240 Unfinalized.clear();
241
242 return false;
243 }
244
245 private:
246 class Alloc {
247 public:
248 Alloc(uint64_t Size, unsigned Align)
249 : Size(Size), Align(Align), Contents(new char[Size + Align - 1]),
250 RemoteAddr(0) {}
251
252 uint64_t getSize() const { return Size; }
253
254 unsigned getAlign() const { return Align; }
255
256 char *getLocalAddress() const {
257 uintptr_t LocalAddr = reinterpret_cast(Contents.get());
258 LocalAddr = RoundUpToAlignment(LocalAddr, Align);
259 return reinterpret_cast(LocalAddr);
260 }
261
262 void setRemoteAddress(TargetAddress RemoteAddr) {
263 this->RemoteAddr = RemoteAddr;
264 }
265
266 TargetAddress getRemoteAddress() const { return RemoteAddr; }
267
268 private:
269 uint64_t Size;
270 unsigned Align;
271 std::unique_ptr Contents;
272 TargetAddress RemoteAddr;
273 };
274
275 struct ObjectAllocs {
276 ObjectAllocs()
277 : RemoteCodeAddr(0), RemoteRODataAddr(0), RemoteRWDataAddr(0) {}
278 TargetAddress RemoteCodeAddr;
279 TargetAddress RemoteRODataAddr;
280 TargetAddress RemoteRWDataAddr;
281 std::vector CodeAllocs, RODataAllocs, RWDataAllocs;
282 };
283
284 OrcRemoteTargetClient &Client;
285 ResourceIdMgr::ResourceId Id;
286 std::vector Unmapped;
287 std::vector Unfinalized;
288 };
289
290 /// Remote indirect stubs manager.
291 class RCIndirectStubsManager : public IndirectStubsManager {
292 public:
293 RCIndirectStubsManager(OrcRemoteTargetClient &Remote,
294 ResourceIdMgr::ResourceId Id)
295 : Remote(Remote), Id(Id) {}
296
297 ~RCIndirectStubsManager() { Remote.destroyIndirectStubsManager(Id); }
298
299 std::error_code createStub(StringRef StubName, TargetAddress StubAddr,
300 JITSymbolFlags StubFlags) override {
301 if (auto EC = reserveStubs(1))
302 return EC;
303
304 return createStubInternal(StubName, StubAddr, StubFlags);
305 }
306
307 std::error_code createStubs(const StubInitsMap &StubInits) override {
308 if (auto EC = reserveStubs(StubInits.size()))
309 return EC;
310
311 for (auto &Entry : StubInits)
312 if (auto EC = createStubInternal(Entry.first(), Entry.second.first,
313 Entry.second.second))
314 return EC;
315
316 return std::error_code();
317 }
318
319 JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
320 auto I = StubIndexes.find(Name);
321 if (I == StubIndexes.end())
322 return nullptr;
323 auto Key = I->second.first;
324 auto Flags = I->second.second;
325 auto StubSymbol = JITSymbol(getStubAddr(Key), Flags);
326 if (ExportedStubsOnly && !StubSymbol.isExported())
327 return nullptr;
328 return StubSymbol;
329 }
330
331 JITSymbol findPointer(StringRef Name) override {
332 auto I = StubIndexes.find(Name);
333 if (I == StubIndexes.end())
334 return nullptr;
335 auto Key = I->second.first;
336 auto Flags = I->second.second;
337 return JITSymbol(getPtrAddr(Key), Flags);
338 }
339
340 std::error_code updatePointer(StringRef Name,
341 TargetAddress NewAddr) override {
342 auto I = StubIndexes.find(Name);
343 assert(I != StubIndexes.end() && "No stub pointer for symbol");
344 auto Key = I->second.first;
345 return Remote.writePointer(getPtrAddr(Key), NewAddr);
346 }
347
348 private:
349 struct RemoteIndirectStubsInfo {
350 RemoteIndirectStubsInfo(TargetAddress StubBase, TargetAddress PtrBase,
351 unsigned NumStubs)
352 : StubBase(StubBase), PtrBase(PtrBase), NumStubs(NumStubs) {}
353 TargetAddress StubBase;
354 TargetAddress PtrBase;
355 unsigned NumStubs;
356 };
357
358 OrcRemoteTargetClient &Remote;
359 ResourceIdMgr::ResourceId Id;
360 std::vector RemoteIndirectStubsInfos;
361 typedef std::pair StubKey;
362 std::vector FreeStubs;
363 StringMap> StubIndexes;
364
365 std::error_code reserveStubs(unsigned NumStubs) {
366 if (NumStubs <= FreeStubs.size())
367 return std::error_code();
368
369 unsigned NewStubsRequired = NumStubs - FreeStubs.size();
370 TargetAddress StubBase;
371 TargetAddress PtrBase;
372 unsigned NumStubsEmitted;
373
374 Remote.emitIndirectStubs(StubBase, PtrBase, NumStubsEmitted, Id,
375 NewStubsRequired);
376
377 unsigned NewBlockId = RemoteIndirectStubsInfos.size();
378 RemoteIndirectStubsInfos.push_back(
379 RemoteIndirectStubsInfo(StubBase, PtrBase, NumStubsEmitted));
380
381 for (unsigned I = 0; I < NumStubsEmitted; ++I)
382 FreeStubs.push_back(std::make_pair(NewBlockId, I));
383
384 return std::error_code();
385 }
386
387 std::error_code createStubInternal(StringRef StubName,
388 TargetAddress InitAddr,
389 JITSymbolFlags StubFlags) {
390 auto Key = FreeStubs.back();
391 FreeStubs.pop_back();
392 StubIndexes[StubName] = std::make_pair(Key, StubFlags);
393 return Remote.writePointer(getPtrAddr(Key), InitAddr);
394 }
395
396 TargetAddress getStubAddr(StubKey K) {
397 assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
398 "Missing stub address");
399 return RemoteIndirectStubsInfos[K.first].StubBase +
400 K.second * Remote.getIndirectStubSize();
401 }
402
403 TargetAddress getPtrAddr(StubKey K) {
404 assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
405 "Missing pointer address");
406 return RemoteIndirectStubsInfos[K.first].PtrBase +
407 K.second * Remote.getPointerSize();
408 }
409 };
410
411 /// Remote compile callback manager.
412 class RCCompileCallbackManager : public JITCompileCallbackManager {
413 public:
414 RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,
415 OrcRemoteTargetClient &Remote)
416 : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {
417 assert(!Remote.CompileCallback && "Compile callback already set");
418 Remote.CompileCallback = [this](TargetAddress TrampolineAddr) {
419 return executeCompileCallback(TrampolineAddr);
420 };
421 Remote.emitResolverBlock();
422 }
423
424 private:
425 void grow() {
426 TargetAddress BlockAddr = 0;
427 uint32_t NumTrampolines = 0;
428 auto EC = Remote.emitTrampolineBlock(BlockAddr, NumTrampolines);
429 assert(!EC && "Failed to create trampolines");
430
431 uint32_t TrampolineSize = Remote.getTrampolineSize();
432 for (unsigned I = 0; I < NumTrampolines; ++I)
433 this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
434 }
435
436 OrcRemoteTargetClient &Remote;
437 };
438
439 /// Create an OrcRemoteTargetClient.
440 /// Channel is the ChannelT instance to communicate on. It is assumed that
441 /// the channel is ready to be read from and written to.
442 static ErrorOr Create(ChannelT &Channel) {
443 std::error_code EC;
444 OrcRemoteTargetClient H(Channel, EC);
445 if (EC)
446 return EC;
447 return H;
448 }
449
450 /// Call the int(void) function at the given address in the target and return
451 /// its result.
452 std::error_code callIntVoid(int &Result, TargetAddress Addr) {
453 DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
454
455 if (auto EC = call(Channel, Addr))
456 return EC;
457
458 unsigned NextProcId;
459 if (auto EC = listenForCompileRequests(NextProcId))
460 return EC;
461
462 if (NextProcId != CallIntVoidResponseId)
463 return orcError(OrcErrorCode::UnexpectedRPCCall);
464
465 return handle(Channel, [&](int R) {
466 Result = R;
467 DEBUG(dbgs() << "Result: " << R << "\n");
468 return std::error_code();
469 });
470 }
471
472 /// Call the int(int, char*[]) function at the given address in the target and
473 /// return its result.
474 std::error_code callMain(int &Result, TargetAddress Addr,
475 const std::vector &Args) {
476 DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
477 << "\n");
478
479 if (auto EC = call(Channel, Addr, Args))
480 return EC;
481
482 unsigned NextProcId;
483 if (auto EC = listenForCompileRequests(NextProcId))
484 return EC;
485
486 if (NextProcId != CallMainResponseId)
487 return orcError(OrcErrorCode::UnexpectedRPCCall);
488
489 return handle(Channel, [&](int R) {
490 Result = R;
491 DEBUG(dbgs() << "Result: " << R << "\n");
492 return std::error_code();
493 });
494 }
495
496 /// Call the void() function at the given address in the target and wait for
497 /// it to finish.
498 std::error_code callVoidVoid(TargetAddress Addr) {
499 DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
500 << "\n");
501
502 if (auto EC = call(Channel, Addr))
503 return EC;
504
505 unsigned NextProcId;
506 if (auto EC = listenForCompileRequests(NextProcId))
507 return EC;
508
509 if (NextProcId != CallVoidVoidResponseId)
510 return orcError(OrcErrorCode::UnexpectedRPCCall);
511
512 return handle(Channel, doNothing);
513 }
514
515 /// Create an RCMemoryManager which will allocate its memory on the remote
516 /// target.
517 std::error_code
518 createRemoteMemoryManager(std::unique_ptr &MM) {
519 assert(!MM && "MemoryManager should be null before creation.");
520
521 auto Id = AllocatorIds.getNext();
522 if (auto EC = call(Channel, Id))
523 return EC;
524 MM = llvm::make_unique(*this, Id);
525 return std::error_code();
526 }
527
528 /// Create an RCIndirectStubsManager that will allocate stubs on the remote
529 /// target.
530 std::error_code
531 createIndirectStubsManager(std::unique_ptr &I) {
532 assert(!I && "Indirect stubs manager should be null before creation.");
533 auto Id = IndirectStubOwnerIds.getNext();
534 if (auto EC = call(Channel, Id))
535 return EC;
536 I = llvm::make_unique(*this, Id);
537 return std::error_code();
538 }
539
540 /// Search for symbols in the remote process. Note: This should be used by
541 /// symbol resolvers *after* they've searched the local symbol table in the
542 /// JIT stack.
543 std::error_code getSymbolAddress(TargetAddress &Addr, StringRef Name) {
544 // Check for an 'out-of-band' error, e.g. from an MM destructor.
545 if (ExistingError)
546 return ExistingError;
547
548 // Request remote symbol address.
549 if (auto EC = call(Channel, Name))
550 return EC;
551
552 return expect(Channel, [&](TargetAddress &A) {
553 Addr = A;
554 DEBUG(dbgs() << "Remote address lookup " << Name << " = "
555 << format("0x%016x", Addr) << "\n");
556 return std::error_code();
557 });
558 }
559
560 /// Get the triple for the remote target.
561 const std::string &getTargetTriple() const { return RemoteTargetTriple; }
562
563 std::error_code terminateSession() { return call(Channel); }
564
565 private:
566 OrcRemoteTargetClient(ChannelT &Channel, std::error_code &EC)
567 : Channel(Channel), RemotePointerSize(0), RemotePageSize(0),
568 RemoteTrampolineSize(0), RemoteIndirectStubSize(0) {
569 if ((EC = call(Channel)))
570 return;
571
572 EC = expect(
573 Channel, readArgs(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
574 RemoteTrampolineSize, RemoteIndirectStubSize));
575 }
576
577 void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
578 if (auto EC = call(Channel, Id)) {
579 // FIXME: This will be triggered by a removeModuleSet call: Propagate
580 // error return up through that.
581 llvm_unreachable("Failed to destroy remote allocator.");
582 AllocatorIds.release(Id);
583 }
584 }
585
586 std::error_code destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
587 IndirectStubOwnerIds.release(Id);
588 return call(Channel, Id);
589 }
590
591 std::error_code emitIndirectStubs(TargetAddress &StubBase,
592 TargetAddress &PtrBase,
593 uint32_t &NumStubsEmitted,
594 ResourceIdMgr::ResourceId Id,
595 uint32_t NumStubsRequired) {
596 if (auto EC = call(Channel, Id, NumStubsRequired))
597 return EC;
598
599 return expect(
600 Channel, readArgs(StubBase, PtrBase, NumStubsEmitted));
601 }
602
603 std::error_code emitResolverBlock() {
604 // Check for an 'out-of-band' error, e.g. from an MM destructor.
605 if (ExistingError)
606 return ExistingError;
607
608 return call(Channel);
609 }
610
611 std::error_code emitTrampolineBlock(TargetAddress &BlockAddr,
612 uint32_t &NumTrampolines) {
613 // Check for an 'out-of-band' error, e.g. from an MM destructor.
614 if (ExistingError)
615 return ExistingError;
616
617 if (auto EC = call(Channel))
618 return EC;
619
620 return expect(
621 Channel, [&](TargetAddress BAddr, uint32_t NTrampolines) {
622 BlockAddr = BAddr;
623 NumTrampolines = NTrampolines;
624 return std::error_code();
625 });
626 }
627
628 uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
629 uint32_t getPageSize() const { return RemotePageSize; }
630 uint32_t getPointerSize() const { return RemotePointerSize; }
631
632 uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
633
634 std::error_code listenForCompileRequests(uint32_t &NextId) {
635 // Check for an 'out-of-band' error, e.g. from an MM destructor.
636 if (ExistingError)
637 return ExistingError;
638
639 if (auto EC = getNextProcId(Channel, NextId))
640 return EC;
641
642 while (NextId == RequestCompileId) {
643 TargetAddress TrampolineAddr = 0;
644 if (auto EC = handle(Channel, readArgs(TrampolineAddr)))
645 return EC;
646
647 TargetAddress ImplAddr = CompileCallback(TrampolineAddr);
648 if (auto EC = call(Channel, ImplAddr))
649 return EC;
650
651 if (auto EC = getNextProcId(Channel, NextId))
652 return EC;
653 }
654
655 return std::error_code();
656 }
657
658 std::error_code readMem(char *Dst, TargetAddress Src, uint64_t Size) {
659 // Check for an 'out-of-band' error, e.g. from an MM destructor.
660 if (ExistingError)
661 return ExistingError;
662
663 if (auto EC = call(Channel, Src, Size))
664 return EC;
665
666 if (auto EC = expect(
667 Channel, [&]() { return Channel.readBytes(Dst, Size); }))
668 return EC;
669
670 return std::error_code();
671 }
672
673 std::error_code reserveMem(TargetAddress &RemoteAddr,
674 ResourceIdMgr::ResourceId Id, uint64_t Size,
675 uint32_t Align) {
676
677 // Check for an 'out-of-band' error, e.g. from an MM destructor.
678 if (ExistingError)
679 return ExistingError;
680
681 if (auto EC = call(Channel, Id, Size, Align))
682 return EC;
683
684 if (auto EC = expect(Channel, [&](TargetAddress Addr) {
685 RemoteAddr = Addr;
686 return std::error_code();
687 }))
688 return EC;
689
690 return std::error_code();
691 }
692
693 std::error_code setProtections(ResourceIdMgr::ResourceId Id,
694 TargetAddress RemoteSegAddr,
695 unsigned ProtFlags) {
696 return call(Channel, Id, RemoteSegAddr, ProtFlags);
697 }
698
699 std::error_code writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
700 // Check for an 'out-of-band' error, e.g. from an MM destructor.
701 if (ExistingError)
702 return ExistingError;
703
704 // Make the send call.
705 if (auto EC = call(Channel, Addr, Size))
706 return EC;
707
708 // Follow this up with the section contents.
709 if (auto EC = Channel.appendBytes(Src, Size))
710 return EC;
711
712 return Channel.send();
713 }
714
715 std::error_code writePointer(TargetAddress Addr, TargetAddress PtrVal) {
716 // Check for an 'out-of-band' error, e.g. from an MM destructor.
717 if (ExistingError)
718 return ExistingError;
719
720 return call(Channel, Addr, PtrVal);
721 }
722
723 static std::error_code doNothing() { return std::error_code(); }
724
725 ChannelT &Channel;
726 std::error_code ExistingError;
727 std::string RemoteTargetTriple;
728 uint32_t RemotePointerSize;
729 uint32_t RemotePageSize;
730 uint32_t RemoteTrampolineSize;
731 uint32_t RemoteIndirectStubSize;
732 ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
733 std::function CompileCallback;
734 };
735
736 } // end namespace remote
737 } // end namespace orc
738 } // end namespace llvm
739
740 #undef DEBUG_TYPE
741
742 #endif
0 //===--- OrcRemoteTargetRPCAPI.h - Orc Remote-target RPC API ----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines the Orc remote-target RPC API. It should not be used
10 // directly, but is used by the RemoteTargetClient and RemoteTargetServer
11 // classes.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
16 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
17
18 #include "JITSymbol.h"
19 #include "RPCChannel.h"
20 #include "RPCUtils.h"
21
22 namespace llvm {
23 namespace orc {
24 namespace remote {
25
26 class OrcRemoteTargetRPCAPI : public RPC {
27 protected:
28 class ResourceIdMgr {
29 public:
30 typedef uint64_t ResourceId;
31 ResourceIdMgr() : NextId(0) {}
32 ResourceId getNext() {
33 if (!FreeIds.empty()) {
34 ResourceId I = FreeIds.back();
35 FreeIds.pop_back();
36 return I;
37 }
38 return NextId++;
39 }
40 void release(ResourceId I) { FreeIds.push_back(I); }
41
42 private:
43 ResourceId NextId;
44 std::vector FreeIds;
45 };
46
47 public:
48 enum JITProcId : uint32_t {
49 InvalidId = 0,
50 CallIntVoidId,
51 CallIntVoidResponseId,
52 CallMainId,
53 CallMainResponseId,
54 CallVoidVoidId,
55 CallVoidVoidResponseId,
56 CreateRemoteAllocatorId,
57 CreateIndirectStubsOwnerId,
58 DestroyRemoteAllocatorId,
59 DestroyIndirectStubsOwnerId,
60 EmitIndirectStubsId,
61 EmitIndirectStubsResponseId,
62 EmitResolverBlockId,
63 EmitTrampolineBlockId,
64 EmitTrampolineBlockResponseId,
65 GetSymbolAddressId,
66 GetSymbolAddressResponseId,
67 GetRemoteInfoId,
68 GetRemoteInfoResponseId,
69 ReadMemId,
70 ReadMemResponseId,
71 ReserveMemId,
72 ReserveMemResponseId,
73 RequestCompileId,
74 RequestCompileResponseId,
75 SetProtectionsId,
76 TerminateSessionId,
77 WriteMemId,
78 WritePtrId
79 };
80
81 static const char *getJITProcIdName(JITProcId Id);
82
83 typedef Procedure CallIntVoid;
84
85 typedef Procedure
86 CallIntVoidResponse;
87
88 typedef Procedure
89 std::vector /* Args */>
90 CallMain;
91
92 typedef Procedure CallMainResponse;
93
94 typedef Procedure CallVoidVoid;
95
96 typedef Procedure CallVoidVoidResponse;
97
98 typedef Procedure
99 ResourceIdMgr::ResourceId /* Allocator ID */>
100 CreateRemoteAllocator;
101
102 typedef Procedure
103 ResourceIdMgr::ResourceId /* StubsOwner ID */>
104 CreateIndirectStubsOwner;
105
106 typedef Procedure
107 ResourceIdMgr::ResourceId /* Allocator ID */>
108 DestroyRemoteAllocator;
109
110 typedef Procedure
111 ResourceIdMgr::ResourceId /* StubsOwner ID */>
112 DestroyIndirectStubsOwner;
113
114 typedef Procedure
115 ResourceIdMgr::ResourceId /* StubsOwner ID */,
116 uint32_t /* NumStubsRequired */>
117 EmitIndirectStubs;
118
119 typedef Procedure<
120 EmitIndirectStubsResponseId, TargetAddress /* StubsBaseAddr */,
121 TargetAddress /* PtrsBaseAddr */, uint32_t /* NumStubsEmitted */>
122 EmitIndirectStubsResponse;
123
124 typedef Procedure EmitResolverBlock;
125
126 typedef Procedure EmitTrampolineBlock;
127
128 typedef Procedure
129 TargetAddress /* BlockAddr */,
130 uint32_t /* NumTrampolines */>
131 EmitTrampolineBlockResponse;
132
133 typedef Procedure
134 GetSymbolAddress;
135
136 typedef Procedure
137 GetSymbolAddressResponse;
138
139 typedef Procedure GetRemoteInfo;
140
141 typedef Procedure
142 uint32_t /* PointerSize */, uint32_t /* PageSize */,
143 uint32_t /* TrampolineSize */,
144 uint32_t /* IndirectStubSize */>
145 GetRemoteInfoResponse;
146
147 typedef Procedure
148 ReadMem;
149
150 typedef Procedure ReadMemResponse;
151
152 typedef Procedure
153 uint64_t /* Size */, uint32_t /* Align */>
154 ReserveMem;
155
156 typedef Procedure
157 ReserveMemResponse;
158
159 typedef Procedure
160 RequestCompile;
161
162 typedef Procedure
163 RequestCompileResponse;
164
165 typedef Procedure
166 TargetAddress /* Dst */, uint32_t /* ProtFlags */>
167 SetProtections;
168
169 typedef Procedure TerminateSession;
170
171 typedef Procedure
172 /* Data should follow */>
173 WriteMem;
174
175 typedef Procedure
176 TargetAddress /* Val */>
177 WritePtr;
178 };
179
180 } // end namespace remote
181 } // end namespace orc
182 } // end namespace llvm
183
184 #endif
0 //===---- OrcRemoteTargetServer.h - Orc Remote-target Server ----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
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.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
15 #define LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETSERVER_H
16
17 #include "OrcRemoteTargetRPCAPI.h"
18 #include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
19 #include "llvm/Support/Debug.h"
20 #include "llvm/Support/Format.h"
21 #include "llvm/Support/Process.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include
24
25 #define DEBUG_TYPE "orc-remote"
26
27 namespace llvm {
28 namespace orc {
29 namespace remote {
30
31 template
32 class OrcRemoteTargetServer : public OrcRemoteTargetRPCAPI {
33 public:
34 typedef std::function
35 SymbolLookupFtor;
36
37 OrcRemoteTargetServer(ChannelT &Channel, SymbolLookupFtor SymbolLookup)
38 : Channel(Channel), SymbolLookup(std::move(SymbolLookup)) {}
39
40 std::error_code getNextProcId(JITProcId &Id) {
41 return deserialize(Channel, Id);
42 }
43
44 std::error_code handleKnownProcedure(JITProcId Id) {
45 DEBUG(dbgs() << "Handling known proc: " << getJITProcIdName(Id) << "\n");
46
47 switch (Id) {
48 case CallIntVoidId:
49 return handleCallIntVoid();
50 case CallMainId:
51 return handleCallMain();
52 case CallVoidVoidId:
53 return handleCallVoidVoid();
54 case CreateRemoteAllocatorId:
55 return handleCreateRemoteAllocator();
56 case CreateIndirectStubsOwnerId:
57 return handleCreateIndirectStubsOwner();
58 case DestroyRemoteAllocatorId:
59 return handleDestroyRemoteAllocator();
60 case EmitIndirectStubsId:
61 return handleEmitIndirectStubs();
62 case EmitResolverBlockId:
63 return handleEmitResolverBlock();
64 case EmitTrampolineBlockId:
65 return handleEmitTrampolineBlock();
66 case GetSymbolAddressId:
67 return handleGetSymbolAddress();
68 case GetRemoteInfoId:
69 return handleGetRemoteInfo();
70 case ReadMemId:
71 return handleReadMem();
72 case ReserveMemId:
73 return handleReserveMem();
74 case SetProtectionsId:
75 return handleSetProtections();
76 case WriteMemId:
77 return handleWriteMem();
78 case WritePtrId:
79 return handleWritePtr();
80 default:
81 return orcError(OrcErrorCode::UnexpectedRPCCall);
82 }
83
84 llvm_unreachable("Unhandled JIT RPC procedure Id.");
85 }
86
87 std::error_code requestCompile(TargetAddress &CompiledFnAddr,
88 TargetAddress TrampolineAddr) {
89 if (auto EC = call(Channel, TrampolineAddr))
90 return EC;
91
92 while (1) {
93 JITProcId Id = InvalidId;
94 if (auto EC = getNextProcId(Id))
95 return EC;
96
97 switch (Id) {
98 case RequestCompileResponseId:
99 return handle(Channel,
100 readArgs(CompiledFnAddr));
101 default:
102 if (auto EC = handleKnownProcedure(Id))
103 return EC;
104 }
105 }
106
107 llvm_unreachable("Fell through request-compile command loop.");
108 }
109
110 private:
111 struct Allocator {
112 Allocator() = default;
113 Allocator(Allocator &&) = default;
114 Allocator &operator=(Allocator &&) = default;
115
116 ~Allocator() {
117 for (auto &Alloc : Allocs)
118 sys::Memory::releaseMappedMemory(Alloc.second);
119 }
120
121 std::error_code 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 EC;
127
128 Addr = MB.base();
129 assert(Allocs.find(MB.base()) == Allocs.end() && "Duplicate alloc");
130 Allocs[MB.base()] = std::move(MB);
131 return std::error_code();
132 }
133
134 std::error_code setProtections(void *block, unsigned Flags) {
135 auto I = Allocs.find(block);
136 if (I == Allocs.end())
137 return orcError(OrcErrorCode::RemoteMProtectAddrUnrecognized);
138 return sys::Memory::protectMappedMemory(I->second, Flags);
139 }
140
141 private:
142 std::map Allocs;
143 };
144
145 static std::error_code doNothing() { return std::error_code(); }
146
147 static TargetAddress reenter(void *JITTargetAddr, void *TrampolineAddr) {
148 TargetAddress CompiledFnAddr = 0;
149
150 auto T = static_cast(JITTargetAddr);
151 auto EC = T->requestCompile(
152 CompiledFnAddr, static_cast(
153 reinterpret_cast(TrampolineAddr)));
154 assert(!EC && "Compile request failed");
155 return CompiledFnAddr;
156 }
157
158 std::error_code handleCallIntVoid() {
159 typedef int (*IntVoidFnTy)();
160
161 IntVoidFnTy Fn = nullptr;
162 if (auto EC = handle(Channel, [&](TargetAddress Addr) {
163 Fn = reinterpret_cast(static_cast(Addr));
164 return std::error_code();
165 }))
166 return EC;
167
168 DEBUG(dbgs() << " Calling " << reinterpret_cast(Fn) << "\n");
169 int Result = Fn();
170 DEBUG(dbgs() << " Result = " << Result << "\n");
171
172 return call(Channel, Result);
173 }
174
175 std::error_code handleCallMain() {
176 typedef int (*MainFnTy)(int, const char *[]);
177
178 MainFnTy Fn = nullptr;
179 std::vector Args;
180 if (auto EC = handle(
181 Channel, [&](TargetAddress Addr, std::vector &A) {
182 Fn = reinterpret_cast(static_cast(Addr));
183 Args = std::move(A);
184 return std::error_code();
185 }))
186 return EC;
187
188 int ArgC = Args.size() + 1;
189 int Idx = 1;
190 std::unique_ptr ArgV(new const char *[ArgC + 1]);
191 ArgV[0] = "";
192 for (auto &Arg : Args)
193 ArgV[Idx++] = Arg.c_str();
194
195 DEBUG(dbgs() << " Calling " << reinterpret_cast(Fn) << "\n");
196 int Result = Fn(ArgC, ArgV.get());
197 DEBUG(dbgs() << " Result = " << Result << "\n");
198
199 return call(Channel, Result);
200 }
201
202 std::error_code handleCallVoidVoid() {
203 typedef void (*VoidVoidFnTy)();
204
205 VoidVoidFnTy Fn = nullptr;
206 if (auto EC = handle(Channel, [&](TargetAddress Addr) {
207 Fn = reinterpret_cast(static_cast(Addr));
208 return std::error_code();
209 }))
210 return EC;
211
212 DEBUG(dbgs() << " Calling " << reinterpret_cast(Fn) << "\n");
213 Fn();
214 DEBUG(dbgs() << " Complete.\n");
215
216 return call(Channel);
217 }
218
219 std::error_code handleCreateRemoteAllocator() {
220 return handle(
221 Channel, [&](ResourceIdMgr::ResourceId Id) {
222 auto I = Allocators.find(Id);
223 if (I != Allocators.end())
224 return orcError(OrcErrorCode::RemoteAllocatorIdAlreadyInUse);
225 DEBUG(dbgs() << " Created allocator " << Id << "\n");
226 Allocators[Id] = Allocator();
227 return std::error_code();
228 });
229 }
230
231 std::error_code handleCreateIndirectStubsOwner() {
232 return handle(
233 Channel, [&](ResourceIdMgr::ResourceId Id) {
234 auto I = IndirectStubsOwners.find(Id);
235 if (I != IndirectStubsOwners.end())
236 return orcError(
237 OrcErrorCode::RemoteIndirectStubsOwnerIdAlreadyInUse);
238 DEBUG(dbgs() << " Create indirect stubs owner " << Id << "\n");
239 IndirectStubsOwners[Id] = ISBlockOwnerList();
240 return std::error_code();
241 });
242 }
243
244 std::error_code handleDestroyRemoteAllocator() {
245 return handle(
246 Channel, [&](ResourceIdMgr::ResourceId Id) {
247 auto I = Allocators.find(Id);
248 if (I == Allocators.end())
249 return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
250 Allocators.erase(I);
251 DEBUG(dbgs() << " Destroyed allocator " << Id << "\n");
252 return std::error_code();
253 });
254 }
255
256 std::error_code handleDestroyIndirectStubsOwner() {
257 return handle(
258 Channel, [&](ResourceIdMgr::ResourceId Id) {
259 auto I = IndirectStubsOwners.find(Id);
260 if (I == IndirectStubsOwners.end())
261 return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
262 IndirectStubsOwners.erase(I);
263 return std::error_code();
264 });
265 }
266
267 std::error_code handleEmitIndirectStubs() {
268 ResourceIdMgr::ResourceId ISOwnerId = ~0U;
269 uint32_t NumStubsRequired = 0;
270
271 if (auto EC = handle(
272 Channel, readArgs(ISOwnerId, NumStubsRequired)))
273 return EC;
274
275 DEBUG(dbgs() << " ISMgr " << ISOwnerId << " request " << NumStubsRequired
276 << " stubs.\n");
277
278 auto StubOwnerItr = IndirectStubsOwners.find(ISOwnerId);
279 if (StubOwnerItr == IndirectStubsOwners.end())
280 return orcError(OrcErrorCode::RemoteIndirectStubsOwnerDoesNotExist);
281
282 typename TargetT::IndirectStubsInfo IS;
283 if (auto EC =
284 TargetT::emitIndirectStubsBlock(IS, NumStubsRequired, nullptr))
285 return EC;
286
287 TargetAddress StubsBase =
288 static_cast(reinterpret_cast(IS.getStub(0)));
289 TargetAddress PtrsBase =
290 static_cast(reinterpret_cast(IS.getPtr(0)));
291 uint32_t NumStubsEmitted = IS.getNumStubs();
292
293 auto &BlockList = StubOwnerItr->second;
294 BlockList.push_back(std::move(IS));
295
296 return call(Channel, StubsBase, PtrsBase,
297 NumStubsEmitted);
298 }
299
300 std::error_code handleEmitResolverBlock() {
301 if (auto EC = handle(Channel, doNothing))
302 return EC;
303
304 std::error_code EC;
305 ResolverBlock = sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
306 TargetT::ResolverCodeSize, nullptr,
307 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
308 if (EC)
309 return EC;
310
311 TargetT::writeResolverCode(static_cast(ResolverBlock.base()),
312 &reenter, this);
313
314 return sys::Memory::protectMappedMemory(ResolverBlock.getMemoryBlock(),
315 sys::Memory::MF_READ |
316 sys::Memory::MF_EXEC);
317 }
318
319 std::error_code handleEmitTrampolineBlock() {
320 if (auto EC = handle(Channel, doNothing))
321 return EC;
322
323 std::error_code EC;
324
325 auto TrampolineBlock =
326 sys::OwningMemoryBlock(sys::Memory::allocateMappedMemory(
327 TargetT::PageSize, nullptr,
328 sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC));
329 if (EC)
330 return EC;
331
332 unsigned NumTrampolines =
333 (TargetT::PageSize - TargetT::PointerSize) / TargetT::TrampolineSize;
334
335 uint8_t *TrampolineMem = static_cast(TrampolineBlock.base());
336 TargetT::writeTrampolines(TrampolineMem, ResolverBlock.base(),
337 NumTrampolines);
338
339 EC = sys::Memory::protectMappedMemory(TrampolineBlock.getMemoryBlock(),
340 sys::Memory::MF_READ |
341 sys::Memory::MF_EXEC);
342
343 TrampolineBlocks.push_back(std::move(TrampolineBlock));
344
345 return call(
346 Channel,
347 static_cast(reinterpret_cast(TrampolineMem)),
348 NumTrampolines);
349 }
350
351 std::error_code handleGetSymbolAddress() {
352 std::string SymbolName;
353 if (auto EC = handle(Channel, readArgs(SymbolName)))
354 return EC;
355
356 TargetAddress SymbolAddr = SymbolLookup(SymbolName);
357 DEBUG(dbgs() << " Symbol '" << SymbolName
358 << "' = " << format("0x%016x", SymbolAddr) << "\n");
359 return call(Channel, SymbolAddr);
360 }
361
362 std::error_code handleGetRemoteInfo() {
363 if (auto EC = handle(Channel, doNothing))
364 return EC;
365
366 std::string ProcessTriple = sys::getProcessTriple();
367 uint32_t PointerSize = TargetT::PointerSize;
368 uint32_t PageSize = sys::Process::getPageSize();
369 uint32_t TrampolineSize = TargetT::TrampolineSize;
370 uint32_t IndirectStubSize = TargetT::IndirectStubsInfo::StubSize;
371 DEBUG(dbgs() << " Remote info:\n"
372 << " triple = '" << ProcessTriple << "'\n"
373 << " pointer size = " << PointerSize << "\n"
374 << " page size = " << PageSize << "\n"
375 << " trampoline size = " << TrampolineSize << "\n"
376 << " indirect stub size = " << IndirectStubSize << "\n");
377 return call(Channel, ProcessTriple, PointerSize,
378 PageSize, TrampolineSize,
379 IndirectStubSize);
380 }
381
382 std::error_code handleReadMem() {
383 char *Src = nullptr;
384 uint64_t Size = 0;
385 if (auto EC =
386 handle(Channel, [&](TargetAddress RSrc, uint64_t RSize) {
387 Src = reinterpret_cast(static_cast(RSrc));
388 Size = RSize;
389 return std::error_code();
390 }))
391 return EC;
392
393 DEBUG(dbgs() << " Reading " << Size << " bytes from "
394 << static_cast(Src) << "\n");
395
396 if (auto EC = call(Channel))
397 return EC;
398
399 if (auto EC = Channel.appendBytes(Src, Size))
400 return EC;
401
402 return Channel.send();
403 }
404
405 std::error_code handleReserveMem() {
406 void *LocalAllocAddr = nullptr;
407
408 if (auto EC =
409 handle(Channel, [&](ResourceIdMgr::ResourceId Id,
410 uint64_t Size, uint32_t Align) {
411 auto I = Allocators.find(Id);
412 if (I == Allocators.end())
413 return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
414 auto &Allocator = I->second;
415 auto EC2 = Allocator.allocate(LocalAllocAddr, Size, Align);
416 DEBUG(dbgs() << " Allocator " << Id << " reserved "
417 << LocalAllocAddr << " (" << Size
418 << " bytes, alignment " << Align << ")\n");
419 return EC2;
420 }))
421 return EC;
422
423 TargetAddress AllocAddr =
424 static_cast(reinterpret_cast(LocalAllocAddr));
425
426 return call(Channel, AllocAddr);
427 }
428
429 std::error_code handleSetProtections() {
430 return handle(Channel, [&](ResourceIdMgr::ResourceId Id,
431 TargetAddress Addr, uint32_t Flags) {
432 auto I = Allocators.find(Id);
433 if (I == Allocators.end())
434 return orcError(OrcErrorCode::RemoteAllocatorDoesNotExist);
435 auto &Allocator = I->second;
436 void *LocalAddr = reinterpret_cast(static_cast(Addr));
437 DEBUG(dbgs() << " Allocator " << Id << " set permissions on "
438 << LocalAddr << " to "
439 << (Flags & sys::Memory::MF_READ ? 'R' : '-')
440 << (Flags & sys::Memory::MF_WRITE ? 'W' : '-')
441 << (Flags & sys::Memory::MF_EXEC ? 'X' : '-') << "\n");
442 return Allocator.setProtections(LocalAddr, Flags);
443 });
444 }
445
446 std::error_code handleWriteMem() {
447 return handle(Channel, [&](TargetAddress RDst, uint64_t Size) {
448 char *Dst = reinterpret_cast(static_cast(RDst));
449 return Channel.readBytes(Dst, Size);
450 });
451 }
452
453 std::error_code handleWritePtr() {
454 return handle(
455 Channel, [&](TargetAddress Addr, TargetAddress PtrVal) {
456 uintptr_t *Ptr =
457 reinterpret_cast(static_cast(Addr));
458 *Ptr = static_cast(PtrVal);
459 return std::error_code();
460 });
461 }
462
463 ChannelT &Channel;
464 SymbolLookupFtor SymbolLookup;
465 std::map Allocators;
466 typedef std::vector ISBlockOwnerList;
467 std::map IndirectStubsOwners;
468 sys::OwningMemoryBlock ResolverBlock;
469 std::vector TrampolineBlocks;
470 };
471
472 } // end namespace remote
473 } // end namespace orc
474 } // end namespace llvm
475
476 #undef DEBUG_TYPE
477
478 #endif
0 // -*- c++ -*-
1
2 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
3 #define LLVM_EXECUTIONENGINE_ORC_RPCCHANNEL_H
4
5 #include "OrcError.h"
6 #include "llvm/ADT/ArrayRef.h"
7 #include "llvm/Support/Endian.h"
8
9 #include
10 #include
11
12 namespace llvm {
13 namespace orc {
14 namespace remote {
15
16 /// Interface for byte-streams to be used with RPC.
17 class RPCChannel {
18 public:
19 virtual ~RPCChannel() {}
20
21 /// Read Size bytes from the stream into *Dst.
22 virtual std::error_code readBytes(char *Dst, unsigned Size) = 0;
23
24 /// Read size bytes from *Src and append them to the stream.
25 virtual std::error_code appendBytes(const char *Src, unsigned Size) = 0;
26
27 /// Flush the stream if possible.
28 virtual std::error_code send() = 0;
29 };
30
31 /// RPC channel that reads from and writes from file descriptors.
32 class FDRPCChannel : public RPCChannel {
33 public:
34 FDRPCChannel(int InFD, int OutFD) : InFD(InFD), OutFD(OutFD) {}
35
36 std::error_code readBytes(char *Dst, unsigned Size) override {
37 assert(Dst && "Attempt to read into null.");
38 ssize_t ReadResult = ::read(InFD, Dst, Size);
39 if (ReadResult != Size)
40 return std::error_code(errno, std::generic_category());
41 return std::error_code();
42 }
43
44 std::error_code appendBytes(const char *Src, unsigned Size) override {
45 assert(Src && "Attempt to append from null.");
46 ssize_t WriteResult = ::write(OutFD, Src, Size);
47 if (WriteResult != Size)
48 std::error_code(errno, std::generic_category());
49 return std::error_code();
50 }
51
52 std::error_code send() override { return std::error_code(); }
53
54 private:
55 int InFD, OutFD;
56 };
57
58 /// RPC channel serialization for a variadic list of arguments.
59 template
60 std::error_code serialize_seq(RPCChannel &C, const T &Arg, const Ts &... Args) {
61 if (auto EC = serialize(C, Arg))
62 return EC;
63 return serialize_seq(C, Args...);
64 }
65
66 /// RPC channel serialization for an (empty) variadic list of arguments.
67 inline std::error_code serialize_seq(RPCChannel &C) {
68 return std::error_code();
69 }
70
71 /// RPC channel deserialization for a variadic list of arguments.
72 template
73 std::error_code deserialize_seq(RPCChannel &C, T &Arg, Ts &... Args) {
74 if (auto EC = deserialize(C, Arg))
75 return EC;
76 return deserialize_seq(C, Args...);
77 }
78
79 /// RPC channel serialization for an (empty) variadic list of arguments.
80 inline std::error_code deserialize_seq(RPCChannel &C) {
81 return std::error_code();
82 }
83
84 /// RPC channel serialization for integer primitives.
85 template
86 typename std::enable_if<
87 std::is_same::value || std::is_same::value ||
88 std::is_same::value || std::is_same::value ||
89 std::is_same::value || std::is_same::value ||
90 std::is_same::value || std::is_same::value,
91 std::error_code>::type
92 serialize(RPCChannel &C, T V) {
93 support::endian::byte_swap(V);
94 return C.appendBytes(reinterpret_cast(&V), sizeof(T));
95 }
96
97 /// RPC channel deserialization for integer primitives.
98 template
99 typename std::enable_if<
100 std::is_same::value || std::is_same::value ||
101 std::is_same::value || std::is_same::value ||
102 std::is_same::value || std::is_same::value ||
103 std::is_same::value || std::is_same::value,
104 std::error_code>::type
105 deserialize(RPCChannel &C, T &V) {
106 if (auto EC = C.readBytes(reinterpret_cast(&V), sizeof(T)))
107 return EC;
108 support::endian::byte_swap(V);
109 return std::error_code();
110 }
111
112 /// RPC channel serialization for enums.
113 template
114 typename std::enable_if::value, std::error_code>::type
115 serialize(RPCChannel &C, T V) {
116 return serialize(C, static_cast::type>(V));
117 }
118
119 /// RPC channel deserialization for enums.
120 template
121 typename std::enable_if::value, std::error_code>::type
122 deserialize(RPCChannel &C, T &V) {
123 typename std::underlying_type::type Tmp;
124 std::error_code EC = deserialize(C, Tmp);
125 V = static_cast(Tmp);
126 return EC;
127 }
128
129 /// RPC channel serialization for bools.
130 inline std::error_code serialize(RPCChannel &C, bool V) {
131 uint8_t VN = V ? 1 : 0;
132 return C.appendBytes(reinterpret_cast(&VN), 1);
133 }
134
135 /// RPC channel deserialization for bools.
136 inline std::error_code deserialize(RPCChannel &C, bool &V) {
137 uint8_t VN = 0;
138 if (auto EC = C.readBytes(reinterpret_cast(&VN), 1))
139 return EC;
140
141 V = (VN != 0) ? true : false;
142 return std::error_code();
143 }
144
145 /// RPC channel serialization for StringRefs.
146 /// Note: There is no corresponding deseralization for this, as StringRef
147 /// doesn't own its memory and so can't hold the deserialized data.
148 inline std::error_code serialize(RPCChannel &C, StringRef S) {
149 if (auto EC = serialize(C, static_cast(S.size())))
150 return EC;
151 return C.appendBytes((const char *)S.bytes_begin(), S.size());
152 }
153
154 /// RPC channel serialization for std::strings.
155 inline std::error_code serialize(RPCChannel &C, const std::string &S) {
156 return serialize(C, StringRef(S));
157 }
158
159 /// RPC channel deserialization for std::strings.
160 inline std::error_code deserialize(RPCChannel &C, std::string &S) {
161 uint64_t Count;
162 if (auto EC = deserialize(C, Count))
163 return EC;
164 S.resize(Count);
165 return C.readBytes(&S[0], Count);
166 }
167
168 /// RPC channel serialization for ArrayRef.
169 template
170 std::error_code serialize(RPCChannel &C, const ArrayRef &A) {
171 if (auto EC = serialize(C, static_cast(A.size())))
172 return EC;
173
174 for (const auto &E : A)
175 if (auto EC = serialize(C, E))
176 return EC;
177
178 return std::error_code();
179 }
180
181 /// RPC channel serialization for std::array.
182 template
183 std::error_code serialize(RPCChannel &C, const std::vector &V) {
184 return serialize(C, ArrayRef(V));
185 }
186
187 /// RPC channel deserialization for std::array.
188 template
189 std::error_code deserialize(RPCChannel &C, std::vector &V) {
190 uint64_t Count = 0;
191 if (auto EC = deserialize(C, Count))
192 return EC;
193
194 V.resize(Count);
195 for (auto &E : V)
196 if (auto EC = deserialize(C, E))
197 return EC;
198
199 return std::error_code();
200 }
201
202 } // end namespace remote
203 } // end namespace orc
204 } // end namespace llvm
205
206 #endif
0 //===----- RPCUTils.h - Basic tilities for building RPC APIs ----*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Basic utilities for building RPC APIs.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
14 #define LLVM_EXECUTIONENGINE_ORC_RPCUTILS_H
15
16 #include "llvm/ADT/STLExtras.h"
17
18 namespace llvm {
19 namespace orc {
20 namespace remote {
21
22 /// Contains primitive utilities for defining, calling and handling calls to
23 /// remote procedures. ChannelT is a bidirectional stream conforming to the
24 /// RPCChannel interface (see RPCChannel.h), and ProcedureIdT is a procedure
25 /// identifier type that must be serializable on ChannelT.
26 ///
27 /// These utilities support the construction of very primitive RPC utilities.
28 /// Their intent is to ensure correct serialization and deserialization of
29 /// procedure arguments, and to keep the client and server's view of the API in
30 /// sync.
31 ///
32 /// These utilities do not support return values. These can be handled by
33 /// declaring a corresponding '.*Response' procedure and expecting it after a
34 /// call). They also do not support versioning: the client and server *must* be
35 /// compiled with the same procedure definitions.
36 ///
37 ///
38 ///
39 /// Overview (see comments individual types/methods for details):
40 ///
41 /// Procedure :
42 ///
43 /// associates a unique serializable id with an argument list.
44 ///
45 ///
46 /// call(Channel, Args...) :
47 ///
48 /// Calls the remote procedure 'Proc' by serializing Proc's id followed by its
49 /// arguments and sending the resulting bytes to 'Channel'.
50 ///
51 ///
52 /// handle(Channel, :
53 ///
54 /// Handles a call to 'Proc' by deserializing its arguments and calling the
55 /// given functor. This assumes that the id for 'Proc' has already been
56 /// deserialized.
57 ///
58 /// expect(Channel, :
59 ///
60 /// The same as 'handle', except that the procedure id should not have been
61 /// read yet. Expect will deserialize the id and assert that it matches Proc's
62 /// id. If it does not, and unexpected RPC call error is returned.
63
64 template class RPC {
65 public:
66 /// Utility class for defining/referring to RPC procedures.
67 ///
68 /// Typedefs of this utility are used when calling/handling remote procedures.
69 ///
70 /// ProcId should be a unique value of ProcedureIdT (i.e. not used with any
71 /// other Procedure typedef in the RPC API being defined.
72 ///
73 /// the template argument Ts... gives the argument list for the remote
74 /// procedure.
75 ///
76 /// E.g.
77 ///
78 /// typedef Procedure<0, bool> Proc1;
79 /// typedef Procedure<1, std::string, std::vector> Proc2;
80 ///
81 /// if (auto EC = call(Channel, true))
82 /// /* handle EC */;
83 ///
84 /// if (auto EC = expect(Channel,
85 /// [](std::string &S, std::vector &V) {
86 /// // Stuff.
87 /// return std::error_code();
88 /// })
89 /// /* handle EC */;
90 ///
91 template class Procedure {
92 public:
93 static const ProcedureIdT Id = ProcId;
94 };
95
96 private:
97 template class CallHelper {};
98
99 template
100 class CallHelper> {
101 public:
102 static std::error_code call(ChannelT &C, const ArgTs &... Args) {
103 if (auto EC = serialize(C, ProcId))
104 return EC;
105 // If you see a compile-error on this line you're probably calling a
106 // function with the wrong signature.
107 return serialize_seq(C, Args...);
108 }
109 };
110
111 template class HandlerHelper {};
112
113 template
114 class HandlerHelper> {
115 public:
116 template
117 static std::error_code handle(ChannelT &C, HandlerT Handler) {
118 return readAndHandle(C, Handler, llvm::index_sequence_for());
119 }
120
121 private:
122 template
123 static std::error_code readAndHandle(ChannelT &C, HandlerT Handler,
124 llvm::index_sequence _) {
125 std::tuple RPCArgs;
126 if (auto EC = deserialize_seq(C, std::get(RPCArgs)...))
127 return EC;
128 return Handler(std::get(RPCArgs)...);
129 }
130 };
131
132 template class ReadArgs {
133 public:
134 std::error_code operator()() { return std::error_code(); }
135 };
136
137 template
138 class ReadArgs : public ReadArgs {
139 public:
140 ReadArgs(ArgT &Arg, ArgTs &... Args)
141 : ReadArgs(Args...), Arg(Arg) {}
142
143 std::error_code operator()(ArgT &ArgVal, ArgTs &... ArgVals) {
144 this->Arg = std::move(ArgVal);
145 return ReadArgs::operator()(ArgVals...);
146 }
147
148 private:
149 ArgT &Arg;
150 };
151
152 public:
153 /// Serialize Args... to channel C, but do not call C.send().
154 ///
155 /// For buffered channels, this can be used to queue up several calls before
156 /// flushing the channel.
157 template
158 static std::error_code appendCall(ChannelT &C, const ArgTs &... Args) {
159 return CallHelper::call(C, Args...);
160 }
161
162 /// Serialize Args... to channel C and call C.send().
163 template
164 static std::error_code call(ChannelT &C, const ArgTs &... Args) {
165 if (auto EC = appendCall(C, Args...))
166 return EC;
167 return C.send();
168 }
169
170 /// Deserialize and return an enum whose underlying type is ProcedureIdT.
171 static std::error_code getNextProcId(ChannelT &C, ProcedureIdT &Id) {
172 return deserialize(C, Id);
173 }
174
175 /// Deserialize args for Proc from C and call Handler. The signature of
176 /// handler must conform to 'std::error_code(Args...)' where Args... matches
177 /// the arguments used in the Proc typedef.
178 template
179 static std::error_code handle(ChannelT &C, HandlerT Handler) {
180 return HandlerHelper::handle(C, Handler);
181 }
182
183 /// Deserialize a ProcedureIdT from C and verify it matches the id for Proc.
184 /// If the id does match, deserialize the arguments and call the handler
185 /// (similarly to handle).
186 /// If the id does not match, return an unexpect RPC call error and do not
187 /// deserialize any further bytes.
188 template
189 static std::error_code expect(ChannelT &C, HandlerT Handler) {
190 ProcedureIdT ProcId;
191 if (auto EC = getNextProcId(C, ProcId))
192 return EC;
193 if (ProcId != Proc::Id)
194 return orcError(OrcErrorCode::UnexpectedRPCCall);
195 return handle(C, Handler);
196 }
197
198 /// Helper for handling setter procedures - this method returns a functor that
199 /// sets the variables referred to by Args... to values deserialized from the
200 /// channel.
201 /// E.g.
202 ///
203 /// typedef Procedure<0, bool, int> Proc1;
204 ///
205 /// ...
206 /// bool B;
207 /// int I;
208 /// if (auto EC = expect(Channel, readArgs(B, I)))
209 /// /* Handle Args */ ;
210 ///
211 template
212 static ReadArgs readArgs(ArgTs &... Args) {
213 return ReadArgs(Args...);
214 }
215 };
216
217 } // end namespace remote
218 } // end namespace orc
219 } // end namespace llvm
220
221 #endif
66 OrcCBindingsStack.cpp
77 OrcError.cpp
88 OrcMCJITReplacement.cpp
9 OrcRemoteTargetRPCAPI.cpp
910
1011 ADDITIONAL_HEADER_DIRS
1112 ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
0 //===------- OrcRemoteTargetRPCAPI.cpp - ORC Remote API utilities ---------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
10
11 namespace llvm {
12 namespace orc {
13 namespace remote {
14
15 const char *OrcRemoteTargetRPCAPI::getJITProcIdName(JITProcId Id) {
16 switch (Id) {
17 case InvalidId:
18 return "*** Invalid JITProcId ***";
19 case CallIntVoidId:
20 return "CallIntVoid";
21 case CallIntVoidResponseId:
22 return "CallIntVoidResponse";
23 case CallMainId:
24 return "CallMain";
25 case CallMainResponseId:
26 return "CallMainResponse";
27 case CallVoidVoidId:
28 return "CallVoidVoid";
29 case CallVoidVoidResponseId:
30 return "CallVoidVoidResponse";
31 case CreateRemoteAllocatorId:
32 return "CreateRemoteAllocator";
33 case CreateIndirectStubsOwnerId:
34 return "CreateIndirectStubsOwner";
35 case DestroyRemoteAllocatorId:
36 return "DestroyRemoteAllocator";
37 case DestroyIndirectStubsOwnerId:
38 return "DestroyIndirectStubsOwner";
39 case EmitIndirectStubsId:
40 return "EmitIndirectStubs";
41 case EmitIndirectStubsResponseId:
42 return "EmitIndirectStubsResponse";
43 case EmitResolverBlockId:
44 return "EmitResolverBlock";
45 case EmitTrampolineBlockId:
46 return "EmitTrampolineBlock";
47 case EmitTrampolineBlockResponseId:
48 return "EmitTrampolineBlockResponse";
49 case GetSymbolAddressId:
50 return "GetSymbolAddress";
51 case GetSymbolAddressResponseId:
52 return "GetSymbolAddressResponse";
53 case GetRemoteInfoId:
54 return "GetRemoteInfo";
55 case GetRemoteInfoResponseId:
56 return "GetRemoteInfoResponse";
57 case ReadMemId:
58 return "ReadMem";
59 case ReadMemResponseId:
60 return "ReadMemResponse";
61 case ReserveMemId:
62 return "ReserveMem";
63 case ReserveMemResponseId:
64 return "ReserveMemResponse";
65 case RequestCompileId:
66 return "RequestCompile";
67 case RequestCompileResponseId:
68 return "RequestCompileResponse";
69 case SetProtectionsId:
70 return "SetProtections";
71 case TerminateSessionId:
72 return "TerminateSession";
73 case WriteMemId:
74 return "WriteMem";
75 case WritePtrId:
76 return "WritePtr";
77 };
78 return nullptr;
79 }
80 }
81 }
82 }
1717 ObjectTransformLayerTest.cpp
1818 OrcCAPITest.cpp
1919 OrcTestCommon.cpp
20 RPCUtilsTest.cpp
2021 )
0 //===----------- RPCUtilsTest.cpp - Unit tests the Orc RPC utils ----------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm/ExecutionEngine/Orc/RPCChannel.h"
10 #include "llvm/ExecutionEngine/Orc/RPCUtils.h"
11 #include "gtest/gtest.h"
12
13 #include
14
15 using namespace llvm;
16 using namespace llvm::orc;
17 using namespace llvm::orc::remote;
18
19 class QueueChannel : public RPCChannel {
20 public:
21 QueueChannel(std::queue &Queue) : Queue(Queue) {}
22
23 std::error_code readBytes(char *Dst, unsigned Size) override {
24 while (Size--) {
25 *Dst++ = Queue.front();
26 Queue.pop();
27 }
28 return std::error_code();
29 }
30
31 std::error_code appendBytes(const char *Src, unsigned Size) override {
32 while (Size--)
33 Queue.push(*Src++);
34 return std::error_code();
35 }
36
37 std::error_code send() override { return std::error_code(); }
38
39 private:
40 std::queue &Queue;
41 };
42
43 class DummyRPC : public testing::Test,
44 public RPC {
45 public:
46 typedef Procedure<1, bool> Proc1;
47 typedef Procedure<2, int8_t,
48 uint8_t,
49 int16_t,
50 uint16_t,
51 int32_t,
52 uint32_t,
53 int64_t,
54 uint64_t,
55 bool,
56 std::string,
57 std::vector> AllTheTypes;
58 };
59
60
61 TEST_F(DummyRPC, TestBasic) {
62 std::queue Queue;
63 QueueChannel C(Queue);
64
65 {
66 // Make a call to Proc1.
67 auto EC = call(C, true);
68 EXPECT_FALSE(EC) << "Simple call over queue failed";
69 }
70
71 {
72 // Expect a call to Proc1.
73 auto EC = expect(C,
74 [&](bool &B) {
75 EXPECT_EQ(B, true)
76 << "Bool serialization broken";
77 return std::error_code();
78 });
79 EXPECT_FALSE(EC) << "Simple expect over queue failed";
80 }
81 }
82
83 TEST_F(DummyRPC, TestSerialization) {
84 std::queue Queue;
85 QueueChannel C(Queue);
86
87 {
88 // Make a call to Proc1.
89 std::vector v({42, 7});
90 auto EC = call(C,
91 -101,
92 250,
93 -10000,
94 10000,
95 -1000000000,
96 1000000000,
97 -10000000000,
98 10000000000,
99 true,
100 "foo",
101 v);
102 EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
103 }
104
105 {
106 // Expect a call to Proc1.
107 auto EC = expect(C,
108 [&](int8_t &s8,
109 uint8_t &u8,
110 int16_t &s16,
111 uint16_t &u16,
112 int32_t &s32,
113 uint32_t &u32,
114 int64_t &s64,
115 uint64_t &u64,
116 bool &b,
117 std::string &s,
118 std::vector &v) {
119
120 EXPECT_EQ(s8, -101)
121 << "int8_t serialization broken";
122 EXPECT_EQ(u8, 250)
123 << "uint8_t serialization broken";
124 EXPECT_EQ(s16, -10000)
125 << "int16_t serialization broken";
126 EXPECT_EQ(u16, 10000)
127 << "uint16_t serialization broken";
128 EXPECT_EQ(s32, -1000000000)
129 << "int32_t serialization broken";
130 EXPECT_EQ(u32, 1000000000ULL)
131 << "uint32_t serialization broken";
132 EXPECT_EQ(s64, -10000000000)
133 << "int64_t serialization broken";
134 EXPECT_EQ(u64, 10000000000ULL)
135 << "uint64_t serialization broken";
136 EXPECT_EQ(b, true)
137 << "bool serialization broken";
138 EXPECT_EQ(s, "foo")
139 << "std::string serialization broken";
140 EXPECT_EQ(v, std::vector({42, 7}))
141 << "std::vector serialization broken";
142 return std::error_code();
143 });
144 EXPECT_FALSE(EC) << "Big (serialization test) call over queue failed";
145 }
146 }