1//===- WrapperFunctionUtils.h - Utilities for wrapper functions -*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9// A buffer for serialized results.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
14#define LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
15
16#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
17#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
18#include "llvm/Support/Error.h"
19
20#include <type_traits>
21
22namespace llvm {
23namespace orc {
24namespace shared {
25
26// Must be kept in-sync with compiler-rt/lib/orc/c-api.h.
27union CWrapperFunctionResultDataUnion {
28 char *ValuePtr;
29 char Value[sizeof(ValuePtr)];
30};
31
32// Must be kept in-sync with compiler-rt/lib/orc/c-api.h.
33typedef struct {
34 CWrapperFunctionResultDataUnion Data;
35 size_t Size;
36} CWrapperFunctionResult;
37
38/// C++ wrapper function result: Same as CWrapperFunctionResult but
39/// auto-releases memory.
40class WrapperFunctionResult {
41public:
42 /// Create a default WrapperFunctionResult.
43 WrapperFunctionResult() { init(R); }
44
45 /// Create a WrapperFunctionResult by taking ownership of a
46 /// CWrapperFunctionResult.
47 ///
48 /// Warning: This should only be used by clients writing wrapper-function
49 /// caller utilities (like TargetProcessControl).
50 WrapperFunctionResult(CWrapperFunctionResult R) : R(R) {
51 // Reset R.
52 init(R);
53 }
54
55 WrapperFunctionResult(const WrapperFunctionResult &) = delete;
56 WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
57
58 WrapperFunctionResult(WrapperFunctionResult &&Other) {
59 init(R);
60 std::swap(a&: R, b&: Other.R);
61 }
62
63 WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
64 WrapperFunctionResult Tmp(std::move(Other));
65 std::swap(a&: R, b&: Tmp.R);
66 return *this;
67 }
68
69 ~WrapperFunctionResult() {
70 if ((R.Size > sizeof(R.Data.Value)) ||
71 (R.Size == 0 && R.Data.ValuePtr != nullptr))
72 free(ptr: R.Data.ValuePtr);
73 }
74
75 /// Release ownership of the contained CWrapperFunctionResult.
76 /// Warning: Do not use -- this method will be removed in the future. It only
77 /// exists to temporarily support some code that will eventually be moved to
78 /// the ORC runtime.
79 CWrapperFunctionResult release() {
80 CWrapperFunctionResult Tmp;
81 init(R&: Tmp);
82 std::swap(a&: R, b&: Tmp);
83 return Tmp;
84 }
85
86 /// Get a pointer to the data contained in this instance.
87 char *data() {
88 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&
89 "Cannot get data for out-of-band error value");
90 return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value;
91 }
92
93 /// Get a const pointer to the data contained in this instance.
94 const char *data() const {
95 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&
96 "Cannot get data for out-of-band error value");
97 return R.Size > sizeof(R.Data.Value) ? R.Data.ValuePtr : R.Data.Value;
98 }
99
100 /// Returns the size of the data contained in this instance.
101 size_t size() const {
102 assert((R.Size != 0 || R.Data.ValuePtr == nullptr) &&
103 "Cannot get data for out-of-band error value");
104 return R.Size;
105 }
106
107 /// Returns true if this value is equivalent to a default-constructed
108 /// WrapperFunctionResult.
109 bool empty() const { return R.Size == 0 && R.Data.ValuePtr == nullptr; }
110
111 /// Create a WrapperFunctionResult with the given size and return a pointer
112 /// to the underlying memory.
113 static WrapperFunctionResult allocate(size_t Size) {
114 // Reset.
115 WrapperFunctionResult WFR;
116 WFR.R.Size = Size;
117 if (WFR.R.Size > sizeof(WFR.R.Data.Value))
118 WFR.R.Data.ValuePtr = (char *)malloc(size: WFR.R.Size);
119 return WFR;
120 }
121
122 /// Copy from the given char range.
123 static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
124 auto WFR = allocate(Size);
125 memcpy(dest: WFR.data(), src: Source, n: Size);
126 return WFR;
127 }
128
129 /// Copy from the given null-terminated string (includes the null-terminator).
130 static WrapperFunctionResult copyFrom(const char *Source) {
131 return copyFrom(Source, Size: strlen(s: Source) + 1);
132 }
133
134 /// Copy from the given std::string (includes the null terminator).
135 static WrapperFunctionResult copyFrom(const std::string &Source) {
136 return copyFrom(Source: Source.c_str());
137 }
138
139 /// Create an out-of-band error by copying the given string.
140 static WrapperFunctionResult createOutOfBandError(const char *Msg) {
141 // Reset.
142 WrapperFunctionResult WFR;
143 char *Tmp = (char *)malloc(size: strlen(s: Msg) + 1);
144 strcpy(dest: Tmp, src: Msg);
145 WFR.R.Data.ValuePtr = Tmp;
146 return WFR;
147 }
148
149 /// Create an out-of-band error by copying the given string.
150 static WrapperFunctionResult createOutOfBandError(const std::string &Msg) {
151 return createOutOfBandError(Msg: Msg.c_str());
152 }
153
154 /// If this value is an out-of-band error then this returns the error message,
155 /// otherwise returns nullptr.
156 const char *getOutOfBandError() const {
157 return R.Size == 0 ? R.Data.ValuePtr : nullptr;
158 }
159
160private:
161 static void init(CWrapperFunctionResult &R) {
162 R.Data.ValuePtr = nullptr;
163 R.Size = 0;
164 }
165
166 CWrapperFunctionResult R;
167};
168
169namespace detail {
170
171template <typename SPSArgListT, typename... ArgTs>
172WrapperFunctionResult
173serializeViaSPSToWrapperFunctionResult(const ArgTs &...Args) {
174 auto Result = WrapperFunctionResult::allocate(Size: SPSArgListT::size(Args...));
175 SPSOutputBuffer OB(Result.data(), Result.size());
176 if (!SPSArgListT::serialize(OB, Args...))
177 return WrapperFunctionResult::createOutOfBandError(
178 Msg: "Error serializing arguments to blob in call");
179 return Result;
180}
181
182template <typename RetT> class WrapperFunctionHandlerCaller {
183public:
184 template <typename HandlerT, typename ArgTupleT, std::size_t... I>
185 static decltype(auto) call(HandlerT &&H, ArgTupleT &Args,
186 std::index_sequence<I...>) {
187 return std::forward<HandlerT>(H)(std::get<I>(Args)...);
188 }
189};
190
191template <> class WrapperFunctionHandlerCaller<void> {
192public:
193 template <typename HandlerT, typename ArgTupleT, std::size_t... I>
194 static SPSEmpty call(HandlerT &&H, ArgTupleT &Args,
195 std::index_sequence<I...>) {
196 std::forward<HandlerT>(H)(std::get<I>(Args)...);
197 return SPSEmpty();
198 }
199};
200
201template <typename WrapperFunctionImplT,
202 template <typename> class ResultSerializer, typename... SPSTagTs>
203class WrapperFunctionHandlerHelper
204 : public WrapperFunctionHandlerHelper<
205 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
206 ResultSerializer, SPSTagTs...> {};
207
208template <typename RetT, typename... ArgTs,
209 template <typename> class ResultSerializer, typename... SPSTagTs>
210class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
211 SPSTagTs...> {
212public:
213 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
214 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
215
216 template <typename HandlerT>
217 static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
218 size_t ArgSize) {
219 ArgTuple Args;
220 if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
221 return WrapperFunctionResult::createOutOfBandError(
222 Msg: "Could not deserialize arguments for wrapper function call");
223
224 auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call(
225 std::forward<HandlerT>(H), Args, ArgIndices{});
226
227 return ResultSerializer<decltype(HandlerResult)>::serialize(
228 std::move(HandlerResult));
229 }
230
231private:
232 template <std::size_t... I>
233 static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
234 std::index_sequence<I...>) {
235 SPSInputBuffer IB(ArgData, ArgSize);
236 return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
237 }
238};
239
240// Map function pointers to function types.
241template <typename RetT, typename... ArgTs,
242 template <typename> class ResultSerializer, typename... SPSTagTs>
243class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
244 SPSTagTs...>
245 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
246 SPSTagTs...> {};
247
248// Map non-const member function types to function types.
249template <typename ClassT, typename RetT, typename... ArgTs,
250 template <typename> class ResultSerializer, typename... SPSTagTs>
251class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
252 SPSTagTs...>
253 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
254 SPSTagTs...> {};
255
256// Map const member function types to function types.
257template <typename ClassT, typename RetT, typename... ArgTs,
258 template <typename> class ResultSerializer, typename... SPSTagTs>
259class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
260 ResultSerializer, SPSTagTs...>
261 : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
262 SPSTagTs...> {};
263
264template <typename WrapperFunctionImplT,
265 template <typename> class ResultSerializer, typename... SPSTagTs>
266class WrapperFunctionAsyncHandlerHelper
267 : public WrapperFunctionAsyncHandlerHelper<
268 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
269 ResultSerializer, SPSTagTs...> {};
270
271template <typename RetT, typename SendResultT, typename... ArgTs,
272 template <typename> class ResultSerializer, typename... SPSTagTs>
273class WrapperFunctionAsyncHandlerHelper<RetT(SendResultT, ArgTs...),
274 ResultSerializer, SPSTagTs...> {
275public:
276 using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
277 using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
278
279 template <typename HandlerT, typename SendWrapperFunctionResultT>
280 static void applyAsync(HandlerT &&H,
281 SendWrapperFunctionResultT &&SendWrapperFunctionResult,
282 const char *ArgData, size_t ArgSize) {
283 ArgTuple Args;
284 if (!deserialize(ArgData, ArgSize, Args, ArgIndices{})) {
285 SendWrapperFunctionResult(WrapperFunctionResult::createOutOfBandError(
286 Msg: "Could not deserialize arguments for wrapper function call"));
287 return;
288 }
289
290 auto SendResult =
291 [SendWFR = std::move(SendWrapperFunctionResult)](auto Result) mutable {
292 using ResultT = decltype(Result);
293 SendWFR(ResultSerializer<ResultT>::serialize(std::move(Result)));
294 };
295
296 callAsync(std::forward<HandlerT>(H), std::move(SendResult), std::move(Args),
297 ArgIndices{});
298 }
299
300private:
301 template <std::size_t... I>
302 static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
303 std::index_sequence<I...>) {
304 SPSInputBuffer IB(ArgData, ArgSize);
305 return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
306 }
307
308 template <typename HandlerT, typename SerializeAndSendResultT,
309 typename ArgTupleT, std::size_t... I>
310 static void callAsync(HandlerT &&H,
311 SerializeAndSendResultT &&SerializeAndSendResult,
312 ArgTupleT Args, std::index_sequence<I...>) {
313 (void)Args; // Silence a buggy GCC warning.
314 return std::forward<HandlerT>(H)(std::move(SerializeAndSendResult),
315 std::move(std::get<I>(Args))...);
316 }
317};
318
319// Map function pointers to function types.
320template <typename RetT, typename... ArgTs,
321 template <typename> class ResultSerializer, typename... SPSTagTs>
322class WrapperFunctionAsyncHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
323 SPSTagTs...>
324 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
325 SPSTagTs...> {};
326
327// Map non-const member function types to function types.
328template <typename ClassT, typename RetT, typename... ArgTs,
329 template <typename> class ResultSerializer, typename... SPSTagTs>
330class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...),
331 ResultSerializer, SPSTagTs...>
332 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
333 SPSTagTs...> {};
334
335// Map const member function types to function types.
336template <typename ClassT, typename RetT, typename... ArgTs,
337 template <typename> class ResultSerializer, typename... SPSTagTs>
338class WrapperFunctionAsyncHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
339 ResultSerializer, SPSTagTs...>
340 : public WrapperFunctionAsyncHandlerHelper<RetT(ArgTs...), ResultSerializer,
341 SPSTagTs...> {};
342
343template <typename SPSRetTagT, typename RetT> class ResultSerializer {
344public:
345 static WrapperFunctionResult serialize(RetT Result) {
346 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
347 Result);
348 }
349};
350
351template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
352public:
353 static WrapperFunctionResult serialize(Error Err) {
354 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
355 toSPSSerializable(Err: std::move(Err)));
356 }
357};
358
359template <typename SPSRetTagT>
360class ResultSerializer<SPSRetTagT, ErrorSuccess> {
361public:
362 static WrapperFunctionResult serialize(ErrorSuccess Err) {
363 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
364 toSPSSerializable(Err: std::move(Err)));
365 }
366};
367
368template <typename SPSRetTagT, typename T>
369class ResultSerializer<SPSRetTagT, Expected<T>> {
370public:
371 static WrapperFunctionResult serialize(Expected<T> E) {
372 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
373 toSPSSerializable(std::move(E)));
374 }
375};
376
377template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
378public:
379 static RetT makeValue() { return RetT(); }
380 static void makeSafe(RetT &Result) {}
381
382 static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
383 SPSInputBuffer IB(ArgData, ArgSize);
384 if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
385 return make_error<StringError>(
386 Args: "Error deserializing return value from blob in call",
387 Args: inconvertibleErrorCode());
388 return Error::success();
389 }
390};
391
392template <> class ResultDeserializer<SPSError, Error> {
393public:
394 static Error makeValue() { return Error::success(); }
395 static void makeSafe(Error &Err) { cantFail(Err: std::move(Err)); }
396
397 static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
398 SPSInputBuffer IB(ArgData, ArgSize);
399 SPSSerializableError BSE;
400 if (!SPSArgList<SPSError>::deserialize(IB, Arg&: BSE))
401 return make_error<StringError>(
402 Args: "Error deserializing return value from blob in call",
403 Args: inconvertibleErrorCode());
404 Err = fromSPSSerializable(BSE: std::move(BSE));
405 return Error::success();
406 }
407};
408
409template <typename SPSTagT, typename T>
410class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
411public:
412 static Expected<T> makeValue() { return T(); }
413 static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
414
415 static Error deserialize(Expected<T> &E, const char *ArgData,
416 size_t ArgSize) {
417 SPSInputBuffer IB(ArgData, ArgSize);
418 SPSSerializableExpected<T> BSE;
419 if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
420 return make_error<StringError>(
421 Args: "Error deserializing return value from blob in call",
422 Args: inconvertibleErrorCode());
423 E = fromSPSSerializable(std::move(BSE));
424 return Error::success();
425 }
426};
427
428template <typename SPSRetTagT, typename RetT> class AsyncCallResultHelper {
429 // Did you forget to use Error / Expected in your handler?
430};
431
432} // end namespace detail
433
434template <typename SPSSignature> class WrapperFunction;
435
436template <typename SPSRetTagT, typename... SPSTagTs>
437class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
438private:
439 template <typename RetT>
440 using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
441
442public:
443 /// Call a wrapper function. Caller should be callable as
444 /// WrapperFunctionResult Fn(const char *ArgData, size_t ArgSize);
445 template <typename CallerFn, typename RetT, typename... ArgTs>
446 static Error call(const CallerFn &Caller, RetT &Result,
447 const ArgTs &...Args) {
448
449 // RetT might be an Error or Expected value. Set the checked flag now:
450 // we don't want the user to have to check the unused result if this
451 // operation fails.
452 detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
453
454 auto ArgBuffer =
455 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>(
456 Args...);
457 if (const char *ErrMsg = ArgBuffer.getOutOfBandError())
458 return make_error<StringError>(Args&: ErrMsg, Args: inconvertibleErrorCode());
459
460 WrapperFunctionResult ResultBuffer =
461 Caller(ArgBuffer.data(), ArgBuffer.size());
462 if (auto ErrMsg = ResultBuffer.getOutOfBandError())
463 return make_error<StringError>(Args&: ErrMsg, Args: inconvertibleErrorCode());
464
465 return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
466 Result, ResultBuffer.data(), ResultBuffer.size());
467 }
468
469 /// Call an async wrapper function.
470 /// Caller should be callable as
471 /// void Fn(unique_function<void(WrapperFunctionResult)> SendResult,
472 /// WrapperFunctionResult ArgBuffer);
473 template <typename AsyncCallerFn, typename SendDeserializedResultFn,
474 typename... ArgTs>
475 static void callAsync(AsyncCallerFn &&Caller,
476 SendDeserializedResultFn &&SendDeserializedResult,
477 const ArgTs &...Args) {
478 using RetT = typename std::tuple_element<
479 1, typename detail::WrapperFunctionHandlerHelper<
480 std::remove_reference_t<SendDeserializedResultFn>,
481 ResultSerializer, SPSRetTagT>::ArgTuple>::type;
482
483 auto ArgBuffer =
484 detail::serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSTagTs...>>(
485 Args...);
486 if (auto *ErrMsg = ArgBuffer.getOutOfBandError()) {
487 SendDeserializedResult(
488 make_error<StringError>(ErrMsg, inconvertibleErrorCode()),
489 detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue());
490 return;
491 }
492
493 auto SendSerializedResult = [SDR = std::move(SendDeserializedResult)](
494 WrapperFunctionResult R) mutable {
495 RetT RetVal = detail::ResultDeserializer<SPSRetTagT, RetT>::makeValue();
496 detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(RetVal);
497
498 if (auto *ErrMsg = R.getOutOfBandError()) {
499 SDR(make_error<StringError>(Args&: ErrMsg, Args: inconvertibleErrorCode()),
500 std::move(RetVal));
501 return;
502 }
503
504 SPSInputBuffer IB(R.data(), R.size());
505 if (auto Err = detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
506 RetVal, R.data(), R.size()))
507 SDR(std::move(Err), std::move(RetVal));
508
509 SDR(Error::success(), std::move(RetVal));
510 };
511
512 Caller(std::move(SendSerializedResult), ArgBuffer.data(), ArgBuffer.size());
513 }
514
515 /// Handle a call to a wrapper function.
516 template <typename HandlerT>
517 static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
518 HandlerT &&Handler) {
519 using WFHH =
520 detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>,
521 ResultSerializer, SPSTagTs...>;
522 return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
523 }
524
525 /// Handle a call to an async wrapper function.
526 template <typename HandlerT, typename SendResultT>
527 static void handleAsync(const char *ArgData, size_t ArgSize,
528 HandlerT &&Handler, SendResultT &&SendResult) {
529 using WFAHH = detail::WrapperFunctionAsyncHandlerHelper<
530 std::remove_reference_t<HandlerT>, ResultSerializer, SPSTagTs...>;
531 WFAHH::applyAsync(std::forward<HandlerT>(Handler),
532 std::forward<SendResultT>(SendResult), ArgData, ArgSize);
533 }
534
535private:
536 template <typename T> static const T &makeSerializable(const T &Value) {
537 return Value;
538 }
539
540 static detail::SPSSerializableError makeSerializable(Error Err) {
541 return detail::toSPSSerializable(Err: std::move(Err));
542 }
543
544 template <typename T>
545 static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
546 return detail::toSPSSerializable(std::move(E));
547 }
548};
549
550template <typename... SPSTagTs>
551class WrapperFunction<void(SPSTagTs...)>
552 : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
553
554public:
555 template <typename CallerFn, typename... ArgTs>
556 static Error call(const CallerFn &Caller, const ArgTs &...Args) {
557 SPSEmpty BE;
558 return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(Caller, BE, Args...);
559 }
560
561 template <typename AsyncCallerFn, typename SendDeserializedResultFn,
562 typename... ArgTs>
563 static void callAsync(AsyncCallerFn &&Caller,
564 SendDeserializedResultFn &&SendDeserializedResult,
565 const ArgTs &...Args) {
566 WrapperFunction<SPSEmpty(SPSTagTs...)>::callAsync(
567 std::forward<AsyncCallerFn>(Caller),
568 [SDR = std::move(SendDeserializedResult)](Error SerializeErr,
569 SPSEmpty E) mutable {
570 SDR(std::move(SerializeErr));
571 },
572 Args...);
573 }
574
575 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
576 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handleAsync;
577};
578
579/// A function object that takes an ExecutorAddr as its first argument,
580/// casts that address to a ClassT*, then calls the given method on that
581/// pointer passing in the remaining function arguments. This utility
582/// removes some of the boilerplate from writing wrappers for method calls.
583///
584/// @code{.cpp}
585/// class MyClass {
586/// public:
587/// void myMethod(uint32_t, bool) { ... }
588/// };
589///
590/// // SPS Method signature -- note MyClass object address as first argument.
591/// using SPSMyMethodWrapperSignature =
592/// SPSTuple<SPSExecutorAddr, uint32_t, bool>;
593///
594/// WrapperFunctionResult
595/// myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
596/// return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
597/// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
598/// }
599/// @endcode
600///
601template <typename RetT, typename ClassT, typename... ArgTs>
602class MethodWrapperHandler {
603public:
604 using MethodT = RetT (ClassT::*)(ArgTs...);
605 MethodWrapperHandler(MethodT M) : M(M) {}
606 RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
607 return (ObjAddr.toPtr<ClassT*>()->*M)(std::forward<ArgTs>(Args)...);
608 }
609
610private:
611 MethodT M;
612};
613
614/// Create a MethodWrapperHandler object from the given method pointer.
615template <typename RetT, typename ClassT, typename... ArgTs>
616MethodWrapperHandler<RetT, ClassT, ArgTs...>
617makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
618 return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
619}
620
621/// Represents a serialized wrapper function call.
622/// Serializing calls themselves allows us to batch them: We can make one
623/// "run-wrapper-functions" utility and send it a list of calls to run.
624///
625/// The motivating use-case for this API is JITLink allocation actions, where
626/// we want to run multiple functions to finalize linked memory without having
627/// to make separate IPC calls for each one.
628class WrapperFunctionCall {
629public:
630 using ArgDataBufferType = SmallVector<char, 24>;
631
632 /// Create a WrapperFunctionCall using the given SPS serializer to serialize
633 /// the arguments.
634 template <typename SPSSerializer, typename... ArgTs>
635 static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr,
636 const ArgTs &...Args) {
637 ArgDataBufferType ArgData;
638 ArgData.resize(SPSSerializer::size(Args...));
639 SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(),
640 ArgData.size());
641 if (SPSSerializer::serialize(OB, Args...))
642 return WrapperFunctionCall(FnAddr, std::move(ArgData));
643 return make_error<StringError>(Args: "Cannot serialize arguments for "
644 "AllocActionCall",
645 Args: inconvertibleErrorCode());
646 }
647
648 WrapperFunctionCall() = default;
649
650 /// Create a WrapperFunctionCall from a target function and arg buffer.
651 WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
652 : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
653
654 /// Returns the address to be called.
655 const ExecutorAddr &getCallee() const { return FnAddr; }
656
657 /// Returns the argument data.
658 const ArgDataBufferType &getArgData() const { return ArgData; }
659
660 /// WrapperFunctionCalls convert to true if the callee is non-null.
661 explicit operator bool() const { return !!FnAddr; }
662
663 /// Run call returning raw WrapperFunctionResult.
664 shared::WrapperFunctionResult run() const {
665 using FnTy =
666 shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
667 return shared::WrapperFunctionResult(
668 FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
669 }
670
671 /// Run call and deserialize result using SPS.
672 template <typename SPSRetT, typename RetT>
673 std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
674 runWithSPSRet(RetT &RetVal) const {
675 auto WFR = run();
676 if (const char *ErrMsg = WFR.getOutOfBandError())
677 return make_error<StringError>(Args&: ErrMsg, Args: inconvertibleErrorCode());
678 shared::SPSInputBuffer IB(WFR.data(), WFR.size());
679 if (!shared::SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
680 return make_error<StringError>(Args: "Could not deserialize result from "
681 "serialized wrapper function call",
682 Args: inconvertibleErrorCode());
683 return Error::success();
684 }
685
686 /// Overload for SPS functions returning void.
687 template <typename SPSRetT>
688 std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
689 runWithSPSRet() const {
690 shared::SPSEmpty E;
691 return runWithSPSRet<shared::SPSEmpty>(RetVal&: E);
692 }
693
694 /// Run call and deserialize an SPSError result. SPSError returns and
695 /// deserialization failures are merged into the returned error.
696 Error runWithSPSRetErrorMerged() const {
697 detail::SPSSerializableError RetErr;
698 if (auto Err = runWithSPSRet<SPSError>(RetVal&: RetErr))
699 return Err;
700 return detail::fromSPSSerializable(BSE: std::move(RetErr));
701 }
702
703private:
704 orc::ExecutorAddr FnAddr;
705 ArgDataBufferType ArgData;
706};
707
708using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
709
710template <>
711class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
712public:
713 static size_t size(const WrapperFunctionCall &WFC) {
714 return SPSWrapperFunctionCall::AsArgList::size(Arg: WFC.getCallee(),
715 Args: WFC.getArgData());
716 }
717
718 static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
719 return SPSWrapperFunctionCall::AsArgList::serialize(OB, Arg: WFC.getCallee(),
720 Args: WFC.getArgData());
721 }
722
723 static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
724 ExecutorAddr FnAddr;
725 WrapperFunctionCall::ArgDataBufferType ArgData;
726 if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, Arg&: FnAddr, Args&: ArgData))
727 return false;
728 WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
729 return true;
730 }
731};
732
733} // end namespace shared
734} // end namespace orc
735} // end namespace llvm
736
737#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
738

source code of llvm/include/llvm/ExecutionEngine/Orc/Shared/WrapperFunctionUtils.h