blob: 9550edceb1008af85cf400158c7112a1909549a8 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===------ RemoteObjectLayer.h - Forwards objs to a remote -----*- C++ -*-===//
2//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9// Forwards objects to a remote object layer via RPC.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
14#define LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
15
16#include "llvm/ExecutionEngine/Orc/OrcRemoteTargetRPCAPI.h"
17#include "llvm/Object/ObjectFile.h"
18#include "llvm/ExecutionEngine/Orc/LambdaResolver.h"
19#include <map>
20
21namespace llvm {
22namespace orc {
23
24/// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
25class RemoteObjectLayerAPI {
26public:
27
28 using ObjHandleT = remote::ResourceIdMgr::ResourceId;
29
30protected:
31
32 using RemoteSymbolId = remote::ResourceIdMgr::ResourceId;
33 using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>;
34
35public:
36
37 using BadSymbolHandleError = remote::ResourceNotFound<RemoteSymbolId>;
38 using BadObjectHandleError = remote::ResourceNotFound<ObjHandleT>;
39
40protected:
41
42 static const ObjHandleT InvalidObjectHandleId = 0;
43 static const RemoteSymbolId NullSymbolId = 0;
44
45 class AddObject
46 : public rpc::Function<AddObject, Expected<ObjHandleT>(std::string)> {
47 public:
48 static const char *getName() { return "AddObject"; }
49 };
50
51 class RemoveObject
52 : public rpc::Function<RemoveObject, Error(ObjHandleT)> {
53 public:
54 static const char *getName() { return "RemoveObject"; }
55 };
56
57 class FindSymbol
58 : public rpc::Function<FindSymbol, Expected<RemoteSymbol>(std::string,
59 bool)> {
60 public:
61 static const char *getName() { return "FindSymbol"; }
62 };
63
64 class FindSymbolIn
65 : public rpc::Function<FindSymbolIn,
66 Expected<RemoteSymbol>(ObjHandleT, std::string,
67 bool)> {
68 public:
69 static const char *getName() { return "FindSymbolIn"; }
70 };
71
72 class EmitAndFinalize
73 : public rpc::Function<EmitAndFinalize,
74 Error(ObjHandleT)> {
75 public:
76 static const char *getName() { return "EmitAndFinalize"; }
77 };
78
79 class Lookup
80 : public rpc::Function<Lookup,
81 Expected<RemoteSymbol>(ObjHandleT, std::string)> {
82 public:
83 static const char *getName() { return "Lookup"; }
84 };
85
86 class LookupInLogicalDylib
87 : public rpc::Function<LookupInLogicalDylib,
88 Expected<RemoteSymbol>(ObjHandleT, std::string)> {
89 public:
90 static const char *getName() { return "LookupInLogicalDylib"; }
91 };
92
93 class ReleaseRemoteSymbol
94 : public rpc::Function<ReleaseRemoteSymbol, Error(RemoteSymbolId)> {
95 public:
96 static const char *getName() { return "ReleaseRemoteSymbol"; }
97 };
98
99 class MaterializeRemoteSymbol
100 : public rpc::Function<MaterializeRemoteSymbol,
101 Expected<JITTargetAddress>(RemoteSymbolId)> {
102 public:
103 static const char *getName() { return "MaterializeRemoteSymbol"; }
104 };
105};
106
107/// Base class containing common utilities for RemoteObjectClientLayer and
108/// RemoteObjectServerLayer.
109template <typename RPCEndpoint>
110class RemoteObjectLayer : public RemoteObjectLayerAPI {
111public:
112
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);
122 }
123
124protected:
125
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
129 /// requested.
130 class RemoteSymbolMaterializer {
131 public:
132
133 /// Construct a RemoteSymbolMaterializer for the given RemoteObjectLayer
134 /// with the given Id.
135 RemoteSymbolMaterializer(RemoteObjectLayer &C,
136 RemoteSymbolId Id)
137 : C(C), Id(Id) {}
138
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;
146 }
147
148 RemoteSymbolMaterializer&
149 operator=(const RemoteSymbolMaterializer&) = delete;
150
151 /// Release the remote symbol.
152 ~RemoteSymbolMaterializer() {
153 if (Id)
154 C.releaseRemoteSymbol(Id);
155 }
156
157 /// Materialize the symbol on the remote and get its address.
158 Expected<JITTargetAddress> materialize() {
159 auto Addr = C.materializeRemoteSymbol(Id);
160 Id = 0;
161 return Addr;
162 }
163
164 private:
165 RemoteObjectLayer &C;
166 RemoteSymbolId Id;
167 };
168
169 /// Convenience function for getting a null remote symbol value.
170 RemoteSymbol nullRemoteSymbol() {
171 return RemoteSymbol(0, JITSymbolFlags());
172 }
173
174 /// Creates a StringError that contains a copy of Err's log message, then
175 /// sends that StringError to ReportError.
176 ///
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>(
183 EIB->message(),
184 EIB->convertToErrorCode()));
185 return Error(std::move(EIB));
186 });
187 }
188
189 Error badRemoteSymbolIdError(RemoteSymbolId Id) {
190 return make_error<BadSymbolHandleError>(Id, "Remote JIT Symbol");
191 }
192
193 Error badObjectHandleError(ObjHandleT H) {
194 return make_error<RemoteObjectLayerAPI::BadObjectHandleError>(
195 H, "Bad object handle");
196 }
197
198 /// Create a RemoteSymbol wrapping the given JITSymbol.
199 Expected<RemoteSymbol> jitSymbolToRemote(JITSymbol Sym) {
200 if (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));
208 // else...
209 return nullRemoteSymbol();
210 }
211
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())
217 return nullptr;
218 // else...
219 RemoteSymbolMaterializer RSM(*this, RemoteSym.first);
220 auto Sym =
221 JITSymbol([RSM]() mutable { return RSM.materialize(); },
222 RemoteSym.second);
223 return Sym;
224 } else
225 return RemoteSymOrErr.takeError();
226 }
227
228 RPCEndpoint &Remote;
229 std::function<void(Error)> ReportError;
230
231private:
232
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));
237 }
238
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);
243 }
244
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();
251 } else
252 return teeLog(badRemoteSymbolIdError(Id));
253 }
254
255 /// Run the materializer for the JITSymbol with the given Id and return its
256 /// address.
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);
263 if (AddrOrErr)
264 return *AddrOrErr;
265 else
266 return teeLog(AddrOrErr.takeError());
267 } else {
268 return teeLog(badRemoteSymbolIdError(Id));
269 }
270 }
271
272 remote::ResourceIdMgr SymbolIdMgr;
273 std::map<RemoteSymbolId, JITSymbol> InUseSymbols;
274};
275
276/// RemoteObjectClientLayer forwards the ORC Object Layer API over an RPC
277/// connection.
278///
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).
283///
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.
287template <typename RPCEndpoint>
288class RemoteObjectClientLayer : public RemoteObjectLayer<RPCEndpoint> {
289private:
290
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;
298
299 using RemoteObjectLayer<RPCEndpoint>::teeLog;
300 using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError;
301 using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol;
302
303public:
304
305 using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
306 using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
307
308 using ObjectPtr = std::unique_ptr<MemoryBuffer>;
309
310 /// Create a RemoteObjectClientLayer that communicates with a
311 /// RemoteObjectServerLayer instance via the given RPCEndpoint.
312 ///
313 /// The ReportError functor can be used locally log errors that are intended
314 /// to be sent sent
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);
322 }
323
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100324 /// Add an object to the JIT.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100325 ///
326 /// @return A handle that can be used to refer to the loaded object (for
327 /// symbol searching, finalization, freeing memory, etc.).
328 Expected<ObjHandleT>
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);
337 return Handle;
338 } else
339 return HandleOrErr.takeError();
340 }
341
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100342 /// Remove the given object from the JIT.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100343 Error removeObject(ObjHandleT H) {
344 return this->Remote.template callB<RemoveObject>(H);
345 }
346
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100347 /// Search for the given named symbol.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100348 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
349 return remoteToJITSymbol(
350 this->Remote.template callB<FindSymbol>(Name,
351 ExportedSymbolsOnly));
352 }
353
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100354 /// Search for the given named symbol within the given context.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100355 JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) {
356 return remoteToJITSymbol(
357 this->Remote.template callB<FindSymbolIn>(H, Name,
358 ExportedSymbolsOnly));
359 }
360
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100361 /// Immediately emit and finalize the object with the given handle.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100362 Error emitAndFinalize(ObjHandleT H) {
363 return this->Remote.template callB<EmitAndFinalize>(H);
364 }
365
366private:
367
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));
372 } else
373 return teeLog(badObjectHandleError(H));
374 }
375
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));
382 else
383 return teeLog(badObjectHandleError(H));
384 }
385
386 std::map<remote::ResourceIdMgr::ResourceId,
387 std::shared_ptr<LegacyJITSymbolResolver>>
388 Resolvers;
389};
390
391/// RemoteObjectServerLayer acts as a server and handling RPC calls for the
392/// object layer API from the given RPC connection.
393///
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.
397template <typename BaseLayerT, typename RPCEndpoint>
398class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> {
399private:
400
401 using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
402 using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
403
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;
411
412 using RemoteObjectLayer<RPCEndpoint>::teeLog;
413 using RemoteObjectLayer<RPCEndpoint>::badObjectHandleError;
414 using RemoteObjectLayer<RPCEndpoint>::remoteToJITSymbol;
415
416public:
417
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,
421 RPCEndpoint &Remote,
422 std::function<void(Error)> ReportError)
423 : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)),
424 BaseLayer(BaseLayer), HandleIdMgr(1) {
425 using ThisT = RemoteObjectServerLayer<BaseLayerT, RPCEndpoint>;
426
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);
432 }
433
434private:
435
436 class StringMemoryBuffer : public MemoryBuffer {
437 public:
438 StringMemoryBuffer(std::string Buffer)
439 : Buffer(std::move(Buffer)) {
440 init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(),
441 false);
442 }
443
444 BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
445 private:
446 std::string Buffer;
447 };
448
449 JITSymbol lookup(ObjHandleT Id, const std::string &Name) {
450 return remoteToJITSymbol(
451 this->Remote.template callB<Lookup>(Id, Name));
452 }
453
454 JITSymbol lookupInLogicalDylib(ObjHandleT Id, const std::string &Name) {
455 return remoteToJITSymbol(
456 this->Remote.template callB<LookupInLogicalDylib>(Id, Name));
457 }
458
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?");
463
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);
468 });
469
470 if (auto HandleOrErr =
471 BaseLayer.addObject(std::move(Buffer), std::move(Resolver))) {
472 BaseLayerHandles[Id] = std::move(*HandleOrErr);
473 return Id;
474 } else
475 return teeLog(HandleOrErr.takeError());
476 }
477
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();
484 } else
485 return teeLog(badObjectHandleError(H));
486 }
487
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();
495 }
496
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();
506 } else
507 return teeLog(badObjectHandleError(H));
508 }
509
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();
516 } else
517 return teeLog(badObjectHandleError(H));
518 }
519
520 BaseLayerT &BaseLayer;
521 remote::ResourceIdMgr HandleIdMgr;
522 std::map<ObjHandleT, typename BaseLayerT::ObjHandleT> BaseLayerHandles;
523};
524
525} // end namespace orc
526} // end namespace llvm
527
528#endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H