1 //===------ RemoteObjectLayer.h - Forwards objs to a remote -----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Forwards objects to a remote object layer via RPC.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
14 #define LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
16 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
17 #include "llvm/Object/ObjectFile.h"
18 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
24 /// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
25 class RemoteObjectLayerAPI
{
28 using ObjHandleT
= remote::ResourceIdMgr::ResourceId
;
32 using RemoteSymbolId
= remote::ResourceIdMgr::ResourceId
;
33 using RemoteSymbol
= std::pair
<RemoteSymbolId
, JITSymbolFlags
>;
37 using BadSymbolHandleError
= remote::ResourceNotFound
<RemoteSymbolId
>;
38 using BadObjectHandleError
= remote::ResourceNotFound
<ObjHandleT
>;
42 static const ObjHandleT InvalidObjectHandleId
= 0;
43 static const RemoteSymbolId NullSymbolId
= 0;
46 : public rpc::Function
<AddObject
, Expected
<ObjHandleT
>(std::string
)> {
48 static const char *getName() { return "AddObject"; }
52 : public rpc::Function
<RemoveObject
, Error(ObjHandleT
)> {
54 static const char *getName() { return "RemoveObject"; }
58 : public rpc::Function
<FindSymbol
, Expected
<RemoteSymbol
>(std::string
,
61 static const char *getName() { return "FindSymbol"; }
65 : public rpc::Function
<FindSymbolIn
,
66 Expected
<RemoteSymbol
>(ObjHandleT
, std::string
,
69 static const char *getName() { return "FindSymbolIn"; }
73 : public rpc::Function
<EmitAndFinalize
,
76 static const char *getName() { return "EmitAndFinalize"; }
80 : public rpc::Function
<Lookup
,
81 Expected
<RemoteSymbol
>(ObjHandleT
, std::string
)> {
83 static const char *getName() { return "Lookup"; }
86 class LookupInLogicalDylib
87 : public rpc::Function
<LookupInLogicalDylib
,
88 Expected
<RemoteSymbol
>(ObjHandleT
, std::string
)> {
90 static const char *getName() { return "LookupInLogicalDylib"; }
93 class ReleaseRemoteSymbol
94 : public rpc::Function
<ReleaseRemoteSymbol
, Error(RemoteSymbolId
)> {
96 static const char *getName() { return "ReleaseRemoteSymbol"; }
99 class MaterializeRemoteSymbol
100 : public rpc::Function
<MaterializeRemoteSymbol
,
101 Expected
<JITTargetAddress
>(RemoteSymbolId
)> {
103 static const char *getName() { return "MaterializeRemoteSymbol"; }
107 /// Base class containing common utilities for RemoteObjectClientLayer and
108 /// RemoteObjectServerLayer.
109 template <typename RPCEndpoint
>
110 class RemoteObjectLayer
: public RemoteObjectLayerAPI
{
113 RemoteObjectLayer(RPCEndpoint
&Remote
,
114 std::function
<void(Error
)> ReportError
)
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
);
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
130 class RemoteSymbolMaterializer
{
133 /// Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer
134 /// with the given Id.
135 RemoteSymbolMaterializer(RemoteObjectLayer
&C
,
139 RemoteSymbolMaterializer(const RemoteSymbolMaterializer
&Other
)
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;
148 RemoteSymbolMaterializer
&
149 operator=(const RemoteSymbolMaterializer
&) = delete;
151 /// Release the remote symbol.
152 ~RemoteSymbolMaterializer() {
154 C
.releaseRemoteSymbol(Id
);
157 /// Materialize the symbol on the remote and get its address.
158 Expected
<JITTargetAddress
> materialize() {
159 auto Addr
= C
.materializeRemoteSymbol(Id
);
165 RemoteObjectLayer
&C
;
169 /// Convenience function for getting a null remote symbol value.
170 RemoteSymbol
nullRemoteSymbol() {
171 return RemoteSymbol(0, JITSymbolFlags());
174 /// Creates a StringError that contains a copy of Err's log message, then
175 /// sends that StringError to ReportError.
177 /// This allows us to locally log error messages for errors that will actually
178 /// be delivered to the remote.
179 Error
teeLog(Error Err
) {
180 return handleErrors(std::move(Err
),
181 [this](std::unique_ptr
<ErrorInfoBase
> EIB
) {
182 ReportError(make_error
<StringError
>(
184 EIB
->convertToErrorCode()));
185 return Error(std::move(EIB
));
189 Error
badRemoteSymbolIdError(RemoteSymbolId Id
) {
190 return make_error
<BadSymbolHandleError
>(Id
, "Remote JIT Symbol");
193 Error
badObjectHandleError(ObjHandleT H
) {
194 return make_error
<RemoteObjectLayerAPI::BadObjectHandleError
>(
195 H
, "Bad object handle");
198 /// Create a RemoteSymbol wrapping the given JITSymbol.
199 Expected
<RemoteSymbol
> jitSymbolToRemote(JITSymbol 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
));
209 return nullRemoteSymbol();
212 /// Convert an Expected<RemoteSymbol> to a JITSymbol.
213 JITSymbol
remoteToJITSymbol(Expected
<RemoteSymbol
> RemoteSymOrErr
) {
214 if (RemoteSymOrErr
) {
215 auto &RemoteSym
= *RemoteSymOrErr
;
216 if (RemoteSym
== nullRemoteSymbol())
219 RemoteSymbolMaterializer
RSM(*this, RemoteSym
.first
);
221 JITSymbol([RSM
]() mutable { return RSM
.materialize(); },
225 return RemoteSymOrErr
.takeError();
229 std::function
<void(Error
)> ReportError
;
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
));
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
);
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();
252 return teeLog(badRemoteSymbolIdError(Id
));
255 /// Run the materializer for the JITSymbol with the given Id and return its
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
);
266 return teeLog(AddrOrErr
.takeError());
268 return teeLog(badRemoteSymbolIdError(Id
));
272 remote::ResourceIdMgr SymbolIdMgr
;
273 std::map
<RemoteSymbolId
, JITSymbol
> InUseSymbols
;
276 /// RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC
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).
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
> {
291 using AddObject
= RemoteObjectLayerAPI::AddObject
;
292 using RemoveObject
= RemoteObjectLayerAPI::RemoveObject
;
293 using FindSymbol
= RemoteObjectLayerAPI::FindSymbol
;
294 using FindSymbolIn
= RemoteObjectLayerAPI::FindSymbolIn
;
295 using EmitAndFinalize
= RemoteObjectLayerAPI::EmitAndFinalize
;
296 using Lookup
= RemoteObjectLayerAPI::Lookup
;
297 using LookupInLogicalDylib
= RemoteObjectLayerAPI::LookupInLogicalDylib
;
299 using RemoteObjectLayer
<RPCEndpoint
>::teeLog
;
300 using RemoteObjectLayer
<RPCEndpoint
>::badObjectHandleError
;
301 using RemoteObjectLayer
<RPCEndpoint
>::remoteToJITSymbol
;
305 using ObjHandleT
= RemoteObjectLayerAPI::ObjHandleT
;
306 using RemoteSymbol
= RemoteObjectLayerAPI::RemoteSymbol
;
308 using ObjectPtr
= std::unique_ptr
<MemoryBuffer
>;
310 /// Create a RemoteObjectClientLayer that communicates with a
311 /// RemoteObjectServerLayer instance via the given RPCEndpoint.
313 /// The ReportError functor can be used locally log errors that are intended
315 RemoteObjectClientLayer(RPCEndpoint
&Remote
,
316 std::function
<void(Error
)> ReportError
)
317 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)) {
318 using ThisT
= RemoteObjectClientLayer
<RPCEndpoint
>;
319 Remote
.template addHandler
<Lookup
>(*this, &ThisT::lookup
);
320 Remote
.template addHandler
<LookupInLogicalDylib
>(
321 *this, &ThisT::lookupInLogicalDylib
);
324 /// Add an object to the JIT.
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
);
339 return HandleOrErr
.takeError();
342 /// Remove the given object from the JIT.
343 Error
removeObject(ObjHandleT H
) {
344 return this->Remote
.template callB
<RemoveObject
>(H
);
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
));
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
));
361 /// Immediately emit and finalize the object with the given handle.
362 Error
emitAndFinalize(ObjHandleT H
) {
363 return this->Remote
.template callB
<EmitAndFinalize
>(H
);
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
));
373 return teeLog(badObjectHandleError(H
));
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
));
383 return teeLog(badObjectHandleError(H
));
386 std::map
<remote::ResourceIdMgr::ResourceId
,
387 std::shared_ptr
<LegacyJITSymbolResolver
>>
391 /// RemoteObjectServerLayer acts as a server and handling RPC calls for the
392 /// object layer API from the given RPC connection.
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
> {
401 using ObjHandleT
= RemoteObjectLayerAPI::ObjHandleT
;
402 using RemoteSymbol
= RemoteObjectLayerAPI::RemoteSymbol
;
404 using AddObject
= RemoteObjectLayerAPI::AddObject
;
405 using RemoveObject
= RemoteObjectLayerAPI::RemoveObject
;
406 using FindSymbol
= RemoteObjectLayerAPI::FindSymbol
;
407 using FindSymbolIn
= RemoteObjectLayerAPI::FindSymbolIn
;
408 using EmitAndFinalize
= RemoteObjectLayerAPI::EmitAndFinalize
;
409 using Lookup
= RemoteObjectLayerAPI::Lookup
;
410 using LookupInLogicalDylib
= RemoteObjectLayerAPI::LookupInLogicalDylib
;
412 using RemoteObjectLayer
<RPCEndpoint
>::teeLog
;
413 using RemoteObjectLayer
<RPCEndpoint
>::badObjectHandleError
;
414 using RemoteObjectLayer
<RPCEndpoint
>::remoteToJITSymbol
;
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
,
422 std::function
<void(Error
)> ReportError
)
423 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)),
424 BaseLayer(BaseLayer
), HandleIdMgr(1) {
425 using ThisT
= RemoteObjectServerLayer
<BaseLayerT
, RPCEndpoint
>;
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
);
436 class StringMemoryBuffer
: public MemoryBuffer
{
438 StringMemoryBuffer(std::string Buffer
)
439 : Buffer(std::move(Buffer
)) {
440 init(this->Buffer
.data(), this->Buffer
.data() + this->Buffer
.size(),
444 BufferKind
getBufferKind() const override
{ return MemoryBuffer_Malloc
; }
449 JITSymbol
lookup(ObjHandleT Id
, const std::string
&Name
) {
450 return remoteToJITSymbol(
451 this->Remote
.template callB
<Lookup
>(Id
, Name
));
454 JITSymbol
lookupInLogicalDylib(ObjHandleT Id
, const std::string
&Name
) {
455 return remoteToJITSymbol(
456 this->Remote
.template callB
<LookupInLogicalDylib
>(Id
, Name
));
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?");
464 auto Resolver
= createLambdaResolver(
465 [this, Id
](const std::string
&Name
) { return lookup(Id
, Name
); },
466 [this, Id
](const std::string
&Name
) {
467 return lookupInLogicalDylib(Id
, Name
);
470 if (auto HandleOrErr
=
471 BaseLayer
.addObject(std::move(Buffer
), std::move(Resolver
))) {
472 BaseLayerHandles
[Id
] = std::move(*HandleOrErr
);
475 return teeLog(HandleOrErr
.takeError());
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();
485 return teeLog(badObjectHandleError(H
));
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();
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();
507 return teeLog(badObjectHandleError(H
));
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();
517 return teeLog(badObjectHandleError(H
));
520 BaseLayerT
&BaseLayer
;
521 remote::ResourceIdMgr HandleIdMgr
;
522 std::map
<ObjHandleT
, typename
BaseLayerT::ObjHandleT
> BaseLayerHandles
;
525 } // end namespace orc
526 } // end namespace llvm
528 #endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H