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 #include <stdio.h>
17 
18 using namespace __orc_rt;
19 
20 namespace {
21 constexpr const char *TestString = "test string";
22 } // end anonymous namespace
23 
24 TEST(WrapperFunctionUtilsTest, DefaultWrapperFunctionResult) {
25   WrapperFunctionResult R;
26   EXPECT_TRUE(R.empty());
27   EXPECT_EQ(R.size(), 0U);
28   EXPECT_EQ(R.getOutOfBandError(), nullptr);
29 }
30 
31 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCStruct) {
32   __orc_rt_CWrapperFunctionResult CR =
33       __orc_rt_CreateCWrapperFunctionResultFromString(TestString);
34   WrapperFunctionResult R(CR);
35   EXPECT_EQ(R.size(), strlen(TestString) + 1);
36   EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
37   EXPECT_FALSE(R.empty());
38   EXPECT_EQ(R.getOutOfBandError(), nullptr);
39 }
40 
41 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromRange) {
42   auto R = WrapperFunctionResult::copyFrom(TestString, strlen(TestString) + 1);
43   EXPECT_EQ(R.size(), strlen(TestString) + 1);
44   EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
45   EXPECT_FALSE(R.empty());
46   EXPECT_EQ(R.getOutOfBandError(), nullptr);
47 }
48 
49 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCString) {
50   auto R = WrapperFunctionResult::copyFrom(TestString);
51   EXPECT_EQ(R.size(), strlen(TestString) + 1);
52   EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
53   EXPECT_FALSE(R.empty());
54   EXPECT_EQ(R.getOutOfBandError(), nullptr);
55 }
56 
57 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromStdString) {
58   auto R = WrapperFunctionResult::copyFrom(std::string(TestString));
59   EXPECT_EQ(R.size(), strlen(TestString) + 1);
60   EXPECT_TRUE(strcmp(R.data(), TestString) == 0);
61   EXPECT_FALSE(R.empty());
62   EXPECT_EQ(R.getOutOfBandError(), nullptr);
63 }
64 
65 TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromOutOfBandError) {
66   auto R = WrapperFunctionResult::createOutOfBandError(TestString);
67   EXPECT_FALSE(R.empty());
68   EXPECT_TRUE(strcmp(R.getOutOfBandError(), TestString) == 0);
69 }
70 
71 TEST(WrapperFunctionUtilsTest, SPSOutputBuffer) {
72   constexpr unsigned NumBytes = 8;
73   char Buffer[NumBytes];
74   char Zero = 0;
75   SPSOutputBuffer OB(Buffer, NumBytes);
76 
77   // Expect that we can write NumBytes of content.
78   for (unsigned I = 0; I != NumBytes; ++I) {
79     char C = I;
80     EXPECT_TRUE(OB.write(&C, 1));
81   }
82 
83   // Expect an error when we attempt to write an extra byte.
84   EXPECT_FALSE(OB.write(&Zero, 1));
85 
86   // Check that the buffer contains the expected content.
87   for (unsigned I = 0; I != NumBytes; ++I)
88     EXPECT_EQ(Buffer[I], (char)I);
89 }
90 
91 TEST(WrapperFunctionUtilsTest, SPSInputBuffer) {
92   char Buffer[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
93   SPSInputBuffer IB(Buffer, sizeof(Buffer));
94 
95   char C;
96   for (unsigned I = 0; I != sizeof(Buffer); ++I) {
97     EXPECT_TRUE(IB.read(&C, 1));
98     EXPECT_EQ(C, (char)I);
99   }
100 
101   EXPECT_FALSE(IB.read(&C, 1));
102 }
103 
104 template <typename SPSTagT, typename T>
105 static void blobSerializationRoundTrip(const T &Value) {
106   using BST = SPSSerializationTraits<SPSTagT, T>;
107 
108   size_t Size = BST::size(Value);
109   auto Buffer = std::make_unique<char[]>(Size);
110   SPSOutputBuffer OB(Buffer.get(), Size);
111 
112   EXPECT_TRUE(BST::serialize(OB, Value));
113 
114   SPSInputBuffer IB(Buffer.get(), Size);
115 
116   T DSValue;
117   EXPECT_TRUE(BST::deserialize(IB, DSValue));
118 
119   EXPECT_EQ(Value, DSValue)
120       << "Incorrect value after serialization/deserialization round-trip";
121 }
122 
123 template <typename T> static void testFixedIntegralTypeSerialization() {
124   blobSerializationRoundTrip<T, T>(0);
125   blobSerializationRoundTrip<T, T>(static_cast<T>(1));
126   if (std::is_signed<T>::value) {
127     blobSerializationRoundTrip<T, T>(static_cast<T>(-1));
128     blobSerializationRoundTrip<T, T>(std::numeric_limits<T>::min());
129   }
130   blobSerializationRoundTrip<T, T>(std::numeric_limits<T>::max());
131 }
132 
133 TEST(WrapperFunctionUtilsTest, BoolSerialization) {
134   blobSerializationRoundTrip<bool, bool>(true);
135   blobSerializationRoundTrip<bool, bool>(false);
136 }
137 
138 TEST(WrapperFunctionUtilsTest, CharSerialization) {
139   blobSerializationRoundTrip<char, char>((char)0x00);
140   blobSerializationRoundTrip<char, char>((char)0xAA);
141   blobSerializationRoundTrip<char, char>((char)0xFF);
142 }
143 
144 TEST(WrapperFunctionUtilsTest, Int8Serialization) {
145   testFixedIntegralTypeSerialization<int8_t>();
146 }
147 
148 TEST(WrapperFunctionUtilsTest, UInt8Serialization) {
149   testFixedIntegralTypeSerialization<uint8_t>();
150 }
151 
152 TEST(WrapperFunctionUtilsTest, Int16Serialization) {
153   testFixedIntegralTypeSerialization<int16_t>();
154 }
155 
156 TEST(WrapperFunctionUtilsTest, UInt16Serialization) {
157   testFixedIntegralTypeSerialization<uint16_t>();
158 }
159 
160 TEST(WrapperFunctionUtilsTest, Int32Serialization) {
161   testFixedIntegralTypeSerialization<int32_t>();
162 }
163 
164 TEST(WrapperFunctionUtilsTest, UInt32Serialization) {
165   testFixedIntegralTypeSerialization<uint32_t>();
166 }
167 
168 TEST(WrapperFunctionUtilsTest, Int64Serialization) {
169   testFixedIntegralTypeSerialization<int64_t>();
170 }
171 
172 TEST(WrapperFunctionUtilsTest, UInt64Serialization) {
173   testFixedIntegralTypeSerialization<uint64_t>();
174 }
175 
176 TEST(WrapperFunctionUtilsTest, SequenceSerialization) {
177   std::vector<int32_t> V({1, 2, -47, 139});
178   blobSerializationRoundTrip<SPSSequence<int32_t>, std::vector<int32_t>>(V);
179 }
180 
181 TEST(WrapperFunctionUtilsTest, StringViewCharSequenceSerialization) {
182   const char *HW = "Hello, world!";
183   blobSerializationRoundTrip<SPSString, string_view>(string_view(HW));
184 }
185 
186 TEST(WrapperFunctionUtilsTest, StdPairSerialization) {
187   std::pair<int32_t, std::string> P(42, "foo");
188   blobSerializationRoundTrip<SPSTuple<int32_t, SPSString>,
189                              std::pair<int32_t, std::string>>(P);
190 }
191 
192 TEST(WrapperFunctionUtilsTest, ArgListSerialization) {
193   using BAL = SPSArgList<bool, int32_t, SPSString>;
194 
195   bool Arg1 = true;
196   int32_t Arg2 = 42;
197   std::string Arg3 = "foo";
198 
199   size_t Size = BAL::size(Arg1, Arg2, Arg3);
200   auto Buffer = std::make_unique<char[]>(Size);
201   SPSOutputBuffer OB(Buffer.get(), Size);
202 
203   EXPECT_TRUE(BAL::serialize(OB, Arg1, Arg2, Arg3));
204 
205   SPSInputBuffer IB(Buffer.get(), Size);
206 
207   bool ArgOut1;
208   int32_t ArgOut2;
209   std::string ArgOut3;
210 
211   EXPECT_TRUE(BAL::deserialize(IB, ArgOut1, ArgOut2, ArgOut3));
212 
213   EXPECT_EQ(Arg1, ArgOut1);
214   EXPECT_EQ(Arg2, ArgOut2);
215   EXPECT_EQ(Arg3, ArgOut3);
216 }
217 
218 static __orc_rt_CWrapperFunctionResult addWrapper(const char *ArgData,
219                                                   size_t ArgSize) {
220   return WrapperFunction<int32_t(int32_t, int32_t)>::handle(
221              ArgData, ArgSize,
222              [](int32_t X, int32_t Y) -> int32_t { return X + Y; })
223       .release();
224 }
225 
226 extern "C" __orc_rt_Opaque __orc_rt_jit_dispatch_ctx{};
227 
228 extern "C" __orc_rt_CWrapperFunctionResult
229 __orc_rt_jit_dispatch(__orc_rt_Opaque *Ctx, const void *FnTag,
230                       const char *ArgData, size_t ArgSize) {
231   using WrapperFunctionType =
232       __orc_rt_CWrapperFunctionResult (*)(const char *, size_t);
233 
234   return reinterpret_cast<WrapperFunctionType>(const_cast<void *>(FnTag))(
235       ArgData, ArgSize);
236 }
237 
238 TEST(WrapperFunctionUtilsTest, WrapperFunctionCallAndHandle) {
239   int32_t Result;
240   EXPECT_FALSE(!!WrapperFunction<int32_t(int32_t, int32_t)>::call(
241       (void *)&addWrapper, Result, 1, 2));
242   EXPECT_EQ(Result, (int32_t)3);
243 }
244