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