1da592413SLang Hames //===-- wrapper_function_utils.h - Utilities for wrapper funcs --*- C++ -*-===//
2da592413SLang Hames //
3da592413SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4da592413SLang Hames // See https://llvm.org/LICENSE.txt for license information.
5da592413SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6da592413SLang Hames //
7da592413SLang Hames //===----------------------------------------------------------------------===//
8da592413SLang Hames //
9da592413SLang Hames // This file is a part of the ORC runtime support library.
10da592413SLang Hames //
11da592413SLang Hames //===----------------------------------------------------------------------===//
12da592413SLang Hames
13da592413SLang Hames #ifndef ORC_RT_WRAPPER_FUNCTION_UTILS_H
14da592413SLang Hames #define ORC_RT_WRAPPER_FUNCTION_UTILS_H
15da592413SLang Hames
16*232bd331SLang Hames #include "orc/c_api.h"
17da592413SLang Hames #include "common.h"
18da592413SLang Hames #include "error.h"
19b574c52dSLang Hames #include "executor_address.h"
2049f4a58dSLang Hames #include "simple_packed_serialization.h"
21da592413SLang Hames #include <type_traits>
22da592413SLang Hames
23da592413SLang Hames namespace __orc_rt {
24da592413SLang Hames
25da592413SLang Hames /// C++ wrapper function result: Same as CWrapperFunctionResult but
26da592413SLang Hames /// auto-releases memory.
27da592413SLang Hames class WrapperFunctionResult {
28da592413SLang Hames public:
29da592413SLang Hames /// Create a default WrapperFunctionResult.
WrapperFunctionResult()30da592413SLang Hames WrapperFunctionResult() { __orc_rt_CWrapperFunctionResultInit(&R); }
31da592413SLang Hames
32da592413SLang Hames /// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
33da592413SLang Hames /// instance takes ownership of the result object and will automatically
34da592413SLang Hames /// call dispose on the result upon destruction.
WrapperFunctionResult(__orc_rt_CWrapperFunctionResult R)35da592413SLang Hames WrapperFunctionResult(__orc_rt_CWrapperFunctionResult R) : R(R) {}
36da592413SLang Hames
37da592413SLang Hames WrapperFunctionResult(const WrapperFunctionResult &) = delete;
38da592413SLang Hames WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
39da592413SLang Hames
WrapperFunctionResult(WrapperFunctionResult && Other)40da592413SLang Hames WrapperFunctionResult(WrapperFunctionResult &&Other) {
41da592413SLang Hames __orc_rt_CWrapperFunctionResultInit(&R);
42da592413SLang Hames std::swap(R, Other.R);
43da592413SLang Hames }
44da592413SLang Hames
45da592413SLang Hames WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
46da592413SLang Hames __orc_rt_CWrapperFunctionResult Tmp;
47da592413SLang Hames __orc_rt_CWrapperFunctionResultInit(&Tmp);
48da592413SLang Hames std::swap(Tmp, Other.R);
49da592413SLang Hames std::swap(R, Tmp);
50da592413SLang Hames return *this;
51da592413SLang Hames }
52da592413SLang Hames
~WrapperFunctionResult()53da592413SLang Hames ~WrapperFunctionResult() { __orc_rt_DisposeCWrapperFunctionResult(&R); }
54da592413SLang Hames
55da592413SLang Hames /// Relinquish ownership of and return the
56da592413SLang Hames /// __orc_rt_CWrapperFunctionResult.
release()57da592413SLang Hames __orc_rt_CWrapperFunctionResult release() {
58da592413SLang Hames __orc_rt_CWrapperFunctionResult Tmp;
59da592413SLang Hames __orc_rt_CWrapperFunctionResultInit(&Tmp);
60da592413SLang Hames std::swap(R, Tmp);
61da592413SLang Hames return Tmp;
62da592413SLang Hames }
63da592413SLang Hames
64e405db07SLang Hames /// Get a pointer to the data contained in this instance.
data()658614cb9fSLang Hames char *data() { return __orc_rt_CWrapperFunctionResultData(&R); }
66da592413SLang Hames
67da592413SLang Hames /// Returns the size of the data contained in this instance.
size()68da592413SLang Hames size_t size() const { return __orc_rt_CWrapperFunctionResultSize(&R); }
69da592413SLang Hames
70da592413SLang Hames /// Returns true if this value is equivalent to a default-constructed
71da592413SLang Hames /// WrapperFunctionResult.
empty()72da592413SLang Hames bool empty() const { return __orc_rt_CWrapperFunctionResultEmpty(&R); }
73da592413SLang Hames
74da592413SLang Hames /// Create a WrapperFunctionResult with the given size and return a pointer
75da592413SLang Hames /// to the underlying memory.
allocate(size_t Size)768614cb9fSLang Hames static WrapperFunctionResult allocate(size_t Size) {
778614cb9fSLang Hames WrapperFunctionResult R;
788614cb9fSLang Hames R.R = __orc_rt_CWrapperFunctionResultAllocate(Size);
798614cb9fSLang Hames return R;
80da592413SLang Hames }
81da592413SLang Hames
82da592413SLang Hames /// Copy from the given char range.
copyFrom(const char * Source,size_t Size)83da592413SLang Hames static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
84da592413SLang Hames return __orc_rt_CreateCWrapperFunctionResultFromRange(Source, Size);
85da592413SLang Hames }
86da592413SLang Hames
87da592413SLang Hames /// Copy from the given null-terminated string (includes the null-terminator).
copyFrom(const char * Source)88da592413SLang Hames static WrapperFunctionResult copyFrom(const char *Source) {
89da592413SLang Hames return __orc_rt_CreateCWrapperFunctionResultFromString(Source);
90da592413SLang Hames }
91da592413SLang Hames
92da592413SLang Hames /// Copy from the given std::string (includes the null terminator).
copyFrom(const std::string & Source)93da592413SLang Hames static WrapperFunctionResult copyFrom(const std::string &Source) {
94da592413SLang Hames return copyFrom(Source.c_str());
95da592413SLang Hames }
96da592413SLang Hames
97da592413SLang Hames /// Create an out-of-band error by copying the given string.
createOutOfBandError(const char * Msg)98da592413SLang Hames static WrapperFunctionResult createOutOfBandError(const char *Msg) {
99da592413SLang Hames return __orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(Msg);
100da592413SLang Hames }
101da592413SLang Hames
10249f4a58dSLang Hames /// Create an out-of-band error by copying the given string.
createOutOfBandError(const std::string & Msg)10349f4a58dSLang Hames static WrapperFunctionResult createOutOfBandError(const std::string &Msg) {
10449f4a58dSLang Hames return createOutOfBandError(Msg.c_str());
10549f4a58dSLang Hames }
10649f4a58dSLang Hames
107dc8e5e1dSLang Hames template <typename SPSArgListT, typename... ArgTs>
fromSPSArgs(const ArgTs &...Args)108dc8e5e1dSLang Hames static WrapperFunctionResult fromSPSArgs(const ArgTs &...Args) {
109dc8e5e1dSLang Hames auto Result = allocate(SPSArgListT::size(Args...));
110dc8e5e1dSLang Hames SPSOutputBuffer OB(Result.data(), Result.size());
111dc8e5e1dSLang Hames if (!SPSArgListT::serialize(OB, Args...))
112dc8e5e1dSLang Hames return createOutOfBandError(
113dc8e5e1dSLang Hames "Error serializing arguments to blob in call");
114dc8e5e1dSLang Hames return Result;
115dc8e5e1dSLang Hames }
116dc8e5e1dSLang Hames
117da592413SLang Hames /// If this value is an out-of-band error then this returns the error message,
118da592413SLang Hames /// otherwise returns nullptr.
getOutOfBandError()119da592413SLang Hames const char *getOutOfBandError() const {
120da592413SLang Hames return __orc_rt_CWrapperFunctionResultGetOutOfBandError(&R);
121da592413SLang Hames }
122da592413SLang Hames
123da592413SLang Hames private:
124da592413SLang Hames __orc_rt_CWrapperFunctionResult R;
125da592413SLang Hames };
126da592413SLang Hames
127da592413SLang Hames namespace detail {
128da592413SLang Hames
12968c16109SLang Hames template <typename RetT> class WrapperFunctionHandlerCaller {
13068c16109SLang Hames public:
13168c16109SLang Hames template <typename HandlerT, typename ArgTupleT, std::size_t... I>
decltype(auto)13268c16109SLang Hames static decltype(auto) call(HandlerT &&H, ArgTupleT &Args,
13368c16109SLang Hames std::index_sequence<I...>) {
13468c16109SLang Hames return std::forward<HandlerT>(H)(std::get<I>(Args)...);
13568c16109SLang Hames }
13668c16109SLang Hames };
13768c16109SLang Hames
13868c16109SLang Hames template <> class WrapperFunctionHandlerCaller<void> {
13968c16109SLang Hames public:
14068c16109SLang Hames template <typename HandlerT, typename ArgTupleT, std::size_t... I>
call(HandlerT && H,ArgTupleT & Args,std::index_sequence<I...>)14168c16109SLang Hames static SPSEmpty call(HandlerT &&H, ArgTupleT &Args,
14268c16109SLang Hames std::index_sequence<I...>) {
14368c16109SLang Hames std::forward<HandlerT>(H)(std::get<I>(Args)...);
14468c16109SLang Hames return SPSEmpty();
14568c16109SLang Hames }
14668c16109SLang Hames };
14768c16109SLang Hames
148da592413SLang Hames template <typename WrapperFunctionImplT,
149da592413SLang Hames template <typename> class ResultSerializer, typename... SPSTagTs>
150da592413SLang Hames class WrapperFunctionHandlerHelper
151da592413SLang Hames : public WrapperFunctionHandlerHelper<
152da592413SLang Hames decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
153da592413SLang Hames ResultSerializer, SPSTagTs...> {};
154da592413SLang Hames
155da592413SLang Hames template <typename RetT, typename... ArgTs,
156da592413SLang Hames template <typename> class ResultSerializer, typename... SPSTagTs>
157da592413SLang Hames class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
158da592413SLang Hames SPSTagTs...> {
159da592413SLang Hames public:
160da592413SLang Hames using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
161da592413SLang Hames using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
162da592413SLang Hames
163da592413SLang Hames template <typename HandlerT>
apply(HandlerT && H,const char * ArgData,size_t ArgSize)164da592413SLang Hames static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
165da592413SLang Hames size_t ArgSize) {
166da592413SLang Hames ArgTuple Args;
167da592413SLang Hames if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
168da592413SLang Hames return WrapperFunctionResult::createOutOfBandError(
169da592413SLang Hames "Could not deserialize arguments for wrapper function call");
170da592413SLang Hames
17168c16109SLang Hames auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call(
17268c16109SLang Hames std::forward<HandlerT>(H), Args, ArgIndices{});
17368c16109SLang Hames
174ea9826ffSLang Hames return ResultSerializer<decltype(HandlerResult)>::serialize(
175ea9826ffSLang Hames std::move(HandlerResult));
176da592413SLang Hames }
177da592413SLang Hames
178da592413SLang Hames private:
179da592413SLang Hames template <std::size_t... I>
deserialize(const char * ArgData,size_t ArgSize,ArgTuple & Args,std::index_sequence<I...>)180da592413SLang Hames static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
181da592413SLang Hames std::index_sequence<I...>) {
182da592413SLang Hames SPSInputBuffer IB(ArgData, ArgSize);
183da592413SLang Hames return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
184da592413SLang Hames }
185da592413SLang Hames };
186da592413SLang Hames
18721369d4bSLang Hames // Map function pointers to function types.
188da592413SLang Hames template <typename RetT, typename... ArgTs,
189da592413SLang Hames template <typename> class ResultSerializer, typename... SPSTagTs>
19021369d4bSLang Hames class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
191da592413SLang Hames SPSTagTs...>
192da592413SLang Hames : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
193da592413SLang Hames SPSTagTs...> {};
194da592413SLang Hames
195da592413SLang Hames // Map non-const member function types to function types.
196da592413SLang Hames template <typename ClassT, typename RetT, typename... ArgTs,
197da592413SLang Hames template <typename> class ResultSerializer, typename... SPSTagTs>
198da592413SLang Hames class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
199da592413SLang Hames SPSTagTs...>
200da592413SLang Hames : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
201da592413SLang Hames SPSTagTs...> {};
202da592413SLang Hames
203da592413SLang Hames // Map const member function types to function types.
204da592413SLang Hames template <typename ClassT, typename RetT, typename... ArgTs,
205da592413SLang Hames template <typename> class ResultSerializer, typename... SPSTagTs>
206da592413SLang Hames class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
207da592413SLang Hames ResultSerializer, SPSTagTs...>
208da592413SLang Hames : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
209da592413SLang Hames SPSTagTs...> {};
210da592413SLang Hames
211da592413SLang Hames template <typename SPSRetTagT, typename RetT> class ResultSerializer {
212da592413SLang Hames public:
serialize(RetT Result)213ea9826ffSLang Hames static WrapperFunctionResult serialize(RetT Result) {
214dc8e5e1dSLang Hames return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(Result);
215da592413SLang Hames }
216da592413SLang Hames };
217da592413SLang Hames
218da592413SLang Hames template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
219da592413SLang Hames public:
serialize(Error Err)220ea9826ffSLang Hames static WrapperFunctionResult serialize(Error Err) {
221dc8e5e1dSLang Hames return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
22249f4a58dSLang Hames toSPSSerializable(std::move(Err)));
223da592413SLang Hames }
224da592413SLang Hames };
225da592413SLang Hames
226da592413SLang Hames template <typename SPSRetTagT, typename T>
227da592413SLang Hames class ResultSerializer<SPSRetTagT, Expected<T>> {
228da592413SLang Hames public:
serialize(Expected<T> E)229ea9826ffSLang Hames static WrapperFunctionResult serialize(Expected<T> E) {
230dc8e5e1dSLang Hames return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
23149f4a58dSLang Hames toSPSSerializable(std::move(E)));
232da592413SLang Hames }
233da592413SLang Hames };
234da592413SLang Hames
235da592413SLang Hames template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
236da592413SLang Hames public:
makeSafe(RetT & Result)237da592413SLang Hames static void makeSafe(RetT &Result) {}
238da592413SLang Hames
deserialize(RetT & Result,const char * ArgData,size_t ArgSize)239da592413SLang Hames static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
240da592413SLang Hames SPSInputBuffer IB(ArgData, ArgSize);
241da592413SLang Hames if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
242da592413SLang Hames return make_error<StringError>(
243da592413SLang Hames "Error deserializing return value from blob in call");
244da592413SLang Hames return Error::success();
245da592413SLang Hames }
246da592413SLang Hames };
247da592413SLang Hames
248da592413SLang Hames template <> class ResultDeserializer<SPSError, Error> {
249da592413SLang Hames public:
makeSafe(Error & Err)250da592413SLang Hames static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
251da592413SLang Hames
deserialize(Error & Err,const char * ArgData,size_t ArgSize)252da592413SLang Hames static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
253da592413SLang Hames SPSInputBuffer IB(ArgData, ArgSize);
254da592413SLang Hames SPSSerializableError BSE;
255da592413SLang Hames if (!SPSArgList<SPSError>::deserialize(IB, BSE))
256da592413SLang Hames return make_error<StringError>(
257da592413SLang Hames "Error deserializing return value from blob in call");
258da592413SLang Hames Err = fromSPSSerializable(std::move(BSE));
259da592413SLang Hames return Error::success();
260da592413SLang Hames }
261da592413SLang Hames };
262da592413SLang Hames
263da592413SLang Hames template <typename SPSTagT, typename T>
264da592413SLang Hames class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
265da592413SLang Hames public:
makeSafe(Expected<T> & E)266da592413SLang Hames static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
267da592413SLang Hames
deserialize(Expected<T> & E,const char * ArgData,size_t ArgSize)268da592413SLang Hames static Error deserialize(Expected<T> &E, const char *ArgData,
269da592413SLang Hames size_t ArgSize) {
270da592413SLang Hames SPSInputBuffer IB(ArgData, ArgSize);
271da592413SLang Hames SPSSerializableExpected<T> BSE;
272da592413SLang Hames if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
273da592413SLang Hames return make_error<StringError>(
274da592413SLang Hames "Error deserializing return value from blob in call");
275da592413SLang Hames E = fromSPSSerializable(std::move(BSE));
276da592413SLang Hames return Error::success();
277da592413SLang Hames }
278da592413SLang Hames };
279da592413SLang Hames
280da592413SLang Hames } // end namespace detail
281da592413SLang Hames
282da592413SLang Hames template <typename SPSSignature> class WrapperFunction;
283da592413SLang Hames
284da592413SLang Hames template <typename SPSRetTagT, typename... SPSTagTs>
285da592413SLang Hames class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
286da592413SLang Hames private:
287da592413SLang Hames template <typename RetT>
288da592413SLang Hames using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
289da592413SLang Hames
290da592413SLang Hames public:
291da592413SLang Hames template <typename RetT, typename... ArgTs>
call(const void * FnTag,RetT & Result,const ArgTs &...Args)292da592413SLang Hames static Error call(const void *FnTag, RetT &Result, const ArgTs &...Args) {
293da592413SLang Hames
294da592413SLang Hames // RetT might be an Error or Expected value. Set the checked flag now:
295da592413SLang Hames // we don't want the user to have to check the unused result if this
296da592413SLang Hames // operation fails.
297da592413SLang Hames detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
298da592413SLang Hames
299da592413SLang Hames if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch_ctx))
300bb5f97e3SLang Hames return make_error<StringError>("__orc_rt_jit_dispatch_ctx not set");
301ba9e2806SLang Hames if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch))
302bb5f97e3SLang Hames return make_error<StringError>("__orc_rt_jit_dispatch not set");
303da592413SLang Hames
30449f4a58dSLang Hames auto ArgBuffer =
305dc8e5e1dSLang Hames WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSTagTs...>>(Args...);
306ea9826ffSLang Hames if (const char *ErrMsg = ArgBuffer.getOutOfBandError())
307ea9826ffSLang Hames return make_error<StringError>(ErrMsg);
30849f4a58dSLang Hames
309ea9826ffSLang Hames WrapperFunctionResult ResultBuffer = __orc_rt_jit_dispatch(
310ea9826ffSLang Hames &__orc_rt_jit_dispatch_ctx, FnTag, ArgBuffer.data(), ArgBuffer.size());
311da592413SLang Hames if (auto ErrMsg = ResultBuffer.getOutOfBandError())
312da592413SLang Hames return make_error<StringError>(ErrMsg);
313da592413SLang Hames
314da592413SLang Hames return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
315da592413SLang Hames Result, ResultBuffer.data(), ResultBuffer.size());
316da592413SLang Hames }
317da592413SLang Hames
318da592413SLang Hames template <typename HandlerT>
handle(const char * ArgData,size_t ArgSize,HandlerT && Handler)319da592413SLang Hames static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
320da592413SLang Hames HandlerT &&Handler) {
321da592413SLang Hames using WFHH =
322b574c52dSLang Hames detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>,
323b574c52dSLang Hames ResultSerializer, SPSTagTs...>;
324da592413SLang Hames return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
325da592413SLang Hames }
326da592413SLang Hames
327da592413SLang Hames private:
makeSerializable(const T & Value)328da592413SLang Hames template <typename T> static const T &makeSerializable(const T &Value) {
329da592413SLang Hames return Value;
330da592413SLang Hames }
331da592413SLang Hames
makeSerializable(Error Err)332da592413SLang Hames static detail::SPSSerializableError makeSerializable(Error Err) {
333da592413SLang Hames return detail::toSPSSerializable(std::move(Err));
334da592413SLang Hames }
335da592413SLang Hames
336da592413SLang Hames template <typename T>
makeSerializable(Expected<T> E)337da592413SLang Hames static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
338da592413SLang Hames return detail::toSPSSerializable(std::move(E));
339da592413SLang Hames }
340da592413SLang Hames };
341da592413SLang Hames
342da592413SLang Hames template <typename... SPSTagTs>
343da592413SLang Hames class WrapperFunction<void(SPSTagTs...)>
344da592413SLang Hames : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
345da592413SLang Hames public:
346da592413SLang Hames template <typename... ArgTs>
call(const void * FnTag,const ArgTs &...Args)347da592413SLang Hames static Error call(const void *FnTag, const ArgTs &...Args) {
348da592413SLang Hames SPSEmpty BE;
349da592413SLang Hames return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(FnTag, BE, Args...);
350da592413SLang Hames }
351da592413SLang Hames
352da592413SLang Hames using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
353da592413SLang Hames };
354da592413SLang Hames
355b574c52dSLang Hames /// A function object that takes an ExecutorAddr as its first argument,
356b574c52dSLang Hames /// casts that address to a ClassT*, then calls the given method on that
357b574c52dSLang Hames /// pointer passing in the remaining function arguments. This utility
358b574c52dSLang Hames /// removes some of the boilerplate from writing wrappers for method calls.
359b574c52dSLang Hames ///
360b574c52dSLang Hames /// @code{.cpp}
361b574c52dSLang Hames /// class MyClass {
362b574c52dSLang Hames /// public:
363b574c52dSLang Hames /// void myMethod(uint32_t, bool) { ... }
364b574c52dSLang Hames /// };
365b574c52dSLang Hames ///
366b574c52dSLang Hames /// // SPS Method signature -- note MyClass object address as first argument.
367b574c52dSLang Hames /// using SPSMyMethodWrapperSignature =
368b574c52dSLang Hames /// SPSTuple<SPSExecutorAddr, uint32_t, bool>;
369b574c52dSLang Hames ///
370b574c52dSLang Hames /// WrapperFunctionResult
371b574c52dSLang Hames /// myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
372b574c52dSLang Hames /// return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
373b574c52dSLang Hames /// ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
374b574c52dSLang Hames /// }
375b574c52dSLang Hames /// @endcode
376b574c52dSLang Hames ///
377b574c52dSLang Hames template <typename RetT, typename ClassT, typename... ArgTs>
378b574c52dSLang Hames class MethodWrapperHandler {
379b574c52dSLang Hames public:
380b574c52dSLang Hames using MethodT = RetT (ClassT::*)(ArgTs...);
MethodWrapperHandler(MethodT M)381b574c52dSLang Hames MethodWrapperHandler(MethodT M) : M(M) {}
operator()382b574c52dSLang Hames RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
383b574c52dSLang Hames return (ObjAddr.toPtr<ClassT *>()->*M)(std::forward<ArgTs>(Args)...);
384b574c52dSLang Hames }
385b574c52dSLang Hames
386b574c52dSLang Hames private:
387b574c52dSLang Hames MethodT M;
388b574c52dSLang Hames };
389b574c52dSLang Hames
390b574c52dSLang Hames /// Create a MethodWrapperHandler object from the given method pointer.
391b574c52dSLang Hames template <typename RetT, typename ClassT, typename... ArgTs>
392b574c52dSLang Hames MethodWrapperHandler<RetT, ClassT, ArgTs...>
makeMethodWrapperHandler(RetT (ClassT::* Method)(ArgTs...))393b574c52dSLang Hames makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
394b574c52dSLang Hames return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
395b574c52dSLang Hames }
396b574c52dSLang Hames
397dc8e5e1dSLang Hames /// Represents a call to a wrapper function.
3980ede1b90SLang Hames class WrapperFunctionCall {
3990ede1b90SLang Hames public:
4000ede1b90SLang Hames // FIXME: Switch to a SmallVector<char, 24> once ORC runtime has a
4010ede1b90SLang Hames // smallvector.
4020ede1b90SLang Hames using ArgDataBufferType = std::vector<char>;
4030ede1b90SLang Hames
4040ede1b90SLang Hames /// Create a WrapperFunctionCall using the given SPS serializer to serialize
4050ede1b90SLang Hames /// the arguments.
4060ede1b90SLang Hames template <typename SPSSerializer, typename... ArgTs>
Create(ExecutorAddr FnAddr,const ArgTs &...Args)4070ede1b90SLang Hames static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr,
4080ede1b90SLang Hames const ArgTs &...Args) {
4090ede1b90SLang Hames ArgDataBufferType ArgData;
4100ede1b90SLang Hames ArgData.resize(SPSSerializer::size(Args...));
4110ede1b90SLang Hames SPSOutputBuffer OB(&ArgData[0], ArgData.size());
4120ede1b90SLang Hames if (SPSSerializer::serialize(OB, Args...))
4130ede1b90SLang Hames return WrapperFunctionCall(FnAddr, std::move(ArgData));
4140ede1b90SLang Hames return make_error<StringError>("Cannot serialize arguments for "
4150ede1b90SLang Hames "AllocActionCall");
4160ede1b90SLang Hames }
417dc8e5e1dSLang Hames
418dc8e5e1dSLang Hames WrapperFunctionCall() = default;
419dc8e5e1dSLang Hames
4200ede1b90SLang Hames /// Create a WrapperFunctionCall from a target function and arg buffer.
WrapperFunctionCall(ExecutorAddr FnAddr,ArgDataBufferType ArgData)4210ede1b90SLang Hames WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
4220ede1b90SLang Hames : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
4230ede1b90SLang Hames
4240ede1b90SLang Hames /// Returns the address to be called.
getCallee()4250ede1b90SLang Hames const ExecutorAddr &getCallee() const { return FnAddr; }
4260ede1b90SLang Hames
4270ede1b90SLang Hames /// Returns the argument data.
getArgData()4280ede1b90SLang Hames const ArgDataBufferType &getArgData() const { return ArgData; }
4290ede1b90SLang Hames
4300ede1b90SLang Hames /// WrapperFunctionCalls convert to true if the callee is non-null.
4310ede1b90SLang Hames explicit operator bool() const { return !!FnAddr; }
4320ede1b90SLang Hames
4330ede1b90SLang Hames /// Run call returning raw WrapperFunctionResult.
run()4340ede1b90SLang Hames WrapperFunctionResult run() const {
4350ede1b90SLang Hames using FnTy =
4360ede1b90SLang Hames __orc_rt_CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
4370ede1b90SLang Hames return WrapperFunctionResult(
4380ede1b90SLang Hames FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
439dc8e5e1dSLang Hames }
440dc8e5e1dSLang Hames
441dc8e5e1dSLang Hames /// Run call and deserialize result using SPS.
4420ede1b90SLang Hames template <typename SPSRetT, typename RetT>
4430ede1b90SLang Hames std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
runWithSPSRet(RetT & RetVal)4440ede1b90SLang Hames runWithSPSRet(RetT &RetVal) const {
445dc8e5e1dSLang Hames auto WFR = run();
446dc8e5e1dSLang Hames if (const char *ErrMsg = WFR.getOutOfBandError())
447dc8e5e1dSLang Hames return make_error<StringError>(ErrMsg);
448dc8e5e1dSLang Hames SPSInputBuffer IB(WFR.data(), WFR.size());
449dc8e5e1dSLang Hames if (!SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
450dc8e5e1dSLang Hames return make_error<StringError>("Could not deserialize result from "
451dc8e5e1dSLang Hames "serialized wrapper function call");
452dc8e5e1dSLang Hames return Error::success();
453dc8e5e1dSLang Hames }
454dc8e5e1dSLang Hames
455dc8e5e1dSLang Hames /// Overload for SPS functions returning void.
4560ede1b90SLang Hames template <typename SPSRetT>
4570ede1b90SLang Hames std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
runWithSPSRet()4580ede1b90SLang Hames runWithSPSRet() const {
459dc8e5e1dSLang Hames SPSEmpty E;
460dc8e5e1dSLang Hames return runWithSPSRet<SPSEmpty>(E);
461dc8e5e1dSLang Hames }
4620ede1b90SLang Hames
4630ede1b90SLang Hames /// Run call and deserialize an SPSError result. SPSError returns and
4640ede1b90SLang Hames /// deserialization failures are merged into the returned error.
runWithSPSRetErrorMerged()4650ede1b90SLang Hames Error runWithSPSRetErrorMerged() const {
4660ede1b90SLang Hames detail::SPSSerializableError RetErr;
4670ede1b90SLang Hames if (auto Err = runWithSPSRet<SPSError>(RetErr))
4680ede1b90SLang Hames return Err;
4690ede1b90SLang Hames return detail::fromSPSSerializable(std::move(RetErr));
4700ede1b90SLang Hames }
4710ede1b90SLang Hames
4720ede1b90SLang Hames private:
4730ede1b90SLang Hames ExecutorAddr FnAddr;
4740ede1b90SLang Hames std::vector<char> ArgData;
475dc8e5e1dSLang Hames };
476dc8e5e1dSLang Hames
4770ede1b90SLang Hames using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
478dc8e5e1dSLang Hames
479dc8e5e1dSLang Hames template <>
480dc8e5e1dSLang Hames class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
481dc8e5e1dSLang Hames public:
size(const WrapperFunctionCall & WFC)482dc8e5e1dSLang Hames static size_t size(const WrapperFunctionCall &WFC) {
4830ede1b90SLang Hames return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::size(
4840ede1b90SLang Hames WFC.getCallee(), WFC.getArgData());
485dc8e5e1dSLang Hames }
486dc8e5e1dSLang Hames
serialize(SPSOutputBuffer & OB,const WrapperFunctionCall & WFC)487dc8e5e1dSLang Hames static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
4880ede1b90SLang Hames return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::serialize(
4890ede1b90SLang Hames OB, WFC.getCallee(), WFC.getArgData());
490dc8e5e1dSLang Hames }
491dc8e5e1dSLang Hames
deserialize(SPSInputBuffer & IB,WrapperFunctionCall & WFC)492dc8e5e1dSLang Hames static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
4930ede1b90SLang Hames ExecutorAddr FnAddr;
4940ede1b90SLang Hames WrapperFunctionCall::ArgDataBufferType ArgData;
4950ede1b90SLang Hames if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
4960ede1b90SLang Hames return false;
4970ede1b90SLang Hames WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
4980ede1b90SLang Hames return true;
499dc8e5e1dSLang Hames }
500dc8e5e1dSLang Hames };
501dc8e5e1dSLang Hames
502da592413SLang Hames } // end namespace __orc_rt
503da592413SLang Hames
504da592413SLang Hames #endif // ORC_RT_WRAPPER_FUNCTION_UTILS_H
505