1 //===- OrcRemoteTargetRPCAPI.h - Orc Remote-target RPC API ------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
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 "llvm/ExecutionEngine/JITSymbol.h"
19 #include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
20 #include "llvm/ExecutionEngine/Orc/Shared/RawByteChannel.h"
21 
22 namespace llvm {
23 namespace orc {
24 
25 namespace remote {
26 
27 /// Template error for missing resources.
28 template <typename ResourceIdT>
29 class ResourceNotFound
30   : public ErrorInfo<ResourceNotFound<ResourceIdT>> {
31 public:
32   static char ID;
33 
34   ResourceNotFound(ResourceIdT ResourceId,
35                    std::string ResourceDescription = "")
ResourceId(std::move (ResourceId))36     : ResourceId(std::move(ResourceId)),
37       ResourceDescription(std::move(ResourceDescription)) {}
38 
convertToErrorCode()39   std::error_code convertToErrorCode() const override {
40     return orcError(OrcErrorCode::UnknownResourceHandle);
41   }
42 
log(raw_ostream & OS)43   void log(raw_ostream &OS) const override {
44     OS << (ResourceDescription.empty()
45              ? "Remote resource with id "
46                : ResourceDescription)
47        << " " << ResourceId << " not found";
48   }
49 
50 private:
51   ResourceIdT ResourceId;
52   std::string ResourceDescription;
53 };
54 
55 template <typename ResourceIdT>
56 char ResourceNotFound<ResourceIdT>::ID = 0;
57 
58 class DirectBufferWriter {
59 public:
60   DirectBufferWriter() = default;
DirectBufferWriter(const char * Src,JITTargetAddress Dst,uint64_t Size)61   DirectBufferWriter(const char *Src, JITTargetAddress Dst, uint64_t Size)
62       : Src(Src), Dst(Dst), Size(Size) {}
63 
getSrc()64   const char *getSrc() const { return Src; }
getDst()65   JITTargetAddress getDst() const { return Dst; }
getSize()66   uint64_t getSize() const { return Size; }
67 
68 private:
69   const char *Src;
70   JITTargetAddress Dst;
71   uint64_t Size;
72 };
73 
74 } // end namespace remote
75 
76 namespace shared {
77 
78 template <> class SerializationTypeName<JITSymbolFlags> {
79 public:
getName()80   static const char *getName() { return "JITSymbolFlags"; }
81 };
82 
83 template <typename ChannelT>
84 class SerializationTraits<ChannelT, JITSymbolFlags> {
85 public:
86 
serialize(ChannelT & C,const JITSymbolFlags & Flags)87   static Error serialize(ChannelT &C, const JITSymbolFlags &Flags) {
88     return serializeSeq(C, Flags.getRawFlagsValue(), Flags.getTargetFlags());
89   }
90 
deserialize(ChannelT & C,JITSymbolFlags & Flags)91   static Error deserialize(ChannelT &C, JITSymbolFlags &Flags) {
92     JITSymbolFlags::UnderlyingType JITFlags;
93     JITSymbolFlags::TargetFlagsType TargetFlags;
94     if (auto Err = deserializeSeq(C, JITFlags, TargetFlags))
95       return Err;
96     Flags = JITSymbolFlags(static_cast<JITSymbolFlags::FlagNames>(JITFlags),
97                            TargetFlags);
98     return Error::success();
99   }
100 };
101 
102 template <> class SerializationTypeName<remote::DirectBufferWriter> {
103 public:
getName()104   static const char *getName() { return "DirectBufferWriter"; }
105 };
106 
107 template <typename ChannelT>
108 class SerializationTraits<
109     ChannelT, remote::DirectBufferWriter, remote::DirectBufferWriter,
110     std::enable_if_t<std::is_base_of<RawByteChannel, ChannelT>::value>> {
111 public:
serialize(ChannelT & C,const remote::DirectBufferWriter & DBW)112   static Error serialize(ChannelT &C, const remote::DirectBufferWriter &DBW) {
113     if (auto EC = serializeSeq(C, DBW.getDst()))
114       return EC;
115     if (auto EC = serializeSeq(C, DBW.getSize()))
116       return EC;
117     return C.appendBytes(DBW.getSrc(), DBW.getSize());
118   }
119 
deserialize(ChannelT & C,remote::DirectBufferWriter & DBW)120   static Error deserialize(ChannelT &C, remote::DirectBufferWriter &DBW) {
121     JITTargetAddress Dst;
122     if (auto EC = deserializeSeq(C, Dst))
123       return EC;
124     uint64_t Size;
125     if (auto EC = deserializeSeq(C, Size))
126       return EC;
127     char *Addr = reinterpret_cast<char *>(static_cast<uintptr_t>(Dst));
128 
129     DBW = remote::DirectBufferWriter(nullptr, Dst, Size);
130 
131     return C.readBytes(Addr, Size);
132   }
133 };
134 
135 } // end namespace shared
136 
137 namespace remote {
138 
139 class ResourceIdMgr {
140 public:
141   using ResourceId = uint64_t;
142   static const ResourceId InvalidId = ~0U;
143 
144   ResourceIdMgr() = default;
ResourceIdMgr(ResourceId FirstValidId)145   explicit ResourceIdMgr(ResourceId FirstValidId)
146     : NextId(std::move(FirstValidId)) {}
147 
getNext()148   ResourceId getNext() {
149     if (!FreeIds.empty()) {
150       ResourceId I = FreeIds.back();
151       FreeIds.pop_back();
152       return I;
153     }
154     assert(NextId + 1 != ~0ULL && "All ids allocated");
155     return NextId++;
156   }
157 
release(ResourceId I)158   void release(ResourceId I) { FreeIds.push_back(I); }
159 
160 private:
161   ResourceId NextId = 1;
162   std::vector<ResourceId> FreeIds;
163 };
164 
165 /// Registers EH frames on the remote.
166 namespace eh {
167 
168   /// Registers EH frames on the remote.
169 class RegisterEHFrames
170     : public shared::RPCFunction<RegisterEHFrames,
171                                  void(JITTargetAddress Addr, uint32_t Size)> {
172 public:
getName()173   static const char *getName() { return "RegisterEHFrames"; }
174 };
175 
176   /// Deregisters EH frames on the remote.
177 class DeregisterEHFrames
178     : public shared::RPCFunction<DeregisterEHFrames,
179                                  void(JITTargetAddress Addr, uint32_t Size)> {
180 public:
getName()181   static const char *getName() { return "DeregisterEHFrames"; }
182 };
183 
184 } // end namespace eh
185 
186 /// RPC functions for executing remote code.
187 namespace exec {
188 
189   /// Call an 'int32_t()'-type function on the remote, returns the called
190   /// function's return value.
191 class CallIntVoid
192     : public shared::RPCFunction<CallIntVoid, int32_t(JITTargetAddress Addr)> {
193 public:
getName()194   static const char *getName() { return "CallIntVoid"; }
195 };
196 
197   /// Call an 'int32_t(int32_t)'-type function on the remote, returns the called
198   /// function's return value.
199 class CallIntInt
200     : public shared::RPCFunction<CallIntInt,
201                                  int32_t(JITTargetAddress Addr, int)> {
202 public:
getName()203   static const char *getName() { return "CallIntInt"; }
204 };
205 
206   /// Call an 'int32_t(int32_t, char**)'-type function on the remote, returns the
207   /// called function's return value.
208 class CallMain
209     : public shared::RPCFunction<CallMain,
210                                  int32_t(JITTargetAddress Addr,
211                                          std::vector<std::string> Args)> {
212 public:
getName()213   static const char *getName() { return "CallMain"; }
214 };
215 
216   /// Calls a 'void()'-type function on the remote, returns when the called
217   /// function completes.
218 class CallVoidVoid
219     : public shared::RPCFunction<CallVoidVoid, void(JITTargetAddress FnAddr)> {
220 public:
getName()221   static const char *getName() { return "CallVoidVoid"; }
222 };
223 
224 } // end namespace exec
225 
226 /// RPC functions for remote memory management / inspection / modification.
227 namespace mem {
228 
229   /// Creates a memory allocator on the remote.
230 class CreateRemoteAllocator
231     : public shared::RPCFunction<CreateRemoteAllocator,
232                                  void(ResourceIdMgr::ResourceId AllocatorID)> {
233 public:
getName()234   static const char *getName() { return "CreateRemoteAllocator"; }
235 };
236 
237   /// Destroys a remote allocator, freeing any memory allocated by it.
238 class DestroyRemoteAllocator
239     : public shared::RPCFunction<DestroyRemoteAllocator,
240                                  void(ResourceIdMgr::ResourceId AllocatorID)> {
241 public:
getName()242   static const char *getName() { return "DestroyRemoteAllocator"; }
243 };
244 
245   /// Read a remote memory block.
246 class ReadMem
247     : public shared::RPCFunction<
248           ReadMem, std::vector<uint8_t>(JITTargetAddress Src, uint64_t Size)> {
249 public:
getName()250   static const char *getName() { return "ReadMem"; }
251 };
252 
253   /// Reserve a block of memory on the remote via the given allocator.
254 class ReserveMem
255     : public shared::RPCFunction<
256           ReserveMem, JITTargetAddress(ResourceIdMgr::ResourceId AllocID,
257                                        uint64_t Size, uint32_t Align)> {
258 public:
getName()259   static const char *getName() { return "ReserveMem"; }
260 };
261 
262   /// Set the memory protection on a memory block.
263 class SetProtections
264     : public shared::RPCFunction<
265           SetProtections, void(ResourceIdMgr::ResourceId AllocID,
266                                JITTargetAddress Dst, uint32_t ProtFlags)> {
267 public:
getName()268   static const char *getName() { return "SetProtections"; }
269 };
270 
271   /// Write to a remote memory block.
272 class WriteMem
273     : public shared::RPCFunction<WriteMem,
274                                  void(remote::DirectBufferWriter DB)> {
275 public:
getName()276   static const char *getName() { return "WriteMem"; }
277 };
278 
279   /// Write to a remote pointer.
280 class WritePtr
281     : public shared::RPCFunction<WritePtr, void(JITTargetAddress Dst,
282                                                 JITTargetAddress Val)> {
283 public:
getName()284   static const char *getName() { return "WritePtr"; }
285 };
286 
287 } // end namespace mem
288 
289 /// RPC functions for remote stub and trampoline management.
290 namespace stubs {
291 
292   /// Creates an indirect stub owner on the remote.
293 class CreateIndirectStubsOwner
294     : public shared::RPCFunction<CreateIndirectStubsOwner,
295                                  void(ResourceIdMgr::ResourceId StubOwnerID)> {
296 public:
getName()297   static const char *getName() { return "CreateIndirectStubsOwner"; }
298 };
299 
300   /// RPC function for destroying an indirect stubs owner.
301 class DestroyIndirectStubsOwner
302     : public shared::RPCFunction<DestroyIndirectStubsOwner,
303                                  void(ResourceIdMgr::ResourceId StubsOwnerID)> {
304 public:
getName()305   static const char *getName() { return "DestroyIndirectStubsOwner"; }
306 };
307 
308   /// EmitIndirectStubs result is (StubsBase, PtrsBase, NumStubsEmitted).
309 class EmitIndirectStubs
310     : public shared::RPCFunction<
311           EmitIndirectStubs,
312           std::tuple<JITTargetAddress, JITTargetAddress, uint32_t>(
313               ResourceIdMgr::ResourceId StubsOwnerID,
314               uint32_t NumStubsRequired)> {
315 public:
getName()316   static const char *getName() { return "EmitIndirectStubs"; }
317 };
318 
319   /// RPC function to emit the resolver block and return its address.
320 class EmitResolverBlock
321     : public shared::RPCFunction<EmitResolverBlock, void()> {
322 public:
getName()323   static const char *getName() { return "EmitResolverBlock"; }
324 };
325 
326   /// EmitTrampolineBlock result is (BlockAddr, NumTrampolines).
327 class EmitTrampolineBlock
328     : public shared::RPCFunction<EmitTrampolineBlock,
329                                  std::tuple<JITTargetAddress, uint32_t>()> {
330 public:
getName()331   static const char *getName() { return "EmitTrampolineBlock"; }
332 };
333 
334 } // end namespace stubs
335 
336 /// Miscelaneous RPC functions for dealing with remotes.
337 namespace utils {
338 
339   /// GetRemoteInfo result is (Triple, PointerSize, PageSize, TrampolineSize,
340   ///                          IndirectStubsSize).
341 class GetRemoteInfo
342     : public shared::RPCFunction<
343           GetRemoteInfo,
344           std::tuple<std::string, uint32_t, uint32_t, uint32_t, uint32_t>()> {
345 public:
getName()346   static const char *getName() { return "GetRemoteInfo"; }
347 };
348 
349   /// Get the address of a remote symbol.
350 class GetSymbolAddress
351     : public shared::RPCFunction<GetSymbolAddress,
352                                  JITTargetAddress(std::string SymbolName)> {
353 public:
getName()354   static const char *getName() { return "GetSymbolAddress"; }
355 };
356 
357   /// Request that the host execute a compile callback.
358 class RequestCompile
359     : public shared::RPCFunction<
360           RequestCompile, JITTargetAddress(JITTargetAddress TrampolineAddr)> {
361 public:
getName()362   static const char *getName() { return "RequestCompile"; }
363 };
364 
365   /// Notify the remote and terminate the session.
366 class TerminateSession : public shared::RPCFunction<TerminateSession, void()> {
367 public:
getName()368   static const char *getName() { return "TerminateSession"; }
369 };
370 
371 } // namespace utils
372 
373 class OrcRemoteTargetRPCAPI
374     : public shared::SingleThreadedRPCEndpoint<shared::RawByteChannel> {
375 public:
376   // FIXME: Remove constructors once MSVC supports synthesizing move-ops.
OrcRemoteTargetRPCAPI(shared::RawByteChannel & C)377   OrcRemoteTargetRPCAPI(shared::RawByteChannel &C)
378       : shared::SingleThreadedRPCEndpoint<shared::RawByteChannel>(C, true) {}
379 };
380 
381 } // end namespace remote
382 
383 } // end namespace orc
384 } // end namespace llvm
385 
386 #endif // LLVM_EXECUTIONENGINE_ORC_ORCREMOTETARGETRPCAPI_H
387