Home | History | Annotate | Download | only in Orc
      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 
     22 namespace llvm {
     23 namespace orc {
     24 
     25 /// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
     26 class RemoteObjectLayerAPI {
     27 public:
     28 
     29   using ObjHandleT = remote::ResourceIdMgr::ResourceId;
     30 
     31 protected:
     32 
     33   using RemoteSymbolId = remote::ResourceIdMgr::ResourceId;
     34   using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>;
     35 
     36 public:
     37 
     38   using BadSymbolHandleError = remote::ResourceNotFound<RemoteSymbolId>;
     39   using BadObjectHandleError = remote::ResourceNotFound<ObjHandleT>;
     40 
     41 protected:
     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.
    110 template <typename RPCEndpoint>
    111 class RemoteObjectLayer : public RemoteObjectLayerAPI {
    112 public:
    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 
    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.
    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 
    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 
    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 
    304 public:
    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 
    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 
    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.
    398 template <typename BaseLayerT, typename RPCEndpoint>
    399 class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> {
    400 private:
    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 
    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,
    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 
    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 =
    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