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