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