xref: /llvm-project/compiler-rt/lib/orc/wrapper_function_utils.h (revision 69f8923efa61034b57805a8d6d859e9c1ca976eb)
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 
16da592413SLang Hames #include "error.h"
17b574c52dSLang Hames #include "executor_address.h"
18*69f8923eSLang Hames #include "orc_rt/c_api.h"
1949f4a58dSLang Hames #include "simple_packed_serialization.h"
20da592413SLang Hames #include <type_traits>
21da592413SLang Hames 
223e04ad42SLang Hames namespace orc_rt {
23da592413SLang Hames 
24da592413SLang Hames /// C++ wrapper function result: Same as CWrapperFunctionResult but
25da592413SLang Hames /// auto-releases memory.
26da592413SLang Hames class WrapperFunctionResult {
27da592413SLang Hames public:
28da592413SLang Hames   /// Create a default WrapperFunctionResult.
2934fccfb2SLang Hames   WrapperFunctionResult() { orc_rt_CWrapperFunctionResultInit(&R); }
30da592413SLang Hames 
31da592413SLang Hames   /// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
32da592413SLang Hames   /// instance takes ownership of the result object and will automatically
33da592413SLang Hames   /// call dispose on the result upon destruction.
3434fccfb2SLang Hames   WrapperFunctionResult(orc_rt_CWrapperFunctionResult R) : R(R) {}
35da592413SLang Hames 
36da592413SLang Hames   WrapperFunctionResult(const WrapperFunctionResult &) = delete;
37da592413SLang Hames   WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
38da592413SLang Hames 
39da592413SLang Hames   WrapperFunctionResult(WrapperFunctionResult &&Other) {
4034fccfb2SLang Hames     orc_rt_CWrapperFunctionResultInit(&R);
41da592413SLang Hames     std::swap(R, Other.R);
42da592413SLang Hames   }
43da592413SLang Hames 
44da592413SLang Hames   WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
4534fccfb2SLang Hames     orc_rt_CWrapperFunctionResult Tmp;
4634fccfb2SLang Hames     orc_rt_CWrapperFunctionResultInit(&Tmp);
47da592413SLang Hames     std::swap(Tmp, Other.R);
48da592413SLang Hames     std::swap(R, Tmp);
49da592413SLang Hames     return *this;
50da592413SLang Hames   }
51da592413SLang Hames 
5234fccfb2SLang Hames   ~WrapperFunctionResult() { orc_rt_DisposeCWrapperFunctionResult(&R); }
53da592413SLang Hames 
54da592413SLang Hames   /// Relinquish ownership of and return the
5534fccfb2SLang Hames   /// orc_rt_CWrapperFunctionResult.
5634fccfb2SLang Hames   orc_rt_CWrapperFunctionResult release() {
5734fccfb2SLang Hames     orc_rt_CWrapperFunctionResult Tmp;
5834fccfb2SLang Hames     orc_rt_CWrapperFunctionResultInit(&Tmp);
59da592413SLang Hames     std::swap(R, Tmp);
60da592413SLang Hames     return Tmp;
61da592413SLang Hames   }
62da592413SLang Hames 
63e405db07SLang Hames   /// Get a pointer to the data contained in this instance.
6434fccfb2SLang Hames   char *data() { return orc_rt_CWrapperFunctionResultData(&R); }
65da592413SLang Hames 
66da592413SLang Hames   /// Returns the size of the data contained in this instance.
6734fccfb2SLang Hames   size_t size() const { return orc_rt_CWrapperFunctionResultSize(&R); }
68da592413SLang Hames 
69da592413SLang Hames   /// Returns true if this value is equivalent to a default-constructed
70da592413SLang Hames   /// WrapperFunctionResult.
7134fccfb2SLang Hames   bool empty() const { return orc_rt_CWrapperFunctionResultEmpty(&R); }
72da592413SLang Hames 
73da592413SLang Hames   /// Create a WrapperFunctionResult with the given size and return a pointer
74da592413SLang Hames   /// to the underlying memory.
758614cb9fSLang Hames   static WrapperFunctionResult allocate(size_t Size) {
768614cb9fSLang Hames     WrapperFunctionResult R;
7734fccfb2SLang Hames     R.R = orc_rt_CWrapperFunctionResultAllocate(Size);
788614cb9fSLang Hames     return R;
79da592413SLang Hames   }
80da592413SLang Hames 
81da592413SLang Hames   /// Copy from the given char range.
82da592413SLang Hames   static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
8334fccfb2SLang Hames     return orc_rt_CreateCWrapperFunctionResultFromRange(Source, Size);
84da592413SLang Hames   }
85da592413SLang Hames 
86da592413SLang Hames   /// Copy from the given null-terminated string (includes the null-terminator).
87da592413SLang Hames   static WrapperFunctionResult copyFrom(const char *Source) {
8834fccfb2SLang Hames     return orc_rt_CreateCWrapperFunctionResultFromString(Source);
89da592413SLang Hames   }
90da592413SLang Hames 
91da592413SLang Hames   /// Copy from the given std::string (includes the null terminator).
92da592413SLang Hames   static WrapperFunctionResult copyFrom(const std::string &Source) {
93da592413SLang Hames     return copyFrom(Source.c_str());
94da592413SLang Hames   }
95da592413SLang Hames 
96da592413SLang Hames   /// Create an out-of-band error by copying the given string.
97da592413SLang Hames   static WrapperFunctionResult createOutOfBandError(const char *Msg) {
9834fccfb2SLang Hames     return orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(Msg);
99da592413SLang Hames   }
100da592413SLang Hames 
10149f4a58dSLang Hames   /// Create an out-of-band error by copying the given string.
10249f4a58dSLang Hames   static WrapperFunctionResult createOutOfBandError(const std::string &Msg) {
10349f4a58dSLang Hames     return createOutOfBandError(Msg.c_str());
10449f4a58dSLang Hames   }
10549f4a58dSLang Hames 
106dc8e5e1dSLang Hames   template <typename SPSArgListT, typename... ArgTs>
107dc8e5e1dSLang Hames   static WrapperFunctionResult fromSPSArgs(const ArgTs &...Args) {
108dc8e5e1dSLang Hames     auto Result = allocate(SPSArgListT::size(Args...));
109dc8e5e1dSLang Hames     SPSOutputBuffer OB(Result.data(), Result.size());
110dc8e5e1dSLang Hames     if (!SPSArgListT::serialize(OB, Args...))
111dc8e5e1dSLang Hames       return createOutOfBandError(
112dc8e5e1dSLang Hames           "Error serializing arguments to blob in call");
113dc8e5e1dSLang Hames     return Result;
114dc8e5e1dSLang Hames   }
115dc8e5e1dSLang Hames 
116da592413SLang Hames   /// If this value is an out-of-band error then this returns the error message,
117da592413SLang Hames   /// otherwise returns nullptr.
118da592413SLang Hames   const char *getOutOfBandError() const {
11934fccfb2SLang Hames     return orc_rt_CWrapperFunctionResultGetOutOfBandError(&R);
120da592413SLang Hames   }
121da592413SLang Hames 
122da592413SLang Hames private:
12334fccfb2SLang Hames   orc_rt_CWrapperFunctionResult R;
124da592413SLang Hames };
125da592413SLang Hames 
126da592413SLang Hames namespace detail {
127da592413SLang Hames 
12868c16109SLang Hames template <typename RetT> class WrapperFunctionHandlerCaller {
12968c16109SLang Hames public:
13068c16109SLang Hames   template <typename HandlerT, typename ArgTupleT, std::size_t... I>
13168c16109SLang Hames   static decltype(auto) call(HandlerT &&H, ArgTupleT &Args,
13268c16109SLang Hames                              std::index_sequence<I...>) {
13368c16109SLang Hames     return std::forward<HandlerT>(H)(std::get<I>(Args)...);
13468c16109SLang Hames   }
13568c16109SLang Hames };
13668c16109SLang Hames 
13768c16109SLang Hames template <> class WrapperFunctionHandlerCaller<void> {
13868c16109SLang Hames public:
13968c16109SLang Hames   template <typename HandlerT, typename ArgTupleT, std::size_t... I>
14068c16109SLang Hames   static SPSEmpty call(HandlerT &&H, ArgTupleT &Args,
14168c16109SLang Hames                        std::index_sequence<I...>) {
14268c16109SLang Hames     std::forward<HandlerT>(H)(std::get<I>(Args)...);
14368c16109SLang Hames     return SPSEmpty();
14468c16109SLang Hames   }
14568c16109SLang Hames };
14668c16109SLang Hames 
147da592413SLang Hames template <typename WrapperFunctionImplT,
148da592413SLang Hames           template <typename> class ResultSerializer, typename... SPSTagTs>
149da592413SLang Hames class WrapperFunctionHandlerHelper
150da592413SLang Hames     : public WrapperFunctionHandlerHelper<
151da592413SLang Hames           decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
152da592413SLang Hames           ResultSerializer, SPSTagTs...> {};
153da592413SLang Hames 
154da592413SLang Hames template <typename RetT, typename... ArgTs,
155da592413SLang Hames           template <typename> class ResultSerializer, typename... SPSTagTs>
156da592413SLang Hames class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
157da592413SLang Hames                                    SPSTagTs...> {
158da592413SLang Hames public:
159da592413SLang Hames   using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
160da592413SLang Hames   using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
161da592413SLang Hames 
162da592413SLang Hames   template <typename HandlerT>
163da592413SLang Hames   static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
164da592413SLang Hames                                      size_t ArgSize) {
165da592413SLang Hames     ArgTuple Args;
166da592413SLang Hames     if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
167da592413SLang Hames       return WrapperFunctionResult::createOutOfBandError(
168da592413SLang Hames           "Could not deserialize arguments for wrapper function call");
169da592413SLang Hames 
17068c16109SLang Hames     auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call(
17168c16109SLang Hames         std::forward<HandlerT>(H), Args, ArgIndices{});
17268c16109SLang Hames 
173ea9826ffSLang Hames     return ResultSerializer<decltype(HandlerResult)>::serialize(
174ea9826ffSLang Hames         std::move(HandlerResult));
175da592413SLang Hames   }
176da592413SLang Hames 
177da592413SLang Hames private:
178da592413SLang Hames   template <std::size_t... I>
179da592413SLang Hames   static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
180da592413SLang Hames                           std::index_sequence<I...>) {
181da592413SLang Hames     SPSInputBuffer IB(ArgData, ArgSize);
182da592413SLang Hames     return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
183da592413SLang Hames   }
184da592413SLang Hames };
185da592413SLang Hames 
18621369d4bSLang Hames // Map function pointers to function types.
187da592413SLang Hames template <typename RetT, typename... ArgTs,
188da592413SLang Hames           template <typename> class ResultSerializer, typename... SPSTagTs>
18921369d4bSLang Hames class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
190da592413SLang Hames                                    SPSTagTs...>
191da592413SLang Hames     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
192da592413SLang Hames                                           SPSTagTs...> {};
193da592413SLang Hames 
194da592413SLang Hames // Map non-const member function types to function types.
195da592413SLang Hames template <typename ClassT, typename RetT, typename... ArgTs,
196da592413SLang Hames           template <typename> class ResultSerializer, typename... SPSTagTs>
197da592413SLang Hames class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
198da592413SLang Hames                                    SPSTagTs...>
199da592413SLang Hames     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
200da592413SLang Hames                                           SPSTagTs...> {};
201da592413SLang Hames 
202da592413SLang Hames // Map const member function types to function types.
203da592413SLang Hames template <typename ClassT, typename RetT, typename... ArgTs,
204da592413SLang Hames           template <typename> class ResultSerializer, typename... SPSTagTs>
205da592413SLang Hames class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
206da592413SLang Hames                                    ResultSerializer, SPSTagTs...>
207da592413SLang Hames     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
208da592413SLang Hames                                           SPSTagTs...> {};
209da592413SLang Hames 
210da592413SLang Hames template <typename SPSRetTagT, typename RetT> class ResultSerializer {
211da592413SLang Hames public:
212ea9826ffSLang Hames   static WrapperFunctionResult serialize(RetT Result) {
213dc8e5e1dSLang Hames     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(Result);
214da592413SLang Hames   }
215da592413SLang Hames };
216da592413SLang Hames 
217da592413SLang Hames template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
218da592413SLang Hames public:
219ea9826ffSLang Hames   static WrapperFunctionResult serialize(Error Err) {
220dc8e5e1dSLang Hames     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
22149f4a58dSLang Hames         toSPSSerializable(std::move(Err)));
222da592413SLang Hames   }
223da592413SLang Hames };
224da592413SLang Hames 
225da592413SLang Hames template <typename SPSRetTagT, typename T>
226da592413SLang Hames class ResultSerializer<SPSRetTagT, Expected<T>> {
227da592413SLang Hames public:
228ea9826ffSLang Hames   static WrapperFunctionResult serialize(Expected<T> E) {
229dc8e5e1dSLang Hames     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
23049f4a58dSLang Hames         toSPSSerializable(std::move(E)));
231da592413SLang Hames   }
232da592413SLang Hames };
233da592413SLang Hames 
234da592413SLang Hames template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
235da592413SLang Hames public:
236da592413SLang Hames   static void makeSafe(RetT &Result) {}
237da592413SLang Hames 
238da592413SLang Hames   static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
239da592413SLang Hames     SPSInputBuffer IB(ArgData, ArgSize);
240da592413SLang Hames     if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
241da592413SLang Hames       return make_error<StringError>(
242da592413SLang Hames           "Error deserializing return value from blob in call");
243da592413SLang Hames     return Error::success();
244da592413SLang Hames   }
245da592413SLang Hames };
246da592413SLang Hames 
247da592413SLang Hames template <> class ResultDeserializer<SPSError, Error> {
248da592413SLang Hames public:
249da592413SLang Hames   static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
250da592413SLang Hames 
251da592413SLang Hames   static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
252da592413SLang Hames     SPSInputBuffer IB(ArgData, ArgSize);
253da592413SLang Hames     SPSSerializableError BSE;
254da592413SLang Hames     if (!SPSArgList<SPSError>::deserialize(IB, BSE))
255da592413SLang Hames       return make_error<StringError>(
256da592413SLang Hames           "Error deserializing return value from blob in call");
257da592413SLang Hames     Err = fromSPSSerializable(std::move(BSE));
258da592413SLang Hames     return Error::success();
259da592413SLang Hames   }
260da592413SLang Hames };
261da592413SLang Hames 
262da592413SLang Hames template <typename SPSTagT, typename T>
263da592413SLang Hames class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
264da592413SLang Hames public:
265da592413SLang Hames   static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
266da592413SLang Hames 
267da592413SLang Hames   static Error deserialize(Expected<T> &E, const char *ArgData,
268da592413SLang Hames                            size_t ArgSize) {
269da592413SLang Hames     SPSInputBuffer IB(ArgData, ArgSize);
270da592413SLang Hames     SPSSerializableExpected<T> BSE;
271da592413SLang Hames     if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
272da592413SLang Hames       return make_error<StringError>(
273da592413SLang Hames           "Error deserializing return value from blob in call");
274da592413SLang Hames     E = fromSPSSerializable(std::move(BSE));
275da592413SLang Hames     return Error::success();
276da592413SLang Hames   }
277da592413SLang Hames };
278da592413SLang Hames 
279da592413SLang Hames } // end namespace detail
280da592413SLang Hames 
281da592413SLang Hames template <typename SPSSignature> class WrapperFunction;
282da592413SLang Hames 
283da592413SLang Hames template <typename SPSRetTagT, typename... SPSTagTs>
284da592413SLang Hames class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
285da592413SLang Hames private:
286da592413SLang Hames   template <typename RetT>
287da592413SLang Hames   using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
288da592413SLang Hames 
289da592413SLang Hames public:
290*69f8923eSLang Hames   template <typename DispatchFn, typename RetT, typename... ArgTs>
291*69f8923eSLang Hames   static Error call(DispatchFn &&Dispatch, RetT &Result, const ArgTs &...Args) {
292da592413SLang Hames 
293da592413SLang Hames     // RetT might be an Error or Expected value. Set the checked flag now:
294da592413SLang Hames     // we don't want the user to have to check the unused result if this
295da592413SLang Hames     // operation fails.
296da592413SLang Hames     detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
297da592413SLang Hames 
29849f4a58dSLang Hames     auto ArgBuffer =
299dc8e5e1dSLang Hames         WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSTagTs...>>(Args...);
300ea9826ffSLang Hames     if (const char *ErrMsg = ArgBuffer.getOutOfBandError())
301ea9826ffSLang Hames       return make_error<StringError>(ErrMsg);
30249f4a58dSLang Hames 
303*69f8923eSLang Hames     WrapperFunctionResult ResultBuffer =
304*69f8923eSLang Hames         Dispatch(ArgBuffer.data(), ArgBuffer.size());
305*69f8923eSLang Hames 
306da592413SLang Hames     if (auto ErrMsg = ResultBuffer.getOutOfBandError())
307da592413SLang Hames       return make_error<StringError>(ErrMsg);
308da592413SLang Hames 
309da592413SLang Hames     return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
310da592413SLang Hames         Result, ResultBuffer.data(), ResultBuffer.size());
311da592413SLang Hames   }
312da592413SLang Hames 
313da592413SLang Hames   template <typename HandlerT>
314da592413SLang Hames   static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
315da592413SLang Hames                                       HandlerT &&Handler) {
316da592413SLang Hames     using WFHH =
317b574c52dSLang Hames         detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>,
318b574c52dSLang Hames                                              ResultSerializer, SPSTagTs...>;
319da592413SLang Hames     return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
320da592413SLang Hames   }
321da592413SLang Hames 
322da592413SLang Hames private:
323da592413SLang Hames   template <typename T> static const T &makeSerializable(const T &Value) {
324da592413SLang Hames     return Value;
325da592413SLang Hames   }
326da592413SLang Hames 
327da592413SLang Hames   static detail::SPSSerializableError makeSerializable(Error Err) {
328da592413SLang Hames     return detail::toSPSSerializable(std::move(Err));
329da592413SLang Hames   }
330da592413SLang Hames 
331da592413SLang Hames   template <typename T>
332da592413SLang Hames   static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
333da592413SLang Hames     return detail::toSPSSerializable(std::move(E));
334da592413SLang Hames   }
335da592413SLang Hames };
336da592413SLang Hames 
337da592413SLang Hames template <typename... SPSTagTs>
338da592413SLang Hames class WrapperFunction<void(SPSTagTs...)>
339da592413SLang Hames     : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
340da592413SLang Hames public:
341*69f8923eSLang Hames   template <typename DispatchFn, typename... ArgTs>
342*69f8923eSLang Hames   static Error call(DispatchFn &&Dispatch, const ArgTs &...Args) {
343da592413SLang Hames     SPSEmpty BE;
344*69f8923eSLang Hames     return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(
345*69f8923eSLang Hames         std::forward<DispatchFn>(Dispatch), BE, Args...);
346da592413SLang Hames   }
347da592413SLang Hames 
348da592413SLang Hames   using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
349da592413SLang Hames };
350da592413SLang Hames 
351b574c52dSLang Hames /// A function object that takes an ExecutorAddr as its first argument,
352b574c52dSLang Hames /// casts that address to a ClassT*, then calls the given method on that
353b574c52dSLang Hames /// pointer passing in the remaining function arguments. This utility
354b574c52dSLang Hames /// removes some of the boilerplate from writing wrappers for method calls.
355b574c52dSLang Hames ///
356b574c52dSLang Hames ///   @code{.cpp}
357b574c52dSLang Hames ///   class MyClass {
358b574c52dSLang Hames ///   public:
359b574c52dSLang Hames ///     void myMethod(uint32_t, bool) { ... }
360b574c52dSLang Hames ///   };
361b574c52dSLang Hames ///
362b574c52dSLang Hames ///   // SPS Method signature -- note MyClass object address as first argument.
363b574c52dSLang Hames ///   using SPSMyMethodWrapperSignature =
364b574c52dSLang Hames ///     SPSTuple<SPSExecutorAddr, uint32_t, bool>;
365b574c52dSLang Hames ///
366b574c52dSLang Hames ///   WrapperFunctionResult
367b574c52dSLang Hames ///   myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
368b574c52dSLang Hames ///     return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
369b574c52dSLang Hames ///        ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
370b574c52dSLang Hames ///   }
371b574c52dSLang Hames ///   @endcode
372b574c52dSLang Hames ///
373b574c52dSLang Hames template <typename RetT, typename ClassT, typename... ArgTs>
374b574c52dSLang Hames class MethodWrapperHandler {
375b574c52dSLang Hames public:
376b574c52dSLang Hames   using MethodT = RetT (ClassT::*)(ArgTs...);
377b574c52dSLang Hames   MethodWrapperHandler(MethodT M) : M(M) {}
378b574c52dSLang Hames   RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
379b574c52dSLang Hames     return (ObjAddr.toPtr<ClassT *>()->*M)(std::forward<ArgTs>(Args)...);
380b574c52dSLang Hames   }
381b574c52dSLang Hames 
382b574c52dSLang Hames private:
383b574c52dSLang Hames   MethodT M;
384b574c52dSLang Hames };
385b574c52dSLang Hames 
386b574c52dSLang Hames /// Create a MethodWrapperHandler object from the given method pointer.
387b574c52dSLang Hames template <typename RetT, typename ClassT, typename... ArgTs>
388b574c52dSLang Hames MethodWrapperHandler<RetT, ClassT, ArgTs...>
389b574c52dSLang Hames makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
390b574c52dSLang Hames   return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
391b574c52dSLang Hames }
392b574c52dSLang Hames 
393dc8e5e1dSLang Hames /// Represents a call to a wrapper function.
3940ede1b90SLang Hames class WrapperFunctionCall {
3950ede1b90SLang Hames public:
3960ede1b90SLang Hames   // FIXME: Switch to a SmallVector<char, 24> once ORC runtime has a
3970ede1b90SLang Hames   // smallvector.
3980ede1b90SLang Hames   using ArgDataBufferType = std::vector<char>;
3990ede1b90SLang Hames 
4000ede1b90SLang Hames   /// Create a WrapperFunctionCall using the given SPS serializer to serialize
4010ede1b90SLang Hames   /// the arguments.
4020ede1b90SLang Hames   template <typename SPSSerializer, typename... ArgTs>
4030ede1b90SLang Hames   static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr,
4040ede1b90SLang Hames                                               const ArgTs &...Args) {
4050ede1b90SLang Hames     ArgDataBufferType ArgData;
4060ede1b90SLang Hames     ArgData.resize(SPSSerializer::size(Args...));
4070e43f3b0SLang Hames     SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(),
4080e43f3b0SLang Hames                        ArgData.size());
4090ede1b90SLang Hames     if (SPSSerializer::serialize(OB, Args...))
4100ede1b90SLang Hames       return WrapperFunctionCall(FnAddr, std::move(ArgData));
4110ede1b90SLang Hames     return make_error<StringError>("Cannot serialize arguments for "
4120ede1b90SLang Hames                                    "AllocActionCall");
4130ede1b90SLang Hames   }
414dc8e5e1dSLang Hames 
415dc8e5e1dSLang Hames   WrapperFunctionCall() = default;
416dc8e5e1dSLang Hames 
4170ede1b90SLang Hames   /// Create a WrapperFunctionCall from a target function and arg buffer.
4180ede1b90SLang Hames   WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
4190ede1b90SLang Hames       : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
4200ede1b90SLang Hames 
4210ede1b90SLang Hames   /// Returns the address to be called.
4220ede1b90SLang Hames   const ExecutorAddr &getCallee() const { return FnAddr; }
4230ede1b90SLang Hames 
4240ede1b90SLang Hames   /// Returns the argument data.
4250ede1b90SLang Hames   const ArgDataBufferType &getArgData() const { return ArgData; }
4260ede1b90SLang Hames 
4270ede1b90SLang Hames   /// WrapperFunctionCalls convert to true if the callee is non-null.
4280ede1b90SLang Hames   explicit operator bool() const { return !!FnAddr; }
4290ede1b90SLang Hames 
4300ede1b90SLang Hames   /// Run call returning raw WrapperFunctionResult.
4310ede1b90SLang Hames   WrapperFunctionResult run() const {
4320ede1b90SLang Hames     using FnTy =
43334fccfb2SLang Hames         orc_rt_CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
4340ede1b90SLang Hames     return WrapperFunctionResult(
4350ede1b90SLang Hames         FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
436dc8e5e1dSLang Hames   }
437dc8e5e1dSLang Hames 
438dc8e5e1dSLang Hames   /// Run call and deserialize result using SPS.
4390ede1b90SLang Hames   template <typename SPSRetT, typename RetT>
4400ede1b90SLang Hames   std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
4410ede1b90SLang Hames   runWithSPSRet(RetT &RetVal) const {
442dc8e5e1dSLang Hames     auto WFR = run();
443dc8e5e1dSLang Hames     if (const char *ErrMsg = WFR.getOutOfBandError())
444dc8e5e1dSLang Hames       return make_error<StringError>(ErrMsg);
445dc8e5e1dSLang Hames     SPSInputBuffer IB(WFR.data(), WFR.size());
446dc8e5e1dSLang Hames     if (!SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
447dc8e5e1dSLang Hames       return make_error<StringError>("Could not deserialize result from "
448dc8e5e1dSLang Hames                                      "serialized wrapper function call");
449dc8e5e1dSLang Hames     return Error::success();
450dc8e5e1dSLang Hames   }
451dc8e5e1dSLang Hames 
452dc8e5e1dSLang Hames   /// Overload for SPS functions returning void.
4530ede1b90SLang Hames   template <typename SPSRetT>
4540ede1b90SLang Hames   std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
4550ede1b90SLang Hames   runWithSPSRet() const {
456dc8e5e1dSLang Hames     SPSEmpty E;
457dc8e5e1dSLang Hames     return runWithSPSRet<SPSEmpty>(E);
458dc8e5e1dSLang Hames   }
4590ede1b90SLang Hames 
4600ede1b90SLang Hames   /// Run call and deserialize an SPSError result. SPSError returns and
4610ede1b90SLang Hames   /// deserialization failures are merged into the returned error.
4620ede1b90SLang Hames   Error runWithSPSRetErrorMerged() const {
4630ede1b90SLang Hames     detail::SPSSerializableError RetErr;
4640ede1b90SLang Hames     if (auto Err = runWithSPSRet<SPSError>(RetErr))
4650ede1b90SLang Hames       return Err;
4660ede1b90SLang Hames     return detail::fromSPSSerializable(std::move(RetErr));
4670ede1b90SLang Hames   }
4680ede1b90SLang Hames 
4690ede1b90SLang Hames private:
4700ede1b90SLang Hames   ExecutorAddr FnAddr;
4710ede1b90SLang Hames   std::vector<char> ArgData;
472dc8e5e1dSLang Hames };
473dc8e5e1dSLang Hames 
4740ede1b90SLang Hames using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
475dc8e5e1dSLang Hames 
476dc8e5e1dSLang Hames template <>
477dc8e5e1dSLang Hames class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
478dc8e5e1dSLang Hames public:
479dc8e5e1dSLang Hames   static size_t size(const WrapperFunctionCall &WFC) {
4800ede1b90SLang Hames     return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::size(
4810ede1b90SLang Hames         WFC.getCallee(), WFC.getArgData());
482dc8e5e1dSLang Hames   }
483dc8e5e1dSLang Hames 
484dc8e5e1dSLang Hames   static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
4850ede1b90SLang Hames     return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::serialize(
4860ede1b90SLang Hames         OB, WFC.getCallee(), WFC.getArgData());
487dc8e5e1dSLang Hames   }
488dc8e5e1dSLang Hames 
489dc8e5e1dSLang Hames   static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
4900ede1b90SLang Hames     ExecutorAddr FnAddr;
4910ede1b90SLang Hames     WrapperFunctionCall::ArgDataBufferType ArgData;
4920ede1b90SLang Hames     if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
4930ede1b90SLang Hames       return false;
4940ede1b90SLang Hames     WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
4950ede1b90SLang Hames     return true;
496dc8e5e1dSLang Hames   }
497dc8e5e1dSLang Hames };
498dc8e5e1dSLang Hames 
4993e04ad42SLang Hames } // namespace orc_rt
500da592413SLang Hames 
501da592413SLang Hames #endif // ORC_RT_WRAPPER_FUNCTION_UTILS_H
502