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