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
TEST(WrapperFunctionUtilsTest,DefaultWrapperFunctionResult)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
TEST(WrapperFunctionUtilsTest,WrapperFunctionResultFromCStruct)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
TEST(WrapperFunctionUtilsTest,WrapperFunctionResultFromRange)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
TEST(WrapperFunctionUtilsTest,WrapperFunctionResultFromCString)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
TEST(WrapperFunctionUtilsTest,WrapperFunctionResultFromStdString)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
TEST(WrapperFunctionUtilsTest,WrapperFunctionResultFromOutOfBandError)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
voidNoop()69 static void voidNoop() {}
70
voidNoopWrapper(const char * ArgData,size_t ArgSize)71 static __orc_rt_CWrapperFunctionResult voidNoopWrapper(const char *ArgData,
72 size_t ArgSize) {
73 return WrapperFunction<void()>::handle(ArgData, ArgSize, voidNoop).release();
74 }
75
addWrapper(const char * ArgData,size_t ArgSize)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
__orc_rt_jit_dispatch(__orc_rt_Opaque * Ctx,const void * FnTag,const char * ArgData,size_t ArgSize)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
TEST(WrapperFunctionUtilsTest,WrapperFunctionCallVoidNoopAndHandle)96 TEST(WrapperFunctionUtilsTest, WrapperFunctionCallVoidNoopAndHandle) {
97 EXPECT_FALSE(!!WrapperFunction<void()>::call((void *)&voidNoopWrapper));
98 }
99
TEST(WrapperFunctionUtilsTest,WrapperFunctionCallAddWrapperAndHandle)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:
AddClass(int32_t X)109 AddClass(int32_t X) : X(X) {}
addMethod(int32_t Y)110 int32_t addMethod(int32_t Y) { return X + Y; }
111
112 private:
113 int32_t X;
114 };
115
addMethodWrapper(const char * ArgData,size_t ArgSize)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
TEST(WrapperFunctionUtilsTest,WrapperFunctionMethodCallAndHandleRet)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
sumArrayWrapper(const char * ArgData,size_t ArgSize)131 static __orc_rt_CWrapperFunctionResult sumArrayWrapper(const char *ArgData,
132 size_t ArgSize) {
133 return WrapperFunction<int8_t(SPSExecutorAddrRange)>::handle(
134 ArgData, ArgSize,
135 [](ExecutorAddrRange R) {
136 int8_t Sum = 0;
137 for (char C : R.toSpan<char>())
138 Sum += C;
139 return Sum;
140 })
141 .release();
142 }
143
TEST(WrapperFunctionUtilsTest,SerializedWrapperFunctionCallTest)144 TEST(WrapperFunctionUtilsTest, SerializedWrapperFunctionCallTest) {
145 {
146 // Check wrapper function calls.
147 char A[] = {1, 2, 3, 4};
148
149 auto WFC =
150 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
151 ExecutorAddr::fromPtr(sumArrayWrapper),
152 ExecutorAddrRange(ExecutorAddr::fromPtr(A),
153 ExecutorAddrDiff(sizeof(A)))));
154
155 WrapperFunctionResult WFR(WFC.run());
156 EXPECT_EQ(WFR.size(), 1U);
157 EXPECT_EQ(WFR.data()[0], 10);
158 }
159
160 {
161 // Check calls to void functions.
162 auto WFC =
163 cantFail(WrapperFunctionCall::Create<SPSArgList<SPSExecutorAddrRange>>(
164 ExecutorAddr::fromPtr(voidNoopWrapper), ExecutorAddrRange()));
165 auto Err = WFC.runWithSPSRet<void>();
166 EXPECT_FALSE(!!Err);
167 }
168
169 {
170 // Check calls with arguments and return values.
171 auto WFC =
172 cantFail(WrapperFunctionCall::Create<SPSArgList<int32_t, int32_t>>(
173 ExecutorAddr::fromPtr(addWrapper), 2, 4));
174
175 int32_t Result = 0;
176 auto Err = WFC.runWithSPSRet<int32_t>(Result);
177 EXPECT_FALSE(!!Err);
178 EXPECT_EQ(Result, 6);
179 }
180 }
181