1 //===-- wrapper_function_utils_test.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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file is a part of the ORC runtime.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "wrapper_function_utils.h"
14 #include "gtest/gtest.h"
15 
16 using namespace __orc_rt;
17 
18 namespace {
19 constexpr const char *TestString = "test string";
20 } // end anonymous namespace
21 
22 TEST(WrapperFunctionUtilsTest, DefaultWrapperFunctionResult) {
23   WrapperFunctionResult R;
24   EXPECT_TRUE(R.empty());
25   EXPECT_EQ(R.size(), 0U);
26   EXPECT_EQ(R.getOutOfBandError(), nullptr);
27 }
28 
29 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCStruct) {
30   __orc_rt_CWrapperFunctionResult CR =
31       __orc_rt_CreateCWrapperFunctionResultFromString(TestString);
32   WrapperFunctionResult R(CR);
33   EXPECT_EQ(R.size(), strlen(TestString) + 1);
34   EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
35   EXPECT_FALSE(R.empty());
36   EXPECT_EQ(R.getOutOfBandError(), nullptr);
37 }
38 
39 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromRange) {
40   auto R = WrapperFunctionResult::copyFrom(TestString, strlen(TestString) + 1);
41   EXPECT_EQ(R.size(), strlen(TestString) + 1);
42   EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
43   EXPECT_FALSE(R.empty());
44   EXPECT_EQ(R.getOutOfBandError(), nullptr);
45 }
46 
47 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCString) {
48   auto R = WrapperFunctionResult::copyFrom(TestString);
49   EXPECT_EQ(R.size(), strlen(TestString) + 1);
50   EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
51   EXPECT_FALSE(R.empty());
52   EXPECT_EQ(R.getOutOfBandError(), nullptr);
53 }
54 
55 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromStdString) {
56   auto R = WrapperFunctionResult::copyFrom(std::string(TestString));
57   EXPECT_EQ(R.size(), strlen(TestString) + 1);
58   EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
59   EXPECT_FALSE(R.empty());
60   EXPECT_EQ(R.getOutOfBandError(), nullptr);
61 }
62 
63 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromOutOfBandError) {
64   auto R = WrapperFunctionResult::createOutOfBandError(TestString);
65   EXPECT_FALSE(R.empty());
66   EXPECT_TRUE(strcmp(R.getOutOfBandError(), TestString) == 0);
67 }
68 
69 static void voidNoop() {}
70 
71 static __orc_rt_CWrapperFunctionResult voidNoopWrapper(const char *ArgData,
72                                                        size_t ArgSize) {
73   return WrapperFunction<void()>::handle(ArgData, ArgSize, voidNoop).release();
74 }
75 
76 static __orc_rt_CWrapperFunctionResult addWrapper(const char *ArgData,
77                                                   size_t ArgSize) {
78   return WrapperFunction<int32_t(int32_t, int32_t)>::handle(
79              ArgData, ArgSize,
80              [](int32_t X, int32_t Y) -> int32_t { return X + Y; })
81       .release();
82 }
83 
84 extern "C" __orc_rt_Opaque __orc_rt_jit_dispatch_ctx{};
85 
86 extern "C" __orc_rt_CWrapperFunctionResult
87 __orc_rt_jit_dispatch(__orc_rt_Opaque *Ctx, const void *FnTag,
88                       const char *ArgData, size_t ArgSize) {
89   using WrapperFunctionType =
90       __orc_rt_CWrapperFunctionResult (*)(const char *, size_t);
91 
92   return reinterpret_cast<WrapperFunctionType>(const_cast<void *>(FnTag))(
93       ArgData, ArgSize);
94 }
95 
96 TEST(WrapperFunctionUtilsTest, WrapperFunctionCallVoidNoopAndHandle) {
97   EXPECT_FALSE(!!WrapperFunction<void()>::call((void *)&voidNoopWrapper));
98 }
99 
100 TEST(WrapperFunctionUtilsTest, WrapperFunctionCallAddWrapperAndHandle) {
101   int32_t Result;
102   EXPECT_FALSE(!!WrapperFunction<int32_t(int32_t, int32_t)>::call(
103       (void *)&addWrapper, Result, 1, 2));
104   EXPECT_EQ(Result, (int32_t)3);
105 }
106 
107 class AddClass {
108 public:
109   AddClass(int32_t X) : X(X) {}
110   int32_t addMethod(int32_t Y) { return X + Y; }
111 
112 private:
113   int32_t X;
114 };
115 
116 static __orc_rt_CWrapperFunctionResult addMethodWrapper(const char *ArgData,
117                                                         size_t ArgSize) {
118   return WrapperFunction<int32_t(SPSExecutorAddr, int32_t)>::handle(
119              ArgData, ArgSize, makeMethodWrapperHandler(&AddClass::addMethod))
120       .release();
121 }
122 
123 TEST(WrapperFunctionUtilsTest, WrapperFunctionMethodCallAndHandleRet) {
124   int32_t Result;
125   AddClass AddObj(1);
126   EXPECT_FALSE(!!WrapperFunction<int32_t(SPSExecutorAddr, int32_t)>::call(
127       (void *)&addMethodWrapper, Result, ExecutorAddr::fromPtr(&AddObj), 2));
128   EXPECT_EQ(Result, (int32_t)3);
129 }
130 
131 // A non-SPS wrapper function that calculates the sum of a byte array.
132 static __orc_rt_CWrapperFunctionResult sumArrayRawWrapper(const char *ArgData,
133                                                           size_t ArgSize) {
134   auto WFR = WrapperFunctionResult::allocate(1);
135   *WFR.data() = 0;
136   for (unsigned I = 0; I != ArgSize; ++I)
137     *WFR.data() += ArgData[I];
138   return WFR.release();
139 }
140 
141 TEST(WrapperFunctionUtilsTest, SerializedWrapperFunctionCallTest) {
142   {
143     // Check raw wrapper function calls.
144     char A[] = {1, 2, 3, 4};
145 
146     WrapperFunctionCall WFC{ExecutorAddr::fromPtr(sumArrayRawWrapper),
147                             ExecutorAddrRange(ExecutorAddr::fromPtr(A),
148                                               ExecutorAddrDiff(sizeof(A)))};
149 
150     WrapperFunctionResult WFR(WFC.run());
151     EXPECT_EQ(WFR.size(), 1U);
152     EXPECT_EQ(WFR.data()[0], 10);
153   }
154 
155   {
156     // Check calls to void functions.
157     WrapperFunctionCall WFC{ExecutorAddr::fromPtr(voidNoopWrapper),
158                             ExecutorAddrRange()};
159     auto Err = WFC.runWithSPSRet();
160     EXPECT_FALSE(!!Err);
161   }
162 
163   {
164     // Check calls with arguments and return values.
165     auto ArgWFR =
166         WrapperFunctionResult::fromSPSArgs<SPSArgList<int32_t, int32_t>>(2, 4);
167     WrapperFunctionCall WFC{
168         ExecutorAddr::fromPtr(addWrapper),
169         ExecutorAddrRange(ExecutorAddr::fromPtr(ArgWFR.data()),
170                           ExecutorAddrDiff(ArgWFR.size()))};
171 
172     int32_t Result = 0;
173     auto Err = WFC.runWithSPSRet<int32_t>(Result);
174     EXPECT_FALSE(!!Err);
175     EXPECT_EQ(Result, 6);
176   }
177 }
178