mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-10 16:28:41 +00:00
Compare commits
4 Commits
8112b122fb
...
2e9fdbed48
Author | SHA1 | Date | |
---|---|---|---|
|
2e9fdbed48 | ||
|
fb5c4a6313 | ||
|
95987e592c | ||
|
0e31d74586 |
@@ -67,13 +67,12 @@ dotnet run --project WoofWare.PawPrint.App/WoofWare.PawPrint.App.fsproj -- CShar
|
|||||||
- `Corelib.fs`: Core library type definitions (String, Array, etc.)
|
- `Corelib.fs`: Core library type definitions (String, Array, etc.)
|
||||||
|
|
||||||
**WoofWare.PawPrint.Test**
|
**WoofWare.PawPrint.Test**
|
||||||
- Uses Expecto as the test framework
|
- Uses NUnit as the test framework
|
||||||
- Test cases are defined in `TestPureCases.fs` and `TestImpureCases.fs`
|
- Test cases are defined in `TestPureCases.fs` and `TestImpureCases.fs`
|
||||||
- C# source files in `sources{Pure,Impure}/` are compiled and executed by the runtime as test cases
|
- C# source files in `sources{Pure,Impure}/` are compiled and executed by the runtime as test cases; files in `sourcesPure` are automatically turned into test cases with no further action (see TestPureCases.fs for the mechanism)
|
||||||
- `TestHarness.fs` provides infrastructure for running test assemblies through the interpreter
|
- `TestHarness.fs` provides infrastructure for running test assemblies through the interpreter
|
||||||
- Run all tests with `dotnet run --project WoofWare.PawPrint.Test/WoofWare.PawPrint.Test.fsproj -- --no-spinner` (note the additional `--`)
|
- Run all tests with `dotnet run --project WoofWare.PawPrint.Test/WoofWare.PawPrint.Test.fsproj -- --no-spinner` (note the additional `--`)
|
||||||
- Run a specific test with `dotnet run --project WoofWare.PawPrint.Test/WoofWare.PawPrint.Test.fsproj -- --filter-test-case StringWithinTestName --no-spinner`
|
- Run a specific test with `dotnet run --project WoofWare.PawPrint.Test/WoofWare.PawPrint.Test.fsproj -- --filter-test-case StringWithinTestName --no-spinner`
|
||||||
- Pending test definitions must be moved into the non-pending test case list before they can be run.
|
|
||||||
|
|
||||||
**WoofWare.PawPrint.App**
|
**WoofWare.PawPrint.App**
|
||||||
- Entry point application for running the interpreter
|
- Entry point application for running the interpreter
|
||||||
|
@@ -337,6 +337,23 @@ module ConcreteActivePatterns =
|
|||||||
| None -> None
|
| None -> None
|
||||||
| _ -> None
|
| _ -> None
|
||||||
|
|
||||||
|
let (|ConcreteUInt64|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) : unit option =
|
||||||
|
match handle with
|
||||||
|
| ConcreteTypeHandle.Concrete id ->
|
||||||
|
match concreteTypes.Mapping |> Map.tryFind id with
|
||||||
|
| Some ct ->
|
||||||
|
if
|
||||||
|
ct.Assembly.Name = "System.Private.CoreLib"
|
||||||
|
&& ct.Namespace = "System"
|
||||||
|
&& ct.Name = "UInt64"
|
||||||
|
&& ct.Generics.IsEmpty
|
||||||
|
then
|
||||||
|
Some ()
|
||||||
|
else
|
||||||
|
None
|
||||||
|
| None -> None
|
||||||
|
| _ -> None
|
||||||
|
|
||||||
let (|ConcreteSingle|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) : unit option =
|
let (|ConcreteSingle|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) : unit option =
|
||||||
match handle with
|
match handle with
|
||||||
| ConcreteTypeHandle.Concrete id ->
|
| ConcreteTypeHandle.Concrete id ->
|
||||||
|
@@ -6,6 +6,8 @@ open System.Reflection.Metadata
|
|||||||
open System.Reflection.Metadata.Ecma335
|
open System.Reflection.Metadata.Ecma335
|
||||||
open Microsoft.FSharp.Core
|
open Microsoft.FSharp.Core
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
[<NoComparison>]
|
||||||
type ResolvedBaseType =
|
type ResolvedBaseType =
|
||||||
| Enum
|
| Enum
|
||||||
| ValueType
|
| ValueType
|
||||||
|
@@ -23,7 +23,7 @@ module LoggerFactory =
|
|||||||
let makeTest () : (unit -> LogLine list) * ILoggerFactory =
|
let makeTest () : (unit -> LogLine list) * ILoggerFactory =
|
||||||
// Shared sink for all loggers created by the factory.
|
// Shared sink for all loggers created by the factory.
|
||||||
let sink = ResizeArray ()
|
let sink = ResizeArray ()
|
||||||
let isEnabled (logLevel : LogLevel) : bool = logLevel >= LogLevel.Debug
|
let isEnabled (logLevel : LogLevel) : bool = logLevel >= LogLevel.Information
|
||||||
|
|
||||||
let createLogger (category : string) : ILogger =
|
let createLogger (category : string) : ILogger =
|
||||||
{ new ILogger with
|
{ new ILogger with
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
namespace WoofWare.Pawprint.Test
|
namespace WoofWare.Pawprint.Test
|
||||||
|
|
||||||
|
open System
|
||||||
open System.Collections.Immutable
|
open System.Collections.Immutable
|
||||||
open System.IO
|
open System.IO
|
||||||
open FsUnitTyped
|
open FsUnitTyped
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
namespace WoofWare.Pawprint.Test
|
namespace WoofWare.Pawprint.Test
|
||||||
|
|
||||||
|
open System
|
||||||
open System.Collections.Immutable
|
open System.Collections.Immutable
|
||||||
open System.IO
|
open System.IO
|
||||||
open FsUnitTyped
|
open FsUnitTyped
|
||||||
@@ -16,166 +17,65 @@ module TestPureCases =
|
|||||||
|
|
||||||
let unimplemented =
|
let unimplemented =
|
||||||
[
|
[
|
||||||
{
|
"CrossAssemblyTypes.cs"
|
||||||
FileName = "CrossAssemblyTypes.cs"
|
"OverlappingStructs.cs"
|
||||||
ExpectedReturnCode = 0
|
"AdvancedStructLayout.cs"
|
||||||
NativeImpls = MockEnv.make ()
|
"InitializeArray.cs"
|
||||||
}
|
"Threads.cs"
|
||||||
{
|
"ComplexTryCatch.cs"
|
||||||
FileName = "OverlappingStructs.cs"
|
"ResizeArray.cs"
|
||||||
ExpectedReturnCode = 0
|
"LdtokenField.cs"
|
||||||
NativeImpls = MockEnv.make ()
|
"GenericEdgeCases.cs"
|
||||||
}
|
"UnsafeAs.cs"
|
||||||
{
|
|
||||||
FileName = "AdvancedStructLayout.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "InitializeArray.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "Threads.cs"
|
|
||||||
ExpectedReturnCode = 3
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "ComplexTryCatch.cs"
|
|
||||||
ExpectedReturnCode = 14
|
|
||||||
NativeImpls = NativeImpls.PassThru ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "ResizeArray.cs"
|
|
||||||
ExpectedReturnCode = 114
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "LdtokenField.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "GenericEdgeCases.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "UnsafeAs.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
|> Set.ofList
|
||||||
|
|
||||||
|
let requiresMocks =
|
||||||
|
let empty = MockEnv.make ()
|
||||||
|
|
||||||
let cases : EndToEndTestCase list =
|
|
||||||
[
|
[
|
||||||
{
|
"BasicLock.cs",
|
||||||
FileName = "NoOp.cs"
|
(1,
|
||||||
ExpectedReturnCode = 1
|
{ empty with
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "Sizeof.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "Sizeof2.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "Initobj.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "TestShl.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "TestShr.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "StaticVariables.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "Ldind.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "CustomDelegate.cs"
|
|
||||||
ExpectedReturnCode = 8
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "ArgumentOrdering.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "BasicLock.cs"
|
|
||||||
ExpectedReturnCode = 1
|
|
||||||
NativeImpls =
|
|
||||||
let mock = MockEnv.make ()
|
|
||||||
|
|
||||||
{ mock with
|
|
||||||
System_Threading_Monitor = System_Threading_Monitor.passThru
|
System_Threading_Monitor = System_Threading_Monitor.passThru
|
||||||
}
|
})
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "TriangleNumber.cs"
|
|
||||||
ExpectedReturnCode = 10
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "ExceptionWithNoOpFinally.cs"
|
|
||||||
ExpectedReturnCode = 3
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "ExceptionWithNoOpCatch.cs"
|
|
||||||
ExpectedReturnCode = 10
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "Floats.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "TryCatchWithThrowInBody.cs"
|
|
||||||
ExpectedReturnCode = 4
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "Ldelema.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "TypeConcretization.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "TestOr.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
{
|
|
||||||
FileName = "InterfaceDispatch.cs"
|
|
||||||
ExpectedReturnCode = 0
|
|
||||||
NativeImpls = MockEnv.make ()
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
|> Map.ofList
|
||||||
|
|
||||||
|
let customExitCodes =
|
||||||
|
[
|
||||||
|
"NoOp.cs", 1
|
||||||
|
"CustomDelegate.cs", 8
|
||||||
|
"ExceptionWithNoOpFinally.cs", 3
|
||||||
|
"ExceptionWithNoOpCatch.cs", 10
|
||||||
|
"TryCatchWithThrowInBody.cs", 4
|
||||||
|
"ResizeArray.cs", 114
|
||||||
|
"Threads.cs", 3
|
||||||
|
"TriangleNumber.cs", 10
|
||||||
|
]
|
||||||
|
|> Map.ofList
|
||||||
|
|
||||||
|
let allPure =
|
||||||
|
assy.GetManifestResourceNames ()
|
||||||
|
|> Seq.choose (fun res ->
|
||||||
|
let s = "WoofWare.PawPrint.Test.sourcesPure."
|
||||||
|
|
||||||
|
if res.StartsWith (s, StringComparison.OrdinalIgnoreCase) then
|
||||||
|
res.Substring s.Length |> Some
|
||||||
|
else
|
||||||
|
None
|
||||||
|
)
|
||||||
|
|> Set.ofSeq
|
||||||
|
|
||||||
|
let simpleCases : string list =
|
||||||
|
allPure
|
||||||
|
|> Seq.filter (fun s ->
|
||||||
|
(customExitCodes.ContainsKey s
|
||||||
|
|| requiresMocks.ContainsKey s
|
||||||
|
|| unimplemented.Contains s)
|
||||||
|
|> not
|
||||||
|
)
|
||||||
|
|> Seq.toList
|
||||||
|
|
||||||
let runTest (case : EndToEndTestCase) : unit =
|
let runTest (case : EndToEndTestCase) : unit =
|
||||||
let source = Assembly.getEmbeddedResourceAsString case.FileName assy
|
let source = Assembly.getEmbeddedResourceAsString case.FileName assy
|
||||||
@@ -210,9 +110,43 @@ module TestPureCases =
|
|||||||
|
|
||||||
reraise ()
|
reraise ()
|
||||||
|
|
||||||
|
[<TestCaseSource(nameof simpleCases)>]
|
||||||
|
let ``Standard tests`` (fileName : string) =
|
||||||
|
{
|
||||||
|
FileName = fileName
|
||||||
|
ExpectedReturnCode = 0
|
||||||
|
NativeImpls = MockEnv.make ()
|
||||||
|
}
|
||||||
|
|> runTest
|
||||||
|
|
||||||
|
[<TestCaseSource(nameof customExitCodes)>]
|
||||||
|
let ``Custom exit code tests`` (KeyValue (fileName : string, exitCode : int)) =
|
||||||
|
if unimplemented.Contains fileName then
|
||||||
|
Assert.Inconclusive ()
|
||||||
|
|
||||||
|
{
|
||||||
|
FileName = fileName
|
||||||
|
ExpectedReturnCode = exitCode
|
||||||
|
NativeImpls = MockEnv.make ()
|
||||||
|
}
|
||||||
|
|> runTest
|
||||||
|
|
||||||
|
[<TestCaseSource(nameof requiresMocks)>]
|
||||||
|
let ``Tests which require mocks`` (KeyValue (fileName : string, (exitCode : int, mock : NativeImpls))) =
|
||||||
|
{
|
||||||
|
FileName = fileName
|
||||||
|
ExpectedReturnCode = exitCode
|
||||||
|
NativeImpls = mock
|
||||||
|
}
|
||||||
|
|> runTest
|
||||||
|
|
||||||
|
|
||||||
[<TestCaseSource(nameof unimplemented)>]
|
[<TestCaseSource(nameof unimplemented)>]
|
||||||
[<Explicit>]
|
[<Explicit>]
|
||||||
let ``Can evaluate C# files, unimplemented`` (case : EndToEndTestCase) = runTest case
|
let ``Can evaluate C# files, unimplemented`` (fileName : string) =
|
||||||
|
{
|
||||||
[<TestCaseSource(nameof cases)>]
|
FileName = fileName
|
||||||
let ``Can evaluate C# files`` (case : EndToEndTestCase) = runTest case
|
ExpectedReturnCode = 0
|
||||||
|
NativeImpls = MockEnv.make ()
|
||||||
|
}
|
||||||
|
|> runTest
|
||||||
|
@@ -10,6 +10,7 @@ type IArithmeticOperation =
|
|||||||
abstract FloatFloat : float -> float -> float
|
abstract FloatFloat : float -> float -> float
|
||||||
abstract NativeIntNativeInt : nativeint -> nativeint -> nativeint
|
abstract NativeIntNativeInt : nativeint -> nativeint -> nativeint
|
||||||
abstract Int32ManagedPtr : IlMachineState -> int32 -> ManagedPointerSource -> Choice<ManagedPointerSource, int>
|
abstract Int32ManagedPtr : IlMachineState -> int32 -> ManagedPointerSource -> Choice<ManagedPointerSource, int>
|
||||||
|
abstract ManagedPtrInt32 : IlMachineState -> ManagedPointerSource -> int32 -> Choice<ManagedPointerSource, int>
|
||||||
|
|
||||||
abstract ManagedPtrManagedPtr :
|
abstract ManagedPtrManagedPtr :
|
||||||
IlMachineState -> ManagedPointerSource -> ManagedPointerSource -> Choice<ManagedPointerSource, nativeint>
|
IlMachineState -> ManagedPointerSource -> ManagedPointerSource -> Choice<ManagedPointerSource, nativeint>
|
||||||
@@ -18,6 +19,35 @@ type IArithmeticOperation =
|
|||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module ArithmeticOperation =
|
module ArithmeticOperation =
|
||||||
|
let private addInt32ManagedPtr state v ptr =
|
||||||
|
match ptr with
|
||||||
|
| LocalVariable (sourceThread, methodFrame, whichVar) -> failwith "refusing to add to a local variable address"
|
||||||
|
| Argument (sourceThread, methodFrame, whichVar) -> failwith "refusing to add to an argument address"
|
||||||
|
| Heap managedHeapAddress -> failwith "refusing to add to a heap address"
|
||||||
|
| ArrayIndex (arr, index) -> failwith "TODO: arrays"
|
||||||
|
| Field (src, fieldName) ->
|
||||||
|
let obj = IlMachineState.dereferencePointer state src
|
||||||
|
let offset, _ = CliType.getFieldLayout fieldName obj
|
||||||
|
|
||||||
|
match CliType.getFieldAt (offset + v) obj with
|
||||||
|
| None -> failwith "TODO: couldn't identify field at offset"
|
||||||
|
| Some field ->
|
||||||
|
ManagedPointerSource.Field (src, CliConcreteField.ToCliField(field).Name)
|
||||||
|
|> Choice1Of2
|
||||||
|
| Null -> Choice2Of2 v
|
||||||
|
| InterpretedAsType (managedPointerSource, concreteType) -> failwith "todo"
|
||||||
|
|
||||||
|
let private mulInt32ManagedPtr (state : IlMachineState) v ptr =
|
||||||
|
if v = 0 then
|
||||||
|
Choice2Of2 0
|
||||||
|
elif v = 1 then
|
||||||
|
Choice1Of2 ptr
|
||||||
|
else
|
||||||
|
|
||||||
|
match ptr with
|
||||||
|
| ManagedPointerSource.Null -> Choice2Of2 0
|
||||||
|
| _ -> failwith "refusing to multiply pointers"
|
||||||
|
|
||||||
let add =
|
let add =
|
||||||
{ new IArithmeticOperation with
|
{ new IArithmeticOperation with
|
||||||
member _.Int32Int32 a b = (# "add" a b : int32 #)
|
member _.Int32Int32 a b = (# "add" a b : int32 #)
|
||||||
@@ -33,24 +63,8 @@ module ArithmeticOperation =
|
|||||||
| _, ManagedPointerSource.Null -> Choice1Of2 ptr1
|
| _, ManagedPointerSource.Null -> Choice1Of2 ptr1
|
||||||
| _, _ -> failwith "refusing to add two managed pointers"
|
| _, _ -> failwith "refusing to add two managed pointers"
|
||||||
|
|
||||||
member _.Int32ManagedPtr state val1 ptr2 =
|
member _.Int32ManagedPtr state val1 ptr2 = addInt32ManagedPtr state val1 ptr2
|
||||||
match ptr2 with
|
member _.ManagedPtrInt32 state ptr1 val2 = addInt32ManagedPtr state val2 ptr1
|
||||||
| LocalVariable (sourceThread, methodFrame, whichVar) ->
|
|
||||||
failwith "refusing to add to a local variable address"
|
|
||||||
| Argument (sourceThread, methodFrame, whichVar) -> failwith "refusing to add to an argument address"
|
|
||||||
| Heap managedHeapAddress -> failwith "refusing to add to a heap address"
|
|
||||||
| ArrayIndex (arr, index) -> failwith "TODO: arrays"
|
|
||||||
| Field (src, fieldName) ->
|
|
||||||
let obj = IlMachineState.dereferencePointer state src
|
|
||||||
let offset, _ = CliType.getFieldLayout fieldName obj
|
|
||||||
|
|
||||||
match CliType.getFieldAt (offset + val1) obj with
|
|
||||||
| None -> failwith "TODO: couldn't identify field at offset"
|
|
||||||
| Some field ->
|
|
||||||
ManagedPointerSource.Field (src, CliConcreteField.ToCliField(field).Name)
|
|
||||||
|> Choice1Of2
|
|
||||||
| Null -> Choice2Of2 val1
|
|
||||||
| InterpretedAsType (managedPointerSource, concreteType) -> failwith "todo"
|
|
||||||
|
|
||||||
member _.Name = "add"
|
member _.Name = "add"
|
||||||
}
|
}
|
||||||
@@ -94,6 +108,8 @@ module ArithmeticOperation =
|
|||||||
| ManagedPointerSource.Null -> Choice2Of2 val1
|
| ManagedPointerSource.Null -> Choice2Of2 val1
|
||||||
| _ -> failwith "refusing to subtract a pointer"
|
| _ -> failwith "refusing to subtract a pointer"
|
||||||
|
|
||||||
|
member _.ManagedPtrInt32 state ptr1 val2 = failwith "TODO: subtract from pointer"
|
||||||
|
|
||||||
member _.Name = "sub"
|
member _.Name = "sub"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,16 +128,26 @@ module ArithmeticOperation =
|
|||||||
| _, ManagedPointerSource.Null -> Choice2Of2 (nativeint 0)
|
| _, ManagedPointerSource.Null -> Choice2Of2 (nativeint 0)
|
||||||
| _, _ -> failwith "refusing to multiply two managed pointers"
|
| _, _ -> failwith "refusing to multiply two managed pointers"
|
||||||
|
|
||||||
member _.Int32ManagedPtr _ a ptr =
|
member _.Int32ManagedPtr state a ptr = mulInt32ManagedPtr state a ptr
|
||||||
if a = 0 then
|
member _.ManagedPtrInt32 state ptr a = mulInt32ManagedPtr state a ptr
|
||||||
Choice2Of2 0
|
|
||||||
elif a = 1 then
|
|
||||||
Choice1Of2 ptr
|
|
||||||
else
|
|
||||||
|
|
||||||
match ptr with
|
member _.Name = "mul"
|
||||||
| ManagedPointerSource.Null -> Choice2Of2 0
|
}
|
||||||
| _ -> failwith "refusing to multiply pointers"
|
|
||||||
|
let rem =
|
||||||
|
{ new IArithmeticOperation with
|
||||||
|
member _.Int32Int32 a b = (# "rem" a b : int32 #)
|
||||||
|
member _.Int64Int64 a b = (# "rem" a b : int64 #)
|
||||||
|
member _.FloatFloat a b = (# "rem" a b : float #)
|
||||||
|
member _.NativeIntNativeInt a b = (# "rem" a b : nativeint #)
|
||||||
|
member _.Int32NativeInt a b = (# "rem" a b : nativeint #)
|
||||||
|
member _.NativeIntInt32 a b = (# "rem" a b : nativeint #)
|
||||||
|
|
||||||
|
member _.ManagedPtrManagedPtr _ ptr1 ptr2 = failwith "refusing to rem pointers"
|
||||||
|
|
||||||
|
member _.Int32ManagedPtr _ a ptr = failwith "refusing to rem pointer"
|
||||||
|
|
||||||
|
member _.ManagedPtrInt32 _ ptr a = failwith "refusing to rem pointer"
|
||||||
|
|
||||||
member _.Name = "mul"
|
member _.Name = "mul"
|
||||||
}
|
}
|
||||||
@@ -141,16 +167,8 @@ module ArithmeticOperation =
|
|||||||
| _, ManagedPointerSource.Null -> Choice2Of2 (nativeint 0)
|
| _, ManagedPointerSource.Null -> Choice2Of2 (nativeint 0)
|
||||||
| _, _ -> failwith "refusing to multiply two managed pointers"
|
| _, _ -> failwith "refusing to multiply two managed pointers"
|
||||||
|
|
||||||
member _.Int32ManagedPtr _ a ptr =
|
member _.Int32ManagedPtr state a ptr = mulInt32ManagedPtr state a ptr
|
||||||
if a = 0 then
|
member _.ManagedPtrInt32 state a ptr = mulInt32ManagedPtr state ptr a
|
||||||
Choice2Of2 0
|
|
||||||
elif a = 1 then
|
|
||||||
Choice1Of2 ptr
|
|
||||||
else
|
|
||||||
|
|
||||||
match ptr with
|
|
||||||
| ManagedPointerSource.Null -> Choice2Of2 0
|
|
||||||
| _ -> failwith "refusing to multiply pointers"
|
|
||||||
|
|
||||||
member _.Name = "mul_ovf"
|
member _.Name = "mul_ovf"
|
||||||
}
|
}
|
||||||
@@ -175,6 +193,12 @@ module ArithmeticOperation =
|
|||||||
else
|
else
|
||||||
failwith "refusing to divide pointers"
|
failwith "refusing to divide pointers"
|
||||||
|
|
||||||
|
member _.ManagedPtrInt32 _ ptr a =
|
||||||
|
if a = 1 then
|
||||||
|
Choice1Of2 ptr
|
||||||
|
else
|
||||||
|
failwith "refusing to divide a pointer"
|
||||||
|
|
||||||
member _.Name = "div"
|
member _.Name = "div"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +262,10 @@ module BinaryArithmetic =
|
|||||||
| EvalStackValue.ManagedPointer val1, EvalStackValue.NativeInt val2 ->
|
| EvalStackValue.ManagedPointer val1, EvalStackValue.NativeInt val2 ->
|
||||||
failwith "" |> EvalStackValue.ManagedPointer
|
failwith "" |> EvalStackValue.ManagedPointer
|
||||||
| EvalStackValue.ObjectRef val1, EvalStackValue.NativeInt val2 -> failwith "" |> EvalStackValue.ObjectRef
|
| EvalStackValue.ObjectRef val1, EvalStackValue.NativeInt val2 -> failwith "" |> EvalStackValue.ObjectRef
|
||||||
| EvalStackValue.ManagedPointer val1, EvalStackValue.Int32 val2 -> failwith "" |> EvalStackValue.ManagedPointer
|
| EvalStackValue.ManagedPointer val1, EvalStackValue.Int32 val2 ->
|
||||||
|
match op.ManagedPtrInt32 state val1 val2 with
|
||||||
|
| Choice1Of2 result -> EvalStackValue.ManagedPointer result
|
||||||
|
| Choice2Of2 result -> EvalStackValue.NativeInt (NativeIntSource.Verbatim (int64<int32> result))
|
||||||
| EvalStackValue.ObjectRef val1, EvalStackValue.Int32 val2 -> failwith "" |> EvalStackValue.ObjectRef
|
| EvalStackValue.ObjectRef val1, EvalStackValue.Int32 val2 -> failwith "" |> EvalStackValue.ObjectRef
|
||||||
| EvalStackValue.ManagedPointer val1, EvalStackValue.ManagedPointer val2 ->
|
| EvalStackValue.ManagedPointer val1, EvalStackValue.ManagedPointer val2 ->
|
||||||
match op.ManagedPtrManagedPtr state val1 val2 with
|
match op.ManagedPtrManagedPtr state val1 val2 with
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
namespace WoofWare.PawPrint
|
namespace WoofWare.PawPrint
|
||||||
|
|
||||||
|
#nowarn "42"
|
||||||
|
|
||||||
/// See I.12.3.2.1 for definition
|
/// See I.12.3.2.1 for definition
|
||||||
type EvalStackValue =
|
type EvalStackValue =
|
||||||
| Int32 of int32
|
| Int32 of int32
|
||||||
@@ -100,6 +102,21 @@ module EvalStackValue =
|
|||||||
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
||||||
| EvalStackValue.UserDefinedValueType evalStackValues -> failwith "todo"
|
| EvalStackValue.UserDefinedValueType evalStackValues -> failwith "todo"
|
||||||
|
|
||||||
|
/// Then truncates to int32.
|
||||||
|
let convToUInt8 (value : EvalStackValue) : int32 option =
|
||||||
|
match value with
|
||||||
|
| EvalStackValue.Int32 (i : int32) ->
|
||||||
|
let v = (# "conv.u1" i : uint8 #)
|
||||||
|
Some (int32<uint8> v)
|
||||||
|
| EvalStackValue.Int64 int64 ->
|
||||||
|
let v = (# "conv.u1" int64 : uint8 #)
|
||||||
|
Some (int32<uint8> v)
|
||||||
|
| EvalStackValue.NativeInt nativeIntSource -> failwith "todo"
|
||||||
|
| EvalStackValue.Float f -> failwith "todo"
|
||||||
|
| EvalStackValue.ManagedPointer managedPointerSource -> failwith "todo"
|
||||||
|
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
||||||
|
| EvalStackValue.UserDefinedValueType evalStackValues -> failwith "todo"
|
||||||
|
|
||||||
let rec ofCliType (v : CliType) : EvalStackValue =
|
let rec ofCliType (v : CliType) : EvalStackValue =
|
||||||
match v with
|
match v with
|
||||||
| CliType.Numeric numeric ->
|
| CliType.Numeric numeric ->
|
||||||
|
@@ -1670,7 +1670,10 @@ module IlMachineState =
|
|||||||
state.ThreadState.[sourceThread].MethodStates.[methodFrame].LocalVariables.[int<uint16> whichVar]
|
state.ThreadState.[sourceThread].MethodStates.[methodFrame].LocalVariables.[int<uint16> whichVar]
|
||||||
| 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 addr -> failwith "todo"
|
| ManagedPointerSource.Heap addr ->
|
||||||
|
let result = ManagedHeap.get addr state.ManagedHeap
|
||||||
|
// TODO: this is awfully dubious, this ain't no value type
|
||||||
|
CliType.ValueType result.Contents
|
||||||
| ManagedPointerSource.ArrayIndex (arr, index) -> getArrayValue arr index state
|
| ManagedPointerSource.ArrayIndex (arr, index) -> getArrayValue arr index state
|
||||||
| ManagedPointerSource.Field (addr, name) ->
|
| ManagedPointerSource.Field (addr, name) ->
|
||||||
let obj = dereferencePointer state addr
|
let obj = dereferencePointer state addr
|
||||||
@@ -1690,7 +1693,7 @@ module IlMachineState =
|
|||||||
| Some ty -> ty
|
| Some ty -> ty
|
||||||
| None -> failwith "not concretised type"
|
| None -> failwith "not concretised type"
|
||||||
|
|
||||||
failwith "TODO"
|
failwith $"TODO: interpret as type %s{ty.Assembly.Name}.%s{ty.Namespace}.%s{ty.Name}, object %O{src}"
|
||||||
|
|
||||||
let lookupTypeDefn
|
let lookupTypeDefn
|
||||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||||
|
@@ -27,6 +27,8 @@ module Intrinsics =
|
|||||||
"System.Private.CoreLib", "Math", "Max"
|
"System.Private.CoreLib", "Math", "Max"
|
||||||
// https://github.com/dotnet/runtime/blob/d258af50034c192bf7f0a18856bf83d2903d98ae/src/libraries/System.Private.CoreLib/src/System/Buffer.cs#L150
|
// https://github.com/dotnet/runtime/blob/d258af50034c192bf7f0a18856bf83d2903d98ae/src/libraries/System.Private.CoreLib/src/System/Buffer.cs#L150
|
||||||
"System.Private.CoreLib", "Buffer", "Memmove"
|
"System.Private.CoreLib", "Buffer", "Memmove"
|
||||||
|
// https://github.com/dotnet/runtime/blob/1c3221b63340d7f81dfd829f3bcd822e582324f6/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.cs#L799
|
||||||
|
"System.Private.CoreLib", "Thread", "get_CurrentThread"
|
||||||
]
|
]
|
||||||
|> Set.ofList
|
|> Set.ofList
|
||||||
|
|
||||||
@@ -190,6 +192,44 @@ module Intrinsics =
|
|||||||
|> IlMachineState.advanceProgramCounter currentThread
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|
||||||
Some state
|
Some state
|
||||||
|
| "System.Private.CoreLib", "Type", "get_IsValueType" ->
|
||||||
|
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||||
|
| [], ConcreteBool state.ConcreteTypes -> ()
|
||||||
|
| _ -> failwith "bad signature Type.get_IsValueType"
|
||||||
|
|
||||||
|
let this, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
|
||||||
|
let this =
|
||||||
|
match this with
|
||||||
|
| EvalStackValue.ObjectRef ptr ->
|
||||||
|
IlMachineState.dereferencePointer state (ManagedPointerSource.Heap ptr)
|
||||||
|
| EvalStackValue.ManagedPointer ptr -> IlMachineState.dereferencePointer state ptr
|
||||||
|
| EvalStackValue.Float _
|
||||||
|
| EvalStackValue.Int32 _
|
||||||
|
| EvalStackValue.Int64 _ -> failwith "refusing to dereference literal"
|
||||||
|
| _ -> failwith "TODO"
|
||||||
|
// `this` should be of type Type
|
||||||
|
let ty =
|
||||||
|
match this with
|
||||||
|
| CliType.ValueType cvt ->
|
||||||
|
match CliValueType.DereferenceField "m_handle" cvt with
|
||||||
|
| CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.TypeHandlePtr cth)) -> cth
|
||||||
|
| _ -> failwith ""
|
||||||
|
| _ -> failwith "expected a Type"
|
||||||
|
|
||||||
|
let ty = AllConcreteTypes.lookup ty state.ConcreteTypes |> Option.get
|
||||||
|
let ty = state.LoadedAssembly(ty.Assembly).Value.TypeDefs.[ty.Definition.Get]
|
||||||
|
|
||||||
|
let isValueType =
|
||||||
|
match DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies ty.Assembly ty.BaseType with
|
||||||
|
| ResolvedBaseType.Enum
|
||||||
|
| ResolvedBaseType.ValueType -> true
|
||||||
|
| ResolvedBaseType.Object
|
||||||
|
| ResolvedBaseType.Delegate -> false
|
||||||
|
|
||||||
|
IlMachineState.pushToEvalStack (CliType.ofBool isValueType) currentThread state
|
||||||
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|> Some
|
||||||
| "System.Private.CoreLib", "Unsafe", "AsPointer" ->
|
| "System.Private.CoreLib", "Unsafe", "AsPointer" ->
|
||||||
// Method signature: 1 generic parameter, we take a Byref of that parameter, and return a TypeDefn.Pointer(Void)
|
// Method signature: 1 generic parameter, we take a Byref of that parameter, and return a TypeDefn.Pointer(Void)
|
||||||
let arg, state = IlMachineState.popEvalStack currentThread state
|
let arg, state = IlMachineState.popEvalStack currentThread state
|
||||||
@@ -233,6 +273,47 @@ module Intrinsics =
|
|||||||
let result =
|
let result =
|
||||||
BitConverter.Int32BitsToSingle arg |> CliNumericType.Float32 |> CliType.Numeric
|
BitConverter.Int32BitsToSingle arg |> CliNumericType.Float32 |> CliType.Numeric
|
||||||
|
|
||||||
|
state
|
||||||
|
|> IlMachineState.pushToEvalStack result currentThread
|
||||||
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|> Some
|
||||||
|
| "System.Private.CoreLib", "BitConverter", "DoubleToUInt64Bits" ->
|
||||||
|
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||||
|
| [ ConcreteDouble state.ConcreteTypes ], ConcreteUInt64 state.ConcreteTypes -> ()
|
||||||
|
| _ -> failwith "bad signature BitConverter.DoubleToUInt64Bits"
|
||||||
|
|
||||||
|
let arg, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
|
||||||
|
let arg =
|
||||||
|
match arg with
|
||||||
|
| EvalStackValue.Float i -> i
|
||||||
|
| _ -> failwith "$TODO: {arr}"
|
||||||
|
|
||||||
|
let result =
|
||||||
|
BitConverter.DoubleToUInt64Bits arg
|
||||||
|
|> int64<uint64>
|
||||||
|
|> CliNumericType.Int64
|
||||||
|
|> CliType.Numeric
|
||||||
|
|
||||||
|
state
|
||||||
|
|> IlMachineState.pushToEvalStack result currentThread
|
||||||
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|> Some
|
||||||
|
| "System.Private.CoreLib", "BitConverter", "UInt64BitsToDouble" ->
|
||||||
|
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||||
|
| [ ConcreteUInt64 state.ConcreteTypes ], ConcreteDouble state.ConcreteTypes -> ()
|
||||||
|
| _ -> failwith "bad signature BitConverter.DoubleToUInt64Bits"
|
||||||
|
|
||||||
|
let arg, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
|
||||||
|
let arg =
|
||||||
|
match arg with
|
||||||
|
| EvalStackValue.Int64 i -> uint64 i
|
||||||
|
| _ -> failwith "$TODO: {arr}"
|
||||||
|
|
||||||
|
let result =
|
||||||
|
BitConverter.UInt64BitsToDouble arg |> CliNumericType.Float64 |> CliType.Numeric
|
||||||
|
|
||||||
state
|
state
|
||||||
|> IlMachineState.pushToEvalStack result currentThread
|
|> IlMachineState.pushToEvalStack result currentThread
|
||||||
|> IlMachineState.advanceProgramCounter currentThread
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
@@ -443,8 +443,8 @@ module NullaryIlOp =
|
|||||||
| Sub_ovf -> failwith "TODO: Sub_ovf unimplemented"
|
| Sub_ovf -> failwith "TODO: Sub_ovf unimplemented"
|
||||||
| Sub_ovf_un -> failwith "TODO: Sub_ovf_un unimplemented"
|
| Sub_ovf_un -> failwith "TODO: Sub_ovf_un unimplemented"
|
||||||
| Add ->
|
| Add ->
|
||||||
let val1, state = IlMachineState.popEvalStack currentThread state
|
|
||||||
let val2, state = IlMachineState.popEvalStack currentThread state
|
let val2, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let val1, state = IlMachineState.popEvalStack currentThread state
|
||||||
let result = BinaryArithmetic.execute ArithmeticOperation.add state val1 val2
|
let result = BinaryArithmetic.execute ArithmeticOperation.add state val1 val2
|
||||||
|
|
||||||
state
|
state
|
||||||
@@ -455,8 +455,8 @@ module NullaryIlOp =
|
|||||||
| Add_ovf -> failwith "TODO: Add_ovf unimplemented"
|
| Add_ovf -> failwith "TODO: Add_ovf unimplemented"
|
||||||
| Add_ovf_un -> failwith "TODO: Add_ovf_un unimplemented"
|
| Add_ovf_un -> failwith "TODO: Add_ovf_un unimplemented"
|
||||||
| Mul ->
|
| Mul ->
|
||||||
let val1, state = IlMachineState.popEvalStack currentThread state
|
|
||||||
let val2, state = IlMachineState.popEvalStack currentThread state
|
let val2, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let val1, state = IlMachineState.popEvalStack currentThread state
|
||||||
let result = BinaryArithmetic.execute ArithmeticOperation.mul state val1 val2
|
let result = BinaryArithmetic.execute ArithmeticOperation.mul state val1 val2
|
||||||
|
|
||||||
state
|
state
|
||||||
@@ -465,8 +465,8 @@ module NullaryIlOp =
|
|||||||
|> Tuple.withRight WhatWeDid.Executed
|
|> Tuple.withRight WhatWeDid.Executed
|
||||||
|> ExecutionResult.Stepped
|
|> ExecutionResult.Stepped
|
||||||
| Mul_ovf ->
|
| Mul_ovf ->
|
||||||
let val1, state = IlMachineState.popEvalStack currentThread state
|
|
||||||
let val2, state = IlMachineState.popEvalStack currentThread state
|
let val2, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let val1, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
try
|
try
|
||||||
@@ -688,7 +688,20 @@ module NullaryIlOp =
|
|||||||
let state = state |> IlMachineState.advanceProgramCounter currentThread
|
let state = state |> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|
||||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||||
| Conv_U1 -> failwith "TODO: Conv_U1 unimplemented"
|
| Conv_U1 ->
|
||||||
|
let popped, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let converted = EvalStackValue.convToUInt8 popped
|
||||||
|
|
||||||
|
let state =
|
||||||
|
match converted with
|
||||||
|
| None -> failwith "TODO: Conv_U8 conversion failure unimplemented"
|
||||||
|
| Some conv ->
|
||||||
|
state
|
||||||
|
|> IlMachineState.pushToEvalStack' (EvalStackValue.Int32 conv) currentThread
|
||||||
|
|
||||||
|
let state = state |> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|
||||||
|
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||||
| Conv_U2 -> failwith "TODO: Conv_U2 unimplemented"
|
| Conv_U2 -> failwith "TODO: Conv_U2 unimplemented"
|
||||||
| Conv_U4 -> failwith "TODO: Conv_U4 unimplemented"
|
| Conv_U4 -> failwith "TODO: Conv_U4 unimplemented"
|
||||||
| Conv_U8 ->
|
| Conv_U8 ->
|
||||||
@@ -896,7 +909,16 @@ module NullaryIlOp =
|
|||||||
| Ldind_u8 -> failwith "TODO: Ldind_u8 unimplemented"
|
| Ldind_u8 -> failwith "TODO: Ldind_u8 unimplemented"
|
||||||
| Ldind_r4 -> executeLdind LdindTargetType.LdindR4 currentThread state
|
| Ldind_r4 -> executeLdind LdindTargetType.LdindR4 currentThread state
|
||||||
| Ldind_r8 -> executeLdind LdindTargetType.LdindR8 currentThread state
|
| Ldind_r8 -> executeLdind LdindTargetType.LdindR8 currentThread state
|
||||||
| Rem -> failwith "TODO: Rem unimplemented"
|
| Rem ->
|
||||||
|
let val2, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let val1, state = IlMachineState.popEvalStack currentThread state
|
||||||
|
let result = BinaryArithmetic.execute ArithmeticOperation.rem state val1 val2
|
||||||
|
|
||||||
|
state
|
||||||
|
|> IlMachineState.pushToEvalStack' result currentThread
|
||||||
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
|> Tuple.withRight WhatWeDid.Executed
|
||||||
|
|> ExecutionResult.Stepped
|
||||||
| Rem_un -> failwith "TODO: Rem_un unimplemented"
|
| Rem_un -> failwith "TODO: Rem_un unimplemented"
|
||||||
| Volatile -> failwith "TODO: Volatile unimplemented"
|
| Volatile -> failwith "TODO: Volatile unimplemented"
|
||||||
| Tail -> failwith "TODO: Tail unimplemented"
|
| Tail -> failwith "TODO: Tail unimplemented"
|
||||||
@@ -924,6 +946,7 @@ module NullaryIlOp =
|
|||||||
|
|
||||||
let state =
|
let state =
|
||||||
match referenced with
|
match referenced with
|
||||||
|
| CliType.RuntimePointer (CliRuntimePointer.Managed _)
|
||||||
| CliType.ObjectRef _ -> IlMachineState.pushToEvalStack referenced currentThread state
|
| CliType.ObjectRef _ -> IlMachineState.pushToEvalStack referenced currentThread state
|
||||||
| _ -> failwith $"Unexpected non-reference {referenced}"
|
| _ -> failwith $"Unexpected non-reference {referenced}"
|
||||||
|> IlMachineState.advanceProgramCounter currentThread
|
|> IlMachineState.advanceProgramCounter currentThread
|
||||||
|
@@ -416,7 +416,55 @@ module internal UnaryMetadataIlOp =
|
|||||||
|> IlMachineState.advanceProgramCounter thread
|
|> IlMachineState.advanceProgramCounter thread
|
||||||
|
|
||||||
state, WhatWeDid.Executed
|
state, WhatWeDid.Executed
|
||||||
| Box -> failwith "TODO: Box unimplemented"
|
| Box ->
|
||||||
|
let state, ty, assy =
|
||||||
|
match metadataToken with
|
||||||
|
| MetadataToken.TypeDefinition h ->
|
||||||
|
let state, ty = IlMachineState.lookupTypeDefn baseClassTypes state activeAssy h
|
||||||
|
state, ty, activeAssy
|
||||||
|
| MetadataToken.TypeReference ref ->
|
||||||
|
IlMachineState.lookupTypeRef
|
||||||
|
loggerFactory
|
||||||
|
baseClassTypes
|
||||||
|
state
|
||||||
|
activeAssy
|
||||||
|
currentMethod.DeclaringType.Generics
|
||||||
|
ref
|
||||||
|
| MetadataToken.TypeSpecification spec -> state, activeAssy.TypeSpecs.[spec].Signature, activeAssy
|
||||||
|
| _ -> failwith $"unexpected token {metadataToken} in Box"
|
||||||
|
|
||||||
|
let state, typeHandle =
|
||||||
|
IlMachineState.concretizeType
|
||||||
|
loggerFactory
|
||||||
|
baseClassTypes
|
||||||
|
state
|
||||||
|
assy.Name
|
||||||
|
currentMethod.DeclaringType.Generics
|
||||||
|
currentMethod.Generics
|
||||||
|
ty
|
||||||
|
|
||||||
|
let toBox, state = state |> IlMachineState.popEvalStack thread
|
||||||
|
|
||||||
|
let targetType =
|
||||||
|
AllConcreteTypes.lookup typeHandle state.ConcreteTypes |> Option.get
|
||||||
|
|
||||||
|
let defn =
|
||||||
|
state._LoadedAssemblies.[targetType.Assembly.FullName].TypeDefs.[targetType.Definition.Get]
|
||||||
|
|
||||||
|
let baseType =
|
||||||
|
DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies targetType.Assembly defn.BaseType
|
||||||
|
|
||||||
|
let toPush =
|
||||||
|
match baseType with
|
||||||
|
| ResolvedBaseType.Enum
|
||||||
|
| ResolvedBaseType.ValueType -> failwith "TODO: implement Box"
|
||||||
|
| ResolvedBaseType.Object
|
||||||
|
| ResolvedBaseType.Delegate -> toBox
|
||||||
|
|
||||||
|
state
|
||||||
|
|> IlMachineState.pushToEvalStack' toPush thread
|
||||||
|
|> IlMachineState.advanceProgramCounter thread
|
||||||
|
|> Tuple.withRight WhatWeDid.Executed
|
||||||
| Ldelema ->
|
| Ldelema ->
|
||||||
let index, state = IlMachineState.popEvalStack thread state
|
let index, state = IlMachineState.popEvalStack thread state
|
||||||
let arr, state = IlMachineState.popEvalStack thread state
|
let arr, state = IlMachineState.popEvalStack thread state
|
||||||
@@ -1376,7 +1424,70 @@ module internal UnaryMetadataIlOp =
|
|||||||
|> IlMachineState.advanceProgramCounter thread
|
|> IlMachineState.advanceProgramCounter thread
|
||||||
|> Tuple.withRight WhatWeDid.Executed
|
|> Tuple.withRight WhatWeDid.Executed
|
||||||
| Cpobj -> failwith "TODO: Cpobj unimplemented"
|
| Cpobj -> failwith "TODO: Cpobj unimplemented"
|
||||||
| Ldobj -> failwith "TODO: Ldobj unimplemented"
|
| Ldobj ->
|
||||||
|
let state, ty, assy =
|
||||||
|
match metadataToken with
|
||||||
|
| MetadataToken.TypeDefinition h ->
|
||||||
|
let state, ty = IlMachineState.lookupTypeDefn baseClassTypes state activeAssy h
|
||||||
|
state, ty, activeAssy
|
||||||
|
| MetadataToken.TypeReference ref ->
|
||||||
|
IlMachineState.lookupTypeRef
|
||||||
|
loggerFactory
|
||||||
|
baseClassTypes
|
||||||
|
state
|
||||||
|
activeAssy
|
||||||
|
currentMethod.DeclaringType.Generics
|
||||||
|
ref
|
||||||
|
| MetadataToken.TypeSpecification spec -> state, activeAssy.TypeSpecs.[spec].Signature, activeAssy
|
||||||
|
| _ -> failwith $"unexpected token {metadataToken} in Ldobj"
|
||||||
|
|
||||||
|
let state, typeHandle =
|
||||||
|
IlMachineState.concretizeType
|
||||||
|
loggerFactory
|
||||||
|
baseClassTypes
|
||||||
|
state
|
||||||
|
assy.Name
|
||||||
|
currentMethod.DeclaringType.Generics
|
||||||
|
currentMethod.Generics
|
||||||
|
ty
|
||||||
|
|
||||||
|
let addr, state = state |> IlMachineState.popEvalStack thread
|
||||||
|
|
||||||
|
let obj =
|
||||||
|
match addr with
|
||||||
|
| EvalStackValue.ObjectRef addr ->
|
||||||
|
IlMachineState.dereferencePointer state (ManagedPointerSource.Heap addr)
|
||||||
|
| EvalStackValue.ManagedPointer ptr -> IlMachineState.dereferencePointer state ptr
|
||||||
|
| EvalStackValue.Float _
|
||||||
|
| EvalStackValue.Int64 _
|
||||||
|
| EvalStackValue.Int32 _ -> failwith "refusing to interpret constant as address"
|
||||||
|
| _ -> failwith "TODO"
|
||||||
|
|
||||||
|
let targetType =
|
||||||
|
AllConcreteTypes.lookup typeHandle state.ConcreteTypes |> Option.get
|
||||||
|
|
||||||
|
let defn =
|
||||||
|
state._LoadedAssemblies.[targetType.Assembly.FullName].TypeDefs.[targetType.Definition.Get]
|
||||||
|
|
||||||
|
let baseType =
|
||||||
|
DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies targetType.Assembly defn.BaseType
|
||||||
|
|
||||||
|
let toPush =
|
||||||
|
match baseType with
|
||||||
|
| ResolvedBaseType.Enum
|
||||||
|
| ResolvedBaseType.ValueType ->
|
||||||
|
failwith
|
||||||
|
$"TODO: push %O{obj} as type %s{targetType.Assembly.Name}.%s{targetType.Namespace}.%s{targetType.Name}"
|
||||||
|
| ResolvedBaseType.Object
|
||||||
|
| ResolvedBaseType.Delegate ->
|
||||||
|
// III.4.13: reference types are just copied as pointers.
|
||||||
|
// We should have received a pointer, so let's just pass it back.
|
||||||
|
obj
|
||||||
|
|
||||||
|
state
|
||||||
|
|> IlMachineState.pushToEvalStack toPush thread
|
||||||
|
|> IlMachineState.advanceProgramCounter thread
|
||||||
|
|> Tuple.withRight WhatWeDid.Executed
|
||||||
| Sizeof ->
|
| Sizeof ->
|
||||||
let state, ty, assy =
|
let state, ty, assy =
|
||||||
match metadataToken with
|
match metadataToken with
|
||||||
|
6
flake.lock
generated
6
flake.lock
generated
@@ -20,11 +20,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1755736253,
|
"lastModified": 1756381814,
|
||||||
"narHash": "sha256-jlIQRypNhB1PcB1BE+expE4xZeJxzoAGr1iUbHQta8s=",
|
"narHash": "sha256-tzo7YvAsGlzo4WiIHT0ooR59VHu+aKRQdHk7sIyoia4=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "596312aae91421d6923f18cecce934a7d3bfd6b8",
|
"rev": "aca2499b79170038df0dbaec8bf2f689b506ad32",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
Reference in New Issue
Block a user