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
17#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
18#include "llvm/Object/ObjectFile.h"
19#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
20#include <map>
21
22namespace llvm {
23namespace orc {
24
25/// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
26class RemoteObjectLayerAPI {
27public:
28
29  using ObjHandleT = remote::ResourceIdMgr::ResourceId;
30
31protected:
32
33  using RemoteSymbolId = remote::ResourceIdMgr::ResourceId;
34  using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>;
35
36public:
37
38  using BadSymbolHandleError = remote::ResourceNotFound<RemoteSymbolId>;
39  using BadObjectHandleError = remote::ResourceNotFound<ObjHandleT>;
40
41protected:
42
43  static const ObjHandleT InvalidObjectHandleId = 0;
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
52  class RemoveObject
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
65  class FindSymbolIn
66    : public rpc::Function<FindSymbolIn,
67                           Expected<RemoteSymbol>(ObjHandleT, std::string,
68                                                  bool)> {
69  public:
70    static const char *getName() { return "FindSymbolIn"; }
71  };
72
73  class EmitAndFinalize
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
87  class LookupInLogicalDylib
88    : public rpc::Function<LookupInLogicalDylib,
89                           Expected<RemoteSymbol>(ObjHandleT, std::string)> {
90  public:
91    static const char *getName() { return "LookupInLogicalDylib"; }
92  };
93
94  class ReleaseRemoteSymbol
95    : public rpc::Function<ReleaseRemoteSymbol, Error(RemoteSymbolId)> {
96  public:
97    static const char *getName() { return "ReleaseRemoteSymbol"; }
98  };
99
100  class MaterializeRemoteSymbol
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.
110template <typename RPCEndpoint>
111class RemoteObjectLayer : public RemoteObjectLayerAPI {
112public:
113
114  RemoteObjectLayer(RPCEndpoint &Remote,
115                    std::function<void(Error)> ReportError)
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
125protected:
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.
131  class RemoteSymbolMaterializer {
132  public:
133
134    /// Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer
135    /// with the given Id.
136    RemoteSymbolMaterializer(RemoteObjectLayer &C,
137                             RemoteSymbolId Id)
138      : C(C), Id(Id) {}
139
140    RemoteSymbolMaterializer(const RemoteSymbolMaterializer &Other)
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
149    RemoteSymbolMaterializer&
150    operator=(const RemoteSymbolMaterializer&) = delete;
151
152    /// Release the remote symbol.
153    ~RemoteSymbolMaterializer() {
154      if (Id)
155        C.releaseRemoteSymbol(Id);
156    }
157
158    /// Materialize the symbol on the remote and get its address.
159    Expected<JITTargetAddress> materialize() {
160      auto Addr = C.materializeRemoteSymbol(Id);
161      Id = 0;
162      return Addr;
163    }
164
165  private:
166    RemoteObjectLayer &C;
167    RemoteSymbolId Id;
168  };
169
170  /// Convenience function for getting a null remote symbol value.
171  RemoteSymbol nullRemoteSymbol() {
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.
180  Error teeLog(Error Err) {
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
190  Error badRemoteSymbolIdError(RemoteSymbolId Id) {
191    return make_error<BadSymbolHandleError>(Id, "Remote JIT Symbol");
192  }
193
194  Error badObjectHandleError(ObjHandleT H) {
195    return make_error<RemoteObjectLayerAPI::BadObjectHandleError>(
196             H, "Bad object handle");
197  }
198
199  /// Create a RemoteSymbol wrapping the given JITSymbol.
200  Expected<RemoteSymbol> jitSymbolToRemote(JITSymbol Sym) {
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.
214  JITSymbol remoteToJITSymbol(Expected<RemoteSymbol> RemoteSymOrErr) {
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
232private:
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.
288template <typename RPCEndpoint>
289class RemoteObjectClientLayer : public RemoteObjectLayer<RPCEndpoint> {
290private:
291
292  using AddObject = RemoteObjectLayerAPI::AddObject;
293  using RemoveObject = RemoteObjectLayerAPI::RemoveObject;
294  using FindSymbol = RemoteObjectLayerAPI::FindSymbol;
295  using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn;
296  using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize;
297  using Lookup = RemoteObjectLayerAPI::Lookup;
298  using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib;
299
300  using RemoteObjectLayer<RPCEndpoint>::teeLog;
301  using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError;
302  using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol;
303
304public:
305
306  using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
307  using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
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,
318                          std::function<void(Error)> ReportError)
319      : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)) {
320    using ThisT = RemoteObjectClientLayer<RPCEndpoint>;
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.).
330  Expected<ObjHandleT>
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.
345  Error removeObject(ObjHandleT H) {
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.
364  Error emitAndFinalize(ObjHandleT H) {
365    return this->Remote.template callB<EmitAndFinalize>(H);
366  }
367
368private:
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
388  std::map<remote::ResourceIdMgr::ResourceId,
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.
398template <typename BaseLayerT, typename RPCEndpoint>
399class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> {
400private:
401
402  using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
403  using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
404
405  using AddObject = RemoteObjectLayerAPI::AddObject;
406  using RemoveObject = RemoteObjectLayerAPI::RemoveObject;
407  using FindSymbol = RemoteObjectLayerAPI::FindSymbol;
408  using FindSymbolIn = RemoteObjectLayerAPI::FindSymbolIn;
409  using EmitAndFinalize = RemoteObjectLayerAPI::EmitAndFinalize;
410  using Lookup = RemoteObjectLayerAPI::Lookup;
411  using LookupInLogicalDylib = RemoteObjectLayerAPI::LookupInLogicalDylib;
412
413  using RemoteObjectLayer<RPCEndpoint>::teeLog;
414  using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError;
415  using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol;
416
417public:
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,
423                          std::function<void(Error)> ReportError)
424    : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)),
425      BaseLayer(BaseLayer), HandleIdMgr(1) {
426    using ThisT = RemoteObjectServerLayer<BaseLayerT, RPCEndpoint>;
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
435private:
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 =
472        createLambdaResolver(
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
539