xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/orc/wrapper_function_utils.h (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
1fe6060f1SDimitry Andric //===-- wrapper_function_utils.h - Utilities for wrapper funcs --*- C++ -*-===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric //
9fe6060f1SDimitry Andric // This file is a part of the ORC runtime support library.
10fe6060f1SDimitry Andric //
11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
12fe6060f1SDimitry Andric 
13fe6060f1SDimitry Andric #ifndef ORC_RT_WRAPPER_FUNCTION_UTILS_H
14fe6060f1SDimitry Andric #define ORC_RT_WRAPPER_FUNCTION_UTILS_H
15fe6060f1SDimitry Andric 
16bdd1243dSDimitry Andric #include "orc_rt/c_api.h"
17fe6060f1SDimitry Andric #include "common.h"
18fe6060f1SDimitry Andric #include "error.h"
19349cc55cSDimitry Andric #include "executor_address.h"
20fe6060f1SDimitry Andric #include "simple_packed_serialization.h"
21fe6060f1SDimitry Andric #include <type_traits>
22fe6060f1SDimitry Andric 
23fe6060f1SDimitry Andric namespace __orc_rt {
24fe6060f1SDimitry Andric 
25fe6060f1SDimitry Andric /// C++ wrapper function result: Same as CWrapperFunctionResult but
26fe6060f1SDimitry Andric /// auto-releases memory.
27fe6060f1SDimitry Andric class WrapperFunctionResult {
28fe6060f1SDimitry Andric public:
29fe6060f1SDimitry Andric   /// Create a default WrapperFunctionResult.
WrapperFunctionResult()3006c3fb27SDimitry Andric   WrapperFunctionResult() { orc_rt_CWrapperFunctionResultInit(&R); }
31fe6060f1SDimitry Andric 
32fe6060f1SDimitry Andric   /// Create a WrapperFunctionResult from a CWrapperFunctionResult. This
33fe6060f1SDimitry Andric   /// instance takes ownership of the result object and will automatically
34fe6060f1SDimitry Andric   /// call dispose on the result upon destruction.
WrapperFunctionResult(orc_rt_CWrapperFunctionResult R)3506c3fb27SDimitry Andric   WrapperFunctionResult(orc_rt_CWrapperFunctionResult R) : R(R) {}
36fe6060f1SDimitry Andric 
37fe6060f1SDimitry Andric   WrapperFunctionResult(const WrapperFunctionResult &) = delete;
38fe6060f1SDimitry Andric   WrapperFunctionResult &operator=(const WrapperFunctionResult &) = delete;
39fe6060f1SDimitry Andric 
WrapperFunctionResult(WrapperFunctionResult && Other)40fe6060f1SDimitry Andric   WrapperFunctionResult(WrapperFunctionResult &&Other) {
4106c3fb27SDimitry Andric     orc_rt_CWrapperFunctionResultInit(&R);
42fe6060f1SDimitry Andric     std::swap(R, Other.R);
43fe6060f1SDimitry Andric   }
44fe6060f1SDimitry Andric 
45fe6060f1SDimitry Andric   WrapperFunctionResult &operator=(WrapperFunctionResult &&Other) {
4606c3fb27SDimitry Andric     orc_rt_CWrapperFunctionResult Tmp;
4706c3fb27SDimitry Andric     orc_rt_CWrapperFunctionResultInit(&Tmp);
48fe6060f1SDimitry Andric     std::swap(Tmp, Other.R);
49fe6060f1SDimitry Andric     std::swap(R, Tmp);
50fe6060f1SDimitry Andric     return *this;
51fe6060f1SDimitry Andric   }
52fe6060f1SDimitry Andric 
~WrapperFunctionResult()5306c3fb27SDimitry Andric   ~WrapperFunctionResult() { orc_rt_DisposeCWrapperFunctionResult(&R); }
54fe6060f1SDimitry Andric 
55fe6060f1SDimitry Andric   /// Relinquish ownership of and return the
5606c3fb27SDimitry Andric   /// orc_rt_CWrapperFunctionResult.
release()5706c3fb27SDimitry Andric   orc_rt_CWrapperFunctionResult release() {
5806c3fb27SDimitry Andric     orc_rt_CWrapperFunctionResult Tmp;
5906c3fb27SDimitry Andric     orc_rt_CWrapperFunctionResultInit(&Tmp);
60fe6060f1SDimitry Andric     std::swap(R, Tmp);
61fe6060f1SDimitry Andric     return Tmp;
62fe6060f1SDimitry Andric   }
63fe6060f1SDimitry Andric 
64fe6060f1SDimitry Andric   /// Get a pointer to the data contained in this instance.
data()6506c3fb27SDimitry Andric   char *data() { return orc_rt_CWrapperFunctionResultData(&R); }
66fe6060f1SDimitry Andric 
67fe6060f1SDimitry Andric   /// Returns the size of the data contained in this instance.
size()6806c3fb27SDimitry Andric   size_t size() const { return orc_rt_CWrapperFunctionResultSize(&R); }
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric   /// Returns true if this value is equivalent to a default-constructed
71fe6060f1SDimitry Andric   /// WrapperFunctionResult.
empty()7206c3fb27SDimitry Andric   bool empty() const { return orc_rt_CWrapperFunctionResultEmpty(&R); }
73fe6060f1SDimitry Andric 
74fe6060f1SDimitry Andric   /// Create a WrapperFunctionResult with the given size and return a pointer
75fe6060f1SDimitry Andric   /// to the underlying memory.
allocate(size_t Size)76349cc55cSDimitry Andric   static WrapperFunctionResult allocate(size_t Size) {
77349cc55cSDimitry Andric     WrapperFunctionResult R;
7806c3fb27SDimitry Andric     R.R = orc_rt_CWrapperFunctionResultAllocate(Size);
79349cc55cSDimitry Andric     return R;
80fe6060f1SDimitry Andric   }
81fe6060f1SDimitry Andric 
82fe6060f1SDimitry Andric   /// Copy from the given char range.
copyFrom(const char * Source,size_t Size)83fe6060f1SDimitry Andric   static WrapperFunctionResult copyFrom(const char *Source, size_t Size) {
8406c3fb27SDimitry Andric     return orc_rt_CreateCWrapperFunctionResultFromRange(Source, Size);
85fe6060f1SDimitry Andric   }
86fe6060f1SDimitry Andric 
87fe6060f1SDimitry Andric   /// Copy from the given null-terminated string (includes the null-terminator).
copyFrom(const char * Source)88fe6060f1SDimitry Andric   static WrapperFunctionResult copyFrom(const char *Source) {
8906c3fb27SDimitry Andric     return orc_rt_CreateCWrapperFunctionResultFromString(Source);
90fe6060f1SDimitry Andric   }
91fe6060f1SDimitry Andric 
92fe6060f1SDimitry Andric   /// Copy from the given std::string (includes the null terminator).
copyFrom(const std::string & Source)93fe6060f1SDimitry Andric   static WrapperFunctionResult copyFrom(const std::string &Source) {
94fe6060f1SDimitry Andric     return copyFrom(Source.c_str());
95fe6060f1SDimitry Andric   }
96fe6060f1SDimitry Andric 
97fe6060f1SDimitry Andric   /// Create an out-of-band error by copying the given string.
createOutOfBandError(const char * Msg)98fe6060f1SDimitry Andric   static WrapperFunctionResult createOutOfBandError(const char *Msg) {
9906c3fb27SDimitry Andric     return orc_rt_CreateCWrapperFunctionResultFromOutOfBandError(Msg);
100fe6060f1SDimitry Andric   }
101fe6060f1SDimitry Andric 
102fe6060f1SDimitry Andric   /// Create an out-of-band error by copying the given string.
createOutOfBandError(const std::string & Msg)103fe6060f1SDimitry Andric   static WrapperFunctionResult createOutOfBandError(const std::string &Msg) {
104fe6060f1SDimitry Andric     return createOutOfBandError(Msg.c_str());
105fe6060f1SDimitry Andric   }
106fe6060f1SDimitry Andric 
107349cc55cSDimitry Andric   template <typename SPSArgListT, typename... ArgTs>
fromSPSArgs(const ArgTs &...Args)108349cc55cSDimitry Andric   static WrapperFunctionResult fromSPSArgs(const ArgTs &...Args) {
109349cc55cSDimitry Andric     auto Result = allocate(SPSArgListT::size(Args...));
110349cc55cSDimitry Andric     SPSOutputBuffer OB(Result.data(), Result.size());
111349cc55cSDimitry Andric     if (!SPSArgListT::serialize(OB, Args...))
112349cc55cSDimitry Andric       return createOutOfBandError(
113349cc55cSDimitry Andric           "Error serializing arguments to blob in call");
114349cc55cSDimitry Andric     return Result;
115349cc55cSDimitry Andric   }
116349cc55cSDimitry Andric 
117fe6060f1SDimitry Andric   /// If this value is an out-of-band error then this returns the error message,
118fe6060f1SDimitry Andric   /// otherwise returns nullptr.
getOutOfBandError()119fe6060f1SDimitry Andric   const char *getOutOfBandError() const {
12006c3fb27SDimitry Andric     return orc_rt_CWrapperFunctionResultGetOutOfBandError(&R);
121fe6060f1SDimitry Andric   }
122fe6060f1SDimitry Andric 
123fe6060f1SDimitry Andric private:
12406c3fb27SDimitry Andric   orc_rt_CWrapperFunctionResult R;
125fe6060f1SDimitry Andric };
126fe6060f1SDimitry Andric 
127fe6060f1SDimitry Andric namespace detail {
128fe6060f1SDimitry Andric 
129fe6060f1SDimitry Andric template <typename RetT> class WrapperFunctionHandlerCaller {
130fe6060f1SDimitry Andric public:
131fe6060f1SDimitry Andric   template <typename HandlerT, typename ArgTupleT, std::size_t... I>
decltype(auto)132fe6060f1SDimitry Andric   static decltype(auto) call(HandlerT &&H, ArgTupleT &Args,
133fe6060f1SDimitry Andric                              std::index_sequence<I...>) {
134fe6060f1SDimitry Andric     return std::forward<HandlerT>(H)(std::get<I>(Args)...);
135fe6060f1SDimitry Andric   }
136fe6060f1SDimitry Andric };
137fe6060f1SDimitry Andric 
138fe6060f1SDimitry Andric template <> class WrapperFunctionHandlerCaller<void> {
139fe6060f1SDimitry Andric public:
140fe6060f1SDimitry Andric   template <typename HandlerT, typename ArgTupleT, std::size_t... I>
call(HandlerT && H,ArgTupleT & Args,std::index_sequence<I...>)141fe6060f1SDimitry Andric   static SPSEmpty call(HandlerT &&H, ArgTupleT &Args,
142fe6060f1SDimitry Andric                        std::index_sequence<I...>) {
143fe6060f1SDimitry Andric     std::forward<HandlerT>(H)(std::get<I>(Args)...);
144fe6060f1SDimitry Andric     return SPSEmpty();
145fe6060f1SDimitry Andric   }
146fe6060f1SDimitry Andric };
147fe6060f1SDimitry Andric 
148fe6060f1SDimitry Andric template <typename WrapperFunctionImplT,
149fe6060f1SDimitry Andric           template <typename> class ResultSerializer, typename... SPSTagTs>
150fe6060f1SDimitry Andric class WrapperFunctionHandlerHelper
151fe6060f1SDimitry Andric     : public WrapperFunctionHandlerHelper<
152fe6060f1SDimitry Andric           decltype(&std::remove_reference_t<WrapperFunctionImplT>::operator()),
153fe6060f1SDimitry Andric           ResultSerializer, SPSTagTs...> {};
154fe6060f1SDimitry Andric 
155fe6060f1SDimitry Andric template <typename RetT, typename... ArgTs,
156fe6060f1SDimitry Andric           template <typename> class ResultSerializer, typename... SPSTagTs>
157fe6060f1SDimitry Andric class WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
158fe6060f1SDimitry Andric                                    SPSTagTs...> {
159fe6060f1SDimitry Andric public:
160fe6060f1SDimitry Andric   using ArgTuple = std::tuple<std::decay_t<ArgTs>...>;
161fe6060f1SDimitry Andric   using ArgIndices = std::make_index_sequence<std::tuple_size<ArgTuple>::value>;
162fe6060f1SDimitry Andric 
163fe6060f1SDimitry Andric   template <typename HandlerT>
apply(HandlerT && H,const char * ArgData,size_t ArgSize)164fe6060f1SDimitry Andric   static WrapperFunctionResult apply(HandlerT &&H, const char *ArgData,
165fe6060f1SDimitry Andric                                      size_t ArgSize) {
166fe6060f1SDimitry Andric     ArgTuple Args;
167fe6060f1SDimitry Andric     if (!deserialize(ArgData, ArgSize, Args, ArgIndices{}))
168fe6060f1SDimitry Andric       return WrapperFunctionResult::createOutOfBandError(
169fe6060f1SDimitry Andric           "Could not deserialize arguments for wrapper function call");
170fe6060f1SDimitry Andric 
171fe6060f1SDimitry Andric     auto HandlerResult = WrapperFunctionHandlerCaller<RetT>::call(
172fe6060f1SDimitry Andric         std::forward<HandlerT>(H), Args, ArgIndices{});
173fe6060f1SDimitry Andric 
174349cc55cSDimitry Andric     return ResultSerializer<decltype(HandlerResult)>::serialize(
175349cc55cSDimitry Andric         std::move(HandlerResult));
176fe6060f1SDimitry Andric   }
177fe6060f1SDimitry Andric 
178fe6060f1SDimitry Andric private:
179fe6060f1SDimitry Andric   template <std::size_t... I>
deserialize(const char * ArgData,size_t ArgSize,ArgTuple & Args,std::index_sequence<I...>)180fe6060f1SDimitry Andric   static bool deserialize(const char *ArgData, size_t ArgSize, ArgTuple &Args,
181fe6060f1SDimitry Andric                           std::index_sequence<I...>) {
182fe6060f1SDimitry Andric     SPSInputBuffer IB(ArgData, ArgSize);
183fe6060f1SDimitry Andric     return SPSArgList<SPSTagTs...>::deserialize(IB, std::get<I>(Args)...);
184fe6060f1SDimitry Andric   }
185fe6060f1SDimitry Andric };
186fe6060f1SDimitry Andric 
187349cc55cSDimitry Andric // Map function pointers to function types.
188fe6060f1SDimitry Andric template <typename RetT, typename... ArgTs,
189fe6060f1SDimitry Andric           template <typename> class ResultSerializer, typename... SPSTagTs>
190349cc55cSDimitry Andric class WrapperFunctionHandlerHelper<RetT (*)(ArgTs...), ResultSerializer,
191fe6060f1SDimitry Andric                                    SPSTagTs...>
192fe6060f1SDimitry Andric     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
193fe6060f1SDimitry Andric                                           SPSTagTs...> {};
194fe6060f1SDimitry Andric 
195fe6060f1SDimitry Andric // Map non-const member function types to function types.
196fe6060f1SDimitry Andric template <typename ClassT, typename RetT, typename... ArgTs,
197fe6060f1SDimitry Andric           template <typename> class ResultSerializer, typename... SPSTagTs>
198fe6060f1SDimitry Andric class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...), ResultSerializer,
199fe6060f1SDimitry Andric                                    SPSTagTs...>
200fe6060f1SDimitry Andric     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
201fe6060f1SDimitry Andric                                           SPSTagTs...> {};
202fe6060f1SDimitry Andric 
203fe6060f1SDimitry Andric // Map const member function types to function types.
204fe6060f1SDimitry Andric template <typename ClassT, typename RetT, typename... ArgTs,
205fe6060f1SDimitry Andric           template <typename> class ResultSerializer, typename... SPSTagTs>
206fe6060f1SDimitry Andric class WrapperFunctionHandlerHelper<RetT (ClassT::*)(ArgTs...) const,
207fe6060f1SDimitry Andric                                    ResultSerializer, SPSTagTs...>
208fe6060f1SDimitry Andric     : public WrapperFunctionHandlerHelper<RetT(ArgTs...), ResultSerializer,
209fe6060f1SDimitry Andric                                           SPSTagTs...> {};
210fe6060f1SDimitry Andric 
211fe6060f1SDimitry Andric template <typename SPSRetTagT, typename RetT> class ResultSerializer {
212fe6060f1SDimitry Andric public:
serialize(RetT Result)213349cc55cSDimitry Andric   static WrapperFunctionResult serialize(RetT Result) {
214349cc55cSDimitry Andric     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(Result);
215fe6060f1SDimitry Andric   }
216fe6060f1SDimitry Andric };
217fe6060f1SDimitry Andric 
218fe6060f1SDimitry Andric template <typename SPSRetTagT> class ResultSerializer<SPSRetTagT, Error> {
219fe6060f1SDimitry Andric public:
serialize(Error Err)220349cc55cSDimitry Andric   static WrapperFunctionResult serialize(Error Err) {
221349cc55cSDimitry Andric     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
222fe6060f1SDimitry Andric         toSPSSerializable(std::move(Err)));
223fe6060f1SDimitry Andric   }
224fe6060f1SDimitry Andric };
225fe6060f1SDimitry Andric 
226fe6060f1SDimitry Andric template <typename SPSRetTagT, typename T>
227fe6060f1SDimitry Andric class ResultSerializer<SPSRetTagT, Expected<T>> {
228fe6060f1SDimitry Andric public:
serialize(Expected<T> E)229349cc55cSDimitry Andric   static WrapperFunctionResult serialize(Expected<T> E) {
230349cc55cSDimitry Andric     return WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSRetTagT>>(
231fe6060f1SDimitry Andric         toSPSSerializable(std::move(E)));
232fe6060f1SDimitry Andric   }
233fe6060f1SDimitry Andric };
234fe6060f1SDimitry Andric 
235fe6060f1SDimitry Andric template <typename SPSRetTagT, typename RetT> class ResultDeserializer {
236fe6060f1SDimitry Andric public:
makeSafe(RetT & Result)237fe6060f1SDimitry Andric   static void makeSafe(RetT &Result) {}
238fe6060f1SDimitry Andric 
deserialize(RetT & Result,const char * ArgData,size_t ArgSize)239fe6060f1SDimitry Andric   static Error deserialize(RetT &Result, const char *ArgData, size_t ArgSize) {
240fe6060f1SDimitry Andric     SPSInputBuffer IB(ArgData, ArgSize);
241fe6060f1SDimitry Andric     if (!SPSArgList<SPSRetTagT>::deserialize(IB, Result))
242fe6060f1SDimitry Andric       return make_error<StringError>(
243fe6060f1SDimitry Andric           "Error deserializing return value from blob in call");
244fe6060f1SDimitry Andric     return Error::success();
245fe6060f1SDimitry Andric   }
246fe6060f1SDimitry Andric };
247fe6060f1SDimitry Andric 
248fe6060f1SDimitry Andric template <> class ResultDeserializer<SPSError, Error> {
249fe6060f1SDimitry Andric public:
makeSafe(Error & Err)250fe6060f1SDimitry Andric   static void makeSafe(Error &Err) { cantFail(std::move(Err)); }
251fe6060f1SDimitry Andric 
deserialize(Error & Err,const char * ArgData,size_t ArgSize)252fe6060f1SDimitry Andric   static Error deserialize(Error &Err, const char *ArgData, size_t ArgSize) {
253fe6060f1SDimitry Andric     SPSInputBuffer IB(ArgData, ArgSize);
254fe6060f1SDimitry Andric     SPSSerializableError BSE;
255fe6060f1SDimitry Andric     if (!SPSArgList<SPSError>::deserialize(IB, BSE))
256fe6060f1SDimitry Andric       return make_error<StringError>(
257fe6060f1SDimitry Andric           "Error deserializing return value from blob in call");
258fe6060f1SDimitry Andric     Err = fromSPSSerializable(std::move(BSE));
259fe6060f1SDimitry Andric     return Error::success();
260fe6060f1SDimitry Andric   }
261fe6060f1SDimitry Andric };
262fe6060f1SDimitry Andric 
263fe6060f1SDimitry Andric template <typename SPSTagT, typename T>
264fe6060f1SDimitry Andric class ResultDeserializer<SPSExpected<SPSTagT>, Expected<T>> {
265fe6060f1SDimitry Andric public:
makeSafe(Expected<T> & E)266fe6060f1SDimitry Andric   static void makeSafe(Expected<T> &E) { cantFail(E.takeError()); }
267fe6060f1SDimitry Andric 
deserialize(Expected<T> & E,const char * ArgData,size_t ArgSize)268fe6060f1SDimitry Andric   static Error deserialize(Expected<T> &E, const char *ArgData,
269fe6060f1SDimitry Andric                            size_t ArgSize) {
270fe6060f1SDimitry Andric     SPSInputBuffer IB(ArgData, ArgSize);
271fe6060f1SDimitry Andric     SPSSerializableExpected<T> BSE;
272fe6060f1SDimitry Andric     if (!SPSArgList<SPSExpected<SPSTagT>>::deserialize(IB, BSE))
273fe6060f1SDimitry Andric       return make_error<StringError>(
274fe6060f1SDimitry Andric           "Error deserializing return value from blob in call");
275fe6060f1SDimitry Andric     E = fromSPSSerializable(std::move(BSE));
276fe6060f1SDimitry Andric     return Error::success();
277fe6060f1SDimitry Andric   }
278fe6060f1SDimitry Andric };
279fe6060f1SDimitry Andric 
280fe6060f1SDimitry Andric } // end namespace detail
281fe6060f1SDimitry Andric 
282fe6060f1SDimitry Andric template <typename SPSSignature> class WrapperFunction;
283fe6060f1SDimitry Andric 
284fe6060f1SDimitry Andric template <typename SPSRetTagT, typename... SPSTagTs>
285fe6060f1SDimitry Andric class WrapperFunction<SPSRetTagT(SPSTagTs...)> {
286fe6060f1SDimitry Andric private:
287fe6060f1SDimitry Andric   template <typename RetT>
288fe6060f1SDimitry Andric   using ResultSerializer = detail::ResultSerializer<SPSRetTagT, RetT>;
289fe6060f1SDimitry Andric 
290fe6060f1SDimitry Andric public:
291fe6060f1SDimitry Andric   template <typename RetT, typename... ArgTs>
call(const void * FnTag,RetT & Result,const ArgTs &...Args)292fe6060f1SDimitry Andric   static Error call(const void *FnTag, RetT &Result, const ArgTs &...Args) {
293fe6060f1SDimitry Andric 
294fe6060f1SDimitry Andric     // RetT might be an Error or Expected value. Set the checked flag now:
295fe6060f1SDimitry Andric     // we don't want the user to have to check the unused result if this
296fe6060f1SDimitry Andric     // operation fails.
297fe6060f1SDimitry Andric     detail::ResultDeserializer<SPSRetTagT, RetT>::makeSafe(Result);
298fe6060f1SDimitry Andric 
299*7a6dacacSDimitry Andric     // Since the functions cannot be zero/unresolved on Windows, the following
300*7a6dacacSDimitry Andric     // reference taking would always be non-zero, thus generating a compiler
301*7a6dacacSDimitry Andric     // warning otherwise.
302*7a6dacacSDimitry Andric #if !defined(_WIN32)
303fe6060f1SDimitry Andric     if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch_ctx))
304fe6060f1SDimitry Andric       return make_error<StringError>("__orc_rt_jit_dispatch_ctx not set");
305fe6060f1SDimitry Andric     if (ORC_RT_UNLIKELY(!&__orc_rt_jit_dispatch))
306fe6060f1SDimitry Andric       return make_error<StringError>("__orc_rt_jit_dispatch not set");
307*7a6dacacSDimitry Andric #endif
308fe6060f1SDimitry Andric     auto ArgBuffer =
309349cc55cSDimitry Andric         WrapperFunctionResult::fromSPSArgs<SPSArgList<SPSTagTs...>>(Args...);
310349cc55cSDimitry Andric     if (const char *ErrMsg = ArgBuffer.getOutOfBandError())
311349cc55cSDimitry Andric       return make_error<StringError>(ErrMsg);
312fe6060f1SDimitry Andric 
313349cc55cSDimitry Andric     WrapperFunctionResult ResultBuffer = __orc_rt_jit_dispatch(
314349cc55cSDimitry Andric         &__orc_rt_jit_dispatch_ctx, FnTag, ArgBuffer.data(), ArgBuffer.size());
315fe6060f1SDimitry Andric     if (auto ErrMsg = ResultBuffer.getOutOfBandError())
316fe6060f1SDimitry Andric       return make_error<StringError>(ErrMsg);
317fe6060f1SDimitry Andric 
318fe6060f1SDimitry Andric     return detail::ResultDeserializer<SPSRetTagT, RetT>::deserialize(
319fe6060f1SDimitry Andric         Result, ResultBuffer.data(), ResultBuffer.size());
320fe6060f1SDimitry Andric   }
321fe6060f1SDimitry Andric 
322fe6060f1SDimitry Andric   template <typename HandlerT>
handle(const char * ArgData,size_t ArgSize,HandlerT && Handler)323fe6060f1SDimitry Andric   static WrapperFunctionResult handle(const char *ArgData, size_t ArgSize,
324fe6060f1SDimitry Andric                                       HandlerT &&Handler) {
325fe6060f1SDimitry Andric     using WFHH =
326349cc55cSDimitry Andric         detail::WrapperFunctionHandlerHelper<std::remove_reference_t<HandlerT>,
327349cc55cSDimitry Andric                                              ResultSerializer, SPSTagTs...>;
328fe6060f1SDimitry Andric     return WFHH::apply(std::forward<HandlerT>(Handler), ArgData, ArgSize);
329fe6060f1SDimitry Andric   }
330fe6060f1SDimitry Andric 
331fe6060f1SDimitry Andric private:
makeSerializable(const T & Value)332fe6060f1SDimitry Andric   template <typename T> static const T &makeSerializable(const T &Value) {
333fe6060f1SDimitry Andric     return Value;
334fe6060f1SDimitry Andric   }
335fe6060f1SDimitry Andric 
makeSerializable(Error Err)336fe6060f1SDimitry Andric   static detail::SPSSerializableError makeSerializable(Error Err) {
337fe6060f1SDimitry Andric     return detail::toSPSSerializable(std::move(Err));
338fe6060f1SDimitry Andric   }
339fe6060f1SDimitry Andric 
340fe6060f1SDimitry Andric   template <typename T>
makeSerializable(Expected<T> E)341fe6060f1SDimitry Andric   static detail::SPSSerializableExpected<T> makeSerializable(Expected<T> E) {
342fe6060f1SDimitry Andric     return detail::toSPSSerializable(std::move(E));
343fe6060f1SDimitry Andric   }
344fe6060f1SDimitry Andric };
345fe6060f1SDimitry Andric 
346fe6060f1SDimitry Andric template <typename... SPSTagTs>
347fe6060f1SDimitry Andric class WrapperFunction<void(SPSTagTs...)>
348fe6060f1SDimitry Andric     : private WrapperFunction<SPSEmpty(SPSTagTs...)> {
349fe6060f1SDimitry Andric public:
350fe6060f1SDimitry Andric   template <typename... ArgTs>
call(const void * FnTag,const ArgTs &...Args)351fe6060f1SDimitry Andric   static Error call(const void *FnTag, const ArgTs &...Args) {
352fe6060f1SDimitry Andric     SPSEmpty BE;
353fe6060f1SDimitry Andric     return WrapperFunction<SPSEmpty(SPSTagTs...)>::call(FnTag, BE, Args...);
354fe6060f1SDimitry Andric   }
355fe6060f1SDimitry Andric 
356fe6060f1SDimitry Andric   using WrapperFunction<SPSEmpty(SPSTagTs...)>::handle;
357fe6060f1SDimitry Andric };
358fe6060f1SDimitry Andric 
359349cc55cSDimitry Andric /// A function object that takes an ExecutorAddr as its first argument,
360349cc55cSDimitry Andric /// casts that address to a ClassT*, then calls the given method on that
361349cc55cSDimitry Andric /// pointer passing in the remaining function arguments. This utility
362349cc55cSDimitry Andric /// removes some of the boilerplate from writing wrappers for method calls.
363349cc55cSDimitry Andric ///
364349cc55cSDimitry Andric ///   @code{.cpp}
365349cc55cSDimitry Andric ///   class MyClass {
366349cc55cSDimitry Andric ///   public:
367349cc55cSDimitry Andric ///     void myMethod(uint32_t, bool) { ... }
368349cc55cSDimitry Andric ///   };
369349cc55cSDimitry Andric ///
370349cc55cSDimitry Andric ///   // SPS Method signature -- note MyClass object address as first argument.
371349cc55cSDimitry Andric ///   using SPSMyMethodWrapperSignature =
372349cc55cSDimitry Andric ///     SPSTuple<SPSExecutorAddr, uint32_t, bool>;
373349cc55cSDimitry Andric ///
374349cc55cSDimitry Andric ///   WrapperFunctionResult
375349cc55cSDimitry Andric ///   myMethodCallWrapper(const char *ArgData, size_t ArgSize) {
376349cc55cSDimitry Andric ///     return WrapperFunction<SPSMyMethodWrapperSignature>::handle(
377349cc55cSDimitry Andric ///        ArgData, ArgSize, makeMethodWrapperHandler(&MyClass::myMethod));
378349cc55cSDimitry Andric ///   }
379349cc55cSDimitry Andric ///   @endcode
380349cc55cSDimitry Andric ///
381349cc55cSDimitry Andric template <typename RetT, typename ClassT, typename... ArgTs>
382349cc55cSDimitry Andric class MethodWrapperHandler {
383349cc55cSDimitry Andric public:
384349cc55cSDimitry Andric   using MethodT = RetT (ClassT::*)(ArgTs...);
MethodWrapperHandler(MethodT M)385349cc55cSDimitry Andric   MethodWrapperHandler(MethodT M) : M(M) {}
operator()386349cc55cSDimitry Andric   RetT operator()(ExecutorAddr ObjAddr, ArgTs &...Args) {
387349cc55cSDimitry Andric     return (ObjAddr.toPtr<ClassT *>()->*M)(std::forward<ArgTs>(Args)...);
388349cc55cSDimitry Andric   }
389349cc55cSDimitry Andric 
390349cc55cSDimitry Andric private:
391349cc55cSDimitry Andric   MethodT M;
392349cc55cSDimitry Andric };
393349cc55cSDimitry Andric 
394349cc55cSDimitry Andric /// Create a MethodWrapperHandler object from the given method pointer.
395349cc55cSDimitry Andric template <typename RetT, typename ClassT, typename... ArgTs>
396349cc55cSDimitry Andric MethodWrapperHandler<RetT, ClassT, ArgTs...>
makeMethodWrapperHandler(RetT (ClassT::* Method)(ArgTs...))397349cc55cSDimitry Andric makeMethodWrapperHandler(RetT (ClassT::*Method)(ArgTs...)) {
398349cc55cSDimitry Andric   return MethodWrapperHandler<RetT, ClassT, ArgTs...>(Method);
399349cc55cSDimitry Andric }
400349cc55cSDimitry Andric 
401349cc55cSDimitry Andric /// Represents a call to a wrapper function.
40204eeddc0SDimitry Andric class WrapperFunctionCall {
40304eeddc0SDimitry Andric public:
40404eeddc0SDimitry Andric   // FIXME: Switch to a SmallVector<char, 24> once ORC runtime has a
40504eeddc0SDimitry Andric   // smallvector.
40604eeddc0SDimitry Andric   using ArgDataBufferType = std::vector<char>;
40704eeddc0SDimitry Andric 
40804eeddc0SDimitry Andric   /// Create a WrapperFunctionCall using the given SPS serializer to serialize
40904eeddc0SDimitry Andric   /// the arguments.
41004eeddc0SDimitry Andric   template <typename SPSSerializer, typename... ArgTs>
Create(ExecutorAddr FnAddr,const ArgTs &...Args)41104eeddc0SDimitry Andric   static Expected<WrapperFunctionCall> Create(ExecutorAddr FnAddr,
41204eeddc0SDimitry Andric                                               const ArgTs &...Args) {
41304eeddc0SDimitry Andric     ArgDataBufferType ArgData;
41404eeddc0SDimitry Andric     ArgData.resize(SPSSerializer::size(Args...));
415bdd1243dSDimitry Andric     SPSOutputBuffer OB(ArgData.empty() ? nullptr : ArgData.data(),
416bdd1243dSDimitry Andric                        ArgData.size());
41704eeddc0SDimitry Andric     if (SPSSerializer::serialize(OB, Args...))
41804eeddc0SDimitry Andric       return WrapperFunctionCall(FnAddr, std::move(ArgData));
41904eeddc0SDimitry Andric     return make_error<StringError>("Cannot serialize arguments for "
42004eeddc0SDimitry Andric                                    "AllocActionCall");
42104eeddc0SDimitry Andric   }
422349cc55cSDimitry Andric 
423349cc55cSDimitry Andric   WrapperFunctionCall() = default;
424349cc55cSDimitry Andric 
42504eeddc0SDimitry Andric   /// Create a WrapperFunctionCall from a target function and arg buffer.
WrapperFunctionCall(ExecutorAddr FnAddr,ArgDataBufferType ArgData)42604eeddc0SDimitry Andric   WrapperFunctionCall(ExecutorAddr FnAddr, ArgDataBufferType ArgData)
42704eeddc0SDimitry Andric       : FnAddr(FnAddr), ArgData(std::move(ArgData)) {}
42804eeddc0SDimitry Andric 
42904eeddc0SDimitry Andric   /// Returns the address to be called.
getCallee()43004eeddc0SDimitry Andric   const ExecutorAddr &getCallee() const { return FnAddr; }
43104eeddc0SDimitry Andric 
43204eeddc0SDimitry Andric   /// Returns the argument data.
getArgData()43304eeddc0SDimitry Andric   const ArgDataBufferType &getArgData() const { return ArgData; }
43404eeddc0SDimitry Andric 
43504eeddc0SDimitry Andric   /// WrapperFunctionCalls convert to true if the callee is non-null.
43604eeddc0SDimitry Andric   explicit operator bool() const { return !!FnAddr; }
43704eeddc0SDimitry Andric 
43804eeddc0SDimitry Andric   /// Run call returning raw WrapperFunctionResult.
run()43904eeddc0SDimitry Andric   WrapperFunctionResult run() const {
44004eeddc0SDimitry Andric     using FnTy =
44106c3fb27SDimitry Andric         orc_rt_CWrapperFunctionResult(const char *ArgData, size_t ArgSize);
44204eeddc0SDimitry Andric     return WrapperFunctionResult(
44304eeddc0SDimitry Andric         FnAddr.toPtr<FnTy *>()(ArgData.data(), ArgData.size()));
444349cc55cSDimitry Andric   }
445349cc55cSDimitry Andric 
446349cc55cSDimitry Andric   /// Run call and deserialize result using SPS.
44704eeddc0SDimitry Andric   template <typename SPSRetT, typename RetT>
44804eeddc0SDimitry Andric   std::enable_if_t<!std::is_same<SPSRetT, void>::value, Error>
runWithSPSRet(RetT & RetVal)44904eeddc0SDimitry Andric   runWithSPSRet(RetT &RetVal) const {
450349cc55cSDimitry Andric     auto WFR = run();
451349cc55cSDimitry Andric     if (const char *ErrMsg = WFR.getOutOfBandError())
452349cc55cSDimitry Andric       return make_error<StringError>(ErrMsg);
453349cc55cSDimitry Andric     SPSInputBuffer IB(WFR.data(), WFR.size());
454349cc55cSDimitry Andric     if (!SPSSerializationTraits<SPSRetT, RetT>::deserialize(IB, RetVal))
455349cc55cSDimitry Andric       return make_error<StringError>("Could not deserialize result from "
456349cc55cSDimitry Andric                                      "serialized wrapper function call");
457349cc55cSDimitry Andric     return Error::success();
458349cc55cSDimitry Andric   }
459349cc55cSDimitry Andric 
460349cc55cSDimitry Andric   /// Overload for SPS functions returning void.
46104eeddc0SDimitry Andric   template <typename SPSRetT>
46204eeddc0SDimitry Andric   std::enable_if_t<std::is_same<SPSRetT, void>::value, Error>
runWithSPSRet()46304eeddc0SDimitry Andric   runWithSPSRet() const {
464349cc55cSDimitry Andric     SPSEmpty E;
465349cc55cSDimitry Andric     return runWithSPSRet<SPSEmpty>(E);
466349cc55cSDimitry Andric   }
46704eeddc0SDimitry Andric 
46804eeddc0SDimitry Andric   /// Run call and deserialize an SPSError result. SPSError returns and
46904eeddc0SDimitry Andric   /// deserialization failures are merged into the returned error.
runWithSPSRetErrorMerged()47004eeddc0SDimitry Andric   Error runWithSPSRetErrorMerged() const {
47104eeddc0SDimitry Andric     detail::SPSSerializableError RetErr;
47204eeddc0SDimitry Andric     if (auto Err = runWithSPSRet<SPSError>(RetErr))
47304eeddc0SDimitry Andric       return Err;
47404eeddc0SDimitry Andric     return detail::fromSPSSerializable(std::move(RetErr));
47504eeddc0SDimitry Andric   }
47604eeddc0SDimitry Andric 
47704eeddc0SDimitry Andric private:
47804eeddc0SDimitry Andric   ExecutorAddr FnAddr;
47904eeddc0SDimitry Andric   std::vector<char> ArgData;
480349cc55cSDimitry Andric };
481349cc55cSDimitry Andric 
48204eeddc0SDimitry Andric using SPSWrapperFunctionCall = SPSTuple<SPSExecutorAddr, SPSSequence<char>>;
483349cc55cSDimitry Andric 
484349cc55cSDimitry Andric template <>
485349cc55cSDimitry Andric class SPSSerializationTraits<SPSWrapperFunctionCall, WrapperFunctionCall> {
486349cc55cSDimitry Andric public:
size(const WrapperFunctionCall & WFC)487349cc55cSDimitry Andric   static size_t size(const WrapperFunctionCall &WFC) {
48804eeddc0SDimitry Andric     return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::size(
48904eeddc0SDimitry Andric         WFC.getCallee(), WFC.getArgData());
490349cc55cSDimitry Andric   }
491349cc55cSDimitry Andric 
serialize(SPSOutputBuffer & OB,const WrapperFunctionCall & WFC)492349cc55cSDimitry Andric   static bool serialize(SPSOutputBuffer &OB, const WrapperFunctionCall &WFC) {
49304eeddc0SDimitry Andric     return SPSArgList<SPSExecutorAddr, SPSSequence<char>>::serialize(
49404eeddc0SDimitry Andric         OB, WFC.getCallee(), WFC.getArgData());
495349cc55cSDimitry Andric   }
496349cc55cSDimitry Andric 
deserialize(SPSInputBuffer & IB,WrapperFunctionCall & WFC)497349cc55cSDimitry Andric   static bool deserialize(SPSInputBuffer &IB, WrapperFunctionCall &WFC) {
49804eeddc0SDimitry Andric     ExecutorAddr FnAddr;
49904eeddc0SDimitry Andric     WrapperFunctionCall::ArgDataBufferType ArgData;
50004eeddc0SDimitry Andric     if (!SPSWrapperFunctionCall::AsArgList::deserialize(IB, FnAddr, ArgData))
50104eeddc0SDimitry Andric       return false;
50204eeddc0SDimitry Andric     WFC = WrapperFunctionCall(FnAddr, std::move(ArgData));
50304eeddc0SDimitry Andric     return true;
504349cc55cSDimitry Andric   }
505349cc55cSDimitry Andric };
506349cc55cSDimitry Andric 
507fe6060f1SDimitry Andric } // end namespace __orc_rt
508fe6060f1SDimitry Andric 
509fe6060f1SDimitry Andric #endif // ORC_RT_WRAPPER_FUNCTION_UTILS_H
510