mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-16 10:58:40 +00:00
Implement Ldelem etc (#72)
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<WarningsAsErrors>false</WarningsAsErrors>
|
||||||
|
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
@@ -123,6 +123,7 @@ type NullaryIlOp =
|
|||||||
| Localloc
|
| Localloc
|
||||||
/// Dereferences the pointer on top of the stack, and pushes the target to the stack as a type O (object reference).
|
/// Dereferences the pointer on top of the stack, and pushes the target to the stack as a type O (object reference).
|
||||||
| Ldind_ref
|
| Ldind_ref
|
||||||
|
/// Stores an object reference value at a supplied address.
|
||||||
| Stind_ref
|
| Stind_ref
|
||||||
| Stind_I
|
| Stind_I
|
||||||
| Stind_I1
|
| Stind_I1
|
||||||
@@ -166,18 +167,25 @@ type NullaryIlOp =
|
|||||||
| Ldelem_u8
|
| Ldelem_u8
|
||||||
| Ldelem_r4
|
| Ldelem_r4
|
||||||
| Ldelem_r8
|
| Ldelem_r8
|
||||||
|
/// Loads the element containing an object reference at a specified array index onto the top of the evaluation stack as type O (object reference).
|
||||||
| Ldelem_ref
|
| Ldelem_ref
|
||||||
|
/// Replaces the array element at a given index with the nativeint value on the evaluation stack.
|
||||||
| Stelem_i
|
| Stelem_i
|
||||||
|
/// Replaces the array element at a given index with the int8 value on the evaluation stack.
|
||||||
| Stelem_i1
|
| Stelem_i1
|
||||||
| Stelem_u1
|
| Stelem_u1
|
||||||
|
/// Replaces the array element at a given index with the int16 value on the evaluation stack.
|
||||||
| Stelem_i2
|
| Stelem_i2
|
||||||
| Stelem_u2
|
| Stelem_u2
|
||||||
|
/// Replaces the array element at a given index with the int32 value on the evaluation stack.
|
||||||
| Stelem_i4
|
| Stelem_i4
|
||||||
| Stelem_u4
|
| Stelem_u4
|
||||||
|
/// Replaces the array element at a given index with the int64 value on the evaluation stack.
|
||||||
| Stelem_i8
|
| Stelem_i8
|
||||||
| Stelem_u8
|
| Stelem_u8
|
||||||
| Stelem_r4
|
| Stelem_r4
|
||||||
| Stelem_r8
|
| Stelem_r8
|
||||||
|
/// Replaces the array element at a given index with the object ref value (type O) on the evaluation stack.
|
||||||
| Stelem_ref
|
| Stelem_ref
|
||||||
| Cpblk
|
| Cpblk
|
||||||
| Initblk
|
| Initblk
|
||||||
@@ -384,6 +392,7 @@ type UnaryConstIlOp =
|
|||||||
| Bge_un_s of int8
|
| Bge_un_s of int8
|
||||||
| Bgt_un_s of int8
|
| Bgt_un_s of int8
|
||||||
| Ble_un_s of int8
|
| Ble_un_s of int8
|
||||||
|
/// Transfers control to a target instruction if the first value is less than the second value.
|
||||||
| Blt_un_s of int8
|
| Blt_un_s of int8
|
||||||
| Bne_un of int32
|
| Bne_un of int32
|
||||||
| Bge_un of int32
|
| Bge_un of int32
|
||||||
@@ -529,6 +538,7 @@ type UnaryMetadataTokenIlOp =
|
|||||||
| Newobj
|
| Newobj
|
||||||
| Newarr
|
| Newarr
|
||||||
| Box
|
| Box
|
||||||
|
/// Loads the address of the array element at a specified array index onto the top of the evaluation stack as type "managed pointer"
|
||||||
| Ldelema
|
| Ldelema
|
||||||
| Isinst
|
| Isinst
|
||||||
/// Pop value from stack; pop object ref from stack; set specified field on that object to that value.
|
/// Pop value from stack; pop object ref from stack; set specified field on that object to that value.
|
||||||
|
@@ -185,6 +185,12 @@ module TestPureCases =
|
|||||||
|> List.map (fun i -> CliType.Numeric (CliNumericType.Int32 i))
|
|> List.map (fun i -> CliType.Numeric (CliNumericType.Int32 i))
|
||||||
|> Some
|
|> Some
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
FileName = "Ldelema.cs"
|
||||||
|
ExpectedReturnCode = 0
|
||||||
|
NativeImpls = MockEnv.make ()
|
||||||
|
LocalVariablesOfMain = None
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
[<TestCaseSource(nameof cases)>]
|
[<TestCaseSource(nameof cases)>]
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="sourcesPure\BasicLock.cs" />
|
<EmbeddedResource Include="sourcesPure\BasicLock.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\NoOp.cs" />
|
<EmbeddedResource Include="sourcesPure\NoOp.cs" />
|
||||||
|
<EmbeddedResource Include="sourcesPure\Ldelema.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpCatch.cs" />
|
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpCatch.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpFinally.cs" />
|
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpFinally.cs" />
|
||||||
<EmbeddedResource Include="sourcesPure\TryCatchWithThrowInBody.cs" />
|
<EmbeddedResource Include="sourcesPure\TryCatchWithThrowInBody.cs" />
|
||||||
|
66
WoofWare.PawPrint.Test/sourcesPure/Ldelema.cs
Normal file
66
WoofWare.PawPrint.Test/sourcesPure/Ldelema.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A simple value type used for testing ldelema.
|
||||||
|
/// </summary>
|
||||||
|
public struct TestStruct
|
||||||
|
{
|
||||||
|
public int Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Modifies a TestStruct instance by reference. Calling this with an array element
|
||||||
|
/// (e.g., `ModifyStruct(ref array[i], ...)` ) will cause the C# compiler to
|
||||||
|
/// generate an `ldelema` instruction.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s">A reference to the TestStruct to modify.</param>
|
||||||
|
/// <param name="newValue">The new value to assign.</param>
|
||||||
|
public static void ModifyStruct(ref TestStruct s, int newValue)
|
||||||
|
{
|
||||||
|
s.Value = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Modifies a string reference.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="s">A reference to a string variable.</param>
|
||||||
|
/// <param name="newValue">The new string to assign.</param>
|
||||||
|
public static void ModifyStringRef(ref string s, string newValue)
|
||||||
|
{
|
||||||
|
s = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Main entry point for the ldelema test.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>0 if all tests pass, otherwise a non-zero error code.</returns>
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
|
// --- Test 1: Modifying a value type element in an array ---
|
||||||
|
TestStruct[] structArray = new TestStruct[5];
|
||||||
|
structArray[2].Value = 100;
|
||||||
|
|
||||||
|
// This call should generate an `ldelema` instruction to get the address of structArray[2].
|
||||||
|
ModifyStruct(ref structArray[2], 999);
|
||||||
|
|
||||||
|
if (structArray[2].Value != 999)
|
||||||
|
{
|
||||||
|
return 301; // Unique error code for this test
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Test 2: Modifying a reference type element in an array ---
|
||||||
|
string[] stringArray = new string[] { "alpha", "beta", "gamma" };
|
||||||
|
|
||||||
|
// This call should also generate an `ldelema` instruction.
|
||||||
|
ModifyStringRef(ref stringArray[1], "zeta");
|
||||||
|
|
||||||
|
if (stringArray[1] != "zeta")
|
||||||
|
{
|
||||||
|
return 302; // Unique error code for this test
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // Success
|
||||||
|
}
|
||||||
|
}
|
@@ -41,6 +41,7 @@ type ManagedPointerSource =
|
|||||||
| LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
| LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
||||||
| Argument of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
| Argument of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
||||||
| Heap of ManagedHeapAddress
|
| Heap of ManagedHeapAddress
|
||||||
|
| ArrayIndex of arr : ManagedHeapAddress * index : int
|
||||||
| Null
|
| Null
|
||||||
|
|
||||||
override this.ToString () =
|
override this.ToString () =
|
||||||
@@ -51,6 +52,7 @@ type ManagedPointerSource =
|
|||||||
$"<variable %i{var} in method frame %i{method} of thread %O{source}>"
|
$"<variable %i{var} in method frame %i{method} of thread %O{source}>"
|
||||||
| ManagedPointerSource.Argument (source, method, var) ->
|
| ManagedPointerSource.Argument (source, method, var) ->
|
||||||
$"<argument %i{var} in method frame %i{method} of thread %O{source}>"
|
$"<argument %i{var} in method frame %i{method} of thread %O{source}>"
|
||||||
|
| ManagedPointerSource.ArrayIndex (arr, index) -> $"<index %i{index} of array %O{arr}>"
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
type UnsignedNativeIntSource =
|
type UnsignedNativeIntSource =
|
||||||
@@ -129,6 +131,7 @@ type CliRuntimePointerSource =
|
|||||||
| LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
| LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
||||||
| Argument of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
| Argument of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
||||||
| Heap of ManagedHeapAddress
|
| Heap of ManagedHeapAddress
|
||||||
|
| ArrayIndex of arr : ManagedHeapAddress * index : int
|
||||||
| Null
|
| Null
|
||||||
|
|
||||||
type CliRuntimePointer =
|
type CliRuntimePointer =
|
||||||
|
@@ -162,6 +162,8 @@ module EvalStackValue =
|
|||||||
|> CliType.RuntimePointer
|
|> CliType.RuntimePointer
|
||||||
| ManagedPointerSource.Heap managedHeapAddress -> CliType.ObjectRef (Some managedHeapAddress)
|
| ManagedPointerSource.Heap managedHeapAddress -> CliType.ObjectRef (Some managedHeapAddress)
|
||||||
| ManagedPointerSource.Null -> CliType.ObjectRef None
|
| ManagedPointerSource.Null -> CliType.ObjectRef None
|
||||||
|
| ManagedPointerSource.ArrayIndex (arr, ind) ->
|
||||||
|
CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.ArrayIndex (arr, ind)))
|
||||||
| EvalStackValue.NativeInt nativeIntSource ->
|
| EvalStackValue.NativeInt nativeIntSource ->
|
||||||
match nativeIntSource with
|
match nativeIntSource with
|
||||||
| NativeIntSource.Verbatim 0L -> CliType.ObjectRef None
|
| NativeIntSource.Verbatim 0L -> CliType.ObjectRef None
|
||||||
@@ -200,6 +202,7 @@ module EvalStackValue =
|
|||||||
CliRuntimePointerSource.Argument (sourceThread, methodFrame, var)
|
CliRuntimePointerSource.Argument (sourceThread, methodFrame, var)
|
||||||
|> CliRuntimePointer.Managed
|
|> CliRuntimePointer.Managed
|
||||||
|> CliType.RuntimePointer
|
|> CliType.RuntimePointer
|
||||||
|
| ManagedPointerSource.ArrayIndex _ -> failwith "TODO"
|
||||||
| EvalStackValue.NativeInt intSrc ->
|
| EvalStackValue.NativeInt intSrc ->
|
||||||
match intSrc with
|
match intSrc with
|
||||||
| NativeIntSource.Verbatim i -> CliType.RuntimePointer (CliRuntimePointer.Unmanaged i)
|
| NativeIntSource.Verbatim i -> CliType.RuntimePointer (CliRuntimePointer.Unmanaged i)
|
||||||
@@ -215,6 +218,7 @@ module EvalStackValue =
|
|||||||
)
|
)
|
||||||
| ManagedPointerSource.Argument (a, b, c) ->
|
| ManagedPointerSource.Argument (a, b, c) ->
|
||||||
CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.Argument (a, b, c)))
|
CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.Argument (a, b, c)))
|
||||||
|
| ManagedPointerSource.ArrayIndex _ -> failwith "TODO"
|
||||||
| NativeIntSource.FunctionPointer methodInfo ->
|
| NativeIntSource.FunctionPointer methodInfo ->
|
||||||
CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.FunctionPointer methodInfo))
|
CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.FunctionPointer methodInfo))
|
||||||
| NativeIntSource.TypeHandlePtr int64 -> failwith "todo"
|
| NativeIntSource.TypeHandlePtr int64 -> failwith "todo"
|
||||||
@@ -269,6 +273,8 @@ module EvalStackValue =
|
|||||||
| CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, var) ->
|
| CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, var) ->
|
||||||
ManagedPointerSource.LocalVariable (sourceThread, methodFrame, var)
|
ManagedPointerSource.LocalVariable (sourceThread, methodFrame, var)
|
||||||
|> EvalStackValue.ManagedPointer
|
|> EvalStackValue.ManagedPointer
|
||||||
|
| CliRuntimePointerSource.ArrayIndex (arr, ind) ->
|
||||||
|
ManagedPointerSource.ArrayIndex (arr, ind) |> EvalStackValue.ManagedPointer
|
||||||
| CliRuntimePointerSource.Argument (sourceThread, methodFrame, var) ->
|
| CliRuntimePointerSource.Argument (sourceThread, methodFrame, var) ->
|
||||||
ManagedPointerSource.Argument (sourceThread, methodFrame, var)
|
ManagedPointerSource.Argument (sourceThread, methodFrame, var)
|
||||||
|> EvalStackValue.ManagedPointer
|
|> EvalStackValue.ManagedPointer
|
||||||
|
@@ -86,6 +86,7 @@ module System_Threading_Monitor =
|
|||||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
||||||
failwith "not really expecting to *edit* an argument..."
|
failwith "not really expecting to *edit* an argument..."
|
||||||
| ManagedPointerSource.Heap addr -> failwith "todo: managed heap"
|
| ManagedPointerSource.Heap addr -> failwith "todo: managed heap"
|
||||||
|
| ManagedPointerSource.ArrayIndex _ -> failwith "todo: array index"
|
||||||
|
|
||||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||||
|
|
||||||
|
@@ -587,6 +587,7 @@ module IlMachineState =
|
|||||||
| ManagedPointerSource.Heap managedHeapAddress ->
|
| ManagedPointerSource.Heap managedHeapAddress ->
|
||||||
CliRuntimePointer.Managed (CliRuntimePointerSource.Heap managedHeapAddress)
|
CliRuntimePointer.Managed (CliRuntimePointerSource.Heap managedHeapAddress)
|
||||||
| ManagedPointerSource.Null -> failwith "todo"
|
| ManagedPointerSource.Null -> failwith "todo"
|
||||||
|
| ManagedPointerSource.ArrayIndex _ -> failwith "TODO"
|
||||||
| x -> failwith $"TODO: Unsafe.AsPointer(%O{x})"
|
| x -> failwith $"TODO: Unsafe.AsPointer(%O{x})"
|
||||||
|
|
||||||
pushToEvalStack (CliType.RuntimePointer toPush) currentThread state
|
pushToEvalStack (CliType.RuntimePointer toPush) currentThread state
|
||||||
@@ -616,6 +617,34 @@ module IlMachineState =
|
|||||||
|> pushToEvalStack' result currentThread
|
|> pushToEvalStack' result currentThread
|
||||||
|> advanceProgramCounter currentThread
|
|> advanceProgramCounter currentThread
|
||||||
|> Some
|
|> Some
|
||||||
|
| "System.Private.CoreLib", "String", "Equals" ->
|
||||||
|
let arg1, state = popEvalStack currentThread state
|
||||||
|
|
||||||
|
let arg1 =
|
||||||
|
match arg1 with
|
||||||
|
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap h) -> h
|
||||||
|
| EvalStackValue.Int32 _
|
||||||
|
| EvalStackValue.Int64 _
|
||||||
|
| EvalStackValue.Float _ -> failwith $"this isn't a string! {arg1}"
|
||||||
|
| _ -> failwith $"TODO: %O{arg1}"
|
||||||
|
|
||||||
|
let arg2, state = popEvalStack currentThread state
|
||||||
|
|
||||||
|
let arg2 =
|
||||||
|
match arg2 with
|
||||||
|
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap h) -> h
|
||||||
|
| EvalStackValue.Int32 _
|
||||||
|
| EvalStackValue.Int64 _
|
||||||
|
| EvalStackValue.Float _ -> failwith $"this isn't a string! {arg2}"
|
||||||
|
| _ -> failwith $"TODO: %O{arg2}"
|
||||||
|
|
||||||
|
if arg1 = arg2 then
|
||||||
|
state
|
||||||
|
|> pushToEvalStack (CliType.OfBool true) currentThread
|
||||||
|
|> advanceProgramCounter currentThread
|
||||||
|
|> Some
|
||||||
|
else
|
||||||
|
failwith "TODO"
|
||||||
| a, b, c -> failwith $"TODO: implement JIT intrinsic {a}.{b}.{c}"
|
| a, b, c -> failwith $"TODO: implement JIT intrinsic {a}.{b}.{c}"
|
||||||
|> Option.map (fun s -> s.WithThreadSwitchedToAssembly callerAssy currentThread |> fst)
|
|> Option.map (fun s -> s.WithThreadSwitchedToAssembly callerAssy currentThread |> fst)
|
||||||
|
|
||||||
@@ -1150,6 +1179,9 @@ module IlMachineState =
|
|||||||
ManagedHeap = heap
|
ManagedHeap = heap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let getArrayValue (arrayAllocation : ManagedHeapAddress) (index : int) (state : IlMachineState) : CliType =
|
||||||
|
ManagedHeap.GetArrayValue arrayAllocation index state.ManagedHeap
|
||||||
|
|
||||||
let jumpProgramCounter (thread : ThreadId) (bytes : int) (state : IlMachineState) : IlMachineState =
|
let jumpProgramCounter (thread : ThreadId) (bytes : int) (state : IlMachineState) : IlMachineState =
|
||||||
{ state with
|
{ state with
|
||||||
ThreadState =
|
ThreadState =
|
||||||
|
@@ -109,6 +109,16 @@ type ManagedHeap =
|
|||||||
|
|
||||||
ManagedHeapAddress addr, heap
|
ManagedHeapAddress addr, heap
|
||||||
|
|
||||||
|
static member GetArrayValue (alloc : ManagedHeapAddress) (offset : int) (heap : ManagedHeap) : CliType =
|
||||||
|
match heap.Arrays.TryGetValue alloc with
|
||||||
|
| false, _ -> failwith "TODO: array not on heap"
|
||||||
|
| true, arr ->
|
||||||
|
|
||||||
|
if offset < 0 || offset >= arr.Length then
|
||||||
|
failwith "TODO: raise IndexOutOfBoundsException"
|
||||||
|
|
||||||
|
arr.Elements.[offset]
|
||||||
|
|
||||||
static member SetArrayValue
|
static member SetArrayValue
|
||||||
(alloc : ManagedHeapAddress)
|
(alloc : ManagedHeapAddress)
|
||||||
(offset : int)
|
(offset : int)
|
||||||
@@ -124,6 +134,9 @@ type ManagedHeap =
|
|||||||
match arr with
|
match arr with
|
||||||
| None -> failwith "tried to change element of nonexistent array"
|
| None -> failwith "tried to change element of nonexistent array"
|
||||||
| Some arr ->
|
| Some arr ->
|
||||||
|
if offset < 0 || offset >= arr.Elements.Length then
|
||||||
|
failwith "TODO: throw somehow"
|
||||||
|
|
||||||
{ arr with
|
{ arr with
|
||||||
Elements = arr.Elements.SetItem (offset, v)
|
Elements = arr.Elements.SetItem (offset, v)
|
||||||
}
|
}
|
||||||
|
@@ -46,6 +46,7 @@ module NullaryIlOp =
|
|||||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||||
state.ThreadState.[sourceThread].MethodStates.[methodFrame].LocalVariables.[int<uint16> whichVar]
|
state.ThreadState.[sourceThread].MethodStates.[methodFrame].LocalVariables.[int<uint16> whichVar]
|
||||||
| ManagedPointerSource.Heap managedHeapAddress -> failwith "TODO: Heap pointer dereferencing not implemented"
|
| ManagedPointerSource.Heap managedHeapAddress -> failwith "TODO: Heap pointer dereferencing not implemented"
|
||||||
|
| ManagedPointerSource.ArrayIndex _ -> failwith "TODO: array index pointer dereferencing not implemented"
|
||||||
|
|
||||||
// Unified Ldind implementation
|
// Unified Ldind implementation
|
||||||
let private executeLdind
|
let private executeLdind
|
||||||
@@ -121,8 +122,84 @@ module NullaryIlOp =
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
| ManagedPointerSource.Heap managedHeapAddress -> failwith "todo"
|
| ManagedPointerSource.Heap managedHeapAddress -> failwith "todo"
|
||||||
|
| ManagedPointerSource.ArrayIndex _ -> failwith "todo"
|
||||||
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
||||||
|
|
||||||
|
let internal ldElem
|
||||||
|
(targetCliTypeZero : CliType)
|
||||||
|
(index : EvalStackValue)
|
||||||
|
(arr : EvalStackValue)
|
||||||
|
(currentThread : ThreadId)
|
||||||
|
(state : IlMachineState)
|
||||||
|
: ExecutionResult
|
||||||
|
=
|
||||||
|
let index =
|
||||||
|
match index with
|
||||||
|
| EvalStackValue.NativeInt src ->
|
||||||
|
match src with
|
||||||
|
| NativeIntSource.FunctionPointer _
|
||||||
|
| NativeIntSource.TypeHandlePtr _
|
||||||
|
| NativeIntSource.ManagedPointer _ -> failwith "Refusing to treat a pointer as an array index"
|
||||||
|
| NativeIntSource.Verbatim i -> i |> int32
|
||||||
|
| EvalStackValue.Int32 i -> i
|
||||||
|
| _ -> failwith $"Invalid index: {index}"
|
||||||
|
|
||||||
|
let arrAddr =
|
||||||
|
match arr with
|
||||||
|
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr)
|
||||||
|
| EvalStackValue.ObjectRef addr -> addr
|
||||||
|
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||||
|
| _ -> failwith $"Invalid array: %O{arr}"
|
||||||
|
|
||||||
|
let value = IlMachineState.getArrayValue arrAddr index state
|
||||||
|
|
||||||
|
let state =
|
||||||
|
state
|
||||||
|
|> IlMachineState.pushToEvalStack value currentThread
|
||||||
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|
||||||
|
ExecutionResult.Stepped (state, WhatWeDid.Executed)
|
||||||
|
|
||||||
|
let internal stElem
|
||||||
|
(targetCliTypeZero : CliType)
|
||||||
|
(value : EvalStackValue)
|
||||||
|
(index : EvalStackValue)
|
||||||
|
(arr : EvalStackValue)
|
||||||
|
(currentThread : ThreadId)
|
||||||
|
(state : IlMachineState)
|
||||||
|
: ExecutionResult
|
||||||
|
=
|
||||||
|
let index =
|
||||||
|
match index with
|
||||||
|
| EvalStackValue.NativeInt src ->
|
||||||
|
match src with
|
||||||
|
| NativeIntSource.FunctionPointer _
|
||||||
|
| NativeIntSource.TypeHandlePtr _
|
||||||
|
| NativeIntSource.ManagedPointer _ -> failwith "Refusing to treat a pointer as an array index"
|
||||||
|
| NativeIntSource.Verbatim i -> i |> int32
|
||||||
|
| EvalStackValue.Int32 i -> i
|
||||||
|
| _ -> failwith $"Invalid index: {index}"
|
||||||
|
|
||||||
|
let arrAddr =
|
||||||
|
match arr with
|
||||||
|
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr)
|
||||||
|
| EvalStackValue.ObjectRef addr -> addr
|
||||||
|
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||||
|
| _ -> failwith $"Invalid array: %O{arr}"
|
||||||
|
// TODO: throw ArrayTypeMismatchException if incorrect types
|
||||||
|
|
||||||
|
let arr = state.ManagedHeap.Arrays.[arrAddr]
|
||||||
|
|
||||||
|
if index < 0 || index >= arr.Length then
|
||||||
|
failwith "TODO: throw IndexOutOfRangeException"
|
||||||
|
|
||||||
|
let state =
|
||||||
|
state
|
||||||
|
|> IlMachineState.setArrayValue arrAddr (EvalStackValue.toCliTypeCoerced targetCliTypeZero value) index
|
||||||
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|
||||||
|
ExecutionResult.Stepped (state, WhatWeDid.Executed)
|
||||||
|
|
||||||
let internal execute
|
let internal execute
|
||||||
(loggerFactory : ILoggerFactory)
|
(loggerFactory : ILoggerFactory)
|
||||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||||
@@ -674,6 +751,7 @@ module NullaryIlOp =
|
|||||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
||||||
state.ThreadState.[sourceThread].MethodStates.[methodFrame].Arguments.[int<uint16> whichVar]
|
state.ThreadState.[sourceThread].MethodStates.[methodFrame].Arguments.[int<uint16> whichVar]
|
||||||
| ManagedPointerSource.Heap managedHeapAddress -> failwith "todo"
|
| ManagedPointerSource.Heap managedHeapAddress -> failwith "todo"
|
||||||
|
| ManagedPointerSource.ArrayIndex _ -> failwith "todo"
|
||||||
| a -> failwith $"TODO: {a}"
|
| a -> failwith $"TODO: {a}"
|
||||||
|
|
||||||
let state =
|
let state =
|
||||||
@@ -683,7 +761,29 @@ module NullaryIlOp =
|
|||||||
|> IlMachineState.advanceProgramCounter currentThread
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|
||||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||||
| Stind_ref -> failwith "TODO: Stind_ref unimplemented"
|
| Stind_ref ->
|
||||||
|
let value, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let addr, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
|
||||||
|
let state =
|
||||||
|
match addr with
|
||||||
|
| EvalStackValue.ManagedPointer src ->
|
||||||
|
match src with
|
||||||
|
| ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||||
|
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) -> failwith "todo"
|
||||||
|
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) -> failwith "todo"
|
||||||
|
| ManagedPointerSource.Heap managedHeapAddress -> failwith "todo"
|
||||||
|
| ManagedPointerSource.ArrayIndex (arr, index) ->
|
||||||
|
state
|
||||||
|
|> IlMachineState.setArrayValue
|
||||||
|
arr
|
||||||
|
(EvalStackValue.toCliTypeCoerced (CliType.ObjectRef None) value)
|
||||||
|
index
|
||||||
|
| addr -> failwith $"TODO: {addr}"
|
||||||
|
|
||||||
|
let state = state |> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|
||||||
|
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||||
| Ldelem_i -> failwith "TODO: Ldelem_i unimplemented"
|
| Ldelem_i -> failwith "TODO: Ldelem_i unimplemented"
|
||||||
| Ldelem_i1 -> failwith "TODO: Ldelem_i1 unimplemented"
|
| Ldelem_i1 -> failwith "TODO: Ldelem_i1 unimplemented"
|
||||||
| Ldelem_u1 -> failwith "TODO: Ldelem_u1 unimplemented"
|
| Ldelem_u1 -> failwith "TODO: Ldelem_u1 unimplemented"
|
||||||
@@ -695,19 +795,54 @@ module NullaryIlOp =
|
|||||||
| Ldelem_u8 -> failwith "TODO: Ldelem_u8 unimplemented"
|
| Ldelem_u8 -> failwith "TODO: Ldelem_u8 unimplemented"
|
||||||
| Ldelem_r4 -> failwith "TODO: Ldelem_r4 unimplemented"
|
| Ldelem_r4 -> failwith "TODO: Ldelem_r4 unimplemented"
|
||||||
| Ldelem_r8 -> failwith "TODO: Ldelem_r8 unimplemented"
|
| Ldelem_r8 -> failwith "TODO: Ldelem_r8 unimplemented"
|
||||||
| Ldelem_ref -> failwith "TODO: Ldelem_ref unimplemented"
|
| Ldelem_ref ->
|
||||||
| Stelem_i -> failwith "TODO: Stelem_i unimplemented"
|
let index, state = IlMachineState.popEvalStack currentThread state
|
||||||
| Stelem_i1 -> failwith "TODO: Stelem_i1 unimplemented"
|
let arr, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
|
||||||
|
ldElem (CliType.ObjectRef None) index arr currentThread state
|
||||||
|
| Stelem_i ->
|
||||||
|
let value, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let index, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let arr, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
|
||||||
|
stElem
|
||||||
|
(CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.Verbatim 0L)))
|
||||||
|
value
|
||||||
|
index
|
||||||
|
arr
|
||||||
|
currentThread
|
||||||
|
state
|
||||||
|
| Stelem_i1 ->
|
||||||
|
let value, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let index, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let arr, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
stElem (CliType.Numeric (CliNumericType.Int8 0y)) value index arr currentThread state
|
||||||
| Stelem_u1 -> failwith "TODO: Stelem_u1 unimplemented"
|
| Stelem_u1 -> failwith "TODO: Stelem_u1 unimplemented"
|
||||||
| Stelem_i2 -> failwith "TODO: Stelem_i2 unimplemented"
|
| Stelem_i2 ->
|
||||||
|
let value, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let index, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let arr, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
stElem (CliType.Numeric (CliNumericType.Int16 0s)) value index arr currentThread state
|
||||||
| Stelem_u2 -> failwith "TODO: Stelem_u2 unimplemented"
|
| Stelem_u2 -> failwith "TODO: Stelem_u2 unimplemented"
|
||||||
| Stelem_i4 -> failwith "TODO: Stelem_i4 unimplemented"
|
| Stelem_i4 ->
|
||||||
|
let value, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let index, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let arr, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
stElem (CliType.Numeric (CliNumericType.Int32 0)) value index arr currentThread state
|
||||||
| Stelem_u4 -> failwith "TODO: Stelem_u4 unimplemented"
|
| Stelem_u4 -> failwith "TODO: Stelem_u4 unimplemented"
|
||||||
| Stelem_i8 -> failwith "TODO: Stelem_i8 unimplemented"
|
| Stelem_i8 ->
|
||||||
|
let value, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let index, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let arr, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
stElem (CliType.Numeric (CliNumericType.Int64 0L)) value index arr currentThread state
|
||||||
| Stelem_u8 -> failwith "TODO: Stelem_u8 unimplemented"
|
| Stelem_u8 -> failwith "TODO: Stelem_u8 unimplemented"
|
||||||
| Stelem_r4 -> failwith "TODO: Stelem_r4 unimplemented"
|
| Stelem_r4 -> failwith "TODO: Stelem_r4 unimplemented"
|
||||||
| Stelem_r8 -> failwith "TODO: Stelem_r8 unimplemented"
|
| Stelem_r8 -> failwith "TODO: Stelem_r8 unimplemented"
|
||||||
| Stelem_ref -> failwith "TODO: Stelem_ref unimplemented"
|
| Stelem_ref ->
|
||||||
|
let value, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let index, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let arr, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
stElem (CliType.ObjectRef None) value index arr currentThread state
|
||||||
| Cpblk -> failwith "TODO: Cpblk unimplemented"
|
| Cpblk -> failwith "TODO: Cpblk unimplemented"
|
||||||
| Initblk -> failwith "TODO: Initblk unimplemented"
|
| Initblk -> failwith "TODO: Initblk unimplemented"
|
||||||
| Conv_ovf_u1 -> failwith "TODO: Conv_ovf_u1 unimplemented"
|
| Conv_ovf_u1 -> failwith "TODO: Conv_ovf_u1 unimplemented"
|
||||||
|
@@ -340,7 +340,38 @@ module internal UnaryMetadataIlOp =
|
|||||||
|
|
||||||
state, WhatWeDid.Executed
|
state, WhatWeDid.Executed
|
||||||
| Box -> failwith "TODO: Box unimplemented"
|
| Box -> failwith "TODO: Box unimplemented"
|
||||||
| Ldelema -> failwith "TODO: Ldelema unimplemented"
|
| Ldelema ->
|
||||||
|
let index, state = IlMachineState.popEvalStack thread state
|
||||||
|
let arr, state = IlMachineState.popEvalStack thread state
|
||||||
|
|
||||||
|
let index =
|
||||||
|
match index with
|
||||||
|
| EvalStackValue.Int32 i -> i
|
||||||
|
| _ -> failwith $"TODO: {index}"
|
||||||
|
|
||||||
|
let arrAddr =
|
||||||
|
match arr with
|
||||||
|
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr)
|
||||||
|
| EvalStackValue.ObjectRef addr -> addr
|
||||||
|
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||||
|
| _ -> failwith $"Invalid array: %O{arr}"
|
||||||
|
|
||||||
|
// TODO: throw ArrayTypeMismatchException if incorrect types
|
||||||
|
|
||||||
|
let arr = state.ManagedHeap.Arrays.[arrAddr]
|
||||||
|
|
||||||
|
if index < 0 || index >= arr.Length then
|
||||||
|
failwith "TODO: throw IndexOutOfRangeException"
|
||||||
|
|
||||||
|
let result =
|
||||||
|
ManagedPointerSource.ArrayIndex (arrAddr, index)
|
||||||
|
|> EvalStackValue.ManagedPointer
|
||||||
|
|
||||||
|
let state =
|
||||||
|
IlMachineState.pushToEvalStack' result thread state
|
||||||
|
|> IlMachineState.advanceProgramCounter thread
|
||||||
|
|
||||||
|
state, WhatWeDid.Executed
|
||||||
| Isinst ->
|
| Isinst ->
|
||||||
let actualObj, state = IlMachineState.popEvalStack thread state
|
let actualObj, state = IlMachineState.popEvalStack thread state
|
||||||
|
|
||||||
@@ -464,6 +495,8 @@ module internal UnaryMetadataIlOp =
|
|||||||
state
|
state
|
||||||
|> IlMachineState.setLocalVariable sourceThread methodFrame whichVar valueToStore
|
|> IlMachineState.setLocalVariable sourceThread methodFrame whichVar valueToStore
|
||||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) -> failwith "todo"
|
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) -> failwith "todo"
|
||||||
|
| ManagedPointerSource.ArrayIndex (arr, index) ->
|
||||||
|
state |> IlMachineState.setArrayValue arr valueToStore index
|
||||||
| ManagedPointerSource.Heap addr ->
|
| ManagedPointerSource.Heap addr ->
|
||||||
match state.ManagedHeap.NonArrayObjects.TryGetValue addr with
|
match state.ManagedHeap.NonArrayObjects.TryGetValue addr with
|
||||||
| false, _ -> failwith $"todo: array {addr}"
|
| false, _ -> failwith $"todo: array {addr}"
|
||||||
@@ -641,6 +674,9 @@ module internal UnaryMetadataIlOp =
|
|||||||
match state.ManagedHeap.NonArrayObjects.TryGetValue managedHeapAddress with
|
match state.ManagedHeap.NonArrayObjects.TryGetValue managedHeapAddress with
|
||||||
| false, _ -> failwith $"todo: array {managedHeapAddress}"
|
| false, _ -> failwith $"todo: array {managedHeapAddress}"
|
||||||
| true, v -> IlMachineState.pushToEvalStack v.Fields.[field.Name] thread state
|
| true, v -> IlMachineState.pushToEvalStack v.Fields.[field.Name] thread state
|
||||||
|
| ManagedPointerSource.ArrayIndex (arr, index) ->
|
||||||
|
let currentValue = state |> IlMachineState.getArrayValue arr index
|
||||||
|
IlMachineState.pushToEvalStack currentValue thread state
|
||||||
| ManagedPointerSource.Null -> failwith "TODO: raise NullReferenceException"
|
| ManagedPointerSource.Null -> failwith "TODO: raise NullReferenceException"
|
||||||
| EvalStackValue.ObjectRef managedHeapAddress -> failwith $"todo: {managedHeapAddress}"
|
| EvalStackValue.ObjectRef managedHeapAddress -> failwith $"todo: {managedHeapAddress}"
|
||||||
| EvalStackValue.UserDefinedValueType _ as udvt -> IlMachineState.pushToEvalStack' udvt thread state
|
| EvalStackValue.UserDefinedValueType _ as udvt -> IlMachineState.pushToEvalStack' udvt thread state
|
||||||
|
Reference in New Issue
Block a user