LLVM 20.0.0git
WrapperFunctionUtils.h
Go to the documentation of this file.
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
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.
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 {
35 size_t Size;
37
38/// C++ wrapper function result: Same as CWrapperFunctionResult but
39/// auto-releases memory.
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).
51 // Reset R.
52 init(R);
53 }
54
57
59 init(R);
60 std::swap(R, Other.R);
61 }
62
64 WrapperFunctionResult Tmp(std::move(Other));
65 std::swap(R, Tmp.R);
66 return *this;
67 }
68
70 if ((R.Size > sizeof(R.Data.Value)) ||
71 (R.Size == 0 && R.Data.ValuePtr != nullptr))
72 free(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.
81 init(Tmp);
82 std::swap(R, 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.
114 // Reset.
116 WFR.R.Size = Size;
117 if (WFR.R.Size > sizeof(WFR.R.Data.Value))
118 WFR.R.Data.ValuePtr = (char *)malloc(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(WFR.data(), Source, 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, strlen(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.c_str());
137 }
138
139 /// Create an out-of-band error by copying the given string.
141 // Reset.
143 char *Tmp = (char *)malloc(strlen(Msg) + 1);
144 strcpy(Tmp, 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.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
174 auto Result = WrapperFunctionResult::allocate(SPSArgListT::size(Args...));
175 SPSOutputBuffer OB(Result.data(), Result.size());
176 if (!SPSArgListT::serialize(OB, Args...))
178 "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>
205 decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
206 ResultSerializer, SPSTagTs...> {};
207
208template <typename RetT, typename... ArgTs,
209 template <typename> class ResultSerializer, typename... SPSTagTs>
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{}))
222 "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>
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>
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 "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>
323 SPSTagTs...>
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:
346 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
347 Result);
348 }
349};
350
351template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
352public:
354 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
355 toSPSSerializable(std::move(Err)));
356 }
357};
358
359template <typename SPSRetTagT>
360class ResultSerializer<SPSRetTagT, ErrorSuccess> {
361public:
363 return serializeViaSPSToWrapperFunctionResult<SPSArgList<SPSRetTagT>>(
364 toSPSSerializable(std::move(Err)));
365 }
366};
367
368template <typename SPSRetTagT, typename T>
369class ResultSerializer<SPSRetTagT, Expected<T>> {
370public:
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);
385 return make_error<StringError>(
386 "Error deserializing return value from blob in call",
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(std::move(Err)); }
396
397 static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
398 SPSInputBuffer IB(ArgData, ArgSize);
401 return make_error<StringError>(
402 "Error deserializing return value from blob in call",
404 Err = fromSPSSerializable(std::move(BSE));
405 return Error::success();
406 }
407};
408
409template <typename SPSTagT, typename 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);
420 return make_error<StringError>(
421 "Error deserializing return value from blob in call",
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>
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.
453
454 auto ArgBuffer =
456 Args...);
457 if (const char *ErrMsg = ArgBuffer.getOutOfBandError())
458 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
459
460 WrapperFunctionResult ResultBuffer =
461 Caller(ArgBuffer.data(), ArgBuffer.size());
462 if (auto ErrMsg = ResultBuffer.getOutOfBandError())
463 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
464
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<
480 std::remove_reference_t<SendDeserializedResultFn>,
481 ResultSerializer, SPSRetTagT>::ArgTuple>::type;
482
483 auto ArgBuffer =
485 Args...);
486 if (auto *ErrMsg = ArgBuffer.getOutOfBandError()) {
487 SendDeserializedResult(
488 make_error<StringError>(ErrMsg, inconvertibleErrorCode()),
490 return;
491 }
492
493 auto SendSerializedResult = [SDR = std::move(SendDeserializedResult)](
494 WrapperFunctionResult R) mutable {
497
498 if (auto *ErrMsg = R.getOutOfBandError()) {
499 SDR(make_error<StringError>(ErrMsg, inconvertibleErrorCode()),
500 std::move(RetVal));
501 return;
502 }
503
504 SPSInputBuffer IB(R.data(), R.size());
506 RetVal, R.data(), R.size())) {
507 SDR(std::move(Err), std::move(RetVal));
508 return;
509 }
510
511 SDR(Error::success(), std::move(RetVal));
512 };
513
514 Caller(std::move(SendSerializedResult), ArgBuffer.data(), ArgBuffer.size());
515 }
516
517 /// Handle a call to a wrapper function.
518 template <typename HandlerT>
519 static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
520 HandlerT &&Handler) {
521 using WFHH =
523 ResultSerializer, SPSTagTs...>;
524 return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
525 }
526
527 /// Handle a call to an async wrapper function.
528 template <typename HandlerT, typename SendResultT>
529 static void handleAsync(const char *ArgData, size_t ArgSize,
530 HandlerT &&Handler, SendResultT &&SendResult) {
532 std::remove_reference_t<HandlerT>, ResultSerializer, SPSTagTs...>;
533 WFAHH::applyAsync(std::forward<HandlerT>(Handler),
534 std::forward<SendResultT>(SendResult), ArgData, ArgSize);
535 }
536
537private:
538 template <typename T> static const T &makeSerializable(const T &Value) {
539 return Value;
540 }
541
542 static detail::SPSSerializableError makeSerializable(Error Err) {
543 return detail::toSPSSerializable(std::move(Err));
544 }
545
546 template <typename T>
547 static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
548 return detail::toSPSSerializable(std::move(E));
549 }
550};
551
552template <typename... SPSTagTs>
553class WrapperFunction<void(SPSTagTs...)>
554 : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
555
556public:
557 template <typename CallerFn, typename... ArgTs>
558 static Error call(const CallerFn &Caller, const ArgTs &...Args) {
559 SPSEmpty BE;
560 return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(Caller, BE, Args...);
561 }
562
563 template <typename AsyncCallerFn, typename SendDeserializedResultFn,
564 typename... ArgTs>
565 static void callAsync(AsyncCallerFn &&Caller,
566 SendDeserializedResultFn &&SendDeserializedResult,
567 const ArgTs &...Args) {
568 WrapperFunction<SPSEmpty(SPSTagTs...)>::callAsync(
569 std::forward<AsyncCallerFn>(Caller),
570 [SDR = std::move(SendDeserializedResult)](Error SerializeErr,
571 SPSEmpty E) mutable {
572 SDR(std::move(SerializeErr));
573 },
574 Args...);
575 }
576
577 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
578 using WrapperFunction<SPSEmpty(SPSTagTs...)>::handleAsync;
579};
580
581/// A function object that takes an ExecutorAddr as its first argument,
582/// casts that address to a ClassT*, then calls the given method on that
583/// pointer passing in the remaining function arguments. This utility
584/// removes some of the boilerplate from writing wrappers for method calls.
585///
586/// @code{.cpp}
587/// class MyClass {
588/// public:
589/// void myMethod(uint32_t, bool) { ... }
590/// };
591///
592/// // SPS Method signature -- note MyClass object address as first argument.
593/// using SPSMyMethodWrapperSignature =
594/// SPSTuple<SPSExecutorAddr, uint32_t, bool>;
595///
596/// WrapperFunctionResult
597/// myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
598/// return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
599/// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
600/// }
601/// @endcode
602///
603template <typename RetT, typename ClassT, typename... ArgTs>
605public:
606 using MethodT = RetT (ClassT::*)(ArgTs...);
608 RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
609 return (ObjAddr.toPtr<ClassT*>()->*M)(std::forward<ArgTs>(Args)...);
610 }
611
612private:
613 MethodT M;
614};
615
616/// Create a MethodWrapperHandler object from the given method pointer.
617template <typename RetT, typename ClassT, typename... ArgTs>
618MethodWrapperHandler<RetT, ClassT, ArgTs...>
619makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
620 return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
621}
622
623/// Represents a serialized wrapper function call.
624/// Serializing calls themselves allows us to batch them: We can make one
625/// "run-wrapper-functions" utility and send it a list of calls to run.
626///
627/// The motivating use-case for this API is JITLink allocation actions, where
628/// we want to run multiple functions to finalize linked memory without having
629/// to make separate IPC calls for each one.
631public:
633
634 /// Create a WrapperFunctionCall using the given SPS serializer to serialize
635 /// the arguments.
636 template <typename SPSSerializer, typename... ArgTs>
638 const ArgTs &...Args) {
639 ArgDataBufferType ArgData;
640 ArgData.resize(SPSSerializer::size(Args...));
641 SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(),
642 ArgData.size());
643 if (SPSSerializer::serialize(OB, Args...))
644 return WrapperFunctionCall(FnAddr, std::move(ArgData));
645 return make_error<StringError>("Cannot serialize arguments for "
646 "AllocActionCall",
648 }
649
651
652 /// Create a WrapperFunctionCall from a target function and arg buffer.
654 : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
655
656 /// Returns the address to be called.
657 const ExecutorAddr &getCallee() const { return FnAddr; }
658
659 /// Returns the argument data.
660 const ArgDataBufferType &getArgData() const { return ArgData; }
661
662 /// WrapperFunctionCalls convert to true if the callee is non-null.
663 explicit operator bool() const { return !!FnAddr; }
664
665 /// Run call returning raw WrapperFunctionResult.
667 using FnTy =
668 shared::CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
670 FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
671 }
672
673 /// Run call and deserialize result using SPS.
674 template <typename SPSRetT, typename RetT>
675 std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
676 runWithSPSRet(RetT &RetVal) const {
677 auto WFR = run();
678 if (const char *ErrMsg = WFR.getOutOfBandError())
679 return make_error<StringError>(ErrMsg, inconvertibleErrorCode());
680 shared::SPSInputBuffer IB(WFR.data(), WFR.size());
682 return make_error<StringError>("Could not deserialize result from "
683 "serialized wrapper function call",
685 return Error::success();
686 }
687
688 /// Overload for SPS functions returning void.
689 template <typename SPSRetT>
690 std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
693 return runWithSPSRet<shared::SPSEmpty>(E);
694 }
695
696 /// Run call and deserialize an SPSError result. SPSError returns and
697 /// deserialization failures are merged into the returned error.
700 if (auto Err = runWithSPSRet<SPSError>(RetErr))
701 return Err;
702 return detail::fromSPSSerializable(std::move(RetErr));
703 }
704
705private:
706 orc::ExecutorAddr FnAddr;
707 ArgDataBufferType ArgData;
708};
709
711
712template <>
714public:
715 static size_t size(const WrapperFunctionCall &WFC) {
716 return SPSWrapperFunctionCall::AsArgList::size(WFC.getCallee(),
717 WFC.getArgData());
718 }
719
720 static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
721 return SPSWrapperFunctionCall::AsArgList::serialize(OB, WFC.getCallee(),
722 WFC.getArgData());
723 }
724
726 ExecutorAddr FnAddr;
728 if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
729 return false;
730 WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
731 return true;
732 }
733};
734
735} // end namespace shared
736} // end namespace orc
737} // end namespace llvm
738
739#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_WRAPPERFUNCTIONUTILS_H
aarch64 promote const
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
uint64_t Size
#define I(x, y, z)
Definition: MD5.cpp:58
#define H(x, y, z)
Definition: MD5.cpp:57
#define T
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Subclass of Error for the sole purpose of identifying the success path in the type system.
Definition: Error.h:335
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:337
Tagged union holding either a T or a Error.
Definition: Error.h:481
bool empty() const
Definition: SmallVector.h:81
size_t size() const
Definition: SmallVector.h:78
void resize(size_type N)
Definition: SmallVector.h:638
pointer data()
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:286
LLVM Value Representation.
Definition: Value.h:74
Represents an address in the executor process.
std::enable_if_t< std::is_pointer< T >::value, T > toPtr(WrapFn &&Wrap=WrapFn()) const
Cast this ExecutorAddr to a pointer of the given type.
A function object that takes an ExecutorAddr as its first argument, casts that address to a ClassT*,...
RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args)
A utility class for serializing to a blob from a variadic list.
SPS tag type for expecteds, which are either a T or a string representing an error.
Input char buffer with underflow check.
Output char buffer with overflow check.
static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC)
Specialize to describe how to serialize/deserialize to/from the given concrete type.
Represents a serialized wrapper function call.
const ArgDataBufferType & getArgData() const
Returns the argument data.
WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
Create a WrapperFunctionCall from a target function and arg buffer.
Error runWithSPSRetErrorMerged() const
Run call and deserialize an SPSError result.
std::enable_if_t<!std::is_same< SPSRetT, void >::value, Error > runWithSPSRet(RetT &RetVal) const
Run call and deserialize result using SPS.
const ExecutorAddr & getCallee() const
Returns the address to be called.
shared::WrapperFunctionResult run() const
Run call returning raw WrapperFunctionResult.
static Expected< WrapperFunctionCall > Create(ExecutorAddr FnAddr, const ArgTs &...Args)
Create a WrapperFunctionCall using the given SPS serializer to serialize the arguments.
std::enable_if_t< std::is_same< SPSRetT, void >::value, Error > runWithSPSRet() const
Overload for SPS functions returning void.
C++ wrapper function result: Same as CWrapperFunctionResult but auto-releases memory.
static WrapperFunctionResult copyFrom(const std::string &Source)
Copy from the given std::string (includes the null terminator).
static WrapperFunctionResult copyFrom(const char *Source, size_t Size)
Copy from the given char range.
static WrapperFunctionResult allocate(size_t Size)
Create a WrapperFunctionResult with the given size and return a pointer to the underlying memory.
WrapperFunctionResult(CWrapperFunctionResult R)
Create a WrapperFunctionResult by taking ownership of a CWrapperFunctionResult.
WrapperFunctionResult(const WrapperFunctionResult &)=delete
static WrapperFunctionResult createOutOfBandError(const std::string &Msg)
Create an out-of-band error by copying the given string.
CWrapperFunctionResult release()
Release ownership of the contained CWrapperFunctionResult.
bool empty() const
Returns true if this value is equivalent to a default-constructed WrapperFunctionResult.
WrapperFunctionResult & operator=(const WrapperFunctionResult &)=delete
const char * getOutOfBandError() const
If this value is an out-of-band error then this returns the error message, otherwise returns nullptr.
WrapperFunctionResult()
Create a default WrapperFunctionResult.
static WrapperFunctionResult copyFrom(const char *Source)
Copy from the given null-terminated string (includes the null-terminator).
WrapperFunctionResult(WrapperFunctionResult &&Other)
const char * data() const
Get a const pointer to the data contained in this instance.
static WrapperFunctionResult createOutOfBandError(const char *Msg)
Create an out-of-band error by copying the given string.
size_t size() const
Returns the size of the data contained in this instance.
WrapperFunctionResult & operator=(WrapperFunctionResult &&Other)
char * data()
Get a pointer to the data contained in this instance.
static void callAsync(AsyncCallerFn &&Caller, SendDeserializedResultFn &&SendDeserializedResult, const ArgTs &...Args)
Call an async wrapper function.
static void handleAsync(const char *ArgData, size_t ArgSize, HandlerT &&Handler, SendResultT &&SendResult)
Handle a call to an async wrapper function.
static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize, HandlerT &&Handler)
Handle a call to a wrapper function.
static Error call(const CallerFn &Caller, RetT &Result, const ArgTs &...Args)
Call a wrapper function.
static Error call(const CallerFn &Caller, const ArgTs &...Args)
static void callAsync(AsyncCallerFn &&Caller, SendDeserializedResultFn &&SendDeserializedResult, const ArgTs &...Args)
static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize)
static Error deserialize(Expected< T > &E, const char *ArgData, size_t ArgSize)
static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize)
static WrapperFunctionResult serialize(RetT Result)
static void applyAsync(HandlerT &&H, SendWrapperFunctionResultT &&SendWrapperFunctionResult, const char *ArgData, size_t ArgSize)
static SPSEmpty call(HandlerT &&H, ArgTupleT &Args, std::index_sequence< I... >)
static decltype(auto) call(HandlerT &&H, ArgTupleT &Args, std::index_sequence< I... >)
static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData, size_t ArgSize)
SPSSerializableError toSPSSerializable(Error Err)
WrapperFunctionResult serializeViaSPSToWrapperFunctionResult(const ArgTs &...Args)
Error fromSPSSerializable(SPSSerializableError BSE)
MethodWrapperHandler< RetT, ClassT, ArgTs... > makeMethodWrapperHandler(RetT(ClassT::*Method)(ArgTs...))
Create a MethodWrapperHandler object from the given method pointer.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:98
@ Other
Any other memory.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Definition: Error.h:756
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
CWrapperFunctionResultDataUnion Data