You've already forked linux-packaging-mono
Imported Upstream version 5.20.0.180
Former-commit-id: ff953ca879339fe1e1211f7220f563e1342e66cb
This commit is contained in:
parent
0e2d47d1c8
commit
0510252385
@@ -1,8 +1,6 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
rem Enable Server GC for this test
|
||||
set RH_UseServerGC=1
|
||||
"%1\%2"
|
||||
set ErrorCode=%ERRORLEVEL%
|
||||
IF "%ErrorCode%"=="100" (
|
||||
|
||||
@@ -17,10 +17,6 @@ class Program
|
||||
{
|
||||
SimpleReadWriteThreadStaticTest.Run(42, "SimpleReadWriteThreadStatic");
|
||||
|
||||
// TODO: After issue https://github.com/dotnet/corert/issues/2695 is fixed, move FinalizeTest to run at the end
|
||||
if (FinalizeTest.Run() != Pass)
|
||||
return Fail;
|
||||
|
||||
ThreadStaticsTestWithTasks.Run();
|
||||
|
||||
if (ThreadTest.Run() != Pass)
|
||||
@@ -28,6 +24,9 @@ class Program
|
||||
|
||||
if (TimerTest.Run() != Pass)
|
||||
return Fail;
|
||||
|
||||
if (FinalizeTest.Run() != Pass)
|
||||
return Fail;
|
||||
|
||||
return Pass;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Enable Server GC for this test
|
||||
export RH_UseServerGC=1
|
||||
$1/$2
|
||||
if [ $? == 100 ]; then
|
||||
echo pass
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
using System;
|
||||
|
||||
using Pointer = System.Reflection.Pointer;
|
||||
|
||||
public class BringUpTests
|
||||
{
|
||||
const int Pass = 100;
|
||||
@@ -105,6 +107,14 @@ public class BringUpTests
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
// This will end up being a delegate to a sealed virtual method.
|
||||
ClassWithIFoo t = new ClassWithIFoo("Class");
|
||||
Func<int, string> d = t.DoFoo;
|
||||
if (d(987) != "Class987")
|
||||
return false;
|
||||
}
|
||||
|
||||
Console.WriteLine("OK");
|
||||
return true;
|
||||
}
|
||||
@@ -247,7 +257,10 @@ public class BringUpTests
|
||||
unsafe
|
||||
{
|
||||
GetAndReturnPointerDelegate d = ClassWithPointers.GetAndReturnPointer;
|
||||
if ((IntPtr)d.DynamicInvoke(new object[] { (IntPtr)8 }) != (IntPtr)50)
|
||||
if (Pointer.Unbox(d.DynamicInvoke(new object[] { (IntPtr)8 })) != (void*)50)
|
||||
return false;
|
||||
|
||||
if (Pointer.Unbox(d.DynamicInvoke(new object[] { Pointer.Box((void*)9, typeof(void*)) })) != (void*)51)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -390,14 +403,14 @@ static class ExtensionClass
|
||||
}
|
||||
}
|
||||
|
||||
unsafe delegate IntPtr GetAndReturnPointerDelegate(void* ptr);
|
||||
unsafe delegate byte* GetAndReturnPointerDelegate(void* ptr);
|
||||
unsafe delegate void PassPointerByRefDelegate(ref void* ptr);
|
||||
|
||||
unsafe static class ClassWithPointers
|
||||
{
|
||||
public static IntPtr GetAndReturnPointer(void* ptr)
|
||||
public static byte* GetAndReturnPointer(void* ptr)
|
||||
{
|
||||
return (IntPtr)((byte*)ptr + 42);
|
||||
return (byte*)ptr + 42;
|
||||
}
|
||||
|
||||
public static void PassPointerByRef(ref void* ptr)
|
||||
|
||||
@@ -31,6 +31,8 @@ class Program
|
||||
TestGvmDependencies.Run();
|
||||
TestFieldAccess.Run();
|
||||
TestNativeLayoutGeneration.Run();
|
||||
TestInterfaceVTableTracking.Run();
|
||||
TestClassVTableTracking.Run();
|
||||
|
||||
return 100;
|
||||
}
|
||||
@@ -2088,4 +2090,60 @@ class Program
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
class TestInterfaceVTableTracking
|
||||
{
|
||||
class Gen<T> { }
|
||||
|
||||
interface IFoo<T>
|
||||
{
|
||||
Array Frob();
|
||||
}
|
||||
|
||||
class GenericBase<T> : IFoo<T>
|
||||
{
|
||||
public Array Frob()
|
||||
{
|
||||
return new Gen<T>[1,1];
|
||||
}
|
||||
}
|
||||
|
||||
class Derived<T> : GenericBase<Gen<T>>
|
||||
{
|
||||
}
|
||||
|
||||
static volatile IFoo<Gen<string>> s_foo;
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
// This only really tests whether we can compile this.
|
||||
s_foo = new Derived<string>();
|
||||
Array arr = s_foo.Frob();
|
||||
arr.SetValue(new Gen<Gen<string>>(), new int[] { 0, 0 });
|
||||
}
|
||||
}
|
||||
|
||||
class TestClassVTableTracking
|
||||
{
|
||||
class Unit { }
|
||||
|
||||
class Gen<T, U>
|
||||
{
|
||||
public virtual int Test()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
static int Call<T>()
|
||||
{
|
||||
return new Gen<T, Unit>().Test();
|
||||
}
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
// This only really tests whether we can compile this.
|
||||
Call<object>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
@echo off
|
||||
setlocal
|
||||
set ErrorCode=100
|
||||
for /f "usebackq delims=;" %%F in (`"%1\%2" world`) do (
|
||||
if "%%F"=="Hello world" set ErrorCode=0
|
||||
)
|
||||
IF "%ErrorCode%"=="0" (
|
||||
echo %~n0: pass
|
||||
|
||||
call emrun --browser=firefox --browser_args=-headless --safe_firefox_profile --silence_timeout 10 "%1\%2"
|
||||
|
||||
IF "%errorlevel%"=="100" (
|
||||
echo %~n0: Pass
|
||||
EXIT /b 0
|
||||
) ELSE (
|
||||
echo %~n0: fail - %ErrorCode%
|
||||
echo %~n0: fail - %ErrorLevel%
|
||||
EXIT /b 1
|
||||
)
|
||||
endlocal
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
<ProjectReference Include="CpObj.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
<IlcArg Include="-r:$(IntermediateOutputPath)\CpObj.dll" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
|
||||
<ProjectReference Include="ILHelpers.ilproj" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
<IlcArg Include="-r:$(IntermediateOutputPath)\ILHelpers.dll" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(OS)' == 'Windows_NT'">
|
||||
|
||||
111
external/corert/tests/src/Simple/HelloWasm/ILHelpers.il
vendored
Normal file
111
external/corert/tests/src/Simple/HelloWasm/ILHelpers.il
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
// 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.
|
||||
|
||||
.assembly extern mscorlib
|
||||
{
|
||||
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
|
||||
.ver 4:0:0:0
|
||||
}
|
||||
|
||||
.assembly extern System.Private.CoreLib
|
||||
{
|
||||
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )
|
||||
.ver 4:0:0:0
|
||||
}
|
||||
|
||||
.assembly ILHelpers { }
|
||||
|
||||
.class public ILHelpers.ILHelpersTest
|
||||
{
|
||||
.method public static void EatArgs(string, object)
|
||||
{
|
||||
ret
|
||||
}
|
||||
|
||||
.method public static void EatArg(object)
|
||||
{
|
||||
ret
|
||||
}
|
||||
//this is copied from the test case for https://github.com/dotnet/coreclr/issues/14784
|
||||
//its been adapted to remove the requirement for Console.WriteLine because thats not supported in WASM
|
||||
//it can be removed once we have support for Console.WriteLine and can run the CoreCLR tests
|
||||
.method public static int32 InlineAssignByte()
|
||||
{
|
||||
.locals init (
|
||||
int8 local,
|
||||
object b
|
||||
)
|
||||
ldstr "InlineAssignByte"
|
||||
ldc.i4 300
|
||||
dup
|
||||
stloc.0
|
||||
box int32
|
||||
stloc.1
|
||||
ldloc.1
|
||||
call void ILHelpers.ILHelpersTest::EatArgs(string, object)
|
||||
ldstr "InlineAssignByte"
|
||||
ldloc.0
|
||||
box int32
|
||||
call void ILHelpers.ILHelpersTest::EatArgs(string, object)
|
||||
ldloc.1
|
||||
//after the unboxing and truncation on the way in ensure that we can subtract 200 and end up with the expected 100 return value
|
||||
unbox.any int32
|
||||
ldc.i4 200
|
||||
sub
|
||||
ret
|
||||
}
|
||||
.method public static int32 DupTest(int32&)
|
||||
{
|
||||
.locals init (
|
||||
int32 local,
|
||||
int32 local2
|
||||
)
|
||||
ldarg.0
|
||||
//push a bunch of entries onto the stack using dup, we will consume them through the rest of this method
|
||||
dup
|
||||
dup
|
||||
dup
|
||||
dup
|
||||
dup
|
||||
//first off lets ensure the passed parameter was pointing to an int of less than 10 (it should be 9)
|
||||
ldind.i4
|
||||
ldc.i4 10
|
||||
clt
|
||||
brtrue target
|
||||
//this is just trying to mess with the stack accross basic block boundries
|
||||
//it should actually leave the evaluation stack unchanged in the end
|
||||
pop
|
||||
dup
|
||||
//make sure we can deref one of our duplicate int refs and box it without any trouble
|
||||
target: ldind.i4
|
||||
box int32
|
||||
call void ILHelpers.ILHelpersTest::EatArg(object)
|
||||
//deref one of our duplicates and add 1 to it, this should not write back to the parameter it should only be stored in the local
|
||||
ldind.i4
|
||||
ldc.i4 1
|
||||
add
|
||||
stloc.0
|
||||
//load one of our duplicates and add 200 to it, we're eventually going to return this value and test for it in the caller
|
||||
ldind.i4
|
||||
ldc.i4 200
|
||||
add
|
||||
//this should write back into the parameter
|
||||
stind.i4
|
||||
ldloc.0
|
||||
dup
|
||||
add
|
||||
dup
|
||||
stloc.1
|
||||
ldloc.0
|
||||
ceq
|
||||
//if the added value equals the source value we've got something writing to its original StackEntry instead of a dup
|
||||
brtrue failure
|
||||
ldind.i4
|
||||
ret
|
||||
failure:
|
||||
pop
|
||||
ldc.i4 0
|
||||
ret
|
||||
}
|
||||
}
|
||||
20
external/corert/tests/src/Simple/HelloWasm/ILHelpers.ilproj
vendored
Normal file
20
external/corert/tests/src/Simple/HelloWasm/ILHelpers.ilproj
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<DebugType>portable</DebugType>
|
||||
<OutputPath>$(MSBuildProjectDirectory)\bin\$(Configuration)\$(Platform)\</OutputPath>
|
||||
<IntermediateOutputPath>$(MSBuildProjectDirectory)\obj\$(Configuration)\$(Platform)\</IntermediateOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="ILHelpers.il" />
|
||||
<PackageReference Include="Microsoft.NETCore.App">
|
||||
<Version>$(MicrosoftNETCoreAppPackageVersion)</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
||||
@@ -13,16 +13,46 @@ internal static class Program
|
||||
private static int staticInt;
|
||||
[ThreadStatic]
|
||||
private static int threadStaticInt;
|
||||
private static unsafe void Main(string[] args)
|
||||
private static unsafe int Main(string[] args)
|
||||
{
|
||||
PrintLine("Starting");
|
||||
|
||||
Add(1, 2);
|
||||
int tempInt = 0;
|
||||
int tempInt2 = 0;
|
||||
(*(&tempInt)) = 9;
|
||||
if(tempInt == 9)
|
||||
{
|
||||
PrintLine("Hello from C#!");
|
||||
}
|
||||
|
||||
int* targetAddr = (tempInt > 0) ? (&tempInt2) : (&tempInt);
|
||||
|
||||
(*targetAddr) = 1;
|
||||
if(tempInt2 == 1 && tempInt == 9)
|
||||
{
|
||||
PrintLine("basic block stack entry Test: Ok.");
|
||||
}
|
||||
|
||||
if(ILHelpers.ILHelpersTest.InlineAssignByte() == 100)
|
||||
{
|
||||
PrintLine("Inline assign byte Test: Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("Inline assign byte Test: Failed.");
|
||||
}
|
||||
|
||||
int dupTestInt = 9;
|
||||
if(ILHelpers.ILHelpersTest.DupTest(ref dupTestInt) == 209 && dupTestInt == 209)
|
||||
{
|
||||
PrintLine("dup test: Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("dup test: Failed.");
|
||||
}
|
||||
|
||||
TestClass tempObj = new TestDerivedClass(1337);
|
||||
tempObj.TestMethod("Hello");
|
||||
tempObj.TestVirtualMethod("Hello");
|
||||
@@ -55,12 +85,19 @@ internal static class Program
|
||||
PrintLine("thread static int field test: Ok.");
|
||||
}
|
||||
|
||||
StaticCtorTest();
|
||||
|
||||
var boxedInt = (object)tempInt;
|
||||
if(((int)boxedInt) == 9)
|
||||
{
|
||||
PrintLine("box test: Ok.");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
PrintLine("box test: Failed. Value:");
|
||||
PrintLine(boxedInt.ToString());
|
||||
}
|
||||
|
||||
var boxedStruct = (object)new BoxStubTest { Value = "Boxed Stub Test: Ok." };
|
||||
PrintLine(boxedStruct.ToString());
|
||||
|
||||
@@ -157,6 +194,10 @@ internal static class Program
|
||||
arrayTest[1].Value = "Array load/store test: Ok.";
|
||||
PrintLine(arrayTest[1].Value);
|
||||
|
||||
int ii = 0;
|
||||
arrayTest[ii++].Value = "dup ref test: Ok.";
|
||||
PrintLine(arrayTest[0].Value);
|
||||
|
||||
var largeArrayTest = new long[] { Int64.MaxValue, 0, Int64.MinValue, 0 };
|
||||
if(largeArrayTest[0] == Int64.MaxValue &&
|
||||
largeArrayTest[1] == 0 &&
|
||||
@@ -186,6 +227,9 @@ internal static class Program
|
||||
IntToStringTest();
|
||||
|
||||
CastingTestClass castingTest = new DerivedCastingTestClass1();
|
||||
|
||||
PrintLine("interface call test: Ok " + (castingTest as ICastingTest1).GetValue().ToString());
|
||||
|
||||
if (((DerivedCastingTestClass1)castingTest).GetValue() == 1 && !(castingTest is DerivedCastingTestClass2))
|
||||
{
|
||||
PrintLine("Type casting with isinst & castclass to class test: Ok.");
|
||||
@@ -208,17 +252,74 @@ internal static class Program
|
||||
|
||||
ldindTest();
|
||||
|
||||
System.Diagnostics.Debugger.Break();
|
||||
InterfaceDispatchTest();
|
||||
|
||||
var testRuntimeHelpersInitArray = new long[] {1, 2, 3};
|
||||
if(testRuntimeHelpersInitArray[0] == 1 &&
|
||||
var testRuntimeHelpersInitArray = new long[] { 1, 2, 3 };
|
||||
if (testRuntimeHelpersInitArray[0] == 1 &&
|
||||
testRuntimeHelpersInitArray[1] == 2 &&
|
||||
testRuntimeHelpersInitArray[2] == 3)
|
||||
{
|
||||
PrintLine("Runtime.Helpers array initialization test: Ok.");
|
||||
}
|
||||
|
||||
var testMdArrayInstantiation = new int[2, 2];
|
||||
if (testMdArrayInstantiation != null && testMdArrayInstantiation.GetLength(0) == 2 && testMdArrayInstantiation.GetLength(1) == 2)
|
||||
PrintLine("Multi-dimension array instantiation test: Ok.");
|
||||
|
||||
int intToCast = 1;
|
||||
double castedDouble = (double)intToCast;
|
||||
if (castedDouble == 1d)
|
||||
{
|
||||
PrintLine("(double) cast test: Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var toInt = (int)castedDouble;
|
||||
// PrintLine("expected 1m, but was " + castedDouble.ToString()); // double.ToString is not compiling at the time of writing, but this would be better output
|
||||
PrintLine($"(double) cast test : Failed. Back to int on next line");
|
||||
PrintLine(toInt.ToString());
|
||||
}
|
||||
|
||||
if (1f < 2d && 1d < 2f && 1f == 1d)
|
||||
{
|
||||
PrintLine("different width float comparisons: Ok.");
|
||||
}
|
||||
|
||||
// floats are 7 digits precision, so check some double more precise to make sure there is no loss occurring through some inadvertent cast to float
|
||||
if (10.23456789d != 10.234567891d)
|
||||
{
|
||||
PrintLine("double precision comparison: Ok.");
|
||||
}
|
||||
|
||||
if (12.34567f == 12.34567f && 12.34567f != 12.34568f)
|
||||
{
|
||||
PrintLine("float comparison: Ok.");
|
||||
}
|
||||
|
||||
// Create a ByReference<char> through the ReadOnlySpan ctor and call the ByReference.Value via the indexer.
|
||||
var span = "123".AsSpan();
|
||||
if (span[0] != '1'
|
||||
|| span[1] != '2'
|
||||
|| span[2] != '3')
|
||||
{
|
||||
PrintLine("ByReference intrinsics exercise via ReadOnlySpan failed");
|
||||
PrintLine(span[0].ToString());
|
||||
PrintLine(span[1].ToString());
|
||||
PrintLine(span[2].ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("ByReference intrinsics exercise via ReadOnlySpan OK.");
|
||||
}
|
||||
|
||||
TestConstrainedClassCalls();
|
||||
|
||||
// This test should remain last to get other results before stopping the debugger
|
||||
PrintLine("Debugger.Break() test: Ok if debugger is open and breaks.");
|
||||
System.Diagnostics.Debugger.Break();
|
||||
|
||||
PrintLine("Done");
|
||||
return 100;
|
||||
}
|
||||
|
||||
private static int StaticDelegateTarget()
|
||||
@@ -346,6 +447,160 @@ internal static class Program
|
||||
}
|
||||
}
|
||||
|
||||
private static void InterfaceDispatchTest()
|
||||
{
|
||||
ItfStruct itfStruct = new ItfStruct();
|
||||
if (ItfCaller(itfStruct) == 4)
|
||||
{
|
||||
PrintLine("Struct interface test: Ok.");
|
||||
}
|
||||
}
|
||||
|
||||
// Calls the ITestItf interface via a generic to ensure the concrete type is known and
|
||||
// an interface call is generated instead of a virtual or direct call
|
||||
private static int ItfCaller<T>(T obj) where T : ITestItf
|
||||
{
|
||||
return obj.GetValue();
|
||||
}
|
||||
|
||||
private static void StaticCtorTest()
|
||||
{
|
||||
BeforeFieldInitTest.Nop();
|
||||
if (StaticsInited.BeforeFieldInitInited)
|
||||
{
|
||||
PrintLine("BeforeFieldInitType inited too early");
|
||||
}
|
||||
else
|
||||
{
|
||||
int x = BeforeFieldInitTest.TestField;
|
||||
if (StaticsInited.BeforeFieldInitInited)
|
||||
{
|
||||
PrintLine("BeforeFieldInit test: Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("BeforeFieldInit cctor not run");
|
||||
}
|
||||
}
|
||||
|
||||
NonBeforeFieldInitTest.Nop();
|
||||
if (StaticsInited.NonBeforeFieldInitInited)
|
||||
{
|
||||
PrintLine("NonBeforeFieldInit test: Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("NonBeforeFieldInitType cctor not run");
|
||||
}
|
||||
}
|
||||
|
||||
private static void TestConstrainedClassCalls()
|
||||
{
|
||||
string s = "utf-8";
|
||||
|
||||
PrintString("Direct ToString test: ");
|
||||
string stringDirectToString = s.ToString();
|
||||
if (s.Equals(stringDirectToString))
|
||||
{
|
||||
PrintLine("Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintString("Failed. Returned string:\"");
|
||||
PrintString(stringDirectToString);
|
||||
PrintLine("\"");
|
||||
}
|
||||
|
||||
// Generic calls on methods not defined on object
|
||||
uint dataFromBase = GenericGetData<MyBase>(new MyBase(11));
|
||||
PrintString("Generic call to base class test: ");
|
||||
if (dataFromBase == 11)
|
||||
{
|
||||
PrintLine("Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("Failed.");
|
||||
}
|
||||
|
||||
uint dataFromUnsealed = GenericGetData<UnsealedDerived>(new UnsealedDerived(13));
|
||||
PrintString("Generic call to unsealed derived class test: ");
|
||||
if (dataFromUnsealed == 26)
|
||||
{
|
||||
PrintLine("Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("Failed.");
|
||||
}
|
||||
|
||||
uint dataFromSealed = GenericGetData<SealedDerived>(new SealedDerived(15));
|
||||
PrintString("Generic call to sealed derived class test: ");
|
||||
if (dataFromSealed == 45)
|
||||
{
|
||||
PrintLine("Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("Failed.");
|
||||
}
|
||||
|
||||
uint dataFromUnsealedAsBase = GenericGetData<MyBase>(new UnsealedDerived(17));
|
||||
PrintString("Generic call to unsealed derived class as base test: ");
|
||||
if (dataFromUnsealedAsBase == 34)
|
||||
{
|
||||
PrintLine("Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("Failed.");
|
||||
}
|
||||
|
||||
uint dataFromSealedAsBase = GenericGetData<MyBase>(new SealedDerived(19));
|
||||
PrintString("Generic call to sealed derived class as base test: ");
|
||||
if (dataFromSealedAsBase == 57)
|
||||
{
|
||||
PrintLine("Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("Failed.");
|
||||
}
|
||||
|
||||
// Generic calls to methods defined on object
|
||||
uint hashCodeOfSealedViaGeneric = (uint)GenericGetHashCode<MySealedClass>(new MySealedClass(37));
|
||||
PrintString("Generic GetHashCode for sealed class test: ");
|
||||
if (hashCodeOfSealedViaGeneric == 74)
|
||||
{
|
||||
PrintLine("Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("Failed.");
|
||||
}
|
||||
|
||||
uint hashCodeOfUnsealedViaGeneric = (uint)GenericGetHashCode<MyUnsealedClass>(new MyUnsealedClass(41));
|
||||
PrintString("Generic GetHashCode for unsealed class test: ");
|
||||
if (hashCodeOfUnsealedViaGeneric == 82)
|
||||
{
|
||||
PrintLine("Ok.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintLine("Failed.");
|
||||
}
|
||||
}
|
||||
|
||||
static uint GenericGetData<T>(T obj) where T : MyBase
|
||||
{
|
||||
return obj.GetData();
|
||||
}
|
||||
|
||||
static int GenericGetHashCode<T>(T obj)
|
||||
{
|
||||
return obj.GetHashCode();
|
||||
}
|
||||
|
||||
[DllImport("*")]
|
||||
private static unsafe extern int printf(byte* str, byte* unused);
|
||||
}
|
||||
@@ -433,6 +688,38 @@ public class TestDerivedClass : TestClass
|
||||
}
|
||||
}
|
||||
|
||||
public class StaticsInited
|
||||
{
|
||||
public static bool BeforeFieldInitInited;
|
||||
public static bool NonBeforeFieldInitInited;
|
||||
}
|
||||
|
||||
public class BeforeFieldInitTest
|
||||
{
|
||||
public static int TestField = BeforeFieldInit();
|
||||
|
||||
public static void Nop() { }
|
||||
|
||||
static int BeforeFieldInit()
|
||||
{
|
||||
StaticsInited.BeforeFieldInitInited = true;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
public class NonBeforeFieldInitTest
|
||||
{
|
||||
public static int TestField;
|
||||
|
||||
public static void Nop() { }
|
||||
|
||||
static NonBeforeFieldInitTest()
|
||||
{
|
||||
TestField = 4;
|
||||
StaticsInited.NonBeforeFieldInitInited = true;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICastingTest1
|
||||
{
|
||||
int GetValue();
|
||||
@@ -457,3 +744,110 @@ public class DerivedCastingTestClass2 : CastingTestClass, ICastingTest2
|
||||
{
|
||||
public override int GetValue() => 2;
|
||||
}
|
||||
|
||||
public interface ITestItf
|
||||
{
|
||||
int GetValue();
|
||||
}
|
||||
|
||||
public struct ItfStruct : ITestItf
|
||||
{
|
||||
public int GetValue()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MySealedClass
|
||||
{
|
||||
uint _data;
|
||||
|
||||
public MySealedClass()
|
||||
{
|
||||
_data = 104;
|
||||
}
|
||||
|
||||
public MySealedClass(uint data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
public uint GetData()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)_data * 2;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
Program.PrintLine("MySealedClass.ToString called. Data:");
|
||||
Program.PrintLine(_data.ToString());
|
||||
return _data.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class MyUnsealedClass
|
||||
{
|
||||
uint _data;
|
||||
|
||||
public MyUnsealedClass()
|
||||
{
|
||||
_data = 24;
|
||||
}
|
||||
|
||||
public MyUnsealedClass(uint data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
public uint GetData()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (int)_data * 2;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _data.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class MyBase
|
||||
{
|
||||
protected uint _data;
|
||||
public MyBase(uint data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
public virtual uint GetData()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
}
|
||||
|
||||
public class UnsealedDerived : MyBase
|
||||
{
|
||||
public UnsealedDerived(uint data) : base(data) { }
|
||||
public override uint GetData()
|
||||
{
|
||||
return _data * 2;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SealedDerived : MyBase
|
||||
{
|
||||
public SealedDerived(uint data) : base(data) { }
|
||||
public override uint GetData()
|
||||
{
|
||||
return _data * 3;
|
||||
}
|
||||
}
|
||||
|
||||
140
external/corert/tests/src/Simple/PInvoke/PInvoke.cs
vendored
140
external/corert/tests/src/Simple/PInvoke/PInvoke.cs
vendored
@@ -3,9 +3,17 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
// Make sure the interop data are present even without reflection
|
||||
namespace System.Runtime.CompilerServices
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.All)]
|
||||
internal class __BlockAllReflectionAttribute : Attribute { }
|
||||
}
|
||||
|
||||
// Name of namespace matches the name of the assembly on purpose to
|
||||
// ensure that we can handle this (mostly an issue for C++ code generation).
|
||||
namespace PInvokeTests
|
||||
@@ -97,6 +105,9 @@ namespace PInvokeTests
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern int SafeHandleOutTest(out SafeMemoryHandle sh1);
|
||||
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall)]
|
||||
public static extern int SafeHandleRefTest(ref SafeMemoryHandle sh1, bool change);
|
||||
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
public static extern bool LastErrorTest();
|
||||
|
||||
@@ -104,6 +115,11 @@ namespace PInvokeTests
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall)]
|
||||
static extern bool ReversePInvoke_Int(Delegate_Int del);
|
||||
|
||||
delegate int Delegate_Int_AggressiveInlining(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j);
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall, EntryPoint = "ReversePInvoke_Int")]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static extern bool ReversePInvoke_Int_AggressiveInlining(Delegate_Int_AggressiveInlining del);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet=CharSet.Ansi)]
|
||||
delegate bool Delegate_String(string s);
|
||||
[DllImport("*", CallingConvention = CallingConvention.StdCall)]
|
||||
@@ -233,8 +249,9 @@ namespace PInvokeTests
|
||||
TestSizeParamIndex();
|
||||
#if !CODEGEN_CPP
|
||||
TestDelegate();
|
||||
#endif
|
||||
TestStruct();
|
||||
TestMarshalStructAPIs();
|
||||
#endif
|
||||
return 100;
|
||||
}
|
||||
|
||||
@@ -435,6 +452,18 @@ namespace PInvokeTests
|
||||
int actual = SafeHandleOutTest(out hnd2);
|
||||
int expected = unchecked((int)hnd2.DangerousGetHandle().ToInt64());
|
||||
ThrowIfNotEquals(actual, expected, "SafeHandle out marshalling failed");
|
||||
|
||||
Console.WriteLine("Testing marshalling ref SafeHandle");
|
||||
SafeMemoryHandle hndOriginal = hnd2;
|
||||
SafeHandleRefTest(ref hnd2, false);
|
||||
ThrowIfNotEquals(hndOriginal, hnd2, "SafeHandle no-op ref marshalling failed");
|
||||
|
||||
int actual3 = SafeHandleRefTest(ref hnd2, true);
|
||||
int expected3 = unchecked((int)hnd2.DangerousGetHandle().ToInt64());
|
||||
ThrowIfNotEquals(actual3, expected3, "SafeHandle ref marshalling failed");
|
||||
|
||||
hndOriginal.Dispose();
|
||||
hnd2.Dispose();
|
||||
}
|
||||
|
||||
private static void TestSizeParamIndex()
|
||||
@@ -473,8 +502,13 @@ namespace PInvokeTests
|
||||
private static void TestDelegate()
|
||||
{
|
||||
Console.WriteLine("Testing Delegate");
|
||||
|
||||
Delegate_Int del = new Delegate_Int(Sum);
|
||||
ThrowIfNotEquals(true, ReversePInvoke_Int(del), "Delegate marshalling failed.");
|
||||
|
||||
Delegate_Int_AggressiveInlining del_aggressive = new Delegate_Int_AggressiveInlining(Sum);
|
||||
ThrowIfNotEquals(true, ReversePInvoke_Int_AggressiveInlining(del_aggressive), "Delegate marshalling with aggressive inlining failed.");
|
||||
|
||||
unsafe
|
||||
{
|
||||
//
|
||||
@@ -562,20 +596,35 @@ namespace PInvokeTests
|
||||
|
||||
public ExplicitStruct f2;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct TestStruct2
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public int f1;
|
||||
|
||||
[FieldOffset(8)]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct NonBlittableStruct
|
||||
{
|
||||
public int f1;
|
||||
public bool f2;
|
||||
public bool f3;
|
||||
public bool f4;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class BlittableClass
|
||||
{
|
||||
public long f1;
|
||||
public int f2;
|
||||
public int f3;
|
||||
public long f4;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public class NonBlittableClass
|
||||
{
|
||||
public bool f1;
|
||||
public bool f2;
|
||||
public int f3;
|
||||
}
|
||||
|
||||
private static void TestStruct()
|
||||
{
|
||||
#if !CODEGEN_CPP
|
||||
Console.WriteLine("Testing Structs");
|
||||
SequentialStruct ss = new SequentialStruct();
|
||||
ss.f0 = 100;
|
||||
@@ -639,24 +688,6 @@ namespace PInvokeTests
|
||||
InlineUnicodeStruct ius = new InlineUnicodeStruct();
|
||||
ius.inlineString = "Hello World";
|
||||
|
||||
|
||||
TestStruct2 ts = new TestStruct2() { f1 = 100, f2 = true};
|
||||
int size = Marshal.SizeOf<TestStruct2>(ts);
|
||||
IntPtr memory = Marshal.AllocHGlobal(size);
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr<TestStruct2>(ts, memory, false);
|
||||
TestStruct2 ts2 = Marshal.PtrToStructure<TestStruct2>(memory);
|
||||
ThrowIfNotEquals(true, ts2.f1 == 100 && ts2.f2 == true, "Struct marshalling Marshal API failed");
|
||||
|
||||
IntPtr offset = Marshal.OffsetOf<TestStruct2>("f2");
|
||||
ThrowIfNotEquals(new IntPtr(8), offset, "Struct marshalling OffsetOf failed.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(memory);
|
||||
}
|
||||
|
||||
ThrowIfNotEquals(true, InlineArrayTest(ref ias, ref ius), "inline array marshalling failed");
|
||||
bool pass = true;
|
||||
for (short i = 0; i < 128; i++)
|
||||
@@ -672,7 +703,6 @@ namespace PInvokeTests
|
||||
|
||||
ThrowIfNotEquals("Hello World", ius.inlineString, "Inline ByValTStr Unicode marshalling failed");
|
||||
|
||||
// RhpThrowEx is not implemented in CPPCodeGen
|
||||
pass = false;
|
||||
AutoStruct autoStruct = new AutoStruct();
|
||||
try
|
||||
@@ -691,7 +721,59 @@ namespace PInvokeTests
|
||||
callbacks.callback1 = new Callback1(callbackFunc1);
|
||||
callbacks.callback2 = new Callback2(callbackFunc2);
|
||||
ThrowIfNotEquals(true, RegisterCallbacks(ref callbacks), "Scenario 7: Struct with delegate marshalling failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void TestMarshalStructAPIs()
|
||||
{
|
||||
Console.WriteLine("Testing Marshal APIs for structs");
|
||||
|
||||
NonBlittableStruct ts = new NonBlittableStruct() { f1 = 100, f2 = true, f3 = false, f4 = true };
|
||||
int size = Marshal.SizeOf<NonBlittableStruct>(ts);
|
||||
ThrowIfNotEquals(16, size, "Marshal.SizeOf<NonBlittableStruct> failed");
|
||||
IntPtr memory = Marshal.AllocHGlobal(size);
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr<NonBlittableStruct>(ts, memory, false);
|
||||
NonBlittableStruct ts2 = Marshal.PtrToStructure<NonBlittableStruct>(memory);
|
||||
ThrowIfNotEquals(true, ts2.f1 == 100 && ts2.f2 == true && ts2.f3 == false && ts2.f4 == true, "NonBlittableStruct marshalling Marshal API failed");
|
||||
|
||||
IntPtr offset = Marshal.OffsetOf<NonBlittableStruct>("f2");
|
||||
ThrowIfNotEquals(new IntPtr(4), offset, "Struct marshalling OffsetOf failed.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(memory);
|
||||
}
|
||||
|
||||
BlittableClass bc = new BlittableClass() { f1 = 100, f2 = 12345678, f3 = 999, f4 = -4 };
|
||||
int bc_size = Marshal.SizeOf<BlittableClass>(bc);
|
||||
ThrowIfNotEquals(24, bc_size, "Marshal.SizeOf<BlittableClass> failed");
|
||||
IntPtr bc_memory = Marshal.AllocHGlobal(bc_size);
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr<BlittableClass>(bc, bc_memory, false);
|
||||
BlittableClass bc2 = Marshal.PtrToStructure<BlittableClass>(bc_memory);
|
||||
ThrowIfNotEquals(true, bc2.f1 == 100 && bc2.f2 == 12345678 && bc2.f3 == 999 && bc2.f4 == -4, "BlittableClass marshalling Marshal API failed");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(bc_memory);
|
||||
}
|
||||
|
||||
NonBlittableClass nbc = new NonBlittableClass() { f1 = false, f2 = true, f3 = 42 };
|
||||
int nbc_size = Marshal.SizeOf<NonBlittableClass>(nbc);
|
||||
ThrowIfNotEquals(12, nbc_size, "Marshal.SizeOf<NonBlittableClass> failed");
|
||||
IntPtr nbc_memory = Marshal.AllocHGlobal(nbc_size);
|
||||
try
|
||||
{
|
||||
Marshal.StructureToPtr<NonBlittableClass>(nbc, nbc_memory, false);
|
||||
NonBlittableClass nbc2 = Marshal.PtrToStructure<NonBlittableClass>(nbc_memory);
|
||||
ThrowIfNotEquals(true, nbc2.f1 == false && nbc2.f2 == true && nbc2.f3 == 42, "NonBlittableClass marshalling Marshal API failed");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(nbc_memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -313,13 +313,17 @@ DLL_EXPORT bool __stdcall SafeHandleTest(HANDLE sh, long shValue)
|
||||
|
||||
DLL_EXPORT long __stdcall SafeHandleOutTest(HANDLE **sh)
|
||||
{
|
||||
if (sh == NULL)
|
||||
return -1;
|
||||
|
||||
*sh = (HANDLE *)malloc(100);
|
||||
return (long)((size_t)(*sh));
|
||||
}
|
||||
|
||||
DLL_EXPORT long __stdcall SafeHandleRefTest(HANDLE **sh, bool alloc)
|
||||
{
|
||||
if (alloc)
|
||||
*sh = (HANDLE *)malloc(100);
|
||||
return (long)((size_t)(*sh));
|
||||
}
|
||||
|
||||
DLL_EXPORT bool __stdcall ReversePInvoke_Int(int(__stdcall *fnPtr) (int, int, int, int, int, int, int, int, int, int))
|
||||
{
|
||||
return fnPtr(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 55;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: TestAssembly]
|
||||
@@ -43,6 +44,7 @@ internal class ReflectionTest
|
||||
TestCreateDelegate.Run();
|
||||
TestInstanceFields.Run();
|
||||
TestReflectionInvoke.Run();
|
||||
TestByRefReturnInvoke.Run();
|
||||
|
||||
return 100;
|
||||
}
|
||||
@@ -89,9 +91,34 @@ internal class ReflectionTest
|
||||
{
|
||||
return "Hello " + _world;
|
||||
}
|
||||
|
||||
#if OPTIMIZED_MODE_WITHOUT_SCANNER
|
||||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
|
||||
#endif
|
||||
public static unsafe string GetHelloPointer(char* ptr)
|
||||
{
|
||||
return "Hello " + unchecked((int)ptr);
|
||||
}
|
||||
|
||||
#if OPTIMIZED_MODE_WITHOUT_SCANNER
|
||||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
|
||||
#endif
|
||||
public static unsafe string GetHelloPointerToo(char** ptr)
|
||||
{
|
||||
return "Hello " + unchecked((int)ptr);
|
||||
}
|
||||
|
||||
#if OPTIMIZED_MODE_WITHOUT_SCANNER
|
||||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
|
||||
#endif
|
||||
public static unsafe bool* GetPointer(void* ptr, object dummyJustToMakeThisUseSharedThunk)
|
||||
{
|
||||
return (bool*)ptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Run()
|
||||
public static unsafe void Run()
|
||||
{
|
||||
Console.WriteLine(nameof(TestReflectionInvoke));
|
||||
|
||||
@@ -102,6 +129,9 @@ internal class ReflectionTest
|
||||
InvokeTests.GetHello(null);
|
||||
InvokeTests.GetHelloGeneric<int>(0);
|
||||
InvokeTests.GetHelloGeneric<double>(0);
|
||||
InvokeTests.GetHelloPointer(null);
|
||||
InvokeTests.GetHelloPointerToo(null);
|
||||
InvokeTests.GetPointer(null, null);
|
||||
string unused;
|
||||
InvokeTests.GetHelloByRef(null, out unused);
|
||||
unused.ToString();
|
||||
@@ -128,6 +158,31 @@ internal class ReflectionTest
|
||||
if ((string)args[1] != "Hello world")
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
{
|
||||
MethodInfo helloPointerMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloPointer");
|
||||
string resultNull = (string)helloPointerMethod.Invoke(null, new object[] { null });
|
||||
if (resultNull != "Hello 0")
|
||||
throw new Exception();
|
||||
|
||||
string resultVal = (string)helloPointerMethod.Invoke(null, new object[] { Pointer.Box((void*)42, typeof(char*)) });
|
||||
if (resultVal != "Hello 42")
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
{
|
||||
MethodInfo helloPointerTooMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetHelloPointerToo");
|
||||
string result = (string)helloPointerTooMethod.Invoke(null, new object[] { Pointer.Box((void*)85, typeof(char**)) });
|
||||
if (result != "Hello 85")
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
{
|
||||
MethodInfo getPointerMethod = typeof(InvokeTests).GetTypeInfo().GetDeclaredMethod("GetPointer");
|
||||
object result = getPointerMethod.Invoke(null, new object[] { Pointer.Box((void*)2018, typeof(void*)), null });
|
||||
if (Pointer.Unbox(result) != (void*)2018)
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +439,23 @@ internal class ReflectionTest
|
||||
}
|
||||
}
|
||||
|
||||
ref struct ByRefLike<T>
|
||||
{
|
||||
public readonly T Value;
|
||||
|
||||
public ByRefLike(T value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Value.ToString() + " " + typeof(T).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
delegate string ToStringDelegate(ref ByRefLike thisObj);
|
||||
delegate string ToStringDelegate<T>(ref ByRefLike<T> thisObj);
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
@@ -396,15 +467,40 @@ internal class ReflectionTest
|
||||
default(ByRefLike).ToString();
|
||||
ToStringDelegate s = null;
|
||||
s = s.Invoke;
|
||||
default(ByRefLike<object>).ToString();
|
||||
ToStringDelegate<object> s2 = null;
|
||||
s2 = s2.Invoke;
|
||||
}
|
||||
|
||||
Type byRefLikeType = GetTestType(nameof(TestByRefLikeTypeMethod), nameof(ByRefLike));
|
||||
MethodInfo toStringMethod = byRefLikeType.GetMethod("ToString");
|
||||
var toString = (ToStringDelegate)toStringMethod.CreateDelegate(typeof(ToStringDelegate));
|
||||
{
|
||||
Type byRefLikeType = GetTestType(nameof(TestByRefLikeTypeMethod), nameof(ByRefLike));
|
||||
MethodInfo toStringMethod = byRefLikeType.GetMethod("ToString");
|
||||
var toString = (ToStringDelegate)toStringMethod.CreateDelegate(typeof(ToStringDelegate));
|
||||
|
||||
ByRefLike foo = new ByRefLike(123);
|
||||
if (toString(ref foo) != "123")
|
||||
throw new Exception();
|
||||
ByRefLike foo = new ByRefLike(123);
|
||||
if (toString(ref foo) != "123")
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
{
|
||||
Type byRefLikeGenericType = typeof(ByRefLike<string>);
|
||||
MethodInfo toStringGenericMethod = byRefLikeGenericType.GetMethod("ToString");
|
||||
var toStringGeneric = (ToStringDelegate<string>)toStringGenericMethod.CreateDelegate(typeof(ToStringDelegate<string>));
|
||||
|
||||
ByRefLike<string> fooGeneric = new ByRefLike<string>("Hello");
|
||||
if (toStringGeneric(ref fooGeneric) != "Hello System.String")
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
{
|
||||
Type byRefLikeGenericType = typeof(ByRefLike<object>);
|
||||
MethodInfo toStringGenericMethod = byRefLikeGenericType.GetMethod("ToString");
|
||||
var toStringGeneric = (ToStringDelegate<object>)toStringGenericMethod.CreateDelegate(typeof(ToStringDelegate<object>));
|
||||
|
||||
ByRefLike<object> fooGeneric = new ByRefLike<object>("Hello");
|
||||
if (toStringGeneric(ref fooGeneric) != "Hello System.Object")
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,6 +597,203 @@ internal class ReflectionTest
|
||||
}
|
||||
}
|
||||
|
||||
class TestByRefReturnInvoke
|
||||
{
|
||||
enum Mine { One = 2018 }
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct BigStruct { public ulong X, Y, Z, W, A, B, C, D; }
|
||||
|
||||
public ref struct ByRefLike { }
|
||||
|
||||
private sealed class TestClass<T>
|
||||
{
|
||||
private T _value;
|
||||
|
||||
public TestClass(T value) { _value = value; }
|
||||
public ref T RefReturningProp
|
||||
{
|
||||
#if OPTIMIZED_MODE_WITHOUT_SCANNER
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
#endif
|
||||
get => ref _value;
|
||||
}
|
||||
#if OPTIMIZED_MODE_WITHOUT_SCANNER
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
#endif
|
||||
public static unsafe ref ByRefLike ByRefLikeRefReturningMethod(ByRefLike* a) => ref *a;
|
||||
}
|
||||
|
||||
private sealed unsafe class TestClassIntPointer
|
||||
{
|
||||
private int* _value;
|
||||
|
||||
public TestClassIntPointer(int* value) { _value = value; }
|
||||
public ref int* RefReturningProp
|
||||
{
|
||||
#if OPTIMIZED_MODE_WITHOUT_SCANNER
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
#endif
|
||||
get => ref _value;
|
||||
}
|
||||
public unsafe ref int* NullRefReturningProp
|
||||
{
|
||||
#if OPTIMIZED_MODE_WITHOUT_SCANNER
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
#endif
|
||||
get => ref *(int**)null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void TestRefReturnPropertyGetValue()
|
||||
{
|
||||
TestRefReturnInvoke('a', (p, t) => p.GetValue(t));
|
||||
TestRefReturnInvoke(Mine.One, (p, t) => p.GetValue(t));
|
||||
TestRefReturnInvoke("Hello", (p, t) => p.GetValue(t));
|
||||
TestRefReturnInvoke(new BigStruct { X = 123, D = 456 }, (p, t) => p.GetValue(t));
|
||||
TestRefReturnInvoke(new object(), (p, t) => p.GetValue(t));
|
||||
TestRefReturnInvoke((object)null, (p, t) => p.GetValue(t));
|
||||
}
|
||||
|
||||
public static void TestRefReturnMethodInvoke()
|
||||
{
|
||||
TestRefReturnInvoke(Mine.One, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>()));
|
||||
TestRefReturnInvoke("Hello", (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>()));
|
||||
TestRefReturnInvoke(new BigStruct { X = 123, D = 456 }, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>()));
|
||||
TestRefReturnInvoke(new object(), (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>()));
|
||||
TestRefReturnInvoke((object)null, (p, t) => p.GetGetMethod().Invoke(t, Array.Empty<object>()));
|
||||
}
|
||||
|
||||
public static void TestRefReturnNullable()
|
||||
{
|
||||
TestRefReturnInvokeNullable<int>(42);
|
||||
TestRefReturnInvokeNullable<Mine>(Mine.One);
|
||||
TestRefReturnInvokeNullable<BigStruct>(new BigStruct { X = 987, D = 543 });
|
||||
}
|
||||
|
||||
public static void TestRefReturnNullableNoValue()
|
||||
{
|
||||
TestRefReturnInvokeNullable<int>(default(int?));
|
||||
TestRefReturnInvokeNullable<Mine>(default(Mine?));
|
||||
TestRefReturnInvokeNullable<BigStruct>(default(BigStruct?));
|
||||
}
|
||||
|
||||
public static unsafe void TestRefReturnOfPointer()
|
||||
{
|
||||
int* expected = (int*)0x1122334455667788;
|
||||
TestClassIntPointer tc = new TestClassIntPointer(expected);
|
||||
|
||||
if (string.Empty.Length > 0)
|
||||
{
|
||||
((IntPtr)tc.RefReturningProp).ToString();
|
||||
}
|
||||
|
||||
PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.RefReturningProp));
|
||||
object rv = p.GetValue(tc);
|
||||
Assert.True(rv is Pointer);
|
||||
int* actual = (int*)(Pointer.Unbox(rv));
|
||||
Assert.Equal((IntPtr)expected, (IntPtr)actual);
|
||||
}
|
||||
|
||||
public static unsafe void TestNullRefReturnOfPointer()
|
||||
{
|
||||
TestClassIntPointer tc = new TestClassIntPointer(null);
|
||||
|
||||
if (string.Empty.Length > 0)
|
||||
{
|
||||
((IntPtr)tc.NullRefReturningProp).ToString();
|
||||
}
|
||||
|
||||
PropertyInfo p = typeof(TestClassIntPointer).GetProperty(nameof(TestClassIntPointer.NullRefReturningProp));
|
||||
Assert.NotNull(p);
|
||||
Assert.Throws<NullReferenceException>(() => p.GetValue(tc));
|
||||
}
|
||||
|
||||
public static unsafe void TestByRefLikeRefReturn()
|
||||
{
|
||||
if (string.Empty.Length > 0)
|
||||
{
|
||||
TestClass<int>.ByRefLikeRefReturningMethod(null);
|
||||
}
|
||||
|
||||
ByRefLike brl = new ByRefLike();
|
||||
ByRefLike* pBrl = &brl;
|
||||
MethodInfo mi = typeof(TestClass<int>).GetMethod(nameof(TestClass<int>.ByRefLikeRefReturningMethod));
|
||||
try
|
||||
{
|
||||
// Don't use Assert.Throws because that will make a lambda and invalidate the pointer
|
||||
object o = mi.Invoke(null, new object[] { Pointer.Box(pBrl, typeof(ByRefLike*)) });
|
||||
Assert.Fail();
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private static void TestRefReturnInvoke<T>(T value, Func<PropertyInfo, TestClass<T>, object> invoker)
|
||||
{
|
||||
TestClass<T> tc = new TestClass<T>(value);
|
||||
|
||||
if (String.Empty.Length > 0)
|
||||
{
|
||||
tc.RefReturningProp.ToString();
|
||||
}
|
||||
|
||||
PropertyInfo p = typeof(TestClass<T>).GetProperty(nameof(TestClass<T>.RefReturningProp));
|
||||
object rv = invoker(p, tc);
|
||||
if (rv != null)
|
||||
{
|
||||
Assert.Equal(typeof(T), rv.GetType());
|
||||
}
|
||||
|
||||
if (typeof(T).IsValueType)
|
||||
{
|
||||
Assert.Equal(value, rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Same(value, rv);
|
||||
}
|
||||
}
|
||||
|
||||
private static void TestRefReturnInvokeNullable<T>(T? nullable) where T : struct
|
||||
{
|
||||
TestClass<T?> tc = new TestClass<T?>(nullable);
|
||||
|
||||
if (string.Empty.Length > 0)
|
||||
{
|
||||
tc.RefReturningProp.ToString();
|
||||
}
|
||||
|
||||
PropertyInfo p = typeof(TestClass<T?>).GetProperty(nameof(TestClass<T?>.RefReturningProp));
|
||||
object rv = p.GetValue(tc);
|
||||
if (rv != null)
|
||||
{
|
||||
Assert.Equal(typeof(T), rv.GetType());
|
||||
}
|
||||
if (nullable.HasValue)
|
||||
{
|
||||
Assert.Equal(nullable.Value, rv);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Null(rv);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
Console.WriteLine(nameof(TestByRefReturnInvoke));
|
||||
TestRefReturnPropertyGetValue();
|
||||
TestRefReturnMethodInvoke();
|
||||
TestRefReturnNullable();
|
||||
TestRefReturnNullableNoValue();
|
||||
TestRefReturnOfPointer();
|
||||
TestNullRefReturnOfPointer();
|
||||
TestByRefLikeRefReturn();
|
||||
}
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private static Type GetTestType(string testName, string typeName)
|
||||
@@ -534,6 +827,66 @@ internal class ReflectionTest
|
||||
return true;
|
||||
}
|
||||
|
||||
class Assert
|
||||
{
|
||||
public static void Equal<T>(T expected, T actual)
|
||||
{
|
||||
if (object.ReferenceEquals(expected, actual))
|
||||
return;
|
||||
|
||||
if ((object)expected == null || (object)actual == null)
|
||||
throw new Exception();
|
||||
|
||||
if (!expected.Equals(actual))
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public static void Same<T>(T expected, T actual)
|
||||
{
|
||||
if (!object.ReferenceEquals(expected, actual))
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public static void Null(object x)
|
||||
{
|
||||
if (x != null)
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public static void NotNull(object x)
|
||||
{
|
||||
if (x == null)
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public static void True(bool x)
|
||||
{
|
||||
if (!x)
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public static void Fail()
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public static void Throws<T>(Action a)
|
||||
{
|
||||
try
|
||||
{
|
||||
a();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex.GetType() != typeof(T))
|
||||
throw new Exception();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
14
external/corert/tests/src/Simple/SharedLibrary/NativeCallable.cs
vendored
Normal file
14
external/corert/tests/src/Simple/SharedLibrary/NativeCallable.cs
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// 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.
|
||||
|
||||
namespace System.Runtime.InteropServices
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class NativeCallableAttribute : Attribute
|
||||
{
|
||||
public string EntryPoint;
|
||||
public CallingConvention CallingConvention;
|
||||
public NativeCallableAttribute() { }
|
||||
}
|
||||
}
|
||||
12
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.cmd
vendored
Normal file
12
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.cmd
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
@echo off
|
||||
setlocal
|
||||
"%1\%2"
|
||||
set ErrorCode=%ERRORLEVEL%
|
||||
IF "%ErrorCode%"=="100" (
|
||||
echo %~n0: pass
|
||||
EXIT /b 0
|
||||
) ELSE (
|
||||
echo %~n0: fail - %ErrorCode%
|
||||
EXIT /b 1
|
||||
)
|
||||
endlocal
|
||||
66
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.cpp
vendored
Normal file
66
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.cpp
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// 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.
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include "dlfcn.h"
|
||||
#endif
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#define __stdcall
|
||||
#endif
|
||||
|
||||
// typedef for shared lib exported methods
|
||||
typedef int(__stdcall *f_ReturnsPrimitiveInt)();
|
||||
typedef bool(__stdcall *f_ReturnsPrimitiveBool)();
|
||||
typedef char(__stdcall *f_ReturnsPrimitiveChar)();
|
||||
typedef void(__stdcall *f_EnsureManagedClassLoaders)();
|
||||
|
||||
#ifdef _WIN32
|
||||
int main()
|
||||
#else
|
||||
int main(int argc, char* argv[])
|
||||
#endif
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HINSTANCE handle = LoadLibrary("SharedLibrary.dll");
|
||||
#elif __APPLE__
|
||||
void *handle = dlopen(strcat(argv[0], ".dylib"), RTLD_LAZY);
|
||||
#else
|
||||
void *handle = dlopen(strcat(argv[0], ".so"), RTLD_LAZY);
|
||||
#endif
|
||||
|
||||
if (!handle)
|
||||
return 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
f_ReturnsPrimitiveInt returnsPrimitiveInt = (f_ReturnsPrimitiveInt)GetProcAddress(handle, "ReturnsPrimitiveInt");
|
||||
f_ReturnsPrimitiveBool returnsPrimitiveBool = (f_ReturnsPrimitiveBool)GetProcAddress(handle, "ReturnsPrimitiveBool");
|
||||
f_ReturnsPrimitiveChar returnsPrimitiveChar = (f_ReturnsPrimitiveChar)GetProcAddress(handle, "ReturnsPrimitiveChar");
|
||||
f_EnsureManagedClassLoaders ensureManagedClassLoaders = (f_EnsureManagedClassLoaders)GetProcAddress(handle, "EnsureManagedClassLoaders");
|
||||
#else
|
||||
f_ReturnsPrimitiveInt returnsPrimitiveInt = (f_ReturnsPrimitiveInt)dlsym(handle, "ReturnsPrimitiveInt");
|
||||
f_ReturnsPrimitiveBool returnsPrimitiveBool = (f_ReturnsPrimitiveBool)dlsym(handle, "ReturnsPrimitiveBool");
|
||||
f_ReturnsPrimitiveChar returnsPrimitiveChar = (f_ReturnsPrimitiveChar)dlsym(handle, "ReturnsPrimitiveChar");
|
||||
f_EnsureManagedClassLoaders ensureManagedClassLoaders = (f_EnsureManagedClassLoaders)dlsym(handle, "EnsureManagedClassLoaders");
|
||||
#endif
|
||||
|
||||
if (returnsPrimitiveInt() != 10)
|
||||
return 1;
|
||||
|
||||
if (!returnsPrimitiveBool())
|
||||
return 1;
|
||||
|
||||
if (returnsPrimitiveChar() != 'a')
|
||||
return 1;
|
||||
|
||||
// As long as no unmanaged exception is thrown
|
||||
// managed class loaders were initialized successfully
|
||||
ensureManagedClassLoaders();
|
||||
|
||||
return 100;
|
||||
}
|
||||
37
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.cs
vendored
Normal file
37
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.cs
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
// 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.Runtime.InteropServices;
|
||||
|
||||
namespace SharedLibrary
|
||||
{
|
||||
public class ClassLibrary
|
||||
{
|
||||
[NativeCallable(EntryPoint = "ReturnsPrimitiveInt", CallingConvention = CallingConvention.StdCall)]
|
||||
public static int ReturnsPrimitiveInt()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
|
||||
[NativeCallable(EntryPoint = "ReturnsPrimitiveBool", CallingConvention = CallingConvention.StdCall)]
|
||||
public static bool ReturnsPrimitiveBool()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
[NativeCallable(EntryPoint = "ReturnsPrimitiveChar", CallingConvention = CallingConvention.StdCall)]
|
||||
public static char ReturnsPrimitiveChar()
|
||||
{
|
||||
return 'a';
|
||||
}
|
||||
|
||||
[NativeCallable(EntryPoint = "EnsureManagedClassLoaders", CallingConvention = CallingConvention.StdCall)]
|
||||
public static void EnsureManagedClassLoaders()
|
||||
{
|
||||
Random random = new Random();
|
||||
random.Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
35
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.csproj
vendored
Normal file
35
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.csproj
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<NativeLib>Shared</NativeLib>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="NativeRunnerCompile" AfterTargets="LinkNative">
|
||||
<PropertyGroup>
|
||||
<NativeRunnerBinary>$(NativeOutputPath)SharedLibrary</NativeRunnerBinary>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<CppCompile Include="SharedLibrary.cpp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<NativeRunnerCompilerArg Include="@(CppCompile)" />
|
||||
<NativeRunnerCompilerArg Include="-o $(NativeRunnerBinary)" Condition="'$(OS)' != 'Windows_NT'" />
|
||||
<NativeRunnerCompilerArg Include="/Fo$(NativeRunnerBinary)" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
<NativeRunnerCompilerArg Include="/Fe$(NativeRunnerBinary)" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
</ItemGroup>
|
||||
|
||||
<Exec Command="$(CppCompiler) @(NativeRunnerCompilerArg, ' ')" Condition="'$(OS)' != 'Windows_NT'" />
|
||||
<WriteLinesToFile File="$(NativeIntermediateOutputPath)SharedLibrary.cl.rsp" Lines="@(NativeRunnerCompilerArg)" Overwrite="true" Condition="'$(OS)' == 'Windows_NT'"/>
|
||||
<Exec Command="$(CppCompiler) @"$(NativeIntermediateOutputPath)SharedLibrary.cl.rsp"" Condition="'$(OS)' == 'Windows_NT'" />
|
||||
</Target>
|
||||
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), SimpleTest.targets))\SimpleTest.targets" />
|
||||
|
||||
</Project>
|
||||
9
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.sh
vendored
Executable file
9
external/corert/tests/src/Simple/SharedLibrary/SharedLibrary.sh
vendored
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
$1/$2
|
||||
if [ $? == 100 ]; then
|
||||
echo pass
|
||||
exit 0
|
||||
else
|
||||
echo fail
|
||||
exit 1
|
||||
fi
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user