xref: /openbsd-src/gnu/llvm/compiler-rt/lib/orc/wrapper_function_utils.h (revision 810390e339a5425391477d5d41c78d7cab2424ac)
1d89ec533Spatrick //===-- wrapper_function_utils.h - Utilities for wrapper funcs --*- C++ -*-===//
2d89ec533Spatrick //
3d89ec533Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4d89ec533Spatrick // See https://llvm.org/LICENSE.txt for license information.
5d89ec533Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d89ec533Spatrick //
7d89ec533Spatrick //===----------------------------------------------------------------------===//
8d89ec533Spatrick //
9d89ec533Spatrick // This file is a part of the ORC runtime support library.
10d89ec533Spatrick //
11d89ec533Spatrick //===----------------------------------------------------------------------===//
12d89ec533Spatrick 
13d89ec533Spatrick #ifndef ORC_RT_WRAPPER_FUNCTION_UTILS_H
14d89ec533Spatrick #define ORC_RT_WRAPPER_FUNCTION_UTILS_H
15d89ec533Spatrick 
16*810390e3Srobert #include "orc_rt/c_api.h"
17d89ec533Spatrick #include "common.h"
18d89ec533Spatrick #include "error.h"
19*810390e3Srobert #include "executor_address.h"
20d89ec533Spatrick #include "simple_packed_serialization.h"
21d89ec533Spatrick #include <type_traits>
22d89ec533Spatrick 
23d89ec533Spatrick namespace __orc_rt {
24d89ec533Spatrick 
25d89ec533Spatrick /// C++ wrapper function result: Same as CWrapperFunctionResult but
26d89ec533Spatrick /// auto-releases memory.
27d89ec533Spatrick class WrapperFunctionResult {
28d89ec533Spatrick public:
29d89ec533Spatrick   /// Create a default WrapperFunctionResult.
WrapperFunctionResult()30d89ec533Spatrick   WrapperFunctionResult() { __orc_rt_CWrapperFunctionResultInit(&R); }
31d89ec533Spatrick 
32d89ec533Spatrick   /// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
33d89ec533Spatrick   /// instance takes ownership of the result object and will automatically
34d89ec533Spatrick   /// call dispose on the result upon destruction.
WrapperFunctionResult(__orc_rt_CWrapperFunctionResult R)35d89ec533Spatrick   WrapperFunctionResult(__orc_rt_CWrapperFunctionResult R) : R(R) {}
36d89ec533Spatrick 
37d89ec533Spatrick   WrapperFunctionResult(const WrapperFunctionResult &) = delete;
38d89ec533Spatrick   WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
39d89ec533Spatrick 
WrapperFunctionResult(WrapperFunctionResult && Other)40d89ec533Spatrick   WrapperFunctionResult(WrapperFunctionResult &&Other) {
41d89ec533Spatrick     __orc_rt_CWrapperFunctionResultInit(&R);
42d89ec533Spatrick     std::swap(R, Other.R);
43d89ec533Spatrick   }
44d89ec533Spatrick 
45d89ec533Spatrick   WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
46d89ec533Spatrick     __orc_rt_CWrapperFunctionResult Tmp;
47d89ec533Spatrick     __orc_rt_CWrapperFunctionResultInit(&Tmp);
48d89ec533Spatrick     std::swap(Tmp, Other.R);
49d89ec533Spatrick     std::swap(R, Tmp);
50d89ec533Spatrick     return *this;
51d89ec533Spatrick   }
52d89ec533Spatrick 
~WrapperFunctionResult()53d89ec533Spatrick   ~WrapperFunctionResult() { __orc_rt_DisposeCWrapperFunctionResult(&R); }
54d89ec533Spatrick 
55d89ec533Spatrick   /// Relinquish ownership of and return the
56d89ec533Spatrick   /// __orc_rt_CWrapperFunctionResult.
release()57d89ec533Spatrick   __orc_rt_CWrapperFunctionResult release() {
58d89ec533Spatrick     __orc_rt_CWrapperFunctionResult Tmp;
59d89ec533Spatrick     __orc_rt_CWrapperFunctionResultInit(&Tmp);
60d89ec533Spatrick     std::swap(R, Tmp);
61d89ec533Spatrick     return Tmp;
62d89ec533Spatrick   }
63d89ec533Spatrick 
64d89ec533Spatrick   /// Get a pointer to the data contained in this instance.
data()65*810390e3Srobert   char *data() { return __orc_rt_CWrapperFunctionResultData(&R); }
66d89ec533Spatrick 
67d89ec533Spatrick   /// Returns the size of the data contained in this instance.
size()68d89ec533Spatrick   size_t size() const { return __orc_rt_CWrapperFunctionResultSize(&R); }
69d89ec533Spatrick 
70d89ec533Spatrick   /// Returns true if this value is equivalent to a default-constructed
71d89ec533Spatrick   /// WrapperFunctionResult.
empty()72d89ec533Spatrick   bool empty() const { return __orc_rt_CWrapperFunctionResultEmpty(&R); }
73d89ec533Spatrick 
74d89ec533Spatrick   /// Create a WrapperFunctionResult with the given size and return a pointer
75d89ec533Spatrick   /// to the underlying memory.
allocate(size_t Size)76*810390e3Srobert   static WrapperFunctionResult allocate(size_t Size) {
77*810390e3Srobert     WrapperFunctionResult R;
78*810390e3Srobert     R.R = __orc_rt_CWrapperFunctionResultAllocate(Size);
79*810390e3Srobert     return R;
80d89ec533Spatrick   }
81d89ec533Spatrick 
82d89ec533Spatrick   /// Copy from the given char range.
copyFrom(const char * Source,size_t Size)83d89ec533Spatrick   static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
84d89ec533Spatrick     return __orc_rt_CreateCWrapperFunctionResultFromRange(Source, Size);
85d89ec533Spatrick   }
86d89ec533Spatrick 
87d89ec533Spatrick   /// Copy from the given null-terminated string (includes the null-terminator).
copyFrom(const char * Source)88d89ec533Spatrick   static WrapperFunctionResult copyFrom(const char *Source) {
89d89ec533Spatrick     return __orc_rt_CreateCWrapperFunctionResultFromString(Source);
90d89ec533Spatrick   }
91d89ec533Spatrick 
92d89ec533Spatrick   /// Copy from the given std::string (includes the null terminator).
copyFrom(const std::string & Source)93d89ec533Spatrick   static WrapperFunctionResult copyFrom(const std::string &Source) {
94d89ec533Spatrick     return copyFrom(Source.c_str());
95d89ec533Spatrick   }
96d89ec533Spatrick 
97d89ec533Spatrick   /// Create an out-of-band error by copying the given string.
createOutOfBandError(const char * Msg)98d89ec533Spatrick   static WrapperFunctionResult createOutOfBandError(const char *Msg) {
99d89ec533Spatrick     return __orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(Msg);
100d89ec533Spatrick   }
101d89ec533Spatrick 
102d89ec533Spatrick   /// Create an out-of-band error by copying the given string.
createOutOfBandError(const std::string & Msg)103d89ec533Spatrick   static WrapperFunctionResult createOutOfBandError(const std::string &Msg) {
104d89ec533Spatrick     return createOutOfBandError(Msg.c_str());
105d89ec533Spatrick   }
106d89ec533Spatrick 
107*810390e3Srobert   template <typename SPSArgListT, typename... ArgTs>
fromSPSArgs(const ArgTs &...Args)108*810390e3Srobert   static WrapperFunctionResult fromSPSArgs(const ArgTs &...Args) {
109*810390e3Srobert     auto Result = allocate(SPSArgListT::size(Args...));
110*810390e3Srobert     SPSOutputBuffer OB(Result.data(), Result.size());
111*810390e3Srobert     if (!SPSArgListT::serialize(OB, Args...))
112*810390e3Srobert       return createOutOfBandError(
113*810390e3Srobert           "Error serializing arguments to blob in call");
114*810390e3Srobert     return Result;
115*810390e3Srobert   }
116*810390e3Srobert 
117d89ec533Spatrick   /// If this value is an out-of-band error then this returns the error message,
118d89ec533Spatrick   /// otherwise returns nullptr.
getOutOfBandError()119d89ec533Spatrick   const char *getOutOfBandError() const {
120d89ec533Spatrick     return __orc_rt_CWrapperFunctionResultGetOutOfBandError(&R);
121d89ec533Spatrick   }
122d89ec533Spatrick 
123d89ec533Spatrick private:
124d89ec533Spatrick   __orc_rt_CWrapperFunctionResult R;
125d89ec533Spatrick };
126d89ec533Spatrick 
127d89ec533Spatrick namespace detail {
128d89ec533Spatrick 
129d89ec533Spatrick template <typename RetT> class WrapperFunctionHandlerCaller {
130d89ec533Spatrick public:
131d89ec533Spatrick   template <typename HandlerT, typename ArgTupleT, std::size_t... I>
decltype(auto)132d89ec533Spatrick   static decltype(auto) call(HandlerT &&H, ArgTupleT &Args,
133d89ec533Spatrick                              std::index_sequence<I...>) {
134d89ec533Spatrick     return std::forward<HandlerT>(H)(std::get<I>(Args)...);
135d89ec533Spatrick   }
136d89ec533Spatrick };
137d89ec533Spatrick 
138d89ec533Spatrick template <> class WrapperFunctionHandlerCaller<void> {
139d89ec533Spatrick public:
140d89ec533Spatrick   template <typename HandlerT, typename ArgTupleT, std::size_t... I>
call(HandlerT && H,ArgTupleT & Args,std::index_sequence<I...>)141d89ec533Spatrick   static SPSEmpty call(HandlerT &&H, ArgTupleT &Args,
142d89ec533Spatrick                        std::index_sequence<I...>) {
143d89ec533Spatrick     std::forward<HandlerT>(H)(std::get<I>(Args)...);
144d89ec533Spatrick     return SPSEmpty();
145d89ec533Spatrick   }
146d89ec533Spatrick };
147d89ec533Spatrick 
148d89ec533Spatrick template <typename WrapperFunctionImplT,
149d89ec533Spatrick           template <typename> class ResultSerializer, typename... SPSTagTs>
150d89ec533Spatrick class WrapperFunctionHandlerHelper
151d89ec533Spatrick     : public WrapperFunctionHandlerHelper<
152d89ec533Spatrick           decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
153d89ec533Spatrick           ResultSerializer, SPSTagTs...> {};
154d89ec533Spatrick 
155d89ec533Spatrick template <typename RetT, typename... ArgTs,
156d89ec533Spatrick           template <typename> class ResultSerializer, typename... SPSTagTs>
157d89ec533Spatrick class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
158d89ec533Spatrick                                    SPSTagTs...> {
159d89ec533Spatrick public:
160d89ec533Spatrick   using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
161d89ec533Spatrick   using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
162d89ec533Spatrick 
163d89ec533Spatrick   template <typename HandlerT>
apply(HandlerT && H,const char * ArgData,size_t ArgSize)164d89ec533Spatrick   static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
165d89ec533Spatrick                                      size_t ArgSize) {
166d89ec533Spatrick     ArgTuple Args;
167d89ec533Spatrick     if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
168d89ec533Spatrick       return WrapperFunctionResult::createOutOfBandError(
169d89ec533Spatrick           "Could not deserialize arguments for wrapper function call");
170d89ec533Spatrick 
171d89ec533Spatrick     auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call(
172d89ec533Spatrick         std::forward<HandlerT>(H), Args, ArgIndices{});
173d89ec533Spatrick 
174*810390e3Srobert     return ResultSerializer<decltype(HandlerResult)>::serialize(
175*810390e3Srobert         std::move(HandlerResult));
176d89ec533Spatrick   }
177d89ec533Spatrick 
178d89ec533Spatrick private:
179d89ec533Spatrick   template <std::size_t... I>
deserialize(const char * ArgData,size_t ArgSize,ArgTuple & Args,std::index_sequence<I...>)180d89ec533Spatrick   static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
181d89ec533Spatrick                           std::index_sequence<I...>) {
182d89ec533Spatrick     SPSInputBuffer IB(ArgData, ArgSize);
183d89ec533Spatrick     return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
184d89ec533Spatrick   }
185d89ec533Spatrick };
186d89ec533Spatrick 
187*810390e3Srobert // Map function pointers to function types.
188d89ec533Spatrick template <typename RetT, typename... ArgTs,
189d89ec533Spatrick           template <typename> class ResultSerializer, typename... SPSTagTs>
190*810390e3Srobert class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
191d89ec533Spatrick                                    SPSTagTs...>
192d89ec533Spatrick     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
193d89ec533Spatrick                                           SPSTagTs...> {};
194d89ec533Spatrick 
195d89ec533Spatrick // Map non-const member function types to function types.
196d89ec533Spatrick template <typename ClassT, typename RetT, typename... ArgTs,
197d89ec533Spatrick           template <typename> class ResultSerializer, typename... SPSTagTs>
198d89ec533Spatrick class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
199d89ec533Spatrick                                    SPSTagTs...>
200d89ec533Spatrick     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
201d89ec533Spatrick                                           SPSTagTs...> {};
202d89ec533Spatrick 
203d89ec533Spatrick // Map const member function types to function types.
204d89ec533Spatrick template <typename ClassT, typename RetT, typename... ArgTs,
205d89ec533Spatrick           template <typename> class ResultSerializer, typename... SPSTagTs>
206d89ec533Spatrick class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
207d89ec533Spatrick                                    ResultSerializer, SPSTagTs...>
208d89ec533Spatrick     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
209d89ec533Spatrick                                           SPSTagTs...> {};
210d89ec533Spatrick 
211d89ec533Spatrick template <typename SPSRetTagT, typename RetT> class ResultSerializer {
212d89ec533Spatrick public:
serialize(RetT Result)213*810390e3Srobert   static WrapperFunctionResult serialize(RetT Result) {
214*810390e3Srobert     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(Result);
215d89ec533Spatrick   }
216d89ec533Spatrick };
217d89ec533Spatrick 
218d89ec533Spatrick template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
219d89ec533Spatrick public:
serialize(Error Err)220*810390e3Srobert   static WrapperFunctionResult serialize(Error Err) {
221*810390e3Srobert     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
222d89ec533Spatrick         toSPSSerializable(std::move(Err)));
223d89ec533Spatrick   }
224d89ec533Spatrick };
225d89ec533Spatrick 
226d89ec533Spatrick template <typename SPSRetTagT, typename T>
227d89ec533Spatrick class ResultSerializer<SPSRetTagT, Expected<T>> {
228d89ec533Spatrick public:
serialize(Expected<T> E)229*810390e3Srobert   static WrapperFunctionResult serialize(Expected<T> E) {
230*810390e3Srobert     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
231d89ec533Spatrick         toSPSSerializable(std::move(E)));
232d89ec533Spatrick   }
233d89ec533Spatrick };
234d89ec533Spatrick 
235d89ec533Spatrick template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
236d89ec533Spatrick public:
makeSafe(RetT & Result)237d89ec533Spatrick   static void makeSafe(RetT &Result) {}
238d89ec533Spatrick 
deserialize(RetT & Result,const char * ArgData,size_t ArgSize)239d89ec533Spatrick   static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
240d89ec533Spatrick     SPSInputBuffer IB(ArgData, ArgSize);
241d89ec533Spatrick     if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
242d89ec533Spatrick       return make_error<StringError>(
243d89ec533Spatrick           "Error deserializing return value from blob in call");
244d89ec533Spatrick     return Error::success();
245d89ec533Spatrick   }
246d89ec533Spatrick };
247d89ec533Spatrick 
248d89ec533Spatrick template <> class ResultDeserializer<SPSError, Error> {
249d89ec533Spatrick public:
makeSafe(Error & Err)250d89ec533Spatrick   static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
251d89ec533Spatrick 
deserialize(Error & Err,const char * ArgData,size_t ArgSize)252d89ec533Spatrick   static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
253d89ec533Spatrick     SPSInputBuffer IB(ArgData, ArgSize);
254d89ec533Spatrick     SPSSerializableError BSE;
255d89ec533Spatrick     if (!SPSArgList<SPSError>::deserialize(IB, BSE))
256d89ec533Spatrick       return make_error<StringError>(
257d89ec533Spatrick           "Error deserializing return value from blob in call");
258d89ec533Spatrick     Err = fromSPSSerializable(std::move(BSE));
259d89ec533Spatrick     return Error::success();
260d89ec533Spatrick   }
261d89ec533Spatrick };
262d89ec533Spatrick 
263d89ec533Spatrick template <typename SPSTagT, typename T>
264d89ec533Spatrick class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
265d89ec533Spatrick public:
makeSafe(Expected<T> & E)266d89ec533Spatrick   static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
267d89ec533Spatrick 
deserialize(Expected<T> & E,const char * ArgData,size_t ArgSize)268d89ec533Spatrick   static Error deserialize(Expected<T> &E, const char *ArgData,
269d89ec533Spatrick                            size_t ArgSize) {
270d89ec533Spatrick     SPSInputBuffer IB(ArgData, ArgSize);
271d89ec533Spatrick     SPSSerializableExpected<T> BSE;
272d89ec533Spatrick     if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
273d89ec533Spatrick       return make_error<StringError>(
274d89ec533Spatrick           "Error deserializing return value from blob in call");
275d89ec533Spatrick     E = fromSPSSerializable(std::move(BSE));
276d89ec533Spatrick     return Error::success();
277d89ec533Spatrick   }
278d89ec533Spatrick };
279d89ec533Spatrick 
280d89ec533Spatrick } // end namespace detail
281d89ec533Spatrick 
282d89ec533Spatrick template <typename SPSSignature> class WrapperFunction;
283d89ec533Spatrick 
284d89ec533Spatrick template <typename SPSRetTagT, typename... SPSTagTs>
285d89ec533Spatrick class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
286d89ec533Spatrick private:
287d89ec533Spatrick   template <typename RetT>
288d89ec533Spatrick   using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
289d89ec533Spatrick 
290d89ec533Spatrick public:
291d89ec533Spatrick   template <typename RetT, typename... ArgTs>
call(const void * FnTag,RetT & Result,const ArgTs &...Args)292d89ec533Spatrick   static Error call(const void *FnTag, RetT &Result, const ArgTs &...Args) {
293d89ec533Spatrick 
294d89ec533Spatrick     // RetT might be an Error or Expected value. Set the checked flag now:
295d89ec533Spatrick     // we don't want the user to have to check the unused result if this
296d89ec533Spatrick     // operation fails.
297d89ec533Spatrick     detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
298d89ec533Spatrick 
299d89ec533Spatrick     if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch_ctx))
300d89ec533Spatrick       return make_error<StringError>("__orc_rt_jit_dispatch_ctx not set");
301d89ec533Spatrick     if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch))
302d89ec533Spatrick       return make_error<StringError>("__orc_rt_jit_dispatch not set");
303d89ec533Spatrick 
304d89ec533Spatrick     auto ArgBuffer =
305*810390e3Srobert         WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSTagTs...>>(Args...);
306*810390e3Srobert     if (const char *ErrMsg = ArgBuffer.getOutOfBandError())
307*810390e3Srobert       return make_error<StringError>(ErrMsg);
308d89ec533Spatrick 
309*810390e3Srobert     WrapperFunctionResult ResultBuffer = __orc_rt_jit_dispatch(
310*810390e3Srobert         &__orc_rt_jit_dispatch_ctx, FnTag, ArgBuffer.data(), ArgBuffer.size());
311d89ec533Spatrick     if (auto ErrMsg = ResultBuffer.getOutOfBandError())
312d89ec533Spatrick       return make_error<StringError>(ErrMsg);
313d89ec533Spatrick 
314d89ec533Spatrick     return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
315d89ec533Spatrick         Result, ResultBuffer.data(), ResultBuffer.size());
316d89ec533Spatrick   }
317d89ec533Spatrick 
318d89ec533Spatrick   template <typename HandlerT>
handle(const char * ArgData,size_t ArgSize,HandlerT && Handler)319d89ec533Spatrick   static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
320d89ec533Spatrick                                       HandlerT &&Handler) {
321d89ec533Spatrick     using WFHH =
322*810390e3Srobert         detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>,
323*810390e3Srobert                                              ResultSerializer, SPSTagTs...>;
324d89ec533Spatrick     return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
325d89ec533Spatrick   }
326d89ec533Spatrick 
327d89ec533Spatrick private:
makeSerializable(const T & Value)328d89ec533Spatrick   template <typename T> static const T &makeSerializable(const T &Value) {
329d89ec533Spatrick     return Value;
330d89ec533Spatrick   }
331d89ec533Spatrick 
makeSerializable(Error Err)332d89ec533Spatrick   static detail::SPSSerializableError makeSerializable(Error Err) {
333d89ec533Spatrick     return detail::toSPSSerializable(std::move(Err));
334d89ec533Spatrick   }
335d89ec533Spatrick 
336d89ec533Spatrick   template <typename T>
makeSerializable(Expected<T> E)337d89ec533Spatrick   static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
338d89ec533Spatrick     return detail::toSPSSerializable(std::move(E));
339d89ec533Spatrick   }
340d89ec533Spatrick };
341d89ec533Spatrick 
342d89ec533Spatrick template <typename... SPSTagTs>
343d89ec533Spatrick class WrapperFunction<void(SPSTagTs...)>
344d89ec533Spatrick     : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
345d89ec533Spatrick public:
346d89ec533Spatrick   template <typename... ArgTs>
call(const void * FnTag,const ArgTs &...Args)347d89ec533Spatrick   static Error call(const void *FnTag, const ArgTs &...Args) {
348d89ec533Spatrick     SPSEmpty BE;
349d89ec533Spatrick     return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(FnTag, BE, Args...);
350d89ec533Spatrick   }
351d89ec533Spatrick 
352d89ec533Spatrick   using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
353d89ec533Spatrick };
354d89ec533Spatrick 
355*810390e3Srobert /// A function object that takes an ExecutorAddr as its first argument,
356*810390e3Srobert /// casts that address to a ClassT*, then calls the given method on that
357*810390e3Srobert /// pointer passing in the remaining function arguments. This utility
358*810390e3Srobert /// removes some of the boilerplate from writing wrappers for method calls.
359*810390e3Srobert ///
360*810390e3Srobert ///   @code{.cpp}
361*810390e3Srobert ///   class MyClass {
362*810390e3Srobert ///   public:
363*810390e3Srobert ///     void myMethod(uint32_t, bool) { ... }
364*810390e3Srobert ///   };
365*810390e3Srobert ///
366*810390e3Srobert ///   // SPS Method signature -- note MyClass object address as first argument.
367*810390e3Srobert ///   using SPSMyMethodWrapperSignature =
368*810390e3Srobert ///     SPSTuple<SPSExecutorAddr, uint32_t, bool>;
369*810390e3Srobert ///
370*810390e3Srobert ///   WrapperFunctionResult
371*810390e3Srobert ///   myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
372*810390e3Srobert ///     return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
373*810390e3Srobert ///        ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
374*810390e3Srobert ///   }
375*810390e3Srobert ///   @endcode
376*810390e3Srobert ///
377*810390e3Srobert template <typename RetT, typename ClassT, typename... ArgTs>
378*810390e3Srobert class MethodWrapperHandler {
379*810390e3Srobert public:
380*810390e3Srobert   using MethodT = RetT (ClassT::*)(ArgTs...);
MethodWrapperHandler(MethodT M)381*810390e3Srobert   MethodWrapperHandler(MethodT M) : M(M) {}
operator()382*810390e3Srobert   RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
383*810390e3Srobert     return (ObjAddr.toPtr<ClassT *>()->*M)(std::forward<ArgTs>(Args)...);
384*810390e3Srobert   }
385*810390e3Srobert 
386*810390e3Srobert private:
387*810390e3Srobert   MethodT M;
388*810390e3Srobert };
389*810390e3Srobert 
390*810390e3Srobert /// Create a MethodWrapperHandler object from the given method pointer.
391*810390e3Srobert template <typename RetT, typename ClassT, typename... ArgTs>
392*810390e3Srobert MethodWrapperHandler<RetT, ClassT, ArgTs...>
makeMethodWrapperHandler(RetT (ClassT::* Method)(ArgTs...))393*810390e3Srobert makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
394*810390e3Srobert   return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
395*810390e3Srobert }
396*810390e3Srobert 
397*810390e3Srobert /// Represents a call to a wrapper function.
398*810390e3Srobert class WrapperFunctionCall {
399*810390e3Srobert public:
400*810390e3Srobert   // FIXME: Switch to a SmallVector<char, 24> once ORC runtime has a
401*810390e3Srobert   // smallvector.
402*810390e3Srobert   using ArgDataBufferType = std::vector<char>;
403*810390e3Srobert 
404*810390e3Srobert   /// Create a WrapperFunctionCall using the given SPS serializer to serialize
405*810390e3Srobert   /// the arguments.
406*810390e3Srobert   template <typename SPSSerializer, typename... ArgTs>
Create(ExecutorAddr FnAddr,const ArgTs &...Args)407*810390e3Srobert   static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr,
408*810390e3Srobert                                               const ArgTs &...Args) {
409*810390e3Srobert     ArgDataBufferType ArgData;
410*810390e3Srobert     ArgData.resize(SPSSerializer::size(Args...));
411*810390e3Srobert     SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(),
412*810390e3Srobert                        ArgData.size());
413*810390e3Srobert     if (SPSSerializer::serialize(OB, Args...))
414*810390e3Srobert       return WrapperFunctionCall(FnAddr, std::move(ArgData));
415*810390e3Srobert     return make_error<StringError>("Cannot serialize arguments for "
416*810390e3Srobert                                    "AllocActionCall");
417*810390e3Srobert   }
418*810390e3Srobert 
419*810390e3Srobert   WrapperFunctionCall() = default;
420*810390e3Srobert 
421*810390e3Srobert   /// Create a WrapperFunctionCall from a target function and arg buffer.
WrapperFunctionCall(ExecutorAddr FnAddr,ArgDataBufferType ArgData)422*810390e3Srobert   WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
423*810390e3Srobert       : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
424*810390e3Srobert 
425*810390e3Srobert   /// Returns the address to be called.
getCallee()426*810390e3Srobert   const ExecutorAddr &getCallee() const { return FnAddr; }
427*810390e3Srobert 
428*810390e3Srobert   /// Returns the argument data.
getArgData()429*810390e3Srobert   const ArgDataBufferType &getArgData() const { return ArgData; }
430*810390e3Srobert 
431*810390e3Srobert   /// WrapperFunctionCalls convert to true if the callee is non-null.
432*810390e3Srobert   explicit operator bool() const { return !!FnAddr; }
433*810390e3Srobert 
434*810390e3Srobert   /// Run call returning raw WrapperFunctionResult.
run()435*810390e3Srobert   WrapperFunctionResult run() const {
436*810390e3Srobert     using FnTy =
437*810390e3Srobert         __orc_rt_CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
438*810390e3Srobert     return WrapperFunctionResult(
439*810390e3Srobert         FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
440*810390e3Srobert   }
441*810390e3Srobert 
442*810390e3Srobert   /// Run call and deserialize result using SPS.
443*810390e3Srobert   template <typename SPSRetT, typename RetT>
444*810390e3Srobert   std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
runWithSPSRet(RetT & RetVal)445*810390e3Srobert   runWithSPSRet(RetT &RetVal) const {
446*810390e3Srobert     auto WFR = run();
447*810390e3Srobert     if (const char *ErrMsg = WFR.getOutOfBandError())
448*810390e3Srobert       return make_error<StringError>(ErrMsg);
449*810390e3Srobert     SPSInputBuffer IB(WFR.data(), WFR.size());
450*810390e3Srobert     if (!SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
451*810390e3Srobert       return make_error<StringError>("Could not deserialize result from "
452*810390e3Srobert                                      "serialized wrapper function call");
453*810390e3Srobert     return Error::success();
454*810390e3Srobert   }
455*810390e3Srobert 
456*810390e3Srobert   /// Overload for SPS functions returning void.
457*810390e3Srobert   template <typename SPSRetT>
458*810390e3Srobert   std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
runWithSPSRet()459*810390e3Srobert   runWithSPSRet() const {
460*810390e3Srobert     SPSEmpty E;
461*810390e3Srobert     return runWithSPSRet<SPSEmpty>(E);
462*810390e3Srobert   }
463*810390e3Srobert 
464*810390e3Srobert   /// Run call and deserialize an SPSError result. SPSError returns and
465*810390e3Srobert   /// deserialization failures are merged into the returned error.
runWithSPSRetErrorMerged()466*810390e3Srobert   Error runWithSPSRetErrorMerged() const {
467*810390e3Srobert     detail::SPSSerializableError RetErr;
468*810390e3Srobert     if (auto Err = runWithSPSRet<SPSError>(RetErr))
469*810390e3Srobert       return Err;
470*810390e3Srobert     return detail::fromSPSSerializable(std::move(RetErr));
471*810390e3Srobert   }
472*810390e3Srobert 
473*810390e3Srobert private:
474*810390e3Srobert   ExecutorAddr FnAddr;
475*810390e3Srobert   std::vector<char> ArgData;
476*810390e3Srobert };
477*810390e3Srobert 
478*810390e3Srobert using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
479*810390e3Srobert 
480*810390e3Srobert template <>
481*810390e3Srobert class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
482*810390e3Srobert public:
size(const WrapperFunctionCall & WFC)483*810390e3Srobert   static size_t size(const WrapperFunctionCall &WFC) {
484*810390e3Srobert     return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::size(
485*810390e3Srobert         WFC.getCallee(), WFC.getArgData());
486*810390e3Srobert   }
487*810390e3Srobert 
serialize(SPSOutputBuffer & OB,const WrapperFunctionCall & WFC)488*810390e3Srobert   static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
489*810390e3Srobert     return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::serialize(
490*810390e3Srobert         OB, WFC.getCallee(), WFC.getArgData());
491*810390e3Srobert   }
492*810390e3Srobert 
deserialize(SPSInputBuffer & IB,WrapperFunctionCall & WFC)493*810390e3Srobert   static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
494*810390e3Srobert     ExecutorAddr FnAddr;
495*810390e3Srobert     WrapperFunctionCall::ArgDataBufferType ArgData;
496*810390e3Srobert     if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
497*810390e3Srobert       return false;
498*810390e3Srobert     WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
499*810390e3Srobert     return true;
500*810390e3Srobert   }
501*810390e3Srobert };
502*810390e3Srobert 
503d89ec533Spatrick } // end namespace __orc_rt
504d89ec533Spatrick 
505d89ec533Spatrick #endif // ORC_RT_WRAPPER_FUNCTION_UTILS_H
506