Uncomment a bit of a test (#64)

This commit is contained in:
Patrick Stevens
2025-06-22 19:36:47 +01:00
committed by GitHub
parent 91f5376e8a
commit 19ec9f8670
8 changed files with 110 additions and 88 deletions

View File

@@ -519,6 +519,12 @@ type UnaryMetadataTokenIlOp =
| Call
| Calli
| Callvirt
/// Attempts to cast an object passed by reference to the specified class.
/// If the class of the object on the top of the stack does not implement the new class
/// (assuming the new class is an interface)
/// and is not a derived class of the new class then an InvalidCastException is thrown.
/// If the object reference is a null reference, castclass succeeds
/// and returns the new object as a null reference.
| Castclass
| Newobj
| Newarr

View File

@@ -92,6 +92,8 @@ type TypeInfoCrate =
abstract ToString : unit -> string
abstract BaseType : BaseTypeInfo option
abstract Assembly : AssemblyName
abstract Namespace : string
abstract Name : string
[<RequireQualifiedAccess>]
module TypeInfoCrate =
@@ -108,6 +110,10 @@ module TypeInfoCrate =
member this.BaseType = t.BaseType
member this.Assembly = t.Assembly
member this.Namespace = t.Namespace
member this.Name = t.Name
}
type BaseClassTypes<'corelib> =

View File

@@ -42,7 +42,7 @@ unsafe class LdindTest
// failures += TestManagedPointers();
// Test Ldind.i (native int)
// failures += TestLdindI();
failures += TestLdindI();
return failures;
}

View File

@@ -65,7 +65,7 @@ module AbstractMachine =
let methodPtr =
match delegateToRun.Fields.["_methodPtr"] with
| CliType.Numeric (CliNumericType.ProvenanceTrackedNativeInt64 mi) -> mi
| CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.FunctionPointer mi)) -> mi
| d -> failwith $"unexpectedly not a method pointer in delegate invocation: {d}"
let typeGenerics =

View File

@@ -36,11 +36,74 @@ type BasicCliType =
| NativeInt of int64
| NativeFloat of float
[<NoComparison>]
type ManagedPointerSource =
| LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
| Argument of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
| Heap of ManagedHeapAddress
| Null
override this.ToString () =
match this with
| ManagedPointerSource.Null -> "<null pointer>"
| ManagedPointerSource.Heap addr -> $"%O{addr}"
| ManagedPointerSource.LocalVariable (source, method, var) ->
$"<variable %i{var} in method frame %i{method} of thread %O{source}>"
| ManagedPointerSource.Argument (source, method, var) ->
$"<argument %i{var} in method frame %i{method} of thread %O{source}>"
[<RequireQualifiedAccess>]
type UnsignedNativeIntSource =
| Verbatim of uint64
| FromManagedPointer of ManagedPointerSource
[<RequireQualifiedAccess>]
type NativeIntSource =
| Verbatim of int64
| ManagedPointer of ManagedPointerSource
| FunctionPointer of MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter>
| TypeHandlePtr of int64<typeHandle>
override this.ToString () : string =
match this with
| NativeIntSource.Verbatim int64 -> $"%i{int64}"
| NativeIntSource.ManagedPointer ptr -> $"<managed pointer {ptr}>"
| NativeIntSource.FunctionPointer methodDefinition ->
$"<pointer to {methodDefinition.Name} in {methodDefinition.DeclaringType.Assembly.Name}>"
| NativeIntSource.TypeHandlePtr ptr -> $"<type ID %i{ptr}>"
[<RequireQualifiedAccess>]
module NativeIntSource =
let isZero (n : NativeIntSource) : bool =
match n with
| NativeIntSource.Verbatim i -> i = 0L
| NativeIntSource.TypeHandlePtr _ -> false
| NativeIntSource.FunctionPointer _ -> failwith "TODO"
| NativeIntSource.ManagedPointer src ->
match src with
| ManagedPointerSource.Null -> true
| _ -> false
let isNonnegative (n : NativeIntSource) : bool =
match n with
| NativeIntSource.Verbatim i -> i >= 0L
| NativeIntSource.FunctionPointer _ -> failwith "TODO"
| NativeIntSource.TypeHandlePtr _ -> true
| NativeIntSource.ManagedPointer _ -> true
/// True if a < b.
let isLess (a : NativeIntSource) (b : NativeIntSource) : bool =
match a, b with
| NativeIntSource.Verbatim a, NativeIntSource.Verbatim b -> a < b
| _, _ -> failwith "TODO"
/// Defined in III.1.1.1
type CliNumericType =
| Int32 of int32
| Int64 of int64
| NativeInt of int64
/// The real CLR just represents these as native ints, but we track their provenance.
| NativeInt of NativeIntSource
| NativeFloat of float
| Int8 of int8
| Int16 of int16
@@ -48,10 +111,6 @@ type CliNumericType =
| UInt16 of uint16
| Float32 of float32
| Float64 of float
/// Not a real CLI numeric type! Represents an int64 obtained by taking a NativeInt from the eval stack.
| ProvenanceTrackedNativeInt64 of MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter>
/// Not a real CLI numeric type! An opaque TypeHandle pointer.
| TypeHandlePtr of int64<typeHandle>
type CliValueType =
private

View File

@@ -1,65 +1,5 @@
namespace WoofWare.PawPrint
type ManagedPointerSource =
| LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
| Argument of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
| Heap of ManagedHeapAddress
| Null
override this.ToString () =
match this with
| ManagedPointerSource.Null -> "<null pointer>"
| ManagedPointerSource.Heap addr -> $"%O{addr}"
| ManagedPointerSource.LocalVariable (source, method, var) ->
$"<variable %i{var} in method frame %i{method} of thread %O{source}>"
| ManagedPointerSource.Argument (source, method, var) ->
$"<argument %i{var} in method frame %i{method} of thread %O{source}>"
[<RequireQualifiedAccess>]
type NativeIntSource =
| Verbatim of int64
| ManagedPointer of ManagedPointerSource
| FunctionPointer of MethodInfo<FakeUnit, GenericParameter>
| TypeHandlePtr of int64<typeHandle>
override this.ToString () : string =
match this with
| NativeIntSource.Verbatim int64 -> $"%i{int64}"
| NativeIntSource.ManagedPointer ptr -> $"<managed pointer {ptr}>"
| NativeIntSource.FunctionPointer methodDefinition ->
$"<pointer to {methodDefinition.Name} in {methodDefinition.DeclaringType.Assembly.Name}>"
| NativeIntSource.TypeHandlePtr ptr -> $"<type ID %i{ptr}>"
[<RequireQualifiedAccess>]
module NativeIntSource =
let isZero (n : NativeIntSource) : bool =
match n with
| NativeIntSource.Verbatim i -> i = 0L
| NativeIntSource.TypeHandlePtr _ -> false
| NativeIntSource.FunctionPointer _ -> failwith "TODO"
| NativeIntSource.ManagedPointer src ->
match src with
| ManagedPointerSource.Null -> true
| _ -> false
let isNonnegative (n : NativeIntSource) : bool =
match n with
| NativeIntSource.Verbatim i -> i >= 0L
| NativeIntSource.FunctionPointer _ -> failwith "TODO"
| NativeIntSource.TypeHandlePtr _ -> true
| NativeIntSource.ManagedPointer _ -> true
/// True if a < b.
let isLess (a : NativeIntSource) (b : NativeIntSource) : bool =
match a, b with
| NativeIntSource.Verbatim a, NativeIntSource.Verbatim b -> a < b
| _, _ -> failwith "TODO"
[<RequireQualifiedAccess>]
type UnsignedNativeIntSource =
| Verbatim of uint64
| FromManagedPointer of ManagedPointerSource
/// See I.12.3.2.1 for definition
type EvalStackValue =
| Int32 of int32
@@ -164,8 +104,6 @@ module EvalStackValue =
| EvalStackValue.Int32 i -> CliType.Numeric (CliNumericType.Int32 i)
| EvalStackValue.UserDefinedValueType [ popped ] -> toCliTypeCoerced target popped
| i -> failwith $"TODO: %O{i}"
| CliNumericType.TypeHandlePtr _
| CliNumericType.ProvenanceTrackedNativeInt64 _
| CliNumericType.Int64 _ ->
match popped with
| EvalStackValue.Int64 i -> CliType.Numeric (CliNumericType.Int64 i)
@@ -173,11 +111,18 @@ module EvalStackValue =
match src with
| NativeIntSource.Verbatim i -> CliType.Numeric (CliNumericType.Int64 i)
| NativeIntSource.ManagedPointer ptr -> failwith "TODO"
| NativeIntSource.FunctionPointer f ->
CliType.Numeric (CliNumericType.ProvenanceTrackedNativeInt64 f)
| NativeIntSource.TypeHandlePtr f -> CliType.Numeric (CliNumericType.TypeHandlePtr f)
| NativeIntSource.FunctionPointer f -> failwith $"TODO: {f}"
// CliType.Numeric (CliNumericType.ProvenanceTrackedNativeInt64 f)
| NativeIntSource.TypeHandlePtr f -> failwith $"TODO: {f}"
// CliType.Numeric (CliNumericType.TypeHandlePtr f)
| i -> failwith $"TODO: %O{i}"
| CliNumericType.NativeInt int64 -> failwith "todo"
| CliNumericType.NativeInt _ ->
match popped with
| EvalStackValue.NativeInt s -> CliNumericType.NativeInt s
| EvalStackValue.ManagedPointer ptrSrc ->
CliNumericType.NativeInt (NativeIntSource.ManagedPointer ptrSrc)
| _ -> failwith $"TODO: {popped}"
|> CliType.Numeric
| CliNumericType.NativeFloat f -> failwith "todo"
| CliNumericType.Int8 _ ->
match popped with
@@ -262,7 +207,8 @@ module EvalStackValue =
match src with
| ManagedPointerSource.Heap src ->
CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.Heap src))
| ManagedPointerSource.Null -> failwith "TODO"
| ManagedPointerSource.Null ->
CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null)
| ManagedPointerSource.LocalVariable (a, b, c) ->
CliType.RuntimePointer (
CliRuntimePointer.Managed (CliRuntimePointerSource.LocalVariable (a, b, c))
@@ -270,7 +216,7 @@ module EvalStackValue =
| ManagedPointerSource.Argument (a, b, c) ->
CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.Argument (a, b, c)))
| NativeIntSource.FunctionPointer methodInfo ->
CliType.Numeric (CliNumericType.ProvenanceTrackedNativeInt64 methodInfo)
CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.FunctionPointer methodInfo))
| NativeIntSource.TypeHandlePtr int64 -> failwith "todo"
| _ -> failwith $"TODO: %O{popped}"
| CliType.Char _ ->
@@ -298,7 +244,7 @@ module EvalStackValue =
match numeric with
| CliNumericType.Int32 i -> EvalStackValue.Int32 i
| CliNumericType.Int64 i -> EvalStackValue.Int64 i
| CliNumericType.NativeInt i -> failwith "TODO"
| CliNumericType.NativeInt i -> EvalStackValue.NativeInt i
// Sign-extend types int8 and int16
// Zero-extend unsigned int8/unsigned int16
| CliNumericType.Int8 b -> int32<int8> b |> EvalStackValue.Int32
@@ -308,9 +254,6 @@ module EvalStackValue =
| CliNumericType.Float32 f -> EvalStackValue.Float (float<float32> f)
| CliNumericType.Float64 f -> EvalStackValue.Float f
| CliNumericType.NativeFloat f -> EvalStackValue.Float f
| CliNumericType.ProvenanceTrackedNativeInt64 f ->
EvalStackValue.NativeInt (NativeIntSource.FunctionPointer f)
| CliNumericType.TypeHandlePtr f -> EvalStackValue.NativeInt (NativeIntSource.TypeHandlePtr f)
| CliType.ObjectRef i ->
match i with
| None -> EvalStackValue.ManagedPointer ManagedPointerSource.Null
@@ -320,7 +263,7 @@ module EvalStackValue =
| CliType.Char (high, low) -> int32 high * 256 + int32 low |> EvalStackValue.Int32
| CliType.RuntimePointer ptr ->
match ptr with
| CliRuntimePointer.Unmanaged _ -> failwith "todo: unmanaged"
| CliRuntimePointer.Unmanaged ptrInt -> NativeIntSource.Verbatim ptrInt |> EvalStackValue.NativeInt
| CliRuntimePointer.Managed ptr ->
match ptr with
| CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, var) ->
@@ -330,7 +273,7 @@ module EvalStackValue =
ManagedPointerSource.Argument (sourceThread, methodFrame, var)
|> EvalStackValue.ManagedPointer
| CliRuntimePointerSource.Heap addr -> EvalStackValue.ObjectRef addr
| CliRuntimePointerSource.Null -> failwith "TODO"
| CliRuntimePointerSource.Null -> EvalStackValue.ManagedPointer ManagedPointerSource.Null
| CliType.ValueType fields -> fields |> List.map ofCliType |> EvalStackValue.UserDefinedValueType
type EvalStack =

View File

@@ -47,7 +47,7 @@ module NullaryIlOp =
// Helper to get the target CliType for each Ldind variant
let private getTargetLdindCliType (targetType : LdindTargetType) : CliType =
match targetType with
| LdindI -> CliType.Numeric (CliNumericType.NativeInt 0L)
| LdindI -> CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.Verbatim 0L))
| LdindI1 -> CliType.Numeric (CliNumericType.Int8 0y)
| LdindI2 -> CliType.Numeric (CliNumericType.Int16 0s)
| LdindI4 -> CliType.Numeric (CliNumericType.Int32 0)
@@ -357,15 +357,23 @@ module NullaryIlOp =
| EvalStackValue.Float var1, EvalStackValue.Float var2 -> failwith "TODO: float CEQ float"
| EvalStackValue.Float _, _ -> failwith $"bad ceq: Float vs {var2}"
| EvalStackValue.NativeInt var1, EvalStackValue.NativeInt var2 ->
failwith $"TODO (CEQ): nativeint vs nativeint"
match var1, var2 with
| NativeIntSource.FunctionPointer f1, NativeIntSource.FunctionPointer f2 ->
if f1 = f2 then
1
else
failwith $"TODO(CEQ): nativeint vs nativeint, {f1} vs {f2}"
| NativeIntSource.TypeHandlePtr f1, NativeIntSource.TypeHandlePtr f2 -> if f1 = f2 then 1 else 0
| NativeIntSource.Verbatim f1, NativeIntSource.Verbatim f2 -> if f1 = f2 then 1 else 0
| NativeIntSource.ManagedPointer f1, NativeIntSource.ManagedPointer f2 -> if f1 = f2 then 1 else 0
| _, _ -> failwith $"TODO (CEQ): nativeint vs nativeint, {var1} vs {var2}"
| EvalStackValue.NativeInt var1, EvalStackValue.Int32 var2 -> failwith $"TODO (CEQ): nativeint vs int32"
| EvalStackValue.NativeInt var1, EvalStackValue.ManagedPointer var2 ->
failwith $"TODO (CEQ): nativeint vs managed pointer"
| EvalStackValue.NativeInt _, _ -> failwith $"bad ceq: NativeInt vs {var2}"
| EvalStackValue.ObjectRef var1, EvalStackValue.ObjectRef var2 -> if var1 = var2 then 1 else 0
| EvalStackValue.ObjectRef _, _ -> failwith $"bad ceq: ObjectRef vs {var2}"
| EvalStackValue.ManagedPointer var1, EvalStackValue.ManagedPointer var2 ->
failwith $"TODO (CEQ): managed pointers"
| EvalStackValue.ManagedPointer var1, EvalStackValue.ManagedPointer var2 -> if var1 = var2 then 1 else 0
| EvalStackValue.ManagedPointer var1, EvalStackValue.NativeInt var2 ->
failwith $"TODO (CEQ): managed pointer vs nativeint"
| EvalStackValue.ManagedPointer _, _ -> failwith $"bad ceq: ManagedPointer vs {var2}"
@@ -717,7 +725,7 @@ module NullaryIlOp =
| Localloc -> failwith "TODO: Localloc unimplemented"
| Stind_I ->
let state =
stind (CliType.Numeric (CliNumericType.NativeInt 0L)) currentThread state
stind (CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.Verbatim 0L))) currentThread state
|> IlMachineState.advanceProgramCounter currentThread
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped

View File

@@ -45,8 +45,8 @@ module TypeHandleRegistry =
// for the GC, I think?
"m_keepalive", CliType.ObjectRef None
// TODO: this is actually a System.IntPtr https://github.com/dotnet/runtime/blob/ec11903827fc28847d775ba17e0cd1ff56cfbc2e/src/coreclr/nativeaot/Runtime.Base/src/System/Primitives.cs#L339
"m_cache", CliType.Numeric (CliNumericType.NativeInt 0L)
"m_handle", CliType.Numeric (CliNumericType.TypeHandlePtr handle)
"m_cache", CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.Verbatim 0L))
"m_handle", CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.TypeHandlePtr handle))
// This is the const -1, apparently?!
// https://github.com/dotnet/runtime/blob/f0168ee80ba9aca18a7e7140b2bb436defda623c/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs#L2496
"GenericParameterCountAny", CliType.Numeric (CliNumericType.Int32 -1)