mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-06 22:48:41 +00:00
Centralise the Ldind logic (#61)
This commit is contained in:
@@ -23,6 +23,7 @@ module LoggerFactory =
|
||||
let makeTest () : (unit -> LogLine list) * ILoggerFactory =
|
||||
// Shared sink for all loggers created by the factory.
|
||||
let sink = ResizeArray ()
|
||||
let isEnabled (logLevel : LogLevel) : bool = logLevel >= LogLevel.Information
|
||||
|
||||
let createLogger (category : string) : ILogger =
|
||||
{ new ILogger with
|
||||
@@ -31,9 +32,13 @@ module LoggerFactory =
|
||||
member _.Dispose () = ()
|
||||
}
|
||||
|
||||
member _.IsEnabled _logLevel = true
|
||||
member _.IsEnabled l = isEnabled l
|
||||
|
||||
member _.Log (logLevel, eventId, state, ex, formatter) =
|
||||
if not (isEnabled logLevel) then
|
||||
()
|
||||
else
|
||||
|
||||
let message =
|
||||
try
|
||||
formatter.Invoke (state, ex)
|
||||
|
@@ -31,7 +31,8 @@ module Roslyn =
|
||||
Directory.GetFiles (runtimeDir, "*.dll")
|
||||
|> Array.map (fun path -> MetadataReference.CreateFromFile path :> MetadataReference)
|
||||
|
||||
let compilationOptions = CSharpCompilationOptions OutputKind.ConsoleApplication
|
||||
let compilationOptions =
|
||||
CSharpCompilationOptions(OutputKind.ConsoleApplication).WithAllowUnsafe (true)
|
||||
|
||||
let compilation =
|
||||
CSharpCompilation.Create (
|
||||
|
@@ -73,6 +73,18 @@ module TestCases =
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 1) ]
|
||||
}
|
||||
{
|
||||
FileName = "Ldind.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain =
|
||||
[
|
||||
// `failures`
|
||||
CliType.Numeric (CliNumericType.Int32 0)
|
||||
// Return value
|
||||
CliType.Numeric (CliNumericType.Int32 0)
|
||||
]
|
||||
}
|
||||
{
|
||||
FileName = "CustomDelegate.cs"
|
||||
ExpectedReturnCode = 8
|
||||
|
@@ -29,6 +29,7 @@
|
||||
<EmbeddedResource Include="sources\ResizeArray.cs" />
|
||||
<EmbeddedResource Include="sources\ArgumentOrdering.cs" />
|
||||
<EmbeddedResource Include="sources\CustomDelegate.cs" />
|
||||
<EmbeddedResource Include="sources\Ldind.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
361
WoofWare.PawPrint.Test/sources/Ldind.cs
Normal file
361
WoofWare.PawPrint.Test/sources/Ldind.cs
Normal file
@@ -0,0 +1,361 @@
|
||||
using System;
|
||||
|
||||
unsafe class LdindTest
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
var failures = 0;
|
||||
// Test Ldind.i1 (signed byte)
|
||||
failures += TestLdindI1();
|
||||
|
||||
// Test Ldind.u1 (unsigned byte)
|
||||
failures += TestLdindU1();
|
||||
|
||||
// Test Ldind.i2 (signed short)
|
||||
failures += TestLdindI2();
|
||||
|
||||
// Test Ldind.u2 (unsigned short)
|
||||
failures += TestLdindU2();
|
||||
|
||||
// Test Ldind.i4 (signed int)
|
||||
failures += TestLdindI4();
|
||||
|
||||
// Test Ldind.u4 (unsigned int)
|
||||
failures += TestLdindU4();
|
||||
|
||||
// Test Ldind.i8 (signed long)
|
||||
failures += TestLdindI8();
|
||||
|
||||
// Test Ldind.i8 via u8 (there's no Ldind.u8)
|
||||
failures += TestLdindI8ViaU8();
|
||||
|
||||
// Test Ldind.r4 (float)
|
||||
failures += TestLdindR4();
|
||||
|
||||
// Test Ldind.r8 (double)
|
||||
failures += TestLdindR8();
|
||||
|
||||
// Test truncation behavior
|
||||
failures += TestTruncation();
|
||||
|
||||
// Test with managed pointers (ref)
|
||||
// failures += TestManagedPointers();
|
||||
|
||||
// Test Ldind.i (native int)
|
||||
// failures += TestLdindI();
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
static int TestLdindI1()
|
||||
{
|
||||
sbyte value = -128;
|
||||
sbyte* ptr = &value;
|
||||
sbyte loaded = *ptr; // This generates ldind.i1
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = 127;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindU1()
|
||||
{
|
||||
byte value = 255;
|
||||
byte* ptr = &value;
|
||||
byte loaded = *ptr; // This generates ldind.u1
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = 0;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindI2()
|
||||
{
|
||||
short value = -32768;
|
||||
short* ptr = &value;
|
||||
short loaded = *ptr; // This generates ldind.i2
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = 32767;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindU2()
|
||||
{
|
||||
ushort value = 65535;
|
||||
ushort* ptr = &value;
|
||||
ushort loaded = *ptr; // This generates ldind.u2
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = 0;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindI4()
|
||||
{
|
||||
int value = int.MinValue;
|
||||
int* ptr = &value;
|
||||
int loaded = *ptr; // This generates ldind.i4
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = int.MaxValue;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindU4()
|
||||
{
|
||||
uint value = uint.MaxValue;
|
||||
uint* ptr = &value;
|
||||
uint loaded = *ptr; // This generates ldind.u4
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = 0;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindI8()
|
||||
{
|
||||
long value = long.MinValue;
|
||||
long* ptr = &value;
|
||||
long loaded = *ptr; // This generates ldind.i8
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = long.MaxValue;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindI8ViaU8()
|
||||
{
|
||||
ulong value = ulong.MaxValue;
|
||||
ulong* ptr = &value;
|
||||
ulong loaded = *ptr; // This generates ldind.i8 again, because there's no ldind.u8
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = 0;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindR4()
|
||||
{
|
||||
float value = float.MinValue;
|
||||
float* ptr = &value;
|
||||
float loaded = *ptr; // This generates ldind.r4
|
||||
if (BitConverter.SingleToInt32Bits(value) != BitConverter.SingleToInt32Bits(loaded))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = float.MaxValue;
|
||||
loaded = *ptr;
|
||||
if (BitConverter.SingleToInt32Bits(value) != BitConverter.SingleToInt32Bits(loaded))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = float.NaN;
|
||||
loaded = *ptr;
|
||||
if (BitConverter.SingleToInt32Bits(value) != BitConverter.SingleToInt32Bits(loaded))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindR8()
|
||||
{
|
||||
double value = double.MinValue;
|
||||
double* ptr = &value;
|
||||
double loaded = *ptr; // This generates ldind.r8
|
||||
if (BitConverter.DoubleToInt64Bits(value) != BitConverter.DoubleToInt64Bits(loaded))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = double.MaxValue;
|
||||
loaded = *ptr;
|
||||
if (BitConverter.DoubleToInt64Bits(value) != BitConverter.DoubleToInt64Bits(loaded))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = double.NaN;
|
||||
loaded = *ptr;
|
||||
if (BitConverter.DoubleToInt64Bits(value) != BitConverter.DoubleToInt64Bits(loaded))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestLdindI()
|
||||
{
|
||||
IntPtr value = new IntPtr(42);
|
||||
IntPtr* ptr = &value;
|
||||
IntPtr loaded = *ptr; // This generates ldind.i
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
value = IntPtr.Zero;
|
||||
loaded = *ptr;
|
||||
if (value != loaded)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestTruncation()
|
||||
{
|
||||
// Store a larger value and load as smaller type
|
||||
int largeValue = 0x1234ABCD;
|
||||
void* ptr = &largeValue;
|
||||
|
||||
byte byteValue = *(byte*)ptr; // Should truncate to 0xCD
|
||||
if (byteValue != 0xCD)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
short shortValue = *(short*)ptr; // Should truncate to 0xABCD
|
||||
if (shortValue != -21555)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Test sign extension
|
||||
sbyte signedByte = *(sbyte*)ptr; // 0xCD as signed byte is -51
|
||||
if (signedByte != -51)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestManagedPointers()
|
||||
{
|
||||
int value = 42;
|
||||
ref int refValue = ref value;
|
||||
var expected42 = TestRefParameter(ref refValue);
|
||||
if (expected42 != 42)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (refValue != 84)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Test with array element
|
||||
int[] array = { 10, 20, 30 };
|
||||
ref int element = ref array[1];
|
||||
if (element != 20)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Test with local variable
|
||||
int local = 100;
|
||||
var expected100 = TestRefLocal(ref local);
|
||||
if (expected100 != 100)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int TestRefParameter(ref int param)
|
||||
{
|
||||
var result = 0;
|
||||
// This will use ldind instructions when accessing param
|
||||
result += param;
|
||||
param = 84;
|
||||
return result;
|
||||
}
|
||||
|
||||
static int TestRefLocal(ref int local)
|
||||
{
|
||||
// Create a ref local
|
||||
ref int refLocal = ref local;
|
||||
return refLocal;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user