• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 RPCChannel with an OrcRemoteTargetServer
12 // 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 "IndirectionUtils.h"
20 #include "OrcRemoteTargetRPCAPI.h"
21 #include <system_error>
22 
23 #define DEBUG_TYPE "orc-remote"
24 
25 namespace llvm {
26 namespace orc {
27 namespace remote {
28 
29 /// This class provides utilities (including memory manager, indirect stubs
30 /// manager, and compile callback manager types) that support remote JITing
31 /// in ORC.
32 ///
33 /// Each of the utility classes talks to a JIT server (an instance of the
34 /// OrcRemoteTargetServer class) via an RPC system (see RPCUtils.h) to carry out
35 /// its actions.
36 template <typename ChannelT>
37 class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
38 public:
39   // FIXME: Remove move/copy ops once MSVC supports synthesizing move ops.
40 
41   OrcRemoteTargetClient(const OrcRemoteTargetClient &) = delete;
42   OrcRemoteTargetClient &operator=(const OrcRemoteTargetClient &) = delete;
43 
OrcRemoteTargetClient(OrcRemoteTargetClient && Other)44   OrcRemoteTargetClient(OrcRemoteTargetClient &&Other)
45       : Channel(Other.Channel), ExistingError(std::move(Other.ExistingError)),
46         RemoteTargetTriple(std::move(Other.RemoteTargetTriple)),
47         RemotePointerSize(std::move(Other.RemotePointerSize)),
48         RemotePageSize(std::move(Other.RemotePageSize)),
49         RemoteTrampolineSize(std::move(Other.RemoteTrampolineSize)),
50         RemoteIndirectStubSize(std::move(Other.RemoteIndirectStubSize)),
51         AllocatorIds(std::move(Other.AllocatorIds)),
52         IndirectStubOwnerIds(std::move(Other.IndirectStubOwnerIds)) {}
53 
54   OrcRemoteTargetClient &operator=(OrcRemoteTargetClient &&) = delete;
55 
56   /// Remote memory manager.
57   class RCMemoryManager : public RuntimeDyld::MemoryManager {
58   public:
RCMemoryManager(OrcRemoteTargetClient & Client,ResourceIdMgr::ResourceId Id)59     RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
60         : Client(Client), Id(Id) {
61       DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
62     }
63 
RCMemoryManager(RCMemoryManager && Other)64     RCMemoryManager(RCMemoryManager &&Other)
65         : Client(std::move(Other.Client)), Id(std::move(Other.Id)),
66           Unmapped(std::move(Other.Unmapped)),
67           Unfinalized(std::move(Other.Unfinalized)) {}
68 
69     RCMemoryManager operator=(RCMemoryManager &&Other) {
70       Client = std::move(Other.Client);
71       Id = std::move(Other.Id);
72       Unmapped = std::move(Other.Unmapped);
73       Unfinalized = std::move(Other.Unfinalized);
74       return *this;
75     }
76 
~RCMemoryManager()77     ~RCMemoryManager() override {
78       Client.destroyRemoteAllocator(Id);
79       DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
80     }
81 
allocateCodeSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName)82     uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
83                                  unsigned SectionID,
84                                  StringRef SectionName) override {
85       Unmapped.back().CodeAllocs.emplace_back(Size, Alignment);
86       uint8_t *Alloc = reinterpret_cast<uint8_t *>(
87           Unmapped.back().CodeAllocs.back().getLocalAddress());
88       DEBUG(dbgs() << "Allocator " << Id << " allocated code for "
89                    << SectionName << ": " << Alloc << " (" << Size
90                    << " bytes, alignment " << Alignment << ")\n");
91       return Alloc;
92     }
93 
allocateDataSection(uintptr_t Size,unsigned Alignment,unsigned SectionID,StringRef SectionName,bool IsReadOnly)94     uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
95                                  unsigned SectionID, StringRef SectionName,
96                                  bool IsReadOnly) override {
97       if (IsReadOnly) {
98         Unmapped.back().RODataAllocs.emplace_back(Size, Alignment);
99         uint8_t *Alloc = reinterpret_cast<uint8_t *>(
100             Unmapped.back().RODataAllocs.back().getLocalAddress());
101         DEBUG(dbgs() << "Allocator " << Id << " allocated ro-data for "
102                      << SectionName << ": " << Alloc << " (" << Size
103                      << " bytes, alignment " << Alignment << ")\n");
104         return Alloc;
105       } // else...
106 
107       Unmapped.back().RWDataAllocs.emplace_back(Size, Alignment);
108       uint8_t *Alloc = reinterpret_cast<uint8_t *>(
109           Unmapped.back().RWDataAllocs.back().getLocalAddress());
110       DEBUG(dbgs() << "Allocator " << Id << " allocated rw-data for "
111                    << SectionName << ": " << Alloc << " (" << Size
112                    << " bytes, alignment " << Alignment << ")\n");
113       return Alloc;
114     }
115 
reserveAllocationSpace(uintptr_t CodeSize,uint32_t CodeAlign,uintptr_t RODataSize,uint32_t RODataAlign,uintptr_t RWDataSize,uint32_t RWDataAlign)116     void reserveAllocationSpace(uintptr_t CodeSize, uint32_t CodeAlign,
117                                 uintptr_t RODataSize, uint32_t RODataAlign,
118                                 uintptr_t RWDataSize,
119                                 uint32_t RWDataAlign) override {
120       Unmapped.push_back(ObjectAllocs());
121 
122       DEBUG(dbgs() << "Allocator " << Id << " reserved:\n");
123 
124       if (CodeSize != 0) {
125         if (auto AddrOrErr = Client.reserveMem(Id, CodeSize, CodeAlign))
126           Unmapped.back().RemoteCodeAddr = *AddrOrErr;
127         else {
128           // FIXME; Add error to poll.
129           assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
130         }
131 
132         DEBUG(dbgs() << "  code: "
133                      << format("0x%016x", Unmapped.back().RemoteCodeAddr)
134                      << " (" << CodeSize << " bytes, alignment " << CodeAlign
135                      << ")\n");
136       }
137 
138       if (RODataSize != 0) {
139         if (auto AddrOrErr = Client.reserveMem(Id, RODataSize, RODataAlign))
140           Unmapped.back().RemoteRODataAddr = *AddrOrErr;
141         else {
142           // FIXME; Add error to poll.
143           assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
144         }
145 
146         DEBUG(dbgs() << "  ro-data: "
147                      << format("0x%016x", Unmapped.back().RemoteRODataAddr)
148                      << " (" << RODataSize << " bytes, alignment "
149                      << RODataAlign << ")\n");
150       }
151 
152       if (RWDataSize != 0) {
153         if (auto AddrOrErr = Client.reserveMem(Id, RWDataSize, RWDataAlign))
154           Unmapped.back().RemoteRWDataAddr = *AddrOrErr;
155         else {
156           // FIXME; Add error to poll.
157           assert(!AddrOrErr.takeError() && "Failed reserving remote memory.");
158         }
159 
160         DEBUG(dbgs() << "  rw-data: "
161                      << format("0x%016x", Unmapped.back().RemoteRWDataAddr)
162                      << " (" << RWDataSize << " bytes, alignment "
163                      << RWDataAlign << ")\n");
164       }
165     }
166 
needsToReserveAllocationSpace()167     bool needsToReserveAllocationSpace() override { return true; }
168 
registerEHFrames(uint8_t * Addr,uint64_t LoadAddr,size_t Size)169     void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr,
170                           size_t Size) override {
171       UnfinalizedEHFrames.push_back(
172           std::make_pair(LoadAddr, static_cast<uint32_t>(Size)));
173     }
174 
deregisterEHFrames(uint8_t * Addr,uint64_t LoadAddr,size_t Size)175     void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr,
176                             size_t Size) override {
177       auto Err = Client.deregisterEHFrames(LoadAddr, Size);
178       // FIXME: Add error poll.
179       assert(!Err && "Failed to register remote EH frames.");
180       (void)Err;
181     }
182 
notifyObjectLoaded(RuntimeDyld & Dyld,const object::ObjectFile & Obj)183     void notifyObjectLoaded(RuntimeDyld &Dyld,
184                             const object::ObjectFile &Obj) override {
185       DEBUG(dbgs() << "Allocator " << Id << " applied mappings:\n");
186       for (auto &ObjAllocs : Unmapped) {
187         {
188           TargetAddress NextCodeAddr = ObjAllocs.RemoteCodeAddr;
189           for (auto &Alloc : ObjAllocs.CodeAllocs) {
190             NextCodeAddr = alignTo(NextCodeAddr, Alloc.getAlign());
191             Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextCodeAddr);
192             DEBUG(dbgs() << "     code: "
193                          << static_cast<void *>(Alloc.getLocalAddress())
194                          << " -> " << format("0x%016x", NextCodeAddr) << "\n");
195             Alloc.setRemoteAddress(NextCodeAddr);
196             NextCodeAddr += Alloc.getSize();
197           }
198         }
199         {
200           TargetAddress NextRODataAddr = ObjAllocs.RemoteRODataAddr;
201           for (auto &Alloc : ObjAllocs.RODataAllocs) {
202             NextRODataAddr = alignTo(NextRODataAddr, Alloc.getAlign());
203             Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRODataAddr);
204             DEBUG(dbgs() << "  ro-data: "
205                          << static_cast<void *>(Alloc.getLocalAddress())
206                          << " -> " << format("0x%016x", NextRODataAddr)
207                          << "\n");
208             Alloc.setRemoteAddress(NextRODataAddr);
209             NextRODataAddr += Alloc.getSize();
210           }
211         }
212         {
213           TargetAddress NextRWDataAddr = ObjAllocs.RemoteRWDataAddr;
214           for (auto &Alloc : ObjAllocs.RWDataAllocs) {
215             NextRWDataAddr = alignTo(NextRWDataAddr, Alloc.getAlign());
216             Dyld.mapSectionAddress(Alloc.getLocalAddress(), NextRWDataAddr);
217             DEBUG(dbgs() << "  rw-data: "
218                          << static_cast<void *>(Alloc.getLocalAddress())
219                          << " -> " << format("0x%016x", NextRWDataAddr)
220                          << "\n");
221             Alloc.setRemoteAddress(NextRWDataAddr);
222             NextRWDataAddr += Alloc.getSize();
223           }
224         }
225         Unfinalized.push_back(std::move(ObjAllocs));
226       }
227       Unmapped.clear();
228     }
229 
230     bool finalizeMemory(std::string *ErrMsg = nullptr) override {
231       DEBUG(dbgs() << "Allocator " << Id << " finalizing:\n");
232 
233       for (auto &ObjAllocs : Unfinalized) {
234 
235         for (auto &Alloc : ObjAllocs.CodeAllocs) {
236           DEBUG(dbgs() << "  copying code: "
237                        << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
238                        << format("0x%016x", Alloc.getRemoteAddress()) << " ("
239                        << Alloc.getSize() << " bytes)\n");
240           if (auto Err =
241                   Client.writeMem(Alloc.getRemoteAddress(),
242                                   Alloc.getLocalAddress(), Alloc.getSize())) {
243             // FIXME: Replace this once finalizeMemory can return an Error.
244             handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
245               if (ErrMsg) {
246                 raw_string_ostream ErrOut(*ErrMsg);
247                 EIB.log(ErrOut);
248               }
249             });
250             return true;
251           }
252         }
253 
254         if (ObjAllocs.RemoteCodeAddr) {
255           DEBUG(dbgs() << "  setting R-X permissions on code block: "
256                        << format("0x%016x", ObjAllocs.RemoteCodeAddr) << "\n");
257           if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteCodeAddr,
258                                                sys::Memory::MF_READ |
259                                                    sys::Memory::MF_EXEC)) {
260             // FIXME: Replace this once finalizeMemory can return an Error.
261             handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
262               if (ErrMsg) {
263                 raw_string_ostream ErrOut(*ErrMsg);
264                 EIB.log(ErrOut);
265               }
266             });
267             return true;
268           }
269         }
270 
271         for (auto &Alloc : ObjAllocs.RODataAllocs) {
272           DEBUG(dbgs() << "  copying ro-data: "
273                        << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
274                        << format("0x%016x", Alloc.getRemoteAddress()) << " ("
275                        << Alloc.getSize() << " bytes)\n");
276           if (auto Err =
277                   Client.writeMem(Alloc.getRemoteAddress(),
278                                   Alloc.getLocalAddress(), Alloc.getSize())) {
279             // FIXME: Replace this once finalizeMemory can return an Error.
280             handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
281               if (ErrMsg) {
282                 raw_string_ostream ErrOut(*ErrMsg);
283                 EIB.log(ErrOut);
284               }
285             });
286             return true;
287           }
288         }
289 
290         if (ObjAllocs.RemoteRODataAddr) {
291           DEBUG(dbgs() << "  setting R-- permissions on ro-data block: "
292                        << format("0x%016x", ObjAllocs.RemoteRODataAddr)
293                        << "\n");
294           if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRODataAddr,
295                                                sys::Memory::MF_READ)) {
296             // FIXME: Replace this once finalizeMemory can return an Error.
297             handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
298               if (ErrMsg) {
299                 raw_string_ostream ErrOut(*ErrMsg);
300                 EIB.log(ErrOut);
301               }
302             });
303             return false;
304           }
305         }
306 
307         for (auto &Alloc : ObjAllocs.RWDataAllocs) {
308           DEBUG(dbgs() << "  copying rw-data: "
309                        << static_cast<void *>(Alloc.getLocalAddress()) << " -> "
310                        << format("0x%016x", Alloc.getRemoteAddress()) << " ("
311                        << Alloc.getSize() << " bytes)\n");
312           if (auto Err =
313                   Client.writeMem(Alloc.getRemoteAddress(),
314                                   Alloc.getLocalAddress(), Alloc.getSize())) {
315             // FIXME: Replace this once finalizeMemory can return an Error.
316             handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
317               if (ErrMsg) {
318                 raw_string_ostream ErrOut(*ErrMsg);
319                 EIB.log(ErrOut);
320               }
321             });
322             return false;
323           }
324         }
325 
326         if (ObjAllocs.RemoteRWDataAddr) {
327           DEBUG(dbgs() << "  setting RW- permissions on rw-data block: "
328                        << format("0x%016x", ObjAllocs.RemoteRWDataAddr)
329                        << "\n");
330           if (auto Err = Client.setProtections(Id, ObjAllocs.RemoteRWDataAddr,
331                                                sys::Memory::MF_READ |
332                                                    sys::Memory::MF_WRITE)) {
333             // FIXME: Replace this once finalizeMemory can return an Error.
334             handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
335               if (ErrMsg) {
336                 raw_string_ostream ErrOut(*ErrMsg);
337                 EIB.log(ErrOut);
338               }
339             });
340             return false;
341           }
342         }
343       }
344       Unfinalized.clear();
345 
346       for (auto &EHFrame : UnfinalizedEHFrames) {
347         if (auto Err = Client.registerEHFrames(EHFrame.first, EHFrame.second)) {
348           // FIXME: Replace this once finalizeMemory can return an Error.
349           handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
350             if (ErrMsg) {
351               raw_string_ostream ErrOut(*ErrMsg);
352               EIB.log(ErrOut);
353             }
354           });
355           return false;
356         }
357       }
358       UnfinalizedEHFrames.clear();
359 
360       return false;
361     }
362 
363   private:
364     class Alloc {
365     public:
Alloc(uint64_t Size,unsigned Align)366       Alloc(uint64_t Size, unsigned Align)
367           : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
368 
Alloc(Alloc && Other)369       Alloc(Alloc &&Other)
370           : Size(std::move(Other.Size)), Align(std::move(Other.Align)),
371             Contents(std::move(Other.Contents)),
372             RemoteAddr(std::move(Other.RemoteAddr)) {}
373 
374       Alloc &operator=(Alloc &&Other) {
375         Size = std::move(Other.Size);
376         Align = std::move(Other.Align);
377         Contents = std::move(Other.Contents);
378         RemoteAddr = std::move(Other.RemoteAddr);
379         return *this;
380       }
381 
getSize()382       uint64_t getSize() const { return Size; }
383 
getAlign()384       unsigned getAlign() const { return Align; }
385 
getLocalAddress()386       char *getLocalAddress() const {
387         uintptr_t LocalAddr = reinterpret_cast<uintptr_t>(Contents.get());
388         LocalAddr = alignTo(LocalAddr, Align);
389         return reinterpret_cast<char *>(LocalAddr);
390       }
391 
setRemoteAddress(TargetAddress RemoteAddr)392       void setRemoteAddress(TargetAddress RemoteAddr) {
393         this->RemoteAddr = RemoteAddr;
394       }
395 
getRemoteAddress()396       TargetAddress getRemoteAddress() const { return RemoteAddr; }
397 
398     private:
399       uint64_t Size;
400       unsigned Align;
401       std::unique_ptr<char[]> Contents;
402       TargetAddress RemoteAddr = 0;
403     };
404 
405     struct ObjectAllocs {
406       ObjectAllocs() = default;
407 
ObjectAllocsObjectAllocs408       ObjectAllocs(ObjectAllocs &&Other)
409           : RemoteCodeAddr(std::move(Other.RemoteCodeAddr)),
410             RemoteRODataAddr(std::move(Other.RemoteRODataAddr)),
411             RemoteRWDataAddr(std::move(Other.RemoteRWDataAddr)),
412             CodeAllocs(std::move(Other.CodeAllocs)),
413             RODataAllocs(std::move(Other.RODataAllocs)),
414             RWDataAllocs(std::move(Other.RWDataAllocs)) {}
415 
416       ObjectAllocs &operator=(ObjectAllocs &&Other) {
417         RemoteCodeAddr = std::move(Other.RemoteCodeAddr);
418         RemoteRODataAddr = std::move(Other.RemoteRODataAddr);
419         RemoteRWDataAddr = std::move(Other.RemoteRWDataAddr);
420         CodeAllocs = std::move(Other.CodeAllocs);
421         RODataAllocs = std::move(Other.RODataAllocs);
422         RWDataAllocs = std::move(Other.RWDataAllocs);
423         return *this;
424       }
425 
426       TargetAddress RemoteCodeAddr = 0;
427       TargetAddress RemoteRODataAddr = 0;
428       TargetAddress RemoteRWDataAddr = 0;
429       std::vector<Alloc> CodeAllocs, RODataAllocs, RWDataAllocs;
430     };
431 
432     OrcRemoteTargetClient &Client;
433     ResourceIdMgr::ResourceId Id;
434     std::vector<ObjectAllocs> Unmapped;
435     std::vector<ObjectAllocs> Unfinalized;
436     std::vector<std::pair<uint64_t, uint32_t>> UnfinalizedEHFrames;
437   };
438 
439   /// Remote indirect stubs manager.
440   class RCIndirectStubsManager : public IndirectStubsManager {
441   public:
RCIndirectStubsManager(OrcRemoteTargetClient & Remote,ResourceIdMgr::ResourceId Id)442     RCIndirectStubsManager(OrcRemoteTargetClient &Remote,
443                            ResourceIdMgr::ResourceId Id)
444         : Remote(Remote), Id(Id) {}
445 
~RCIndirectStubsManager()446     ~RCIndirectStubsManager() override {
447       if (auto Err = Remote.destroyIndirectStubsManager(Id)) {
448         // FIXME: Thread this error back to clients.
449         consumeError(std::move(Err));
450       }
451     }
452 
createStub(StringRef StubName,TargetAddress StubAddr,JITSymbolFlags StubFlags)453     Error createStub(StringRef StubName, TargetAddress StubAddr,
454                      JITSymbolFlags StubFlags) override {
455       if (auto Err = reserveStubs(1))
456         return Err;
457 
458       return createStubInternal(StubName, StubAddr, StubFlags);
459     }
460 
createStubs(const StubInitsMap & StubInits)461     Error createStubs(const StubInitsMap &StubInits) override {
462       if (auto Err = reserveStubs(StubInits.size()))
463         return Err;
464 
465       for (auto &Entry : StubInits)
466         if (auto Err = createStubInternal(Entry.first(), Entry.second.first,
467                                           Entry.second.second))
468           return Err;
469 
470       return Error::success();
471     }
472 
findStub(StringRef Name,bool ExportedStubsOnly)473     JITSymbol findStub(StringRef Name, bool ExportedStubsOnly) override {
474       auto I = StubIndexes.find(Name);
475       if (I == StubIndexes.end())
476         return nullptr;
477       auto Key = I->second.first;
478       auto Flags = I->second.second;
479       auto StubSymbol = JITSymbol(getStubAddr(Key), Flags);
480       if (ExportedStubsOnly && !StubSymbol.isExported())
481         return nullptr;
482       return StubSymbol;
483     }
484 
findPointer(StringRef Name)485     JITSymbol findPointer(StringRef Name) override {
486       auto I = StubIndexes.find(Name);
487       if (I == StubIndexes.end())
488         return nullptr;
489       auto Key = I->second.first;
490       auto Flags = I->second.second;
491       return JITSymbol(getPtrAddr(Key), Flags);
492     }
493 
updatePointer(StringRef Name,TargetAddress NewAddr)494     Error updatePointer(StringRef Name, TargetAddress NewAddr) override {
495       auto I = StubIndexes.find(Name);
496       assert(I != StubIndexes.end() && "No stub pointer for symbol");
497       auto Key = I->second.first;
498       return Remote.writePointer(getPtrAddr(Key), NewAddr);
499     }
500 
501   private:
502     struct RemoteIndirectStubsInfo {
503       TargetAddress StubBase;
504       TargetAddress PtrBase;
505       unsigned NumStubs;
506     };
507 
508     OrcRemoteTargetClient &Remote;
509     ResourceIdMgr::ResourceId Id;
510     std::vector<RemoteIndirectStubsInfo> RemoteIndirectStubsInfos;
511     typedef std::pair<uint16_t, uint16_t> StubKey;
512     std::vector<StubKey> FreeStubs;
513     StringMap<std::pair<StubKey, JITSymbolFlags>> StubIndexes;
514 
reserveStubs(unsigned NumStubs)515     Error reserveStubs(unsigned NumStubs) {
516       if (NumStubs <= FreeStubs.size())
517         return Error::success();
518 
519       unsigned NewStubsRequired = NumStubs - FreeStubs.size();
520       TargetAddress StubBase;
521       TargetAddress PtrBase;
522       unsigned NumStubsEmitted;
523 
524       if (auto StubInfoOrErr = Remote.emitIndirectStubs(Id, NewStubsRequired))
525         std::tie(StubBase, PtrBase, NumStubsEmitted) = *StubInfoOrErr;
526       else
527         return StubInfoOrErr.takeError();
528 
529       unsigned NewBlockId = RemoteIndirectStubsInfos.size();
530       RemoteIndirectStubsInfos.push_back({StubBase, PtrBase, NumStubsEmitted});
531 
532       for (unsigned I = 0; I < NumStubsEmitted; ++I)
533         FreeStubs.push_back(std::make_pair(NewBlockId, I));
534 
535       return Error::success();
536     }
537 
createStubInternal(StringRef StubName,TargetAddress InitAddr,JITSymbolFlags StubFlags)538     Error createStubInternal(StringRef StubName, TargetAddress InitAddr,
539                              JITSymbolFlags StubFlags) {
540       auto Key = FreeStubs.back();
541       FreeStubs.pop_back();
542       StubIndexes[StubName] = std::make_pair(Key, StubFlags);
543       return Remote.writePointer(getPtrAddr(Key), InitAddr);
544     }
545 
getStubAddr(StubKey K)546     TargetAddress getStubAddr(StubKey K) {
547       assert(RemoteIndirectStubsInfos[K.first].StubBase != 0 &&
548              "Missing stub address");
549       return RemoteIndirectStubsInfos[K.first].StubBase +
550              K.second * Remote.getIndirectStubSize();
551     }
552 
getPtrAddr(StubKey K)553     TargetAddress getPtrAddr(StubKey K) {
554       assert(RemoteIndirectStubsInfos[K.first].PtrBase != 0 &&
555              "Missing pointer address");
556       return RemoteIndirectStubsInfos[K.first].PtrBase +
557              K.second * Remote.getPointerSize();
558     }
559   };
560 
561   /// Remote compile callback manager.
562   class RCCompileCallbackManager : public JITCompileCallbackManager {
563   public:
RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,OrcRemoteTargetClient & Remote)564     RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,
565                              OrcRemoteTargetClient &Remote)
566         : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {}
567 
568   private:
grow()569     void grow() override {
570       TargetAddress BlockAddr = 0;
571       uint32_t NumTrampolines = 0;
572       if (auto TrampolineInfoOrErr = Remote.emitTrampolineBlock())
573         std::tie(BlockAddr, NumTrampolines) = *TrampolineInfoOrErr;
574       else {
575         // FIXME: Return error.
576         llvm_unreachable("Failed to create trampolines");
577       }
578 
579       uint32_t TrampolineSize = Remote.getTrampolineSize();
580       for (unsigned I = 0; I < NumTrampolines; ++I)
581         this->AvailableTrampolines.push_back(BlockAddr + (I * TrampolineSize));
582     }
583 
584     OrcRemoteTargetClient &Remote;
585   };
586 
587   /// Create an OrcRemoteTargetClient.
588   /// Channel is the ChannelT instance to communicate on. It is assumed that
589   /// the channel is ready to be read from and written to.
Create(ChannelT & Channel)590   static Expected<OrcRemoteTargetClient> Create(ChannelT &Channel) {
591     Error Err;
592     OrcRemoteTargetClient H(Channel, Err);
593     if (Err)
594       return std::move(Err);
595     return Expected<OrcRemoteTargetClient>(std::move(H));
596   }
597 
598   /// Call the int(void) function at the given address in the target and return
599   /// its result.
callIntVoid(TargetAddress Addr)600   Expected<int> callIntVoid(TargetAddress Addr) {
601     DEBUG(dbgs() << "Calling int(*)(void) " << format("0x%016x", Addr) << "\n");
602 
603     auto Listen = [&](RPCChannel &C, uint32_t Id) {
604       return listenForCompileRequests(C, Id);
605     };
606     return callSTHandling<CallIntVoid>(Channel, Listen, Addr);
607   }
608 
609   /// Call the int(int, char*[]) function at the given address in the target and
610   /// return its result.
callMain(TargetAddress Addr,const std::vector<std::string> & Args)611   Expected<int> callMain(TargetAddress Addr,
612                          const std::vector<std::string> &Args) {
613     DEBUG(dbgs() << "Calling int(*)(int, char*[]) " << format("0x%016x", Addr)
614                  << "\n");
615 
616     auto Listen = [&](RPCChannel &C, uint32_t Id) {
617       return listenForCompileRequests(C, Id);
618     };
619     return callSTHandling<CallMain>(Channel, Listen, Addr, Args);
620   }
621 
622   /// Call the void() function at the given address in the target and wait for
623   /// it to finish.
callVoidVoid(TargetAddress Addr)624   Error callVoidVoid(TargetAddress Addr) {
625     DEBUG(dbgs() << "Calling void(*)(void) " << format("0x%016x", Addr)
626                  << "\n");
627 
628     auto Listen = [&](RPCChannel &C, uint32_t Id) {
629       return listenForCompileRequests(C, Id);
630     };
631     return callSTHandling<CallVoidVoid>(Channel, Listen, Addr);
632   }
633 
634   /// Create an RCMemoryManager which will allocate its memory on the remote
635   /// target.
createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> & MM)636   Error createRemoteMemoryManager(std::unique_ptr<RCMemoryManager> &MM) {
637     assert(!MM && "MemoryManager should be null before creation.");
638 
639     auto Id = AllocatorIds.getNext();
640     if (auto Err = callST<CreateRemoteAllocator>(Channel, Id))
641       return Err;
642     MM = llvm::make_unique<RCMemoryManager>(*this, Id);
643     return Error::success();
644   }
645 
646   /// Create an RCIndirectStubsManager that will allocate stubs on the remote
647   /// target.
createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> & I)648   Error createIndirectStubsManager(std::unique_ptr<RCIndirectStubsManager> &I) {
649     assert(!I && "Indirect stubs manager should be null before creation.");
650     auto Id = IndirectStubOwnerIds.getNext();
651     if (auto Err = callST<CreateIndirectStubsOwner>(Channel, Id))
652       return Err;
653     I = llvm::make_unique<RCIndirectStubsManager>(*this, Id);
654     return Error::success();
655   }
656 
657   Expected<RCCompileCallbackManager &>
enableCompileCallbacks(TargetAddress ErrorHandlerAddress)658   enableCompileCallbacks(TargetAddress ErrorHandlerAddress) {
659     // Check for an 'out-of-band' error, e.g. from an MM destructor.
660     if (ExistingError)
661       return std::move(ExistingError);
662 
663     // Emit the resolver block on the JIT server.
664     if (auto Err = callST<EmitResolverBlock>(Channel))
665       return std::move(Err);
666 
667     // Create the callback manager.
668     CallbackManager.emplace(ErrorHandlerAddress, *this);
669     RCCompileCallbackManager &Mgr = *CallbackManager;
670     return Mgr;
671   }
672 
673   /// Search for symbols in the remote process. Note: This should be used by
674   /// symbol resolvers *after* they've searched the local symbol table in the
675   /// JIT stack.
getSymbolAddress(StringRef Name)676   Expected<TargetAddress> getSymbolAddress(StringRef Name) {
677     // Check for an 'out-of-band' error, e.g. from an MM destructor.
678     if (ExistingError)
679       return std::move(ExistingError);
680 
681     return callST<GetSymbolAddress>(Channel, Name);
682   }
683 
684   /// Get the triple for the remote target.
getTargetTriple()685   const std::string &getTargetTriple() const { return RemoteTargetTriple; }
686 
terminateSession()687   Error terminateSession() { return callST<TerminateSession>(Channel); }
688 
689 private:
OrcRemoteTargetClient(ChannelT & Channel,Error & Err)690   OrcRemoteTargetClient(ChannelT &Channel, Error &Err) : Channel(Channel) {
691     ErrorAsOutParameter EAO(Err);
692     if (auto RIOrErr = callST<GetRemoteInfo>(Channel)) {
693       std::tie(RemoteTargetTriple, RemotePointerSize, RemotePageSize,
694                RemoteTrampolineSize, RemoteIndirectStubSize) = *RIOrErr;
695       Err = Error::success();
696     } else {
697       Err = joinErrors(RIOrErr.takeError(), std::move(ExistingError));
698     }
699   }
700 
deregisterEHFrames(TargetAddress Addr,uint32_t Size)701   Error deregisterEHFrames(TargetAddress Addr, uint32_t Size) {
702     return callST<RegisterEHFrames>(Channel, Addr, Size);
703   }
704 
destroyRemoteAllocator(ResourceIdMgr::ResourceId Id)705   void destroyRemoteAllocator(ResourceIdMgr::ResourceId Id) {
706     if (auto Err = callST<DestroyRemoteAllocator>(Channel, Id)) {
707       // FIXME: This will be triggered by a removeModuleSet call: Propagate
708       //        error return up through that.
709       llvm_unreachable("Failed to destroy remote allocator.");
710       AllocatorIds.release(Id);
711     }
712   }
713 
destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id)714   Error destroyIndirectStubsManager(ResourceIdMgr::ResourceId Id) {
715     IndirectStubOwnerIds.release(Id);
716     return callST<DestroyIndirectStubsOwner>(Channel, Id);
717   }
718 
719   Expected<std::tuple<TargetAddress, TargetAddress, uint32_t>>
emitIndirectStubs(ResourceIdMgr::ResourceId Id,uint32_t NumStubsRequired)720   emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
721     return callST<EmitIndirectStubs>(Channel, Id, NumStubsRequired);
722   }
723 
emitTrampolineBlock()724   Expected<std::tuple<TargetAddress, uint32_t>> emitTrampolineBlock() {
725     // Check for an 'out-of-band' error, e.g. from an MM destructor.
726     if (ExistingError)
727       return std::move(ExistingError);
728 
729     return callST<EmitTrampolineBlock>(Channel);
730   }
731 
getIndirectStubSize()732   uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
getPageSize()733   uint32_t getPageSize() const { return RemotePageSize; }
getPointerSize()734   uint32_t getPointerSize() const { return RemotePointerSize; }
735 
getTrampolineSize()736   uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
737 
listenForCompileRequests(RPCChannel & C,uint32_t & Id)738   Error listenForCompileRequests(RPCChannel &C, uint32_t &Id) {
739     assert(CallbackManager &&
740            "No calback manager. enableCompileCallbacks must be called first");
741 
742     // Check for an 'out-of-band' error, e.g. from an MM destructor.
743     if (ExistingError)
744       return std::move(ExistingError);
745 
746     // FIXME: CompileCallback could be an anonymous lambda defined at the use
747     //        site below, but that triggers a GCC 4.7 ICE. When we move off
748     //        GCC 4.7, tidy this up.
749     auto CompileCallback =
750       [this](TargetAddress Addr) -> Expected<TargetAddress> {
751         return this->CallbackManager->executeCompileCallback(Addr);
752       };
753 
754     if (Id == RequestCompileId) {
755       if (auto Err = handle<RequestCompile>(C, CompileCallback))
756         return Err;
757       return Error::success();
758     }
759     // else
760     return orcError(OrcErrorCode::UnexpectedRPCCall);
761   }
762 
readMem(char * Dst,TargetAddress Src,uint64_t Size)763   Expected<std::vector<char>> readMem(char *Dst, TargetAddress Src,
764                                       uint64_t Size) {
765     // Check for an 'out-of-band' error, e.g. from an MM destructor.
766     if (ExistingError)
767       return std::move(ExistingError);
768 
769     return callST<ReadMem>(Channel, Src, Size);
770   }
771 
registerEHFrames(TargetAddress & RAddr,uint32_t Size)772   Error registerEHFrames(TargetAddress &RAddr, uint32_t Size) {
773     return callST<RegisterEHFrames>(Channel, RAddr, Size);
774   }
775 
reserveMem(ResourceIdMgr::ResourceId Id,uint64_t Size,uint32_t Align)776   Expected<TargetAddress> reserveMem(ResourceIdMgr::ResourceId Id,
777                                      uint64_t Size, uint32_t Align) {
778 
779     // Check for an 'out-of-band' error, e.g. from an MM destructor.
780     if (ExistingError)
781       return std::move(ExistingError);
782 
783     return callST<ReserveMem>(Channel, Id, Size, Align);
784   }
785 
setProtections(ResourceIdMgr::ResourceId Id,TargetAddress RemoteSegAddr,unsigned ProtFlags)786   Error setProtections(ResourceIdMgr::ResourceId Id,
787                        TargetAddress RemoteSegAddr, unsigned ProtFlags) {
788     return callST<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);
789   }
790 
writeMem(TargetAddress Addr,const char * Src,uint64_t Size)791   Error writeMem(TargetAddress Addr, const char *Src, uint64_t Size) {
792     // Check for an 'out-of-band' error, e.g. from an MM destructor.
793     if (ExistingError)
794       return std::move(ExistingError);
795 
796     return callST<WriteMem>(Channel, DirectBufferWriter(Src, Addr, Size));
797   }
798 
writePointer(TargetAddress Addr,TargetAddress PtrVal)799   Error writePointer(TargetAddress Addr, TargetAddress PtrVal) {
800     // Check for an 'out-of-band' error, e.g. from an MM destructor.
801     if (ExistingError)
802       return std::move(ExistingError);
803 
804     return callST<WritePtr>(Channel, Addr, PtrVal);
805   }
806 
doNothing()807   static Error doNothing() { return Error::success(); }
808 
809   ChannelT &Channel;
810   Error ExistingError;
811   std::string RemoteTargetTriple;
812   uint32_t RemotePointerSize = 0;
813   uint32_t RemotePageSize = 0;
814   uint32_t RemoteTrampolineSize = 0;
815   uint32_t RemoteIndirectStubSize = 0;
816   ResourceIdMgr AllocatorIds, IndirectStubOwnerIds;
817   Optional<RCCompileCallbackManager> CallbackManager;
818 };
819 
820 } // end namespace remote
821 } // end namespace orc
822 } // end namespace llvm
823 
824 #undef DEBUG_TYPE
825 
826 #endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETCLIENT_H
827