//===-- wrapper_function_utils_test.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file is a part of the ORC runtime. // //===----------------------------------------------------------------------===// #include "wrapper_function_utils.h" #include "gtest/gtest.h" #include using namespace __orc_rt; namespace { constexpr const char *TestString = "test string"; } // end anonymous namespace TEST(WrapperFunctionUtilsTest, DefaultWrapperFunctionResult) { WrapperFunctionResult R; EXPECT_TRUE(R.empty()); EXPECT_EQ(R.size(), 0U); EXPECT_EQ(R.getOutOfBandError(), nullptr); } TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCStruct) { __orc_rt_CWrapperFunctionResult CR = __orc_rt_CreateCWrapperFunctionResultFromString(TestString); WrapperFunctionResult R(CR); EXPECT_EQ(R.size(), strlen(TestString) + 1); EXPECT_TRUE(strcmp(R.data(), TestString) == 0); EXPECT_FALSE(R.empty()); EXPECT_EQ(R.getOutOfBandError(), nullptr); } TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromRange) { auto R = WrapperFunctionResult::copyFrom(TestString, strlen(TestString) + 1); EXPECT_EQ(R.size(), strlen(TestString) + 1); EXPECT_TRUE(strcmp(R.data(), TestString) == 0); EXPECT_FALSE(R.empty()); EXPECT_EQ(R.getOutOfBandError(), nullptr); } TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromCString) { auto R = WrapperFunctionResult::copyFrom(TestString); EXPECT_EQ(R.size(), strlen(TestString) + 1); EXPECT_TRUE(strcmp(R.data(), TestString) == 0); EXPECT_FALSE(R.empty()); EXPECT_EQ(R.getOutOfBandError(), nullptr); } TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromStdString) { auto R = WrapperFunctionResult::copyFrom(std::string(TestString)); EXPECT_EQ(R.size(), strlen(TestString) + 1); EXPECT_TRUE(strcmp(R.data(), TestString) == 0); EXPECT_FALSE(R.empty()); EXPECT_EQ(R.getOutOfBandError(), nullptr); } TEST(WrapperFunctionUtilsTest, WrapperFunctionResultFromOutOfBandError) { auto R = WrapperFunctionResult::createOutOfBandError(TestString); EXPECT_FALSE(R.empty()); EXPECT_TRUE(strcmp(R.getOutOfBandError(), TestString) == 0); } TEST(WrapperFunctionUtilsTest, SPSOutputBuffer) { constexpr unsigned NumBytes = 8; char Buffer[NumBytes]; char Zero = 0; SPSOutputBuffer OB(Buffer, NumBytes); // Expect that we can write NumBytes of content. for (unsigned I = 0; I != NumBytes; ++I) { char C = I; EXPECT_TRUE(OB.write(&C, 1)); } // Expect an error when we attempt to write an extra byte. EXPECT_FALSE(OB.write(&Zero, 1)); // Check that the buffer contains the expected content. for (unsigned I = 0; I != NumBytes; ++I) EXPECT_EQ(Buffer[I], (char)I); } TEST(WrapperFunctionUtilsTest, SPSInputBuffer) { char Buffer[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; SPSInputBuffer IB(Buffer, sizeof(Buffer)); char C; for (unsigned I = 0; I != sizeof(Buffer); ++I) { EXPECT_TRUE(IB.read(&C, 1)); EXPECT_EQ(C, (char)I); } EXPECT_FALSE(IB.read(&C, 1)); } template static void blobSerializationRoundTrip(const T &Value) { using BST = SPSSerializationTraits; size_t Size = BST::size(Value); auto Buffer = std::make_unique(Size); SPSOutputBuffer OB(Buffer.get(), Size); EXPECT_TRUE(BST::serialize(OB, Value)); SPSInputBuffer IB(Buffer.get(), Size); T DSValue; EXPECT_TRUE(BST::deserialize(IB, DSValue)); EXPECT_EQ(Value, DSValue) << "Incorrect value after serialization/deserialization round-trip"; } template static void testFixedIntegralTypeSerialization() { blobSerializationRoundTrip(0); blobSerializationRoundTrip(static_cast(1)); if (std::is_signed::value) { blobSerializationRoundTrip(static_cast(-1)); blobSerializationRoundTrip(std::numeric_limits::min()); } blobSerializationRoundTrip(std::numeric_limits::max()); } TEST(WrapperFunctionUtilsTest, BoolSerialization) { blobSerializationRoundTrip(true); blobSerializationRoundTrip(false); } TEST(WrapperFunctionUtilsTest, CharSerialization) { blobSerializationRoundTrip((char)0x00); blobSerializationRoundTrip((char)0xAA); blobSerializationRoundTrip((char)0xFF); } TEST(WrapperFunctionUtilsTest, Int8Serialization) { testFixedIntegralTypeSerialization(); } TEST(WrapperFunctionUtilsTest, UInt8Serialization) { testFixedIntegralTypeSerialization(); } TEST(WrapperFunctionUtilsTest, Int16Serialization) { testFixedIntegralTypeSerialization(); } TEST(WrapperFunctionUtilsTest, UInt16Serialization) { testFixedIntegralTypeSerialization(); } TEST(WrapperFunctionUtilsTest, Int32Serialization) { testFixedIntegralTypeSerialization(); } TEST(WrapperFunctionUtilsTest, UInt32Serialization) { testFixedIntegralTypeSerialization(); } TEST(WrapperFunctionUtilsTest, Int64Serialization) { testFixedIntegralTypeSerialization(); } TEST(WrapperFunctionUtilsTest, UInt64Serialization) { testFixedIntegralTypeSerialization(); } TEST(WrapperFunctionUtilsTest, SequenceSerialization) { std::vector V({1, 2, -47, 139}); blobSerializationRoundTrip, std::vector>(V); } TEST(WrapperFunctionUtilsTest, StringViewCharSequenceSerialization) { const char *HW = "Hello, world!"; blobSerializationRoundTrip(string_view(HW)); } TEST(WrapperFunctionUtilsTest, StdPairSerialization) { std::pair P(42, "foo"); blobSerializationRoundTrip, std::pair>(P); } TEST(WrapperFunctionUtilsTest, ArgListSerialization) { using BAL = SPSArgList; bool Arg1 = true; int32_t Arg2 = 42; std::string Arg3 = "foo"; size_t Size = BAL::size(Arg1, Arg2, Arg3); auto Buffer = std::make_unique(Size); SPSOutputBuffer OB(Buffer.get(), Size); EXPECT_TRUE(BAL::serialize(OB, Arg1, Arg2, Arg3)); SPSInputBuffer IB(Buffer.get(), Size); bool ArgOut1; int32_t ArgOut2; std::string ArgOut3; EXPECT_TRUE(BAL::deserialize(IB, ArgOut1, ArgOut2, ArgOut3)); EXPECT_EQ(Arg1, ArgOut1); EXPECT_EQ(Arg2, ArgOut2); EXPECT_EQ(Arg3, ArgOut3); } static __orc_rt_CWrapperFunctionResult addWrapper(const char *ArgData, size_t ArgSize) { return WrapperFunction::handle( ArgData, ArgSize, [](int32_t X, int32_t Y) -> int32_t { return X + Y; }) .release(); } extern "C" __orc_rt_Opaque __orc_rt_jit_dispatch_ctx{}; extern "C" __orc_rt_CWrapperFunctionResult __orc_rt_jit_dispatch(__orc_rt_Opaque *Ctx, const void *FnTag, const char *ArgData, size_t ArgSize) { using WrapperFunctionType = __orc_rt_CWrapperFunctionResult (*)(const char *, size_t); return reinterpret_cast(const_cast(FnTag))( ArgData, ArgSize); } TEST(WrapperFunctionUtilsTest, WrapperFunctionCallAndHandle) { int32_t Result; EXPECT_FALSE(!!WrapperFunction::call( (void *)&addWrapper, Result, 1, 2)); EXPECT_EQ(Result, (int32_t)3); }