Line data Source code
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 :
22 : namespace llvm {
23 : namespace orc {
24 :
25 : /// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
26 : class RemoteObjectLayerAPI {
27 : public:
28 :
29 : using ObjHandleT = remote::ResourceIdMgr::ResourceId;
30 :
31 : protected:
32 :
33 : using RemoteSymbolId = remote::ResourceIdMgr::ResourceId;
34 : using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>;
35 :
36 : public:
37 :
38 : using BadSymbolHandleError = remote::ResourceNotFound<RemoteSymbolId>;
39 : using BadObjectHandleError = remote::ResourceNotFound<ObjHandleT>;
40 :
41 : protected:
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.
110 : template <typename RPCEndpoint>
111 : class RemoteObjectLayer : public RemoteObjectLayerAPI {
112 : public:
113 :
114 16 : RemoteObjectLayer(RPCEndpoint &Remote,
115 : std::function<void(Error)> ReportError)
116 : : Remote(Remote), ReportError(std::move(ReportError)),
117 16 : 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 16 : }
124 :
125 : protected:
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 2 : RemoteSymbolMaterializer(const RemoteSymbolMaterializer &Other)
141 2 : : 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 0 : const_cast<RemoteSymbolMaterializer&>(Other).Id = 0;
147 : }
148 :
149 : RemoteSymbolMaterializer&
150 : operator=(const RemoteSymbolMaterializer&) = delete;
151 :
152 : /// Release the remote symbol.
153 : ~RemoteSymbolMaterializer() {
154 0 : if (Id)
155 0 : C.releaseRemoteSymbol(Id);
156 : }
157 :
158 : /// Materialize the symbol on the remote and get its address.
159 0 : Expected<JITTargetAddress> materialize() {
160 4 : auto Addr = C.materializeRemoteSymbol(Id);
161 2 : Id = 0;
162 0 : 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 0 : RemoteSymbol nullRemoteSymbol() {
172 0 : 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 5 : 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 10 : });
188 : }
189 :
190 0 : Error badRemoteSymbolIdError(RemoteSymbolId Id) {
191 0 : return make_error<BadSymbolHandleError>(Id, "Remote JIT Symbol");
192 : }
193 :
194 0 : Error badObjectHandleError(ObjHandleT H) {
195 : return make_error<RemoteObjectLayerAPI::BadObjectHandleError>(
196 0 : H, "Bad object handle");
197 : }
198 :
199 : /// Create a RemoteSymbol wrapping the given JITSymbol.
200 2 : 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 2 : InUseSymbols.insert(std::make_pair(Id, std::move(Sym)));
206 : return RemoteSymbol(Id, Flags);
207 0 : } else if (auto Err = Sym.takeError())
208 0 : return teeLog(std::move(Err));
209 : // else...
210 : return nullRemoteSymbol();
211 : }
212 :
213 : /// Convert an Expected<RemoteSymbol> to a JITSymbol.
214 5 : JITSymbol remoteToJITSymbol(Expected<RemoteSymbol> RemoteSymOrErr) {
215 5 : if (RemoteSymOrErr) {
216 : auto &RemoteSym = *RemoteSymOrErr;
217 : if (RemoteSym == nullRemoteSymbol())
218 : return nullptr;
219 : // else...
220 : RemoteSymbolMaterializer RSM(*this, RemoteSym.first);
221 2 : auto Sym =
222 0 : JITSymbol([RSM]() mutable { return RSM.materialize(); },
223 : RemoteSym.second);
224 2 : return Sym;
225 : } else
226 : return RemoteSymOrErr.takeError();
227 : }
228 :
229 : RPCEndpoint &Remote;
230 : std::function<void(Error)> ReportError;
231 :
232 : private:
233 :
234 : /// Notify the remote to release the given JITSymbol.
235 0 : void releaseRemoteSymbol(RemoteSymbolId Id) {
236 0 : if (auto Err = Remote.template callB<ReleaseRemoteSymbol>(Id))
237 0 : ReportError(std::move(Err));
238 0 : }
239 :
240 : /// Notify the remote to materialize the JITSymbol with the given Id and
241 : /// return its address.
242 0 : Expected<JITTargetAddress> materializeRemoteSymbol(RemoteSymbolId Id) {
243 2 : return Remote.template callB<MaterializeRemoteSymbol>(Id);
244 : }
245 :
246 : /// Release the JITSymbol with the given Id.
247 0 : Error handleReleaseRemoteSymbol(RemoteSymbolId Id) {
248 : auto SI = InUseSymbols.find(Id);
249 0 : if (SI != InUseSymbols.end()) {
250 : InUseSymbols.erase(SI);
251 : return Error::success();
252 : } else
253 0 : return teeLog(badRemoteSymbolIdError(Id));
254 : }
255 :
256 : /// Run the materializer for the JITSymbol with the given Id and return its
257 : /// address.
258 2 : Expected<JITTargetAddress> handleMaterializeRemoteSymbol(RemoteSymbolId Id) {
259 : auto SI = InUseSymbols.find(Id);
260 2 : if (SI != InUseSymbols.end()) {
261 2 : auto AddrOrErr = SI->second.getAddress();
262 : InUseSymbols.erase(SI);
263 2 : SymbolIdMgr.release(Id);
264 2 : if (AddrOrErr)
265 : return *AddrOrErr;
266 : else
267 0 : return teeLog(AddrOrErr.takeError());
268 : } else {
269 0 : 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.
288 : template <typename RPCEndpoint>
289 8 : class RemoteObjectClientLayer : public RemoteObjectLayer<RPCEndpoint> {
290 : private:
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 :
304 : public:
305 :
306 : using ObjHandleT = RemoteObjectLayerAPI::ObjHandleT;
307 : using RemoteSymbol = RemoteObjectLayerAPI::RemoteSymbol;
308 :
309 : using ObjectPtr = std::unique_ptr<MemoryBuffer>;
310 :
311 : /// Create a RemoteObjectClientLayer that communicates with a
312 : /// RemoteObjectServerLayer instance via the given RPCEndpoint.
313 : ///
314 : /// The ReportError functor can be used locally log errors that are intended
315 : /// to be sent sent
316 8 : RemoteObjectClientLayer(RPCEndpoint &Remote,
317 : std::function<void(Error)> ReportError)
318 24 : : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)) {
319 : using ThisT = RemoteObjectClientLayer<RPCEndpoint>;
320 : Remote.template addHandler<Lookup>(*this, &ThisT::lookup);
321 : Remote.template addHandler<LookupInLogicalDylib>(
322 : *this, &ThisT::lookupInLogicalDylib);
323 8 : }
324 :
325 : /// Add an object to the JIT.
326 : ///
327 : /// @return A handle that can be used to refer to the loaded object (for
328 : /// symbol searching, finalization, freeing memory, etc.).
329 : Expected<ObjHandleT>
330 8 : addObject(ObjectPtr ObjBuffer,
331 : std::shared_ptr<LegacyJITSymbolResolver> Resolver) {
332 8 : if (auto HandleOrErr =
333 16 : this->Remote.template callB<AddObject>(ObjBuffer->getBuffer())) {
334 : auto &Handle = *HandleOrErr;
335 : // FIXME: Return an error for this:
336 : assert(!Resolvers.count(Handle) && "Handle already in use?");
337 7 : Resolvers[Handle] = std::move(Resolver);
338 : return Handle;
339 : } else
340 : return HandleOrErr.takeError();
341 : }
342 :
343 : /// Remove the given object from the JIT.
344 0 : Error removeObject(ObjHandleT H) {
345 2 : return this->Remote.template callB<RemoveObject>(H);
346 : }
347 :
348 : /// Search for the given named symbol.
349 3 : JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
350 : return remoteToJITSymbol(
351 3 : this->Remote.template callB<FindSymbol>(Name,
352 3 : ExportedSymbolsOnly));
353 : }
354 :
355 : /// Search for the given named symbol within the given context.
356 2 : JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) {
357 : return remoteToJITSymbol(
358 2 : this->Remote.template callB<FindSymbolIn>(H, Name,
359 2 : ExportedSymbolsOnly));
360 : }
361 :
362 : /// Immediately emit and finalize the object with the given handle.
363 0 : Error emitAndFinalize(ObjHandleT H) {
364 2 : return this->Remote.template callB<EmitAndFinalize>(H);
365 : }
366 :
367 : private:
368 :
369 0 : Expected<RemoteSymbol> lookup(ObjHandleT H, const std::string &Name) {
370 : auto RI = Resolvers.find(H);
371 0 : if (RI != Resolvers.end()) {
372 0 : return this->jitSymbolToRemote(RI->second->findSymbol(Name));
373 : } else
374 0 : return teeLog(badObjectHandleError(H));
375 : }
376 :
377 0 : Expected<RemoteSymbol> lookupInLogicalDylib(ObjHandleT H,
378 : const std::string &Name) {
379 : auto RI = Resolvers.find(H);
380 0 : if (RI != Resolvers.end())
381 : return this->jitSymbolToRemote(
382 0 : RI->second->findSymbolInLogicalDylib(Name));
383 : else
384 0 : return teeLog(badObjectHandleError(H));
385 : }
386 :
387 : std::map<remote::ResourceIdMgr::ResourceId,
388 : std::shared_ptr<LegacyJITSymbolResolver>>
389 : 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.
398 : template <typename BaseLayerT, typename RPCEndpoint>
399 : class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> {
400 : private:
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 :
417 : public:
418 :
419 : /// Create a RemoteObjectServerLayer with the given base layer (which must be
420 : /// an object layer), RPC endpoint, and error reporter function.
421 8 : RemoteObjectServerLayer(BaseLayerT &BaseLayer,
422 : RPCEndpoint &Remote,
423 : std::function<void(Error)> ReportError)
424 : : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)),
425 24 : 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 8 : }
434 :
435 : private:
436 :
437 0 : class StringMemoryBuffer : public MemoryBuffer {
438 : public:
439 8 : StringMemoryBuffer(std::string Buffer)
440 8 : : Buffer(std::move(Buffer)) {
441 16 : init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(),
442 : false);
443 8 : }
444 :
445 0 : BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
446 : private:
447 : std::string Buffer;
448 : };
449 :
450 0 : JITSymbol lookup(ObjHandleT Id, const std::string &Name) {
451 : return remoteToJITSymbol(
452 0 : this->Remote.template callB<Lookup>(Id, Name));
453 : }
454 :
455 0 : JITSymbol lookupInLogicalDylib(ObjHandleT Id, const std::string &Name) {
456 : return remoteToJITSymbol(
457 0 : this->Remote.template callB<LookupInLogicalDylib>(Id, Name));
458 : }
459 :
460 8 : Expected<ObjHandleT> addObject(std::string ObjBuffer) {
461 16 : auto Buffer = llvm::make_unique<StringMemoryBuffer>(std::move(ObjBuffer));
462 8 : auto Id = HandleIdMgr.getNext();
463 : assert(!BaseLayerHandles.count(Id) && "Id already in use?");
464 :
465 8 : auto Resolver = createLambdaResolver(
466 0 : [this, Id](const std::string &Name) { return lookup(Id, Name); },
467 : [this, Id](const std::string &Name) {
468 0 : return lookupInLogicalDylib(Id, Name);
469 : });
470 :
471 24 : if (auto HandleOrErr =
472 8 : BaseLayer.addObject(std::move(Buffer), std::move(Resolver))) {
473 7 : BaseLayerHandles[Id] = std::move(*HandleOrErr);
474 : return Id;
475 : } else
476 2 : return teeLog(HandleOrErr.takeError());
477 : }
478 :
479 2 : Error removeObject(ObjHandleT H) {
480 : auto HI = BaseLayerHandles.find(H);
481 2 : if (HI != BaseLayerHandles.end()) {
482 4 : if (auto Err = BaseLayer.removeObject(HI->second))
483 3 : return teeLog(std::move(Err));
484 : return Error::success();
485 : } else
486 0 : return teeLog(badObjectHandleError(H));
487 : }
488 :
489 3 : Expected<RemoteSymbol> findSymbol(const std::string &Name,
490 : bool ExportedSymbolsOnly) {
491 7 : if (auto Sym = BaseLayer.findSymbol(Name, ExportedSymbolsOnly))
492 1 : return this->jitSymbolToRemote(std::move(Sym));
493 2 : else if (auto Err = Sym.takeError())
494 2 : return teeLog(std::move(Err));
495 : return this->nullRemoteSymbol();
496 : }
497 :
498 2 : Expected<RemoteSymbol> findSymbolIn(ObjHandleT H, const std::string &Name,
499 : bool ExportedSymbolsOnly) {
500 : auto HI = BaseLayerHandles.find(H);
501 2 : if (HI != BaseLayerHandles.end()) {
502 4 : if (auto Sym = BaseLayer.findSymbolIn(HI->second, Name, ExportedSymbolsOnly))
503 1 : return this->jitSymbolToRemote(std::move(Sym));
504 1 : else if (auto Err = Sym.takeError())
505 2 : return teeLog(std::move(Err));
506 : return this->nullRemoteSymbol();
507 : } else
508 0 : return teeLog(badObjectHandleError(H));
509 : }
510 :
511 2 : Error emitAndFinalize(ObjHandleT H) {
512 : auto HI = BaseLayerHandles.find(H);
513 2 : if (HI != BaseLayerHandles.end()) {
514 4 : if (auto Err = BaseLayer.emitAndFinalize(HI->second))
515 3 : return teeLog(std::move(Err));
516 : return Error::success();
517 : } else
518 0 : return teeLog(badObjectHandleError(H));
519 : }
520 :
521 : BaseLayerT &BaseLayer;
522 : remote::ResourceIdMgr HandleIdMgr;
523 : std::map<ObjHandleT, typename BaseLayerT::ObjHandleT> BaseLayerHandles;
524 : };
525 :
526 : } // end namespace orc
527 : } // end namespace llvm
528 :
529 : #endif // LLVM_EXECUTIONENGINE_ORC_REMOTEOBJECTLAYER_H
|