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
25namespace llvm {
26namespace orc {
27namespace 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.
36template <typename ChannelT>
37class OrcRemoteTargetClient : public OrcRemoteTargetRPCAPI {
38public:
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
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:
59    RCMemoryManager(OrcRemoteTargetClient &Client, ResourceIdMgr::ResourceId Id)
60        : Client(Client), Id(Id) {
61      DEBUG(dbgs() << "Created remote allocator " << Id << "\n");
62    }
63
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
77    ~RCMemoryManager() override {
78      Client.destroyRemoteAllocator(Id);
79      DEBUG(dbgs() << "Destroyed remote allocator " << Id << "\n");
80    }
81
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
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
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
167    bool needsToReserveAllocationSpace() override { return true; }
168
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
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
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:
366      Alloc(uint64_t Size, unsigned Align)
367          : Size(Size), Align(Align), Contents(new char[Size + Align - 1]) {}
368
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
382      uint64_t getSize() const { return Size; }
383
384      unsigned getAlign() const { return Align; }
385
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
392      void setRemoteAddress(TargetAddress RemoteAddr) {
393        this->RemoteAddr = RemoteAddr;
394      }
395
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
408      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:
442    RCIndirectStubsManager(OrcRemoteTargetClient &Remote,
443                           ResourceIdMgr::ResourceId Id)
444        : Remote(Remote), Id(Id) {}
445
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
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
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
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
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
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
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
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
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
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:
564    RCCompileCallbackManager(TargetAddress ErrorHandlerAddress,
565                             OrcRemoteTargetClient &Remote)
566        : JITCompileCallbackManager(ErrorHandlerAddress), Remote(Remote) {}
567
568  private:
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.
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.
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.
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.
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.
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.
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 &>
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.
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.
685  const std::string &getTargetTriple() const { return RemoteTargetTriple; }
686
687  Error terminateSession() { return callST<TerminateSession>(Channel); }
688
689private:
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
701  Error deregisterEHFrames(TargetAddress Addr, uint32_t Size) {
702    return callST<RegisterEHFrames>(Channel, Addr, Size);
703  }
704
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
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>>
720  emitIndirectStubs(ResourceIdMgr::ResourceId Id, uint32_t NumStubsRequired) {
721    return callST<EmitIndirectStubs>(Channel, Id, NumStubsRequired);
722  }
723
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
732  uint32_t getIndirectStubSize() const { return RemoteIndirectStubSize; }
733  uint32_t getPageSize() const { return RemotePageSize; }
734  uint32_t getPointerSize() const { return RemotePointerSize; }
735
736  uint32_t getTrampolineSize() const { return RemoteTrampolineSize; }
737
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
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
772  Error registerEHFrames(TargetAddress &RAddr, uint32_t Size) {
773    return callST<RegisterEHFrames>(Channel, RAddr, Size);
774  }
775
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
786  Error setProtections(ResourceIdMgr::ResourceId Id,
787                       TargetAddress RemoteSegAddr, unsigned ProtFlags) {
788    return callST<SetProtections>(Channel, Id, RemoteSegAddr, ProtFlags);
789  }
790
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
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
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