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(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;
149 RemoteSymbolMaterializer
&
150 operator=(const RemoteSymbolMaterializer
&) = delete;
152 /// Release the remote symbol.
153 ~RemoteSymbolMaterializer() {
155 C
.releaseRemoteSymbol(Id
);
158 /// Materialize the symbol on the remote and get its address.
159 Expected
<JITTargetAddress
> materialize() {
160 auto Addr
= C
.materializeRemoteSymbol(Id
);
166 RemoteObjectLayer
&C
;
170 /// Convenience function for getting a null remote symbol value.
171 RemoteSymbol
nullRemoteSymbol() {
172 return RemoteSymbol(0, JITSymbolFlags());
175 /// Creates a StringError that contains a copy of Err's log message, then
176 /// sends that StringError to ReportError.
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
>(
185 EIB
->convertToErrorCode()));
186 return Error(std::move(EIB
));
190 Error
badRemoteSymbolIdError(RemoteSymbolId Id
) {
191 return make_error
<BadSymbolHandleError
>(Id
, "Remote JIT Symbol");
194 Error
badObjectHandleError(ObjHandleT H
) {
195 return make_error
<RemoteObjectLayerAPI::BadObjectHandleError
>(
196 H
, "Bad object handle");
199 /// Create a RemoteSymbol wrapping the given JITSymbol.
200 Expected
<RemoteSymbol
> jitSymbolToRemote(JITSymbol 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
));
210 return nullRemoteSymbol();
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())
220 RemoteSymbolMaterializer
RSM(*this, RemoteSym
.first
);
222 JITSymbol([RSM
]() mutable { return RSM
.materialize(); },
226 return RemoteSymOrErr
.takeError();
230 std::function
<void(Error
)> ReportError
;
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
));
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
);
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();
253 return teeLog(badRemoteSymbolIdError(Id
));
256 /// Run the materializer for the JITSymbol with the given Id and return its
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
);
267 return teeLog(AddrOrErr
.takeError());
269 return teeLog(badRemoteSymbolIdError(Id
));
273 remote::ResourceIdMgr SymbolIdMgr
;
274 std::map
<RemoteSymbolId
, JITSymbol
> InUseSymbols
;
277 /// RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC
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).
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
> {
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
;
300 using RemoteObjectLayer
<RPCEndpoint
>::teeLog
;
301 using RemoteObjectLayer
<RPCEndpoint
>::badObjectHandleError
;
302 using RemoteObjectLayer
<RPCEndpoint
>::remoteToJITSymbol
;
306 using ObjHandleT
= RemoteObjectLayerAPI::ObjHandleT
;
307 using RemoteSymbol
= RemoteObjectLayerAPI::RemoteSymbol
;
309 using ObjectPtr
= std::unique_ptr
<MemoryBuffer
>;
311 /// Create a RemoteObjectClientLayer that communicates with a
312 /// RemoteObjectServerLayer instance via the given RPCEndpoint.
314 /// The ReportError functor can be used locally log errors that are intended
316 LLVM_ATTRIBUTE_DEPRECATED(
317 RemoteObjectClientLayer(RPCEndpoint
&Remote
,
318 std::function
<void(Error
)> ReportError
),
319 "ORCv1 layers (including RemoteObjectClientLayer) are deprecated. Please "
321 "ORCv2 (see docs/ORCv2.rst)");
323 RemoteObjectClientLayer(ORCv1DeprecationAcknowledgement
, RPCEndpoint
&Remote
,
324 std::function
<void(Error
)> ReportError
)
325 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)) {
326 using ThisT
= RemoteObjectClientLayer
<RPCEndpoint
>;
327 Remote
.template addHandler
<Lookup
>(*this, &ThisT::lookup
);
328 Remote
.template addHandler
<LookupInLogicalDylib
>(
329 *this, &ThisT::lookupInLogicalDylib
);
332 /// Add an object to the JIT.
334 /// @return A handle that can be used to refer to the loaded object (for
335 /// symbol searching, finalization, freeing memory, etc.).
337 addObject(ObjectPtr ObjBuffer
,
338 std::shared_ptr
<LegacyJITSymbolResolver
> Resolver
) {
339 if (auto HandleOrErr
=
340 this->Remote
.template callB
<AddObject
>(ObjBuffer
->getBuffer())) {
341 auto &Handle
= *HandleOrErr
;
342 // FIXME: Return an error for this:
343 assert(!Resolvers
.count(Handle
) && "Handle already in use?");
344 Resolvers
[Handle
] = std::move(Resolver
);
347 return HandleOrErr
.takeError();
350 /// Remove the given object from the JIT.
351 Error
removeObject(ObjHandleT H
) {
352 return this->Remote
.template callB
<RemoveObject
>(H
);
355 /// Search for the given named symbol.
356 JITSymbol
findSymbol(StringRef Name
, bool ExportedSymbolsOnly
) {
357 return remoteToJITSymbol(
358 this->Remote
.template callB
<FindSymbol
>(Name
,
359 ExportedSymbolsOnly
));
362 /// Search for the given named symbol within the given context.
363 JITSymbol
findSymbolIn(ObjHandleT H
, StringRef Name
, bool ExportedSymbolsOnly
) {
364 return remoteToJITSymbol(
365 this->Remote
.template callB
<FindSymbolIn
>(H
, Name
,
366 ExportedSymbolsOnly
));
369 /// Immediately emit and finalize the object with the given handle.
370 Error
emitAndFinalize(ObjHandleT H
) {
371 return this->Remote
.template callB
<EmitAndFinalize
>(H
);
376 Expected
<RemoteSymbol
> lookup(ObjHandleT H
, const std::string
&Name
) {
377 auto RI
= Resolvers
.find(H
);
378 if (RI
!= Resolvers
.end()) {
379 return this->jitSymbolToRemote(RI
->second
->findSymbol(Name
));
381 return teeLog(badObjectHandleError(H
));
384 Expected
<RemoteSymbol
> lookupInLogicalDylib(ObjHandleT H
,
385 const std::string
&Name
) {
386 auto RI
= Resolvers
.find(H
);
387 if (RI
!= Resolvers
.end())
388 return this->jitSymbolToRemote(
389 RI
->second
->findSymbolInLogicalDylib(Name
));
391 return teeLog(badObjectHandleError(H
));
394 std::map
<remote::ResourceIdMgr::ResourceId
,
395 std::shared_ptr
<LegacyJITSymbolResolver
>>
399 /// RemoteObjectServerLayer acts as a server and handling RPC calls for the
400 /// object layer API from the given RPC connection.
402 /// This class can be composed on top of a 'real' object layer (e.g.
403 /// RTDyldObjectLinkingLayer) to do the actual work of relocating objects
404 /// and making them executable.
405 template <typename BaseLayerT
, typename RPCEndpoint
>
406 class RemoteObjectServerLayer
: public RemoteObjectLayer
<RPCEndpoint
> {
409 using ObjHandleT
= RemoteObjectLayerAPI::ObjHandleT
;
410 using RemoteSymbol
= RemoteObjectLayerAPI::RemoteSymbol
;
412 using AddObject
= RemoteObjectLayerAPI::AddObject
;
413 using RemoveObject
= RemoteObjectLayerAPI::RemoveObject
;
414 using FindSymbol
= RemoteObjectLayerAPI::FindSymbol
;
415 using FindSymbolIn
= RemoteObjectLayerAPI::FindSymbolIn
;
416 using EmitAndFinalize
= RemoteObjectLayerAPI::EmitAndFinalize
;
417 using Lookup
= RemoteObjectLayerAPI::Lookup
;
418 using LookupInLogicalDylib
= RemoteObjectLayerAPI::LookupInLogicalDylib
;
420 using RemoteObjectLayer
<RPCEndpoint
>::teeLog
;
421 using RemoteObjectLayer
<RPCEndpoint
>::badObjectHandleError
;
422 using RemoteObjectLayer
<RPCEndpoint
>::remoteToJITSymbol
;
426 /// Create a RemoteObjectServerLayer with the given base layer (which must be
427 /// an object layer), RPC endpoint, and error reporter function.
428 LLVM_ATTRIBUTE_DEPRECATED(
429 RemoteObjectServerLayer(BaseLayerT
&BaseLayer
, RPCEndpoint
&Remote
,
430 std::function
<void(Error
)> ReportError
),
431 "ORCv1 layers (including RemoteObjectServerLayer) are deprecated. Please "
433 "ORCv2 (see docs/ORCv2.rst)");
435 RemoteObjectServerLayer(ORCv1DeprecationAcknowledgement
,
436 BaseLayerT
&BaseLayer
, RPCEndpoint
&Remote
,
437 std::function
<void(Error
)> ReportError
)
438 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)),
439 BaseLayer(BaseLayer
), HandleIdMgr(1) {
440 using ThisT
= RemoteObjectServerLayer
<BaseLayerT
, RPCEndpoint
>;
442 Remote
.template addHandler
<AddObject
>(*this, &ThisT::addObject
);
443 Remote
.template addHandler
<RemoveObject
>(*this, &ThisT::removeObject
);
444 Remote
.template addHandler
<FindSymbol
>(*this, &ThisT::findSymbol
);
445 Remote
.template addHandler
<FindSymbolIn
>(*this, &ThisT::findSymbolIn
);
446 Remote
.template addHandler
<EmitAndFinalize
>(*this, &ThisT::emitAndFinalize
);
451 class StringMemoryBuffer
: public MemoryBuffer
{
453 StringMemoryBuffer(std::string Buffer
)
454 : Buffer(std::move(Buffer
)) {
455 init(this->Buffer
.data(), this->Buffer
.data() + this->Buffer
.size(),
459 BufferKind
getBufferKind() const override
{ return MemoryBuffer_Malloc
; }
464 JITSymbol
lookup(ObjHandleT Id
, const std::string
&Name
) {
465 return remoteToJITSymbol(
466 this->Remote
.template callB
<Lookup
>(Id
, Name
));
469 JITSymbol
lookupInLogicalDylib(ObjHandleT Id
, const std::string
&Name
) {
470 return remoteToJITSymbol(
471 this->Remote
.template callB
<LookupInLogicalDylib
>(Id
, Name
));
474 Expected
<ObjHandleT
> addObject(std::string ObjBuffer
) {
475 auto Buffer
= std::make_unique
<StringMemoryBuffer
>(std::move(ObjBuffer
));
476 auto Id
= HandleIdMgr
.getNext();
477 assert(!BaseLayerHandles
.count(Id
) && "Id already in use?");
479 auto Resolver
= createLambdaResolver(
480 AcknowledgeORCv1Deprecation
,
481 [this, Id
](const std::string
&Name
) { return lookup(Id
, Name
); },
482 [this, Id
](const std::string
&Name
) {
483 return lookupInLogicalDylib(Id
, Name
);
486 if (auto HandleOrErr
=
487 BaseLayer
.addObject(std::move(Buffer
), std::move(Resolver
))) {
488 BaseLayerHandles
[Id
] = std::move(*HandleOrErr
);
491 return teeLog(HandleOrErr
.takeError());
494 Error
removeObject(ObjHandleT H
) {
495 auto HI
= BaseLayerHandles
.find(H
);
496 if (HI
!= BaseLayerHandles
.end()) {
497 if (auto Err
= BaseLayer
.removeObject(HI
->second
))
498 return teeLog(std::move(Err
));
499 return Error::success();
501 return teeLog(badObjectHandleError(H
));
504 Expected
<RemoteSymbol
> findSymbol(const std::string
&Name
,
505 bool ExportedSymbolsOnly
) {
506 if (auto Sym
= BaseLayer
.findSymbol(Name
, ExportedSymbolsOnly
))
507 return this->jitSymbolToRemote(std::move(Sym
));
508 else if (auto Err
= Sym
.takeError())
509 return teeLog(std::move(Err
));
510 return this->nullRemoteSymbol();
513 Expected
<RemoteSymbol
> findSymbolIn(ObjHandleT H
, const std::string
&Name
,
514 bool ExportedSymbolsOnly
) {
515 auto HI
= BaseLayerHandles
.find(H
);
516 if (HI
!= BaseLayerHandles
.end()) {
517 if (auto Sym
= BaseLayer
.findSymbolIn(HI
->second
, Name
, ExportedSymbolsOnly
))
518 return this->jitSymbolToRemote(std::move(Sym
));
519 else if (auto Err
= Sym
.takeError())
520 return teeLog(std::move(Err
));
521 return this->nullRemoteSymbol();
523 return teeLog(badObjectHandleError(H
));
526 Error
emitAndFinalize(ObjHandleT H
) {
527 auto HI
= BaseLayerHandles
.find(H
);
528 if (HI
!= BaseLayerHandles
.end()) {
529 if (auto Err
= BaseLayer
.emitAndFinalize(HI
->second
))
530 return teeLog(std::move(Err
));
531 return Error::success();
533 return teeLog(badObjectHandleError(H
));
536 BaseLayerT
&BaseLayer
;
537 remote::ResourceIdMgr HandleIdMgr
;
538 std::map
<ObjHandleT
, typename
BaseLayerT::ObjHandleT
> BaseLayerHandles
;
541 template <typename RPCEndpoint
>
542 RemoteObjectClientLayer
<RPCEndpoint
>::RemoteObjectClientLayer(
543 RPCEndpoint
&Remote
, std::function
<void(Error
)> ReportError
)
544 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)) {
545 using ThisT
= RemoteObjectClientLayer
<RPCEndpoint
>;
546 Remote
.template addHandler
<Lookup
>(*this, &ThisT::lookup
);
547 Remote
.template addHandler
<LookupInLogicalDylib
>(
548 *this, &ThisT::lookupInLogicalDylib
);
551 template <typename BaseLayerT
, typename RPCEndpoint
>
552 RemoteObjectServerLayer
<BaseLayerT
, RPCEndpoint
>::RemoteObjectServerLayer(
553 BaseLayerT
&BaseLayer
, RPCEndpoint
&Remote
,
554 std::function
<void(Error
)> ReportError
)
555 : RemoteObjectLayer
<RPCEndpoint
>(Remote
, std::move(ReportError
)),
556 BaseLayer(BaseLayer
), HandleIdMgr(1) {
557 using ThisT
= RemoteObjectServerLayer
<BaseLayerT
, RPCEndpoint
>;
559 Remote
.template addHandler
<AddObject
>(*this, &ThisT::addObject
);
560 Remote
.template addHandler
<RemoveObject
>(*this, &ThisT::removeObject
);
561 Remote
.template addHandler
<FindSymbol
>(*this, &ThisT::findSymbol
);
562 Remote
.template addHandler
<FindSymbolIn
>(*this, &ThisT::findSymbolIn
);
563 Remote
.template addHandler
<EmitAndFinalize
>(*this, &ThisT::emitAndFinalize
);
566 } // end namespace orc
567 } // end namespace llvm
569 #endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H