318 lines · cpp
1//===-- SPSWrapperFunctionTest.cpp ----------------------------------------===//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// Test SPSWrapperFunction and associated utilities.10//11//===----------------------------------------------------------------------===//12 13#include "CommonTestUtils.h"14 15#include "orc-rt/SPSWrapperFunction.h"16#include "orc-rt/WrapperFunction.h"17#include "orc-rt/move_only_function.h"18 19#include "DirectCaller.h"20 21#include "gtest/gtest.h"22 23using namespace orc_rt;24 25static void void_noop_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,26 orc_rt_WrapperFunctionReturn Return,27 orc_rt_WrapperFunctionBuffer ArgBytes) {28 SPSWrapperFunction<void()>::handle(29 S, CallId, Return, ArgBytes,30 [](move_only_function<void()> Return) { Return(); });31}32 33TEST(SPSWrapperFunctionUtilsTest, VoidNoop) {34 bool Ran = false;35 SPSWrapperFunction<void()>::call(DirectCaller(nullptr, void_noop_sps_wrapper),36 [&](Error Err) {37 cantFail(std::move(Err));38 Ran = true;39 });40 EXPECT_TRUE(Ran);41}42 43static void add_via_lambda_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,44 orc_rt_WrapperFunctionReturn Return,45 orc_rt_WrapperFunctionBuffer ArgBytes) {46 SPSWrapperFunction<int32_t(int32_t, int32_t)>::handle(47 S, CallId, Return, ArgBytes,48 [](move_only_function<void(int32_t)> Return, int32_t X, int32_t Y) {49 Return(X + Y);50 });51}52 53TEST(SPSWrapperFunctionUtilsTest, BinaryOpViaLambda) {54 int32_t Result = 0;55 SPSWrapperFunction<int32_t(int32_t, int32_t)>::call(56 DirectCaller(nullptr, add_via_lambda_sps_wrapper),57 [&](Expected<int32_t> R) { Result = cantFail(std::move(R)); }, 41, 1);58 EXPECT_EQ(Result, 42);59}60 61static void add_via_function(move_only_function<void(int32_t)> Return,62 int32_t X, int32_t Y) {63 Return(X + Y);64}65 66static void67add_via_function_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,68 orc_rt_WrapperFunctionReturn Return,69 orc_rt_WrapperFunctionBuffer ArgBytes) {70 SPSWrapperFunction<int32_t(int32_t, int32_t)>::handle(71 S, CallId, Return, ArgBytes, add_via_function);72}73 74TEST(SPSWrapperFunctionUtilsTest, BinaryOpViaFunction) {75 int32_t Result = 0;76 SPSWrapperFunction<int32_t(int32_t, int32_t)>::call(77 DirectCaller(nullptr, add_via_function_sps_wrapper),78 [&](Expected<int32_t> R) { Result = cantFail(std::move(R)); }, 41, 1);79 EXPECT_EQ(Result, 42);80}81 82static void83add_via_function_pointer_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,84 orc_rt_WrapperFunctionReturn Return,85 orc_rt_WrapperFunctionBuffer ArgBytes) {86 SPSWrapperFunction<int32_t(int32_t, int32_t)>::handle(87 S, CallId, Return, ArgBytes, &add_via_function);88}89 90TEST(SPSWrapperFunctionUtilsTest, BinaryOpViaFunctionPointer) {91 int32_t Result = 0;92 SPSWrapperFunction<int32_t(int32_t, int32_t)>::call(93 DirectCaller(nullptr, add_via_function_pointer_sps_wrapper),94 [&](Expected<int32_t> R) { Result = cantFail(std::move(R)); }, 41, 1);95 EXPECT_EQ(Result, 42);96}97 98static void99round_trip_string_via_span_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,100 orc_rt_WrapperFunctionReturn Return,101 orc_rt_WrapperFunctionBuffer ArgBytes) {102 SPSWrapperFunction<SPSString(SPSString)>::handle(103 S, CallId, Return, ArgBytes,104 [](move_only_function<void(std::string)> Return, span<const char> S) {105 Return({S.data(), S.size()});106 });107}108 109TEST(SPSWrapperFunctionUtilsTest, RoundTripStringViaSpan) {110 /// Test that the SPSWrapperFunction<...>::handle call in111 /// round_trip_string_via_span_sps_wrapper can deserialize into a usable112 /// span<const char>.113 std::string Result;114 SPSWrapperFunction<SPSString(SPSString)>::call(115 DirectCaller(nullptr, round_trip_string_via_span_sps_wrapper),116 [&](Expected<std::string> R) { Result = cantFail(std::move(R)); },117 std::string_view("hello, world!"));118 EXPECT_EQ(Result, "hello, world!");119}120 121static void improbable_feat_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,122 orc_rt_WrapperFunctionReturn Return,123 orc_rt_WrapperFunctionBuffer ArgBytes) {124 SPSWrapperFunction<SPSError(bool)>::handle(125 S, CallId, Return, ArgBytes,126 [](move_only_function<void(Error)> Return, bool LuckyHat) {127 if (LuckyHat)128 Return(Error::success());129 else130 Return(make_error<StringError>("crushed by boulder"));131 });132}133 134TEST(SPSWrapperFunctionUtilsTest, TransparentConversionErrorSuccessCase) {135 bool DidRun = false;136 SPSWrapperFunction<SPSError(bool)>::call(137 DirectCaller(nullptr, improbable_feat_sps_wrapper),138 [&](Expected<Error> E) {139 DidRun = true;140 cantFail(cantFail(std::move(E)));141 },142 true);143 144 EXPECT_TRUE(DidRun);145}146 147TEST(SPSWrapperFunctionUtilsTest, TransparentConversionErrorFailureCase) {148 std::string ErrMsg;149 SPSWrapperFunction<SPSError(bool)>::call(150 DirectCaller(nullptr, improbable_feat_sps_wrapper),151 [&](Expected<Error> E) { ErrMsg = toString(cantFail(std::move(E))); },152 false);153 154 EXPECT_EQ(ErrMsg, "crushed by boulder");155}156 157static void halve_number_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,158 orc_rt_WrapperFunctionReturn Return,159 orc_rt_WrapperFunctionBuffer ArgBytes) {160 SPSWrapperFunction<SPSExpected<int32_t>(int32_t)>::handle(161 S, CallId, Return, ArgBytes,162 [](move_only_function<void(Expected<int32_t>)> Return, int N) {163 if (N % 2 == 0)164 Return(N >> 1);165 else166 Return(make_error<StringError>("N is not a multiple of 2"));167 });168}169 170TEST(SPSWrapperFunctionUtilsTest, TransparentConversionExpectedSuccessCase) {171 int32_t Result = 0;172 SPSWrapperFunction<SPSExpected<int32_t>(int32_t)>::call(173 DirectCaller(nullptr, halve_number_sps_wrapper),174 [&](Expected<Expected<int32_t>> R) {175 Result = cantFail(cantFail(std::move(R)));176 },177 2);178 179 EXPECT_EQ(Result, 1);180}181 182TEST(SPSWrapperFunctionUtilsTest, TransparentConversionExpectedFailureCase) {183 std::string ErrMsg;184 SPSWrapperFunction<SPSExpected<int32_t>(int32_t)>::call(185 DirectCaller(nullptr, halve_number_sps_wrapper),186 [&](Expected<Expected<int32_t>> R) {187 ErrMsg = toString(cantFail(std::move(R)).takeError());188 },189 3);190 191 EXPECT_EQ(ErrMsg, "N is not a multiple of 2");192}193 194template <size_t N> struct SPSOpCounter {};195 196namespace orc_rt {197template <size_t N>198class SPSSerializationTraits<SPSOpCounter<N>, OpCounter<N>> {199public:200 static size_t size(const OpCounter<N> &O) { return 0; }201 static bool serialize(SPSOutputBuffer &OB, const OpCounter<N> &O) {202 return true;203 }204 static bool deserialize(SPSInputBuffer &OB, OpCounter<N> &O) { return true; }205};206} // namespace orc_rt207 208static void209handle_with_reference_types_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,210 orc_rt_WrapperFunctionReturn Return,211 orc_rt_WrapperFunctionBuffer ArgBytes) {212 SPSWrapperFunction<void(213 SPSOpCounter<0>, SPSOpCounter<1>, SPSOpCounter<2>,214 SPSOpCounter<3>)>::handle(S, CallId, Return, ArgBytes,215 [](move_only_function<void()> Return,216 OpCounter<0>, OpCounter<1> &,217 const OpCounter<2> &,218 OpCounter<3> &&) { Return(); });219}220 221TEST(SPSWrapperFunctionUtilsTest, HandlerWithReferences) {222 // Test that we can handle by-value, by-ref, by-const-ref, and by-rvalue-ref223 // arguments, and that we generate the expected number of moves.224 OpCounter<0>::reset();225 OpCounter<1>::reset();226 OpCounter<2>::reset();227 OpCounter<3>::reset();228 229 bool DidRun = false;230 SPSWrapperFunction<void(SPSOpCounter<0>, SPSOpCounter<1>, SPSOpCounter<2>,231 SPSOpCounter<3>)>::232 call(233 DirectCaller(nullptr, handle_with_reference_types_sps_wrapper),234 [&](Error R) {235 cantFail(std::move(R));236 DidRun = true;237 },238 OpCounter<0>(), OpCounter<1>(), OpCounter<2>(), OpCounter<3>());239 240 EXPECT_TRUE(DidRun);241 242 // We expect two default constructions for each parameter: one for the243 // argument to call, and one for the object to deserialize into.244 EXPECT_EQ(OpCounter<0>::defaultConstructions(), 2U);245 EXPECT_EQ(OpCounter<1>::defaultConstructions(), 2U);246 EXPECT_EQ(OpCounter<2>::defaultConstructions(), 2U);247 EXPECT_EQ(OpCounter<3>::defaultConstructions(), 2U);248 249 // Pass-by-value: we expect two moves (one for SPS transparent conversion,250 // one to copy the value to the parameter), and no copies.251 EXPECT_EQ(OpCounter<0>::moves(), 2U);252 EXPECT_EQ(OpCounter<0>::copies(), 0U);253 254 // Pass-by-lvalue-reference: we expect one move (for SPS transparent255 // conversion), no copies.256 EXPECT_EQ(OpCounter<1>::moves(), 1U);257 EXPECT_EQ(OpCounter<1>::copies(), 0U);258 259 // Pass-by-const-lvalue-reference: we expect one move (for SPS transparent260 // conversion), no copies.261 EXPECT_EQ(OpCounter<2>::moves(), 1U);262 EXPECT_EQ(OpCounter<2>::copies(), 0U);263 264 // Pass-by-rvalue-reference: we expect one move (for SPS transparent265 // conversion), no copies.266 EXPECT_EQ(OpCounter<3>::moves(), 1U);267 EXPECT_EQ(OpCounter<3>::copies(), 0U);268}269 270namespace {271class Adder {272public:273 int32_t addSync(int32_t X, int32_t Y) { return X + Y; }274 void addAsync(move_only_function<void(int32_t)> Return, int32_t X,275 int32_t Y) {276 Return(addSync(X, Y));277 }278};279} // anonymous namespace280 281static void adder_add_async_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,282 orc_rt_WrapperFunctionReturn Return,283 orc_rt_WrapperFunctionBuffer ArgBytes) {284 SPSWrapperFunction<int32_t(SPSExecutorAddr, int32_t, int32_t)>::handle(285 S, CallId, Return, ArgBytes,286 WrapperFunction::handleWithAsyncMethod(&Adder::addAsync));287}288 289TEST(SPSWrapperFunctionUtilsTest, HandleWtihAsyncMethod) {290 auto A = std::make_unique<Adder>();291 int32_t Result = 0;292 SPSWrapperFunction<int32_t(SPSExecutorAddr, int32_t, int32_t)>::call(293 DirectCaller(nullptr, adder_add_async_sps_wrapper),294 [&](Expected<int32_t> R) { Result = cantFail(std::move(R)); },295 ExecutorAddr::fromPtr(A.get()), 41, 1);296 297 EXPECT_EQ(Result, 42);298}299 300static void adder_add_sync_sps_wrapper(orc_rt_SessionRef S, uint64_t CallId,301 orc_rt_WrapperFunctionReturn Return,302 orc_rt_WrapperFunctionBuffer ArgBytes) {303 SPSWrapperFunction<int32_t(SPSExecutorAddr, int32_t, int32_t)>::handle(304 S, CallId, Return, ArgBytes,305 WrapperFunction::handleWithSyncMethod(&Adder::addSync));306}307 308TEST(SPSWrapperFunctionUtilsTest, HandleWithSyncMethod) {309 auto A = std::make_unique<Adder>();310 int32_t Result = 0;311 SPSWrapperFunction<int32_t(SPSExecutorAddr, int32_t, int32_t)>::call(312 DirectCaller(nullptr, adder_add_sync_sps_wrapper),313 [&](Expected<int32_t> R) { Result = cantFail(std::move(R)); },314 ExecutorAddr::fromPtr(A.get()), 41, 1);315 316 EXPECT_EQ(Result, 42);317}318