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