LLVM  9.0.0svn
RemoteObjectLayer.h
Go to the documentation of this file.
1 //===------ RemoteObjectLayer.h - Forwards objs to a remote -----*- 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 // Forwards objects to a remote object layer via RPC.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
14 #define LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
15 
17 #include "llvm/Object/ObjectFile.h"
19 #include <map>
20 
21 namespace llvm {
22 namespace orc {
23 
24 /// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
26 public:
27 
29 
30 protected:
31 
33  using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>;
34 
35 public:
36 
39 
40 protected:
41 
43  static const RemoteSymbolId NullSymbolId = 0;
44 
45  class AddObject
46  : public rpc::Function<AddObject, Expected<ObjHandleT>(std::string)> {
47  public:
48  static const char *getName() { return "AddObject"; }
49  };
50 
52  : public rpc::Function<RemoveObject, Error(ObjHandleT)> {
53  public:
54  static const char *getName() { return "RemoveObject"; }
55  };
56 
57  class FindSymbol
58  : public rpc::Function<FindSymbol, Expected<RemoteSymbol>(std::string,
59  bool)> {
60  public:
61  static const char *getName() { return "FindSymbol"; }
62  };
63 
65  : public rpc::Function<FindSymbolIn,
66  Expected<RemoteSymbol>(ObjHandleT, std::string,
67  bool)> {
68  public:
69  static const char *getName() { return "FindSymbolIn"; }
70  };
71 
73  : public rpc::Function<EmitAndFinalize,
74  Error(ObjHandleT)> {
75  public:
76  static const char *getName() { return "EmitAndFinalize"; }
77  };
78 
79  class Lookup
80  : public rpc::Function<Lookup,
81  Expected<RemoteSymbol>(ObjHandleT, std::string)> {
82  public:
83  static const char *getName() { return "Lookup"; }
84  };
85 
87  : public rpc::Function<LookupInLogicalDylib,
88  Expected<RemoteSymbol>(ObjHandleT, std::string)> {
89  public:
90  static const char *getName() { return "LookupInLogicalDylib"; }
91  };
92 
94  : public rpc::Function<ReleaseRemoteSymbol, Error(RemoteSymbolId)> {
95  public:
96  static const char *getName() { return "ReleaseRemoteSymbol"; }
97  };
98 
100  : public rpc::Function<MaterializeRemoteSymbol,
101  Expected<JITTargetAddress>(RemoteSymbolId)> {
102  public:
103  static const char *getName() { return "MaterializeRemoteSymbol"; }
104  };
105 };
106 
107 /// Base class containing common utilities for RemoteObjectClientLayer and
108 /// RemoteObjectServerLayer.
109 template <typename RPCEndpoint>
111 public:
112 
113  RemoteObjectLayer(RPCEndpoint &Remote,
115  : Remote(Remote), ReportError(std::move(ReportError)),
116  SymbolIdMgr(NullSymbolId + 1) {
117  using ThisT = RemoteObjectLayer<RPCEndpoint>;
118  Remote.template addHandler<ReleaseRemoteSymbol>(
119  *this, &ThisT::handleReleaseRemoteSymbol);
120  Remote.template addHandler<MaterializeRemoteSymbol>(
121  *this, &ThisT::handleMaterializeRemoteSymbol);
122  }
123 
124 protected:
125 
126  /// This class is used as the symbol materializer for JITSymbols returned by
127  /// RemoteObjectLayerClient/RemoteObjectLayerServer -- the materializer knows
128  /// how to call back to the other RPC endpoint to get the address when
129  /// requested.
131  public:
132 
133  /// Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer
134  /// with the given Id.
137  : C(C), Id(Id) {}
138 
140  : C(Other.C), Id(Other.Id) {
141  // FIXME: This is a horrible, auto_ptr-style, copy-as-move operation.
142  // It should be removed as soon as LLVM has C++14's generalized
143  // lambda capture (at which point the materializer can be moved
144  // into the lambda in remoteToJITSymbol below).
145  const_cast<RemoteSymbolMaterializer&>(Other).Id = 0;
146  }
147 
149  operator=(const RemoteSymbolMaterializer&) = delete;
150 
151  /// Release the remote symbol.
153  if (Id)
154  C.releaseRemoteSymbol(Id);
155  }
156 
157  /// Materialize the symbol on the remote and get its address.
159  auto Addr = C.materializeRemoteSymbol(Id);
160  Id = 0;
161  return Addr;
162  }
163 
164  private:
167  };
168 
169  /// Convenience function for getting a null remote symbol value.
171  return RemoteSymbol(0, JITSymbolFlags());
172  }
173 
174  /// Creates a StringError that contains a copy of Err's log message, then
175  /// sends that StringError to ReportError.
176  ///
177  /// This allows us to locally log error messages for errors that will actually
178  /// be delivered to the remote.
180  return handleErrors(std::move(Err),
181  [this](std::unique_ptr<ErrorInfoBase> EIB) {
182  ReportError(make_error<StringError>(
183  EIB->message(),
184  EIB->convertToErrorCode()));
185  return Error(std::move(EIB));
186  });
187  }
188 
190  return make_error<BadSymbolHandleError>(Id, "Remote JIT Symbol");
191  }
192 
194  return make_error<RemoteObjectLayerAPI::BadObjectHandleError>(
195  H, "Bad object handle");
196  }
197 
198  /// Create a RemoteSymbol wrapping the given JITSymbol.
200  if (Sym) {
201  auto Id = SymbolIdMgr.getNext();
202  auto Flags = Sym.getFlags();
203  assert(!InUseSymbols.count(Id) && "Symbol id already in use");
204  InUseSymbols.insert(std::make_pair(Id, std::move(Sym)));
205  return RemoteSymbol(Id, Flags);
206  } else if (auto Err = Sym.takeError())
207  return teeLog(std::move(Err));
208  // else...
209  return nullRemoteSymbol();
210  }
211 
212  /// Convert an Expected<RemoteSymbol> to a JITSymbol.
214  if (RemoteSymOrErr) {
215  auto &RemoteSym = *RemoteSymOrErr;
216  if (RemoteSym == nullRemoteSymbol())
217  return nullptr;
218  // else...
219  RemoteSymbolMaterializer RSM(*this, RemoteSym.first);
220  auto Sym =
221  JITSymbol([RSM]() mutable { return RSM.materialize(); },
222  RemoteSym.second);
223  return Sym;
224  } else
225  return RemoteSymOrErr.takeError();
226  }
227 
228  RPCEndpoint &Remote;
229  std::function<void(Error)> ReportError;
230 
231 private:
232 
233  /// Notify the remote to release the given JITSymbol.
234  void releaseRemoteSymbol(RemoteSymbolId Id) {
235  if (auto Err = Remote.template callB<ReleaseRemoteSymbol>(Id))
236  ReportError(std::move(Err));
237  }
238 
239  /// Notify the remote to materialize the JITSymbol with the given Id and
240  /// return its address.
241  Expected<JITTargetAddress> materializeRemoteSymbol(RemoteSymbolId Id) {
242  return Remote.template callB<MaterializeRemoteSymbol>(Id);
243  }
244 
245  /// Release the JITSymbol with the given Id.
246  Error handleReleaseRemoteSymbol(RemoteSymbolId Id) {
247  auto SI = InUseSymbols.find(Id);
248  if (SI != InUseSymbols.end()) {
249  InUseSymbols.erase(SI);
250  return Error::success();
251  } else
252  return teeLog(badRemoteSymbolIdError(Id));
253  }
254 
255  /// Run the materializer for the JITSymbol with the given Id and return its
256  /// address.
257  Expected<JITTargetAddress> handleMaterializeRemoteSymbol(RemoteSymbolId Id) {
258  auto SI = InUseSymbols.find(Id);
259  if (SI != InUseSymbols.end()) {
260  auto AddrOrErr = SI->second.getAddress();
261  InUseSymbols.erase(SI);
262  SymbolIdMgr.release(Id);
263  if (AddrOrErr)
264  return *AddrOrErr;
265  else
266  return teeLog(AddrOrErr.takeError());
267  } else {
268  return teeLog(badRemoteSymbolIdError(Id));
269  }
270  }
271 
272  remote::ResourceIdMgr SymbolIdMgr;
273  std::map<RemoteSymbolId, JITSymbol> InUseSymbols;
274 };
275 
276 /// RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC
277 /// connection.
278 ///
279 /// This class can be used as the base layer of a JIT stack on the client and
280 /// will forward operations to a corresponding RemoteObjectServerLayer on the
281 /// server (which can be composed on top of a "real" object layer like
282 /// RTDyldObjectLinkingLayer to actually carry out the operations).
283 ///
284 /// Sending relocatable objects to the server (rather than fully relocated
285 /// bits) allows JIT'd code to be cached on the server side and re-used in
286 /// subsequent JIT sessions.
287 template <typename RPCEndpoint>
288 class RemoteObjectClientLayer : public RemoteObjectLayer<RPCEndpoint> {
289 private:
290 
298 
302 
303 public:
304 
307 
308  using ObjectPtr = std::unique_ptr<MemoryBuffer>;
309 
310  /// Create a RemoteObjectClientLayer that communicates with a
311  /// RemoteObjectServerLayer instance via the given RPCEndpoint.
312  ///
313  /// The ReportError functor can be used locally log errors that are intended
314  /// to be sent sent
315  RemoteObjectClientLayer(RPCEndpoint &Remote,
317  : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)) {
319  Remote.template addHandler<Lookup>(*this, &ThisT::lookup);
320  Remote.template addHandler<LookupInLogicalDylib>(
321  *this, &ThisT::lookupInLogicalDylib);
322  }
323 
324  /// Add an object to the JIT.
325  ///
326  /// @return A handle that can be used to refer to the loaded object (for
327  /// symbol searching, finalization, freeing memory, etc.).
329  addObject(ObjectPtr ObjBuffer,
330  std::shared_ptr<LegacyJITSymbolResolver> Resolver) {
331  if (auto HandleOrErr =
332  this->Remote.template callB<AddObject>(ObjBuffer->getBuffer())) {
333  auto &Handle = *HandleOrErr;
334  // FIXME: Return an error for this:
335  assert(!Resolvers.count(Handle) && "Handle already in use?");
336  Resolvers[Handle] = std::move(Resolver);
337  return Handle;
338  } else
339  return HandleOrErr.takeError();
340  }
341 
342  /// Remove the given object from the JIT.
344  return this->Remote.template callB<RemoveObject>(H);
345  }
346 
347  /// Search for the given named symbol.
348  JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
349  return remoteToJITSymbol(
350  this->Remote.template callB<FindSymbol>(Name,
351  ExportedSymbolsOnly));
352  }
353 
354  /// Search for the given named symbol within the given context.
355  JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) {
356  return remoteToJITSymbol(
357  this->Remote.template callB<FindSymbolIn>(H, Name,
358  ExportedSymbolsOnly));
359  }
360 
361  /// Immediately emit and finalize the object with the given handle.
363  return this->Remote.template callB<EmitAndFinalize>(H);
364  }
365 
366 private:
367 
368  Expected<RemoteSymbol> lookup(ObjHandleT H, const std::string &Name) {
369  auto RI = Resolvers.find(H);
370  if (RI != Resolvers.end()) {
371  return this->jitSymbolToRemote(RI->second->findSymbol(Name));
372  } else
373  return teeLog(badObjectHandleError(H));
374  }
375 
376  Expected<RemoteSymbol> lookupInLogicalDylib(ObjHandleT H,
377  const std::string &Name) {
378  auto RI = Resolvers.find(H);
379  if (RI != Resolvers.end())
380  return this->jitSymbolToRemote(
381  RI->second->findSymbolInLogicalDylib(Name));
382  else
383  return teeLog(badObjectHandleError(H));
384  }
385 
387  std::shared_ptr<LegacyJITSymbolResolver>>
388  Resolvers;
389 };
390 
391 /// RemoteObjectServerLayer acts as a server and handling RPC calls for the
392 /// object layer API from the given RPC connection.
393 ///
394 /// This class can be composed on top of a 'real' object layer (e.g.
395 /// RTDyldObjectLinkingLayer) to do the actual work of relocating objects
396 /// and making them executable.
397 template <typename BaseLayerT, typename RPCEndpoint>
398 class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> {
399 private:
400 
403 
411 
415 
416 public:
417 
418  /// Create a RemoteObjectServerLayer with the given base layer (which must be
419  /// an object layer), RPC endpoint, and error reporter function.
420  RemoteObjectServerLayer(BaseLayerT &BaseLayer,
421  RPCEndpoint &Remote,
423  : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)),
424  BaseLayer(BaseLayer), HandleIdMgr(1) {
426 
427  Remote.template addHandler<AddObject>(*this, &ThisT::addObject);
428  Remote.template addHandler<RemoveObject>(*this, &ThisT::removeObject);
429  Remote.template addHandler<FindSymbol>(*this, &ThisT::findSymbol);
430  Remote.template addHandler<FindSymbolIn>(*this, &ThisT::findSymbolIn);
431  Remote.template addHandler<EmitAndFinalize>(*this, &ThisT::emitAndFinalize);
432  }
433 
434 private:
435 
436  class StringMemoryBuffer : public MemoryBuffer {
437  public:
438  StringMemoryBuffer(std::string Buffer)
439  : Buffer(std::move(Buffer)) {
440  init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(),
441  false);
442  }
443 
444  BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
445  private:
446  std::string Buffer;
447  };
448 
449  JITSymbol lookup(ObjHandleT Id, const std::string &Name) {
450  return remoteToJITSymbol(
451  this->Remote.template callB<Lookup>(Id, Name));
452  }
453 
454  JITSymbol lookupInLogicalDylib(ObjHandleT Id, const std::string &Name) {
455  return remoteToJITSymbol(
456  this->Remote.template callB<LookupInLogicalDylib>(Id, Name));
457  }
458 
459  Expected<ObjHandleT> addObject(std::string ObjBuffer) {
460  auto Buffer = llvm::make_unique<StringMemoryBuffer>(std::move(ObjBuffer));
461  auto Id = HandleIdMgr.getNext();
462  assert(!BaseLayerHandles.count(Id) && "Id already in use?");
463 
465  [this, Id](const std::string &Name) { return lookup(Id, Name); },
466  [this, Id](const std::string &Name) {
467  return lookupInLogicalDylib(Id, Name);
468  });
469 
470  if (auto HandleOrErr =
471  BaseLayer.addObject(std::move(Buffer), std::move(Resolver))) {
472  BaseLayerHandles[Id] = std::move(*HandleOrErr);
473  return Id;
474  } else
475  return teeLog(HandleOrErr.takeError());
476  }
477 
478  Error removeObject(ObjHandleT H) {
479  auto HI = BaseLayerHandles.find(H);
480  if (HI != BaseLayerHandles.end()) {
481  if (auto Err = BaseLayer.removeObject(HI->second))
482  return teeLog(std::move(Err));
483  return Error::success();
484  } else
485  return teeLog(badObjectHandleError(H));
486  }
487 
488  Expected<RemoteSymbol> findSymbol(const std::string &Name,
489  bool ExportedSymbolsOnly) {
490  if (auto Sym = BaseLayer.findSymbol(Name, ExportedSymbolsOnly))
491  return this->jitSymbolToRemote(std::move(Sym));
492  else if (auto Err = Sym.takeError())
493  return teeLog(std::move(Err));
494  return this->nullRemoteSymbol();
495  }
496 
497  Expected<RemoteSymbol> findSymbolIn(ObjHandleT H, const std::string &Name,
498  bool ExportedSymbolsOnly) {
499  auto HI = BaseLayerHandles.find(H);
500  if (HI != BaseLayerHandles.end()) {
501  if (auto Sym = BaseLayer.findSymbolIn(HI->second, Name, ExportedSymbolsOnly))
502  return this->jitSymbolToRemote(std::move(Sym));
503  else if (auto Err = Sym.takeError())
504  return teeLog(std::move(Err));
505  return this->nullRemoteSymbol();
506  } else
507  return teeLog(badObjectHandleError(H));
508  }
509 
510  Error emitAndFinalize(ObjHandleT H) {
511  auto HI = BaseLayerHandles.find(H);
512  if (HI != BaseLayerHandles.end()) {
513  if (auto Err = BaseLayer.emitAndFinalize(HI->second))
514  return teeLog(std::move(Err));
515  return Error::success();
516  } else
517  return teeLog(badObjectHandleError(H));
518  }
519 
520  BaseLayerT &BaseLayer;
521  remote::ResourceIdMgr HandleIdMgr;
522  std::map<ObjHandleT, typename BaseLayerT::ObjHandleT> BaseLayerHandles;
523 };
524 
525 } // end namespace orc
526 } // end namespace llvm
527 
528 #endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
uint64_t CallInst * C
Represents a symbol in the JIT.
Definition: JITSymbol.h:218
This class represents lattice values for constants.
Definition: AllocatorList.h:23
RemoteSymbol nullRemoteSymbol()
Convenience function for getting a null remote symbol value.
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
RemoteObjectClientLayer(RPCEndpoint &Remote, std::function< void(Error)> ReportError)
Create a RemoteObjectClientLayer that communicates with a RemoteObjectServerLayer instance via the gi...
Error badObjectHandleError(ObjHandleT H)
Error takeError()
Take ownership of the stored error.
Definition: Error.h:552
RemoteSymbolMaterializer(const RemoteSymbolMaterializer &Other)
remote::ResourceIdMgr::ResourceId ObjHandleT
JITSymbolFlags getFlags() const
Definition: JITSymbol.h:307
std::unique_ptr< MemoryBuffer > ObjectPtr
Definition: BitVector.h:937
RemoteObjectLayer(RPCEndpoint &Remote, std::function< void(Error)> ReportError)
static int Lookup(ArrayRef< TableEntry > Table, unsigned Opcode)
Tagged union holding either a T or a Error.
Definition: CachePruning.h:22
Error emitAndFinalize(ObjHandleT H)
Immediately emit and finalize the object with the given handle.
static const uint16_t * lookup(unsigned opcode, unsigned domain, ArrayRef< uint16_t[3]> Table)
JITSymbol remoteToJITSymbol(Expected< RemoteSymbol > RemoteSymOrErr)
Convert an Expected<RemoteSymbol> to a JITSymbol.
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:432
Expected< RemoteSymbol > jitSymbolToRemote(JITSymbol Sym)
Create a RemoteSymbol wrapping the given JITSymbol.
#define H(x, y, z)
Definition: MD5.cpp:57
Interface for looking up the initializer for a variable name, used by Init::resolveReferences.
Definition: Record.h:1856
This class is used as the symbol materializer for JITSymbols returned by RemoteObjectLayerClient/Remo...
RemoteSymbolMaterializer(RemoteObjectLayer &C, RemoteSymbolId Id)
Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer with the given Id...
Error badRemoteSymbolIdError(RemoteSymbolId Id)
static const RemoteSymbolId NullSymbolId
Flags for symbols in the JIT.
Definition: JITSymbol.h:55
remote::ResourceIdMgr::ResourceId RemoteSymbolId
JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly)
Search for the given named symbol within the given context.
RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
std::function< void(Error)> ReportError
Expected< ObjHandleT > addObject(ObjectPtr ObjBuffer, std::shared_ptr< LegacyJITSymbolResolver > Resolver)
Add an object to the JIT.
Template error for missing resources.
JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly)
Search for the given named symbol.
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
std::pair< RemoteSymbolId, JITSymbolFlags > RemoteSymbol
Base class containing common utilities for RemoteObjectClientLayer and RemoteObjectServerLayer.
RemoteObjectServerLayer(BaseLayerT &BaseLayer, RPCEndpoint &Remote, std::function< void(Error)> ReportError)
Create a RemoteObjectServerLayer with the given base layer (which must be an object layer)...
RemoteObjectServerLayer acts as a server and handling RPC calls for the object layer API from the giv...
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:41
Error teeLog(Error Err)
Creates a StringError that contains a copy of Err&#39;s log message, then sends that StringError to Repor...
static const ObjHandleT InvalidObjectHandleId
RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC connection. ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Error removeObject(ObjHandleT H)
Remove the given object from the JIT.
std::shared_ptr< LambdaResolver< DylibLookupFtorT, ExternalLookupFtorT > > createLambdaResolver(DylibLookupFtorT DylibLookupFtor, ExternalLookupFtorT ExternalLookupFtor)
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Definition: Error.h:881
Error takeError()
Move the error field value out of this JITSymbol.
Definition: JITSymbol.h:286
print Print MemDeps of function
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
static void LLVM_ATTRIBUTE_NORETURN ReportError(uint32_t StartOffset, const char *ErrorMsg)
Expected< JITTargetAddress > materialize()
Materialize the symbol on the remote and get its address.