* Refactor IJW test infra. Add some tests for some interesting simple native varargs.
* Add missing include of IjwHelper.cs
* Fix Cmake test project name.
* PR Feedback.
* Fix compilation error.
* Deploy msvcp*d.dll as part of the copy-local'd CRT.
add_subdirectory(IJW/IjwNativeDll)
add_subdirectory(IJW/IjwNativeCallingManagedDll)
add_subdirectory(IJW/CopyConstructorMarshaler)
+ add_subdirectory(IJW/NativeVarargs)
endif()
endif(WIN32)
cmake_minimum_required (VERSION 2.6)
project (CopyConstructorMarshaler)
+include("../IJW.cmake")
+
include_directories( ${INC_PLATFORM_DIR} )
set(SOURCES IjwCopyConstructorMarshaler.cpp)
-if (WIN32)
- # 4365 - signed/unsigned mismatch
- add_compile_options(/wd4365)
-
- # IJW
- add_compile_options(/clr)
-
- # IJW requires the CRT as a dll, not linked in
- add_compile_options(/MD$<$<OR:$<CONFIG:Debug>,$<CONFIG:Checked>>:d>)
-
- # CMake enables /RTC1 and /EHsc by default, but they're not compatible with /clr, so remove them
- if(CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1")
- string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
- endif()
-
- if(CMAKE_CXX_FLAGS MATCHES "/EHsc")
- string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
- # IJW isn't compatible with CFG
- if(CMAKE_CXX_FLAGS MATCHES "/guard:cf")
- string(REPLACE "/guard:cf" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
- # IJW isn't compatible with GR-
- if(CMAKE_CXX_FLAGS MATCHES "/GR-")
- string(REPLACE "/GR-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
-endif()
-
# add the shared library
add_library (IjwCopyConstructorMarshaler SHARED ${SOURCES})
target_link_libraries(IjwCopyConstructorMarshaler ${LINK_LIBRARIES_ADDITIONAL})
try
{
- // Load a fake mscoree.dll to avoid starting desktop
- LoadLibraryEx(Path.Combine(Environment.CurrentDirectory, "mscoree.dll"), IntPtr.Zero, 0);
-
- Assembly ijwNativeDll = Assembly.Load("IjwCopyConstructorMarshaler");
+ Assembly ijwNativeDll = IjwHelper.LoadIjwAssembly("IjwCopyConstructorMarshaler");
Type testType = ijwNativeDll.GetType("TestClass");
object testInstance = Activator.CreateInstance(testType);
MethodInfo testMethod = testType.GetMethod("PInvokeNumCopies");
</ItemGroup>
<ItemGroup>
<Compile Include="CopyConstructorMarshaler.cs" />
+ <Compile Include="../IjwHelper.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="CMakeLists.txt" />
try
{
// Load a fake mscoree.dll to avoid starting desktop
- IntPtr ijwHost = NativeLibrary.Load(Path.Combine(Environment.CurrentDirectory, "mscoree.dll"));
+ IntPtr ijwHost = NativeLibrary.Load(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "mscoree.dll"));
WasModuleVTableQueriedDelegate wasModuleVTableQueried = Marshal.GetDelegateForFunctionPointer<WasModuleVTableQueriedDelegate>(NativeLibrary.GetExport(ijwHost, "WasModuleVTableQueried"));
</ItemGroup>
<ItemGroup>
<Compile Include="FixupCallsHostWhenLoaded.cs" />
+ <Compile Include="../IjwHelper.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../IjwNativeDll/CMakeLists.txt" />
--- /dev/null
+if (WIN32)
+ # 4365 - signed/unsigned mismatch
+ add_compile_options(/wd4365)
+
+ # IJW
+ add_compile_options(/clr)
+
+ # IJW requires the CRT as a dll, not linked in
+ add_compile_options(/MD$<$<OR:$<CONFIG:Debug>,$<CONFIG:Checked>>:d>)
+
+ # CMake enables /RTC1 and /EHsc by default, but they're not compatible with /clr, so remove them
+ if(CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1")
+ string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
+ endif()
+
+ if(CMAKE_CXX_FLAGS MATCHES "/EHsc")
+ string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ endif()
+
+ # IJW isn't compatible with CFG
+ if(CMAKE_CXX_FLAGS MATCHES "/guard:cf")
+ string(REPLACE "/guard:cf" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ endif()
+
+ # IJW isn't compatible with GR-
+ if(CMAKE_CXX_FLAGS MATCHES "/GR-")
+ string(REPLACE "/GR-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ endif()
+
+endif()
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using TestLibrary;
+
+class IjwHelper
+{
+ private const string ijwHostName = "mscoree.dll";
+
+ public static Assembly LoadIjwAssembly(string name)
+ {
+ // Load our mock ijwhost before we load the IJW assembly.
+ NativeLibrary.Load(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), ijwHostName));
+
+ return Assembly.Load(name);
+ }
+}
cmake_minimum_required (VERSION 2.6)
project (IjwNativeCallingManagedDll)
+include("../IJW.cmake")
+
include_directories( ${INC_PLATFORM_DIR} )
set(SOURCES IjwNativeCallingManagedDll.cpp)
-if (WIN32)
- # 4365 - signed/unsigned mismatch
- add_compile_options(/wd4365)
-
- # IJW
- add_compile_options(/clr)
-
- # IJW requires the CRT as a dll, not linked in
- add_compile_options(/MD$<$<OR:$<CONFIG:Debug>,$<CONFIG:Checked>>:d>)
-
- # CMake enables /RTC1 and /EHsc by default, but they're not compatible with /clr, so remove them
- if(CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1")
- string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
- endif()
-
- if(CMAKE_CXX_FLAGS MATCHES "/EHsc")
- string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
- # IJW isn't compatible with CFG
- if(CMAKE_CXX_FLAGS MATCHES "/guard:cf")
- string(REPLACE "/guard:cf" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
- # IJW isn't compatible with GR-
- if(CMAKE_CXX_FLAGS MATCHES "/GR-")
- string(REPLACE "/GR-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
-endif()
-
# add the shared library
add_library (IjwNativeCallingManagedDll SHARED ${SOURCES})
target_link_libraries(IjwNativeCallingManagedDll ${LINK_LIBRARIES_ADDITIONAL})
cmake_minimum_required (VERSION 2.6)
project (IjwNativeDll)
+include("../IJW.cmake")
+
include_directories( ${INC_PLATFORM_DIR} )
set(SOURCES IjwNativeDll.cpp)
-if (WIN32)
- # 4365 - signed/unsigned mismatch
- add_compile_options(/wd4365)
-
- # IJW
- add_compile_options(/clr)
-
- # IJW requires the CRT as a dll, not linked in
- add_compile_options(/MD$<$<OR:$<CONFIG:Debug>,$<CONFIG:Checked>>:d>)
-
- # CMake enables /RTC1 and /EHsc by default, but they're not compatible with /clr, so remove them
- if(CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1")
- string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
- endif()
-
- if(CMAKE_CXX_FLAGS MATCHES "/EHsc")
- string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
- # IJW isn't compatible with CFG
- if(CMAKE_CXX_FLAGS MATCHES "/guard:cf")
- string(REPLACE "/guard:cf" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
- # IJW isn't compatible with GR-
- if(CMAKE_CXX_FLAGS MATCHES "/GR-")
- string(REPLACE "/GR-" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
- endif()
-
-endif()
-
# add the shared library
add_library (IjwNativeDll SHARED ${SOURCES})
target_link_libraries(IjwNativeDll ${LINK_LIBRARIES_ADDITIONAL})
}
bool success = true;
- // Load a fake mscoree.dll to avoid starting desktop
- LoadLibraryEx(Path.Combine(Environment.CurrentDirectory, "mscoree.dll"), IntPtr.Zero, 0);
-
- TestFramework.BeginScenario("Calling from managed to native IJW code");
-
- // Building with a reference to the IJW dll is difficult, so load via reflection instead
- TestFramework.BeginTestCase("Load IJW dll via reflection");
- Assembly ijwNativeDll = Assembly.Load("IjwNativeDll");
- TestFramework.EndTestCase();
+ Assembly ijwNativeDll = IjwHelper.LoadIjwAssembly("IjwNativeDll");
TestFramework.BeginTestCase("Call native method returning int");
Type testType = ijwNativeDll.GetType("TestClass");
}
[DllImport("kernel32.dll")]
- static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, int dwFlags);
-
- [DllImport("kernel32.dll")]
static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
</ItemGroup>
<ItemGroup>
<Compile Include="ManagedCallingNative.cs" />
+ <Compile Include="../IjwHelper.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../IjwNativeDll/CMakeLists.txt" />
}
bool success = true;
- // Load a fake mscoree.dll to avoid starting desktop
- LoadLibraryEx(Path.Combine(Environment.CurrentDirectory, "mscoree.dll"), IntPtr.Zero, 0);
-
- TestFramework.BeginScenario("Calling from managed to native IJW code");
-
- // Building with a reference to the IJW dll is difficult, so load via reflection instead
- TestFramework.BeginTestCase("Load IJW dll via reflection");
- Assembly ijwNativeDll = Assembly.Load("IjwNativeCallingManagedDll");
- TestFramework.EndTestCase();
+ Assembly ijwNativeDll = IjwHelper.LoadIjwAssembly("IjwNativeCallingManagedDll");
TestFramework.BeginTestCase("Call native method returning int");
Type testType = ijwNativeDll.GetType("TestClass");
}
[DllImport("kernel32.dll")]
- static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, int dwFlags);
-
- [DllImport("kernel32.dll")]
static extern IntPtr GetModuleHandle(string lpModuleName);
}
}
</ItemGroup>
<ItemGroup>
<Compile Include="NativeCallingManaged.cs" />
+ <Compile Include="../IjwHelper.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../IjwNativeCallingManagedDll/CMakeLists.txt" />
--- /dev/null
+cmake_minimum_required (VERSION 2.6)
+project (IjwNativeVarargs)
+include("../IJW.cmake")
+
+include_directories( ${INC_PLATFORM_DIR} )
+set(SOURCES IjwNativeVarargs.cpp)
+
+# add the shared library
+add_library (IjwNativeVarargs SHARED ${SOURCES})
+target_link_libraries(IjwNativeVarargs ${LINK_LIBRARIES_ADDITIONAL})
+
+# add the install targets
+install (TARGETS IjwNativeVarargs DESTINATION bin)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#include <cstddef>
+#include <vector>
+#include <cstdarg>
+#include <cstdint>
+#include <numeric>
+#include <array>
+#include <functional>
+#include <iostream>
+#using <mscorlib.dll>
+using namespace System::Collections::Generic;
+
+public enum class TestCases
+{
+ SumInts,
+ SumFloats,
+ SumSumInt64s,
+ SumWidenedShorts,
+ SumDoubles,
+ SumWidenedFloats,
+ SumHFAs,
+ DoublesInIntegerRegisters
+};
+
+struct HFA
+{
+ float f1;
+ float f2;
+ float f3;
+ float f4;
+};
+
+#pragma unmanaged
+
+int SumInts(std::size_t numElements, ...)
+{
+ va_list args;
+ va_start(args, numElements);
+ int sum = 0;
+ for (std::size_t i = 0; i < numElements; ++i)
+ {
+ sum += va_arg(args, int);
+ }
+ va_end(args);
+ return sum;
+}
+
+std::int64_t SumSumInt64s(std::size_t numElements, ...)
+{
+ va_list args;
+ va_start(args, numElements);
+ std::int64_t sum = 0;
+ for (std::size_t i = 0; i < numElements; ++i)
+ {
+ sum += va_arg(args, std::int64_t);
+ }
+ va_end(args);
+ return sum;
+}
+
+double SumDoubles(std::size_t numElements, ...)
+{
+ va_list args;
+ va_start(args, numElements);
+ double sum = 0;
+ for (std::size_t i = 0; i < numElements; ++i)
+ {
+ sum += va_arg(args, double);
+ }
+ va_end(args);
+ return sum;
+}
+
+float SumHFAs(std::size_t numElements, ...)
+{
+ va_list args;
+ va_start(args, numElements);
+ float sum = 0;
+ for (std::size_t i = 0; i < numElements; ++i)
+ {
+ HFA hfa = va_arg(args, HFA);
+ sum += hfa.f1 + hfa.f2 + hfa.f3 + hfa.f4;
+ }
+ va_end(args);
+ return sum;
+}
+
+constexpr std::size_t NumArgsPerCall = 41; // Match number of arguments used in JIT/Directed/arglist/vararg test.
+
+#pragma managed
+
+public ref class TestClass
+{
+public:
+ List<TestCases>^ RunTests(int seed)
+ {
+ System::Random^ rng = gcnew System::Random(seed);
+ List<TestCases>^ failedTests = gcnew List<TestCases>();
+
+ if (!RunIntsTest(rng))
+ {
+ failedTests->Add(TestCases::SumInts);
+ }
+ if (!RunDoublesTest(rng))
+ {
+ failedTests->Add(TestCases::SumDoubles);
+ }
+ if (!RunSumInt64sTest(rng))
+ {
+ failedTests->Add(TestCases::SumSumInt64s);
+ }
+ if (!RunWidenedShortsTest(rng))
+ {
+ failedTests->Add(TestCases::SumWidenedShorts);
+ }
+ if (!RunWidenedFloatsTest(rng))
+ {
+ failedTests->Add(TestCases::SumWidenedFloats);
+ }
+ if (!RunHFAsTest(rng))
+ {
+ failedTests->Add(TestCases::SumHFAs);
+ }
+#if _WIN64
+ if (!RunDoublesInIntegerRegistersTest())
+ {
+ failedTests->Add(TestCases::DoublesInIntegerRegisters);
+ }
+#endif
+
+ return failedTests;
+ }
+private:
+ bool RunIntsTest(System::Random^ rng)
+ {
+ std::array<int, NumArgsPerCall> values;
+ for(std::size_t i = 0; i < NumArgsPerCall; ++i)
+ {
+ values[i] = rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ }
+
+ auto expected = std::accumulate(values.begin(), values.end(), 0, std::plus<>{});
+ auto actual = SumInts(NumArgsPerCall,
+ values[0],
+ values[1],
+ values[2],
+ values[3],
+ values[4],
+ values[5],
+ values[6],
+ values[7],
+ values[8],
+ values[9],
+ values[10],
+ values[11],
+ values[12],
+ values[13],
+ values[14],
+ values[15],
+ values[16],
+ values[17],
+ values[18],
+ values[19],
+ values[20],
+ values[21],
+ values[22],
+ values[23],
+ values[24],
+ values[25],
+ values[26],
+ values[27],
+ values[28],
+ values[29],
+ values[30],
+ values[31],
+ values[32],
+ values[33],
+ values[34],
+ values[35],
+ values[36],
+ values[37],
+ values[38],
+ values[39],
+ values[40]
+ );
+ bool result = expected == actual;
+ if (!result)
+ {
+ std::cout << "RunIntsTest Failed:" << "Expected:" << expected << '\t' << "Actual:" << actual << std::endl;
+ }
+ return result;
+ }
+
+ bool RunDoublesTest(System::Random^ rng)
+ {
+ std::array<double, NumArgsPerCall> values;
+ for (std::size_t i = 0; i < NumArgsPerCall; ++i)
+ {
+ values[i] = (double)rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ }
+
+ auto expected = std::accumulate(values.begin(), values.end(), 0.0, std::plus<>{});
+ auto actual = SumDoubles(NumArgsPerCall,
+ values[0],
+ values[1],
+ values[2],
+ values[3],
+ values[4],
+ values[5],
+ values[6],
+ values[7],
+ values[8],
+ values[9],
+ values[10],
+ values[11],
+ values[12],
+ values[13],
+ values[14],
+ values[15],
+ values[16],
+ values[17],
+ values[18],
+ values[19],
+ values[20],
+ values[21],
+ values[22],
+ values[23],
+ values[24],
+ values[25],
+ values[26],
+ values[27],
+ values[28],
+ values[29],
+ values[30],
+ values[31],
+ values[32],
+ values[33],
+ values[34],
+ values[35],
+ values[36],
+ values[37],
+ values[38],
+ values[39],
+ values[40]
+ );
+ bool result = expected == actual;
+ if (!result)
+ {
+ std::cout << "RunDoublesTest Failed:" << "Expected:" << expected << '\t' << "Actual:" << actual << std::endl;
+ }
+ return result;
+ }
+
+ bool RunHFAsTest(System::Random^ rng)
+ {
+ std::array<HFA, NumArgsPerCall> values;
+ for (std::size_t i = 0; i < NumArgsPerCall; ++i)
+ {
+ values[i].f1 = (float)rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ values[i].f2 = (float)rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ values[i].f3 = (float)rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ values[i].f4 = (float)rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ }
+
+ auto expected = std::accumulate(values.begin(), values.end(), 0.0f, AggregateHFAs);
+ auto actual = SumHFAs(NumArgsPerCall,
+ values[0],
+ values[1],
+ values[2],
+ values[3],
+ values[4],
+ values[5],
+ values[6],
+ values[7],
+ values[8],
+ values[9],
+ values[10],
+ values[11],
+ values[12],
+ values[13],
+ values[14],
+ values[15],
+ values[16],
+ values[17],
+ values[18],
+ values[19],
+ values[20],
+ values[21],
+ values[22],
+ values[23],
+ values[24],
+ values[25],
+ values[26],
+ values[27],
+ values[28],
+ values[29],
+ values[30],
+ values[31],
+ values[32],
+ values[33],
+ values[34],
+ values[35],
+ values[36],
+ values[37],
+ values[38],
+ values[39],
+ values[40]
+ );
+ bool result = expected == actual;
+ if (!result)
+ {
+ std::cout << "RunHFAsTest Failed:" << "Expected:" << expected << '\t' << "Actual:" << actual << std::endl;
+ }
+ return result;
+ }
+
+ static float AggregateHFAs(float current, HFA hfa)
+ {
+ return current + hfa.f1 + hfa.f2 + hfa.f3 + hfa.f4;
+ }
+
+ bool RunSumInt64sTest(System::Random^ rng)
+ {
+ std::array<std::int64_t, NumArgsPerCall> values;
+ for (std::size_t i = 0; i < NumArgsPerCall; ++i)
+ {
+ values[i] = rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ }
+
+ auto expected = std::accumulate(values.begin(), values.end(), 0LL, std::plus<>{});
+ auto actual = SumSumInt64s(NumArgsPerCall,
+ values[0],
+ values[1],
+ values[2],
+ values[3],
+ values[4],
+ values[5],
+ values[6],
+ values[7],
+ values[8],
+ values[9],
+ values[10],
+ values[11],
+ values[12],
+ values[13],
+ values[14],
+ values[15],
+ values[16],
+ values[17],
+ values[18],
+ values[19],
+ values[20],
+ values[21],
+ values[22],
+ values[23],
+ values[24],
+ values[25],
+ values[26],
+ values[27],
+ values[28],
+ values[29],
+ values[30],
+ values[31],
+ values[32],
+ values[33],
+ values[34],
+ values[35],
+ values[36],
+ values[37],
+ values[38],
+ values[39],
+ values[40]
+ );
+ bool result = expected == actual;
+ if (!result)
+ {
+ std::cout << "RunSumInt64sTest Failed:" << "Expected:" << expected << '\t' << "Actual:" << actual << std::endl;
+ }
+ return result;
+ }
+
+ bool RunWidenedShortsTest(System::Random^ rng)
+ {
+ std::array<int, NumArgsPerCall / 2> intValues;
+ std::array<short, NumArgsPerCall - (NumArgsPerCall / 2)> shortValues;
+ for (std::size_t i = 0; i < intValues.size(); ++i)
+ {
+ intValues[i] = rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ }
+ for (std::size_t i = 0; i < shortValues.size(); ++i)
+ {
+ shortValues[i] = (short)rng->Next(System::Int16::MinValue, System::Int16::MaxValue);
+ }
+
+ auto expected = std::accumulate(intValues.begin(), intValues.end(), 0, std::plus<>{}) + std::accumulate(shortValues.begin(), shortValues.end(), 0LL, std::plus<>{});
+ auto actual = SumInts(NumArgsPerCall,
+ shortValues[0],
+ intValues[0], shortValues[1],
+ intValues[1], shortValues[2],
+ intValues[2], shortValues[3],
+ intValues[3], shortValues[4],
+ intValues[4], shortValues[5],
+ intValues[5], shortValues[6],
+ intValues[6], shortValues[7],
+ intValues[7], shortValues[8],
+ intValues[8], shortValues[9],
+ intValues[9], shortValues[10],
+ intValues[10], shortValues[11],
+ intValues[11], shortValues[12],
+ intValues[12], shortValues[13],
+ intValues[13], shortValues[14],
+ intValues[14], shortValues[15],
+ intValues[15], shortValues[16],
+ intValues[16], shortValues[17],
+ intValues[17], shortValues[18],
+ intValues[18], shortValues[19],
+ intValues[19], shortValues[20]
+ );
+ bool result = expected == actual;
+ if (!result)
+ {
+ std::cout << "RunWidenedShortsTest Failed:" << "Expected:" << expected << '\t' << "Actual:" << actual << std::endl;
+ }
+ return result;
+ }
+
+ bool RunWidenedFloatsTest(System::Random^ rng)
+ {
+ std::array<float, NumArgsPerCall / 2> floatValues;
+ std::array<double, NumArgsPerCall - (NumArgsPerCall / 2)> doubleValues;
+ for (std::size_t i = 0; i < floatValues.size(); ++i)
+ {
+ floatValues[i] = (float)rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ }
+ for (std::size_t i = 0; i < doubleValues.size(); ++i)
+ {
+ doubleValues[i] = (double)rng->Next(System::Int32::MinValue, System::Int32::MaxValue);
+ }
+
+ double expected = 0.0;
+ for (std::size_t i = 0; i < floatValues.size(); ++i)
+ {
+ expected += floatValues[i];
+ }
+ for (std::size_t i = 0; i < doubleValues.size(); ++i)
+ {
+ expected += doubleValues[i];
+ }
+
+ auto actual = SumDoubles(NumArgsPerCall,
+ doubleValues[0],
+ floatValues[0], doubleValues[1],
+ floatValues[1], doubleValues[2],
+ floatValues[2], doubleValues[3],
+ floatValues[3], doubleValues[4],
+ floatValues[4], doubleValues[5],
+ floatValues[5], doubleValues[6],
+ floatValues[6], doubleValues[7],
+ floatValues[7], doubleValues[8],
+ floatValues[8], doubleValues[9],
+ floatValues[9], doubleValues[10],
+ floatValues[10], doubleValues[11],
+ floatValues[11], doubleValues[12],
+ floatValues[12], doubleValues[13],
+ floatValues[13], doubleValues[14],
+ floatValues[14], doubleValues[15],
+ floatValues[15], doubleValues[16],
+ floatValues[16], doubleValues[17],
+ floatValues[17], doubleValues[18],
+ floatValues[18], doubleValues[19],
+ floatValues[19], doubleValues[20]
+ );
+ bool result = expected == actual;
+ if (!result)
+ {
+ std::cout << "RunWidenedFloatsTest Failed:" << "Expected:" << expected << '\t' << "Actual:" << actual << std::endl;
+ }
+ return result;
+ }
+
+ bool RunDoublesInIntegerRegistersTest()
+ {
+ double a = 123.456;
+ std::int64_t expected = *reinterpret_cast<std::int64_t*>(&a);
+ std::int64_t actual = SumSumInt64s(1, a);
+ bool result = expected == actual;
+ if (!result)
+ {
+ std::cout << "RunDoublesInIntegerRegistersTest Failed:" << "Expected:" << expected << '\t' << "Actual:" << actual << std::endl;
+ }
+ return result;
+ }
+};
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using TestLibrary;
+
+namespace NativeVarargsTest
+{
+ class NativeVarargsTest
+ {
+ static int Main(string[] args)
+ {
+ if(Environment.OSVersion.Platform != PlatformID.Win32NT || TestLibrary.Utilities.IsWindows7)
+ {
+ return 100;
+ }
+
+ // Use the same seed for consistency between runs.
+ int seed = 42;
+
+ try
+ {
+ Assembly ijwNativeDll = IjwHelper.LoadIjwAssembly("IjwNativeVarargs");
+ Type testType = ijwNativeDll.GetType("TestClass");
+ object testInstance = Activator.CreateInstance(testType);
+ MethodInfo testMethod = testType.GetMethod("RunTests");
+ IEnumerable failedTests = (IEnumerable)testMethod.Invoke(testInstance, BindingFlags.DoNotWrapExceptions, null, new object[] {seed}, null);
+
+ if (failedTests.OfType<object>().Any())
+ {
+ Console.WriteLine("Failed Varargs tests:");
+ foreach (var failedTest in failedTests)
+ {
+ Console.WriteLine($"\t{failedTest}");
+ }
+ return 102;
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ return 101;
+ }
+ return 100;
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>NativeVarargsTest</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{49D1D482-E783-4CA9-B6BA-A9714BF81036}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+ <!-- IJW is Windows-only -->
+ <!-- Test unsupported outside of windows -->
+ <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+ <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+
+ <!-- IJW is not supported on ARM64 -->
+ <DisableProjectBuild Condition="'$(Platform)' == 'arm64'">true</DisableProjectBuild>
+ <!-- Native varargs not supported on ARM -->
+ <DisableProjectBuild Condition="'$(Platform)' == 'arm'">true</DisableProjectBuild>
+
+ <!-- Loading IJW assemblies into an unloadable context is not allowed -->
+ <UnloadabilityIncompatible>true</UnloadabilityIncompatible>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <PropertyGroup>
+ <CopyDebugCRTDllsToOutputDirectory>true</CopyDebugCRTDllsToOutputDirectory>
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="NativeVarargsTest.cs" />
+ <Compile Include="../IjwHelper.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="CMakeLists.txt" />
+ <ProjectReference Include="../ijwhostmock/CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
Condition="'$(TargetsWindows)' == 'true' And ('$(Configuration)' == 'Debug' Or '$(Configuration)' == 'Checked') And '$(CopyDebugCRTDllsToOutputDirectory)' == 'true'" >
<None Include="$(VCToolsRedistDir)onecore/debug_nonredist/$(Platform)/Microsoft.VC*.DebugCRT/vcruntime*d.dll" CopyToOutputDirectory="Always" />
+ <None Include="$(VCToolsRedistDir)onecore/debug_nonredist/$(Platform)/Microsoft.VC*.DebugCRT/msvcp*d.dll" CopyToOutputDirectory="Always" />
<None Include="$(ExtensionSdkDir)/Microsoft.UniversalCRT.Debug/$(UCRTVersion)/Redist/Debug/$(Platform)/ucrtbased.dll" CopyToOutputDirectory="Always" />
</ItemGroup>
</Project>