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/Core.h"
17 #include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
18 #include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
19 #include "llvm/Object/ObjectFile.h"
25 /// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
26 class RemoteObjectLayerAPI
{
29 using ObjHandleT
= remote::ResourceIdMgr::ResourceId
;
33 using RemoteSymbolId
= remote::ResourceIdMgr::ResourceId
;
34 using RemoteSymbol
= std::pair
<RemoteSymbolId
, JITSymbolFlags
>;
38 using BadSymbolHandleError
= remote::ResourceNotFound
<RemoteSymbolId
>;
39 using BadObjectHandleError
= remote::ResourceNotFound
<ObjHandleT
>;
43 static const ObjHandleT InvalidObjectHandleId
= 0;
44 static const RemoteSymbolId NullSymbolId
= 0;
47 : public rpc::Function
<AddObject
, Expected
<ObjHandleT
>(std::string
)> {
49 static const char *getName() { return "AddObject"; }
53 : public rpc::Function
<RemoveObject
, Error(ObjHandleT
)> {
55 static const char *getName() { return "RemoveObject"; }
59 : public rpc::Function
<FindSymbol
, Expected
<RemoteSymbol
>(std::string
,
62 static const char *getName() { return "FindSymbol"; }
66 : public rpc::Function
<FindSymbolIn
,
67 Expected
<RemoteSymbol
>(ObjHandleT
, std::string
,
70 static const char *getName() { return "FindSymbolIn"; }
74 : public rpc::Function
<EmitAndFinalize
,
77 static const char *getName() { return "EmitAndFinalize"; }
81 : public rpc::Function
<Lookup
,
82 Expected
<RemoteSymbol
>(ObjHandleT
, std::string
)> {
84 static const char *getName() { return "Lookup"; }
87 class LookupInLogicalDylib
88 : public rpc::Function
<LookupInLogicalDylib
,
89 Expected
<RemoteSymbol
>(ObjHandleT
, std::string
)> {
91 static const char *getName() { return "LookupInLogicalDylib"; }
94 class ReleaseRemoteSymbol
95 : public rpc::Function
<ReleaseRemoteSymbol
, Error(RemoteSymbolId
)> {
97 static const char *getName() { return "ReleaseRemoteSymbol"; }
100 class MaterializeRemoteSymbol
101 : public rpc::Function
<MaterializeRemoteSymbol
,
102 Expected
<JITTargetAddress
>(RemoteSymbolId
)> {
104 static const char *getName() { return "MaterializeRemoteSymbol"; }
108 /// Base class containing common utilities for RemoteObjectClientLayer and
109 /// RemoteObjectServerLayer.
110 template <typename RPCEndpoint
>
111 class RemoteObjectLayer
: public RemoteObjectLayerAPI
{
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
);
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
131 class RemoteSymbolMaterializer
{
134 /// Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer
135 /// with the given Id.
136 RemoteSymbolMaterializer(RemoteObjectLayer
&C
,
140 RemoteSymbolMaterializer(RemoteSymbolMaterializer
&&Other
)
141 : C(Other
.C
), Id(Other
.Id
) {
145 RemoteSymbolMaterializer
&operator=(RemoteSymbolMaterializer
&&) = delete;
147 /// Release the remote symbol.
148 ~RemoteSymbolMaterializer() {
150 C
.releaseRemoteSymbol(Id
);
153 /// Materialize the symbol on the remote and get its address.
154 Expected
<JITTargetAddress
> materialize() {
155 auto Addr
= C
.materializeRemoteSymbol(Id
);
161 RemoteObjectLayer
&C
;
165 /// Convenience function for getting a null remote symbol value.
166 RemoteSymbol
nullRemoteSymbol() {
167 return RemoteSymbol(0, JITSymbolFlags());
170 /// Creates a StringError that contains a copy of Err's log message, then
171 /// sends that StringError to ReportError.
173 /// This allows us to locally log error messages for errors that will actually
174 /// be delivered to the remote.
175 Error
teeLog(Error Err
) {
176 return handleErrors(std::move(Err
),
177 [this](std::unique_ptr
<ErrorInfoBase
> EIB
) {
178 ReportError(make_error
<StringError
>(
180 EIB
->convertToErrorCode()));
181 return Error(std::move(EIB
));
185 Error
badRemoteSymbolIdError(RemoteSymbolId Id
) {
186 return make_error
<BadSymbolHandleError
>(Id
, "Remote JIT Symbol");
189 Error
badObjectHandleError(ObjHandleT H
) {
190 return make_error
<RemoteObjectLayerAPI::BadObjectHandleError
>(
191 H
, "Bad object handle");
194 /// Create a RemoteSymbol wrapping the given JITSymbol.
195 Expected
<RemoteSymbol
> jitSymbolToRemote(JITSymbol Sym
) {
197 auto Id
= SymbolIdMgr
.getNext();
198 auto Flags
= Sym
.getFlags();
199 assert(!InUseSymbols
.count(Id
) && "Symbol id already in use");
200 InUseSymbols
.insert(std::make_pair(Id
, std::move(Sym
)));
201 return RemoteSymbol(Id
, Flags
);
202 } else if (auto Err
= Sym
.takeError())
203 return teeLog(std::move(Err
));
205 return nullRemoteSymbol();
208 /// Convert an Expected<RemoteSymbol> to a JITSymbol.
209 JITSymbol
remoteToJITSymbol(Expected
<RemoteSymbol
> RemoteSymOrErr
) {
210 if (RemoteSymOrErr
) {
211 auto &RemoteSym
= *RemoteSymOrErr
;
212 if (RemoteSym
== nullRemoteSymbol())
215 RemoteSymbolMaterializer
RSM(*this, RemoteSym
.first
);
216 auto Sym
= JITSymbol(
217 [RSM
= std::move(RSM
)]() mutable { return RSM
.materialize(); },
221 return RemoteSymOrErr
.takeError();
225 std::function
<void(Error
)> ReportError
;
229 /// Notify the remote to release the given JITSymbol.
230 void releaseRemoteSymbol(RemoteSymbolId Id
) {
231 if (auto Err
= Remote
.template callB
<ReleaseRemoteSymbol
>(Id
))
232 ReportError(std::move(Err
));
235 /// Notify the remote to materialize the JITSymbol with the given Id and
236 /// return its address.
237 Expected
<JITTargetAddress
> materializeRemoteSymbol(RemoteSymbolId Id
) {
238 return Remote
.template callB
<MaterializeRemoteSymbol
>(Id
);
241 /// Release the JITSymbol with the given Id.
242 Error
handleReleaseRemoteSymbol(RemoteSymbolId Id
) {
243 auto SI
= InUseSymbols
.find(Id
);
244 if (SI
!= InUseSymbols
.end()) {
245 InUseSymbols
.erase(SI
);
246 return Error::success();
248 return teeLog(badRemoteSymbolIdError(Id
));
251 /// Run the materializer for the JITSymbol with the given Id and return its
253 Expected
<JITTargetAddress
> handleMaterializeRemoteSymbol(RemoteSymbolId Id
) {
254 auto SI
= InUseSymbols
.find(Id
);
255 if (SI
!= InUseSymbols
.end()) {
256 auto AddrOrErr
= SI
->second
.getAddress();
257 InUseSymbols
.erase(SI
);
258 SymbolIdMgr
.release(Id
);
262 return teeLog(AddrOrErr
.takeError());
264 return teeLog(badRemoteSymbolIdError(Id
));
268 remote::ResourceIdMgr SymbolIdMgr
;
269 std::map
<RemoteSymbolId
, JITSymbol
> InUseSymbols
;
272 /// RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC
275 /// This class can be used as the base layer of a JIT stack on the client and
276 /// will forward operations to a corresponding RemoteObjectServerLayer on the
277 /// server (which can be composed on top of a "real" object layer like
278 /// RTDyldObjectLinkingLayer to actually carry out the operations).
280 /// Sending relocatable objects to the server (rather than fully relocated
281 /// bits) allows JIT'd code to be cached on the server side and re-used in
282 /// subsequent JIT sessions.
283 template <typename RPCEndpoint
>
284 class RemoteObjectClientLayer
: public RemoteObjectLayer
<RPCEndpoint
> {
287 using AddObject
= RemoteObjectLayerAPI::AddObject
;
288 using RemoveObject
= RemoteObjectLayerAPI::RemoveObject
;
289 using FindSymbol
= RemoteObjectLayerAPI::FindSymbol
;
290 using FindSymbolIn
= RemoteObjectLayerAPI::FindSymbolIn
;
291 using EmitAndFinalize
= RemoteObjectLayerAPI::EmitAndFinalize
;
292 using Lookup
= RemoteObjectLayerAPI::Lookup
;
293 using LookupInLogicalDylib
= RemoteObjectLayerAPI::LookupInLogicalDylib
;
295 using RemoteObjectLayer
<RPCEndpoint
>::teeLog
;
296 using RemoteObjectLayer
<RPCEndpoint
>::badObjectHandleError
;
297 using RemoteObjectLayer
<RPCEndpoint
>::remoteToJITSymbol
;
301 using ObjHandleT
= RemoteObjectLayerAPI::ObjHandleT
;
302 using RemoteSymbol
= RemoteObjectLayerAPI::RemoteSymbol
;
304 using ObjectPtr
= std::unique_ptr
<MemoryBuffer
>;
306 /// Create a RemoteObjectClientLayer that communicates with a
307 /// RemoteObjectServerLayer instance via the given RPCEndpoint.
309 /// The ReportError functor can be used locally log errors that are intended
311 LLVM_ATTRIBUTE_DEPRECATED(
312 RemoteObjectClientLayer(RPCEndpoint
&Remote
,
313 std::function
<void(Error
)> ReportError
),
314 "ORCv1 layers (including RemoteObjectClientLayer) are deprecated. Please "
316 "ORCv2 (see docs/ORCv2.rst)");
318 RemoteObjectClientLayer(ORCv1DeprecationAcknowledgement
, RPCEndpoint
&Remote
,
319 std::function
<void(Error
)> ReportError
)
320 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)) {
321 using ThisT
= RemoteObjectClientLayer
<RPCEndpoint
>;
322 Remote
.template addHandler
<Lookup
>(*this, &ThisT::lookup
);
323 Remote
.template addHandler
<LookupInLogicalDylib
>(
324 *this, &ThisT::lookupInLogicalDylib
);
327 /// Add an object to the JIT.
329 /// @return A handle that can be used to refer to the loaded object (for
330 /// symbol searching, finalization, freeing memory, etc.).
332 addObject(ObjectPtr ObjBuffer
,
333 std::shared_ptr
<LegacyJITSymbolResolver
> Resolver
) {
334 if (auto HandleOrErr
=
335 this->Remote
.template callB
<AddObject
>(ObjBuffer
->getBuffer())) {
336 auto &Handle
= *HandleOrErr
;
337 // FIXME: Return an error for this:
338 assert(!Resolvers
.count(Handle
) && "Handle already in use?");
339 Resolvers
[Handle
] = std::move(Resolver
);
342 return HandleOrErr
.takeError();
345 /// Remove the given object from the JIT.
346 Error
removeObject(ObjHandleT H
) {
347 return this->Remote
.template callB
<RemoveObject
>(H
);
350 /// Search for the given named symbol.
351 JITSymbol
findSymbol(StringRef Name
, bool ExportedSymbolsOnly
) {
352 return remoteToJITSymbol(
353 this->Remote
.template callB
<FindSymbol
>(Name
,
354 ExportedSymbolsOnly
));
357 /// Search for the given named symbol within the given context.
358 JITSymbol
findSymbolIn(ObjHandleT H
, StringRef Name
, bool ExportedSymbolsOnly
) {
359 return remoteToJITSymbol(
360 this->Remote
.template callB
<FindSymbolIn
>(H
, Name
,
361 ExportedSymbolsOnly
));
364 /// Immediately emit and finalize the object with the given handle.
365 Error
emitAndFinalize(ObjHandleT H
) {
366 return this->Remote
.template callB
<EmitAndFinalize
>(H
);
371 Expected
<RemoteSymbol
> lookup(ObjHandleT H
, const std::string
&Name
) {
372 auto RI
= Resolvers
.find(H
);
373 if (RI
!= Resolvers
.end()) {
374 return this->jitSymbolToRemote(RI
->second
->findSymbol(Name
));
376 return teeLog(badObjectHandleError(H
));
379 Expected
<RemoteSymbol
> lookupInLogicalDylib(ObjHandleT H
,
380 const std::string
&Name
) {
381 auto RI
= Resolvers
.find(H
);
382 if (RI
!= Resolvers
.end())
383 return this->jitSymbolToRemote(
384 RI
->second
->findSymbolInLogicalDylib(Name
));
386 return teeLog(badObjectHandleError(H
));
389 std::map
<remote::ResourceIdMgr::ResourceId
,
390 std::shared_ptr
<LegacyJITSymbolResolver
>>
394 /// RemoteObjectServerLayer acts as a server and handling RPC calls for the
395 /// object layer API from the given RPC connection.
397 /// This class can be composed on top of a 'real' object layer (e.g.
398 /// RTDyldObjectLinkingLayer) to do the actual work of relocating objects
399 /// and making them executable.
400 template <typename BaseLayerT
, typename RPCEndpoint
>
401 class RemoteObjectServerLayer
: public RemoteObjectLayer
<RPCEndpoint
> {
404 using ObjHandleT
= RemoteObjectLayerAPI::ObjHandleT
;
405 using RemoteSymbol
= RemoteObjectLayerAPI::RemoteSymbol
;
407 using AddObject
= RemoteObjectLayerAPI::AddObject
;
408 using RemoveObject
= RemoteObjectLayerAPI::RemoveObject
;
409 using FindSymbol
= RemoteObjectLayerAPI::FindSymbol
;
410 using FindSymbolIn
= RemoteObjectLayerAPI::FindSymbolIn
;
411 using EmitAndFinalize
= RemoteObjectLayerAPI::EmitAndFinalize
;
412 using Lookup
= RemoteObjectLayerAPI::Lookup
;
413 using LookupInLogicalDylib
= RemoteObjectLayerAPI::LookupInLogicalDylib
;
415 using RemoteObjectLayer
<RPCEndpoint
>::teeLog
;
416 using RemoteObjectLayer
<RPCEndpoint
>::badObjectHandleError
;
417 using RemoteObjectLayer
<RPCEndpoint
>::remoteToJITSymbol
;
421 /// Create a RemoteObjectServerLayer with the given base layer (which must be
422 /// an object layer), RPC endpoint, and error reporter function.
423 LLVM_ATTRIBUTE_DEPRECATED(
424 RemoteObjectServerLayer(BaseLayerT
&BaseLayer
, RPCEndpoint
&Remote
,
425 std::function
<void(Error
)> ReportError
),
426 "ORCv1 layers (including RemoteObjectServerLayer) are deprecated. Please "
428 "ORCv2 (see docs/ORCv2.rst)");
430 RemoteObjectServerLayer(ORCv1DeprecationAcknowledgement
,
431 BaseLayerT
&BaseLayer
, RPCEndpoint
&Remote
,
432 std::function
<void(Error
)> ReportError
)
433 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)),
434 BaseLayer(BaseLayer
), HandleIdMgr(1) {
435 using ThisT
= RemoteObjectServerLayer
<BaseLayerT
, RPCEndpoint
>;
437 Remote
.template addHandler
<AddObject
>(*this, &ThisT::addObject
);
438 Remote
.template addHandler
<RemoveObject
>(*this, &ThisT::removeObject
);
439 Remote
.template addHandler
<FindSymbol
>(*this, &ThisT::findSymbol
);
440 Remote
.template addHandler
<FindSymbolIn
>(*this, &ThisT::findSymbolIn
);
441 Remote
.template addHandler
<EmitAndFinalize
>(*this, &ThisT::emitAndFinalize
);
446 class StringMemoryBuffer
: public MemoryBuffer
{
448 StringMemoryBuffer(std::string Buffer
)
449 : Buffer(std::move(Buffer
)) {
450 init(this->Buffer
.data(), this->Buffer
.data() + this->Buffer
.size(),
454 BufferKind
getBufferKind() const override
{ return MemoryBuffer_Malloc
; }
459 JITSymbol
lookup(ObjHandleT Id
, const std::string
&Name
) {
460 return remoteToJITSymbol(
461 this->Remote
.template callB
<Lookup
>(Id
, Name
));
464 JITSymbol
lookupInLogicalDylib(ObjHandleT Id
, const std::string
&Name
) {
465 return remoteToJITSymbol(
466 this->Remote
.template callB
<LookupInLogicalDylib
>(Id
, Name
));
469 Expected
<ObjHandleT
> addObject(std::string ObjBuffer
) {
470 auto Buffer
= std::make_unique
<StringMemoryBuffer
>(std::move(ObjBuffer
));
471 auto Id
= HandleIdMgr
.getNext();
472 assert(!BaseLayerHandles
.count(Id
) && "Id already in use?");
474 auto Resolver
= createLambdaResolver(
475 AcknowledgeORCv1Deprecation
,
476 [this, Id
](const std::string
&Name
) { return lookup(Id
, Name
); },
477 [this, Id
](const std::string
&Name
) {
478 return lookupInLogicalDylib(Id
, Name
);
481 if (auto HandleOrErr
=
482 BaseLayer
.addObject(std::move(Buffer
), std::move(Resolver
))) {
483 BaseLayerHandles
[Id
] = std::move(*HandleOrErr
);
486 return teeLog(HandleOrErr
.takeError());
489 Error
removeObject(ObjHandleT H
) {
490 auto HI
= BaseLayerHandles
.find(H
);
491 if (HI
!= BaseLayerHandles
.end()) {
492 if (auto Err
= BaseLayer
.removeObject(HI
->second
))
493 return teeLog(std::move(Err
));
494 return Error::success();
496 return teeLog(badObjectHandleError(H
));
499 Expected
<RemoteSymbol
> findSymbol(const std::string
&Name
,
500 bool ExportedSymbolsOnly
) {
501 if (auto Sym
= BaseLayer
.findSymbol(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();
508 Expected
<RemoteSymbol
> findSymbolIn(ObjHandleT H
, const std::string
&Name
,
509 bool ExportedSymbolsOnly
) {
510 auto HI
= BaseLayerHandles
.find(H
);
511 if (HI
!= BaseLayerHandles
.end()) {
512 if (auto Sym
= BaseLayer
.findSymbolIn(HI
->second
, Name
, ExportedSymbolsOnly
))
513 return this->jitSymbolToRemote(std::move(Sym
));
514 else if (auto Err
= Sym
.takeError())
515 return teeLog(std::move(Err
));
516 return this->nullRemoteSymbol();
518 return teeLog(badObjectHandleError(H
));
521 Error
emitAndFinalize(ObjHandleT H
) {
522 auto HI
= BaseLayerHandles
.find(H
);
523 if (HI
!= BaseLayerHandles
.end()) {
524 if (auto Err
= BaseLayer
.emitAndFinalize(HI
->second
))
525 return teeLog(std::move(Err
));
526 return Error::success();
528 return teeLog(badObjectHandleError(H
));
531 BaseLayerT
&BaseLayer
;
532 remote::ResourceIdMgr HandleIdMgr
;
533 std::map
<ObjHandleT
, typename
BaseLayerT::ObjHandleT
> BaseLayerHandles
;
536 template <typename RPCEndpoint
>
537 RemoteObjectClientLayer
<RPCEndpoint
>::RemoteObjectClientLayer(
538 RPCEndpoint
&Remote
, std::function
<void(Error
)> ReportError
)
539 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)) {
540 using ThisT
= RemoteObjectClientLayer
<RPCEndpoint
>;
541 Remote
.template addHandler
<Lookup
>(*this, &ThisT::lookup
);
542 Remote
.template addHandler
<LookupInLogicalDylib
>(
543 *this, &ThisT::lookupInLogicalDylib
);
546 template <typename BaseLayerT
, typename RPCEndpoint
>
547 RemoteObjectServerLayer
<BaseLayerT
, RPCEndpoint
>::RemoteObjectServerLayer(
548 BaseLayerT
&BaseLayer
, RPCEndpoint
&Remote
,
549 std::function
<void(Error
)> ReportError
)
550 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)),
551 BaseLayer(BaseLayer
), HandleIdMgr(1) {
552 using ThisT
= RemoteObjectServerLayer
<BaseLayerT
, RPCEndpoint
>;
554 Remote
.template addHandler
<AddObject
>(*this, &ThisT::addObject
);
555 Remote
.template addHandler
<RemoveObject
>(*this, &ThisT::removeObject
);
556 Remote
.template addHandler
<FindSymbol
>(*this, &ThisT::findSymbol
);
557 Remote
.template addHandler
<FindSymbolIn
>(*this, &ThisT::findSymbolIn
);
558 Remote
.template addHandler
<EmitAndFinalize
>(*this, &ThisT::emitAndFinalize
);
561 } // end namespace orc
562 } // end namespace llvm
564 #endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H