blob: b95faaa5d8def1bde5d48475dbf3173342dc043a [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===------ 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
22namespace llvm {
23namespace orc {
24
25/// RPC API needed by RemoteObjectClientLayer and RemoteObjectServerLayer.
26class RemoteObjectLayerAPI {
27public:
28
29 using ObjHandleT = remote::ResourceIdMgr::ResourceId;
30
31protected:
32
33 using RemoteSymbolId = remote::ResourceIdMgr::ResourceId;
34 using RemoteSymbol = std::pair<RemoteSymbolId, JITSymbolFlags>;
35
36public:
37
38 using BadSymbolHandleError = remote::ResourceNotFound<RemoteSymbolId>;
39 using BadObjectHandleError = remote::ResourceNotFound<ObjHandleT>;
40
41protected:
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.
110template <typename RPCEndpoint>
111class RemoteObjectLayer : public RemoteObjectLayerAPI {
112public:
113
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);
123 }
124
125protected:
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 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;
147 }
148
149 RemoteSymbolMaterializer&
150 operator=(const RemoteSymbolMaterializer&) = delete;
151
152 /// Release the remote symbol.
153 ~RemoteSymbolMaterializer() {
154 if (Id)
155 C.releaseRemoteSymbol(Id);
156 }
157
158 /// Materialize the symbol on the remote and get its address.
159 Expected<JITTargetAddress> materialize() {
160 auto Addr = C.materializeRemoteSymbol(Id);
161 Id = 0;
162 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 RemoteSymbol nullRemoteSymbol() {
172 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 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 });
188 }
189
190 Error badRemoteSymbolIdError(RemoteSymbolId Id) {
191 return make_error<BadSymbolHandleError>(Id, "Remote JIT Symbol");
192 }
193
194 Error badObjectHandleError(ObjHandleT H) {
195 return make_error<RemoteObjectLayerAPI::BadObjectHandleError>(
196 H, "Bad object handle");
197 }
198
199 /// Create a RemoteSymbol wrapping the given JITSymbol.
200 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 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));
209 // else...
210 return nullRemoteSymbol();
211 }
212
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())
218 return nullptr;
219 // else...
220 RemoteSymbolMaterializer RSM(*this, RemoteSym.first);
221 auto Sym =
222 JITSymbol([RSM]() mutable { return RSM.materialize(); },
223 RemoteSym.second);
224 return Sym;
225 } else
226 return RemoteSymOrErr.takeError();
227 }
228
229 RPCEndpoint &Remote;
230 std::function<void(Error)> ReportError;
231
232private:
233
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));
238 }
239
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);
244 }
245
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();
252 } else
253 return teeLog(badRemoteSymbolIdError(Id));
254 }
255
256 /// Run the materializer for the JITSymbol with the given Id and return its
257 /// address.
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);
264 if (AddrOrErr)
265 return *AddrOrErr;
266 else
267 return teeLog(AddrOrErr.takeError());
268 } else {
269 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.
288template <typename RPCEndpoint>
289class RemoteObjectClientLayer : public RemoteObjectLayer<RPCEndpoint> {
290private:
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
304public:
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 RemoteObjectClientLayer(RPCEndpoint &Remote,
317 std::function<void(Error)> ReportError)
318 : 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 }
324
325 /// @brief 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 addObject(ObjectPtr ObjBuffer,
331 std::shared_ptr<LegacyJITSymbolResolver> Resolver) {
332 if (auto HandleOrErr =
333 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 Resolvers[Handle] = std::move(Resolver);
338 return Handle;
339 } else
340 return HandleOrErr.takeError();
341 }
342
343 /// @brief Remove the given object from the JIT.
344 Error removeObject(ObjHandleT H) {
345 return this->Remote.template callB<RemoveObject>(H);
346 }
347
348 /// @brief Search for the given named symbol.
349 JITSymbol findSymbol(StringRef Name, bool ExportedSymbolsOnly) {
350 return remoteToJITSymbol(
351 this->Remote.template callB<FindSymbol>(Name,
352 ExportedSymbolsOnly));
353 }
354
355 /// @brief Search for the given named symbol within the given context.
356 JITSymbol findSymbolIn(ObjHandleT H, StringRef Name, bool ExportedSymbolsOnly) {
357 return remoteToJITSymbol(
358 this->Remote.template callB<FindSymbolIn>(H, Name,
359 ExportedSymbolsOnly));
360 }
361
362 /// @brief Immediately emit and finalize the object with the given handle.
363 Error emitAndFinalize(ObjHandleT H) {
364 return this->Remote.template callB<EmitAndFinalize>(H);
365 }
366
367private:
368
369 Expected<RemoteSymbol> lookup(ObjHandleT H, const std::string &Name) {
370 auto RI = Resolvers.find(H);
371 if (RI != Resolvers.end()) {
372 return this->jitSymbolToRemote(RI->second->findSymbol(Name));
373 } else
374 return teeLog(badObjectHandleError(H));
375 }
376
377 Expected<RemoteSymbol> lookupInLogicalDylib(ObjHandleT H,
378 const std::string &Name) {
379 auto RI = Resolvers.find(H);
380 if (RI != Resolvers.end())
381 return this->jitSymbolToRemote(
382 RI->second->findSymbolInLogicalDylib(Name));
383 else
384 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.
398template <typename BaseLayerT, typename RPCEndpoint>
399class RemoteObjectServerLayer : public RemoteObjectLayer<RPCEndpoint> {
400private:
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
417public:
418
419 /// Create a RemoteObjectServerLayer with the given base layer (which must be
420 /// an object layer), RPC endpoint, and error reporter function.
421 RemoteObjectServerLayer(BaseLayerT &BaseLayer,
422 RPCEndpoint &Remote,
423 std::function<void(Error)> ReportError)
424 : RemoteObjectLayer<RPCEndpoint>(Remote, std::move(ReportError)),
425 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 }
434
435private:
436
437 class StringMemoryBuffer : public MemoryBuffer {
438 public:
439 StringMemoryBuffer(std::string Buffer)
440 : Buffer(std::move(Buffer)) {
441 init(this->Buffer.data(), this->Buffer.data() + this->Buffer.size(),
442 false);
443 }
444
445 BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
446 private:
447 std::string Buffer;
448 };
449
450 JITSymbol lookup(ObjHandleT Id, const std::string &Name) {
451 return remoteToJITSymbol(
452 this->Remote.template callB<Lookup>(Id, Name));
453 }
454
455 JITSymbol lookupInLogicalDylib(ObjHandleT Id, const std::string &Name) {
456 return remoteToJITSymbol(
457 this->Remote.template callB<LookupInLogicalDylib>(Id, Name));
458 }
459
460 Expected<ObjHandleT> addObject(std::string ObjBuffer) {
461 auto Buffer = llvm::make_unique<StringMemoryBuffer>(std::move(ObjBuffer));
462 auto Id = HandleIdMgr.getNext();
463 assert(!BaseLayerHandles.count(Id) && "Id already in use?");
464
465 auto Resolver = createLambdaResolver(
466 [this, Id](const std::string &Name) { return lookup(Id, Name); },
467 [this, Id](const std::string &Name) {
468 return lookupInLogicalDylib(Id, Name);
469 });
470
471 if (auto HandleOrErr =
472 BaseLayer.addObject(std::move(Buffer), std::move(Resolver))) {
473 BaseLayerHandles[Id] = std::move(*HandleOrErr);
474 return Id;
475 } else
476 return teeLog(HandleOrErr.takeError());
477 }
478
479 Error removeObject(ObjHandleT H) {
480 auto HI = BaseLayerHandles.find(H);
481 if (HI != BaseLayerHandles.end()) {
482 if (auto Err = BaseLayer.removeObject(HI->second))
483 return teeLog(std::move(Err));
484 return Error::success();
485 } else
486 return teeLog(badObjectHandleError(H));
487 }
488
489 Expected<RemoteSymbol> findSymbol(const std::string &Name,
490 bool ExportedSymbolsOnly) {
491 if (auto Sym = BaseLayer.findSymbol(Name, ExportedSymbolsOnly))
492 return this->jitSymbolToRemote(std::move(Sym));
493 else if (auto Err = Sym.takeError())
494 return teeLog(std::move(Err));
495 return this->nullRemoteSymbol();
496 }
497
498 Expected<RemoteSymbol> findSymbolIn(ObjHandleT H, const std::string &Name,
499 bool ExportedSymbolsOnly) {
500 auto HI = BaseLayerHandles.find(H);
501 if (HI != BaseLayerHandles.end()) {
502 if (auto Sym = BaseLayer.findSymbolIn(HI->second, Name, ExportedSymbolsOnly))
503 return this->jitSymbolToRemote(std::move(Sym));
504 else if (auto Err = Sym.takeError())
505 return teeLog(std::move(Err));
506 return this->nullRemoteSymbol();
507 } else
508 return teeLog(badObjectHandleError(H));
509 }
510
511 Error emitAndFinalize(ObjHandleT H) {
512 auto HI = BaseLayerHandles.find(H);
513 if (HI != BaseLayerHandles.end()) {
514 if (auto Err = BaseLayer.emitAndFinalize(HI->second))
515 return teeLog(std::move(Err));
516 return Error::success();
517 } else
518 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