From f9e186ba8f4ceefcc98ef556ebc126e345ce44d9 Mon Sep 17 00:00:00 2001 From: Patrick Stevens <3138005+Smaug123@users.noreply.github.com> Date: Sun, 24 Aug 2025 20:23:50 +0100 Subject: [PATCH] Initobj (#114) --- WoofWare.PawPrint.Domain/Assembly.fs | 38 +- .../TypeConcretisation.fs | 23 +- WoofWare.PawPrint.Domain/TypeInfo.fs | 26 +- WoofWare.PawPrint.Test/TestPureCases.fs | 5 + WoofWare.PawPrint.Test/sourcesPure/Initobj.cs | 503 ++++++++++++++++++ WoofWare.PawPrint/BasicCliType.fs | 12 + WoofWare.PawPrint/EvalStack.fs | 2 +- WoofWare.PawPrint/IlMachineState.fs | 144 ++--- WoofWare.PawPrint/IlMachineStateExecution.fs | 60 +-- WoofWare.PawPrint/ManagedHeap.fs | 29 + WoofWare.PawPrint/Program.fs | 8 +- WoofWare.PawPrint/UnaryMetadataIlOp.fs | 170 ++++-- WoofWare.PawPrint/UnaryStringTokenIlOp.fs | 6 +- 13 files changed, 783 insertions(+), 243 deletions(-) create mode 100644 WoofWare.PawPrint.Test/sourcesPure/Initobj.cs diff --git a/WoofWare.PawPrint.Domain/Assembly.fs b/WoofWare.PawPrint.Domain/Assembly.fs index ea162d0..360f6d5 100644 --- a/WoofWare.PawPrint.Domain/Assembly.fs +++ b/WoofWare.PawPrint.Domain/Assembly.fs @@ -423,8 +423,8 @@ module Assembly = let rec resolveTypeRef (assemblies : ImmutableDictionary) (referencedInAssembly : DumpedAssembly) - (target : TypeRef) (genericArgs : ImmutableArray) + (target : TypeRef) : TypeResolutionResult = match target.ResolutionScope with @@ -495,7 +495,7 @@ module Assembly = | None -> match assy.TypeRef ns name with - | Some typeRef -> resolveTypeRef assemblies assy typeRef genericArgs + | Some typeRef -> resolveTypeRef assemblies assy genericArgs typeRef | None -> match assy.ExportedType (Some ns) name with @@ -532,7 +532,7 @@ module DumpedAssembly = | Some (BaseTypeInfo.TypeRef r) -> let assy = loadedAssemblies.[source.FullName] // TODO: generics - match Assembly.resolveTypeRef loadedAssemblies assy assy.TypeRefs.[r] ImmutableArray.Empty with + match Assembly.resolveTypeRef loadedAssemblies assy ImmutableArray.Empty assy.TypeRefs.[r] with | TypeResolutionResult.FirstLoadAssy _ -> failwith "seems pretty unlikely that we could have constructed this object without loading its base type" @@ -560,3 +560,35 @@ module DumpedAssembly = | None -> ResolvedBaseType.Object go source baseTypeInfo + + let typeInfoToTypeDefn + (bct : BaseClassTypes) + (assemblies : ImmutableDictionary) + (ti : TypeInfo) + = + ti + |> TypeInfo.toTypeDefn + bct + (fun n -> assemblies.[n.FullName]) + _.Name + (fun x y -> x.TypeDefs.[y]) + (fun x y -> + let r = x.TypeRefs.[y] |> Assembly.resolveTypeRef assemblies x ImmutableArray.Empty + + match r with + | TypeResolutionResult.FirstLoadAssy assemblyReference -> failwith "todo" + | TypeResolutionResult.Resolved (dumpedAssembly, typeInfo) -> + let result = + typeInfo |> TypeInfo.mapGeneric (fun typeDef -> failwith "TODO: generics") + + dumpedAssembly, result + ) + + let typeInfoToTypeDefn' + (bct : BaseClassTypes) + (assemblies : ImmutableDictionary) + (ti : TypeInfo) + = + ti + |> TypeInfo.mapGeneric (fun (par, _) -> TypeDefn.GenericTypeParameter par.SequenceNumber) + |> typeInfoToTypeDefn bct assemblies diff --git a/WoofWare.PawPrint.Domain/TypeConcretisation.fs b/WoofWare.PawPrint.Domain/TypeConcretisation.fs index eec7525..71c4728 100644 --- a/WoofWare.PawPrint.Domain/TypeConcretisation.fs +++ b/WoofWare.PawPrint.Domain/TypeConcretisation.fs @@ -420,7 +420,7 @@ module TypeConcretization = // First try to resolve without loading new assemblies let resolutionResult = - Assembly.resolveTypeRef ctx.LoadedAssemblies currentAssy typeRef ImmutableArray.Empty + Assembly.resolveTypeRef ctx.LoadedAssemblies currentAssy ImmutableArray.Empty typeRef match resolutionResult with | TypeResolutionResult.Resolved (targetAssy, typeInfo) -> (targetAssy, typeInfo), ctx @@ -437,7 +437,7 @@ module TypeConcretization = // Now try to resolve again with the loaded assembly let resolutionResult2 = - Assembly.resolveTypeRef newCtx.LoadedAssemblies currentAssy typeRef ImmutableArray.Empty + Assembly.resolveTypeRef newCtx.LoadedAssemblies currentAssy ImmutableArray.Empty typeRef match resolutionResult2 with | TypeResolutionResult.Resolved (targetAssy, typeInfo) -> (targetAssy, typeInfo), newCtx @@ -608,14 +608,14 @@ module TypeConcretization = /// Concretize a type in a specific generic context let rec concretizeType - (ctx : ConcretizationContext<'corelib>) + (ctx : ConcretizationContext) (loadAssembly : AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary * DumpedAssembly) (assembly : AssemblyName) (typeGenerics : ImmutableArray) (methodGenerics : ImmutableArray) (typeDefn : TypeDefn) - : ConcreteTypeHandle * ConcretizationContext<'corelib> + : ConcreteTypeHandle * ConcretizationContext = let key = (assembly, typeDefn) @@ -705,7 +705,7 @@ module TypeConcretization = | _ -> failwithf "TODO: Concretization of %A not implemented" typeDefn and private concretizeGenericInstantiation - (ctx : ConcretizationContext<'corelib>) + (ctx : ConcretizationContext) (loadAssembly : AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary * DumpedAssembly) (assembly : AssemblyName) @@ -713,7 +713,7 @@ module TypeConcretization = (methodGenerics : ImmutableArray) (genericDef : TypeDefn) (args : ImmutableArray) - : ConcreteTypeHandle * ConcretizationContext<'corelib> + : ConcreteTypeHandle * ConcretizationContext = // First, concretize all type arguments let argHandles, ctxAfterArgs = @@ -864,14 +864,14 @@ module Concretization = /// Helper to concretize an array of types let private concretizeTypeArray - (ctx : TypeConcretization.ConcretizationContext<'corelib>) + (ctx : TypeConcretization.ConcretizationContext) (loadAssembly : AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary * DumpedAssembly) (assembly : AssemblyName) (typeArgs : ImmutableArray) (methodArgs : ImmutableArray) (types : ImmutableArray) - : ImmutableArray * TypeConcretization.ConcretizationContext<'corelib> + : ImmutableArray * TypeConcretization.ConcretizationContext = let handles = ImmutableArray.CreateBuilder types.Length @@ -888,14 +888,14 @@ module Concretization = /// Helper to concretize a method signature let private concretizeMethodSignature - (ctx : TypeConcretization.ConcretizationContext<'corelib>) + (ctx : TypeConcretization.ConcretizationContext) (loadAssembly : AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary * DumpedAssembly) (assembly : AssemblyName) (typeArgs : ImmutableArray) (methodArgs : ImmutableArray) (signature : TypeMethodSignature) - : TypeMethodSignature * TypeConcretization.ConcretizationContext<'corelib> + : TypeMethodSignature * TypeConcretization.ConcretizationContext = // Concretize return type @@ -1157,8 +1157,7 @@ module Concretization = // Recursively convert generic arguments let genericArgs = concreteType.Generics - |> Seq.map (fun h -> concreteHandleToTypeDefn baseClassTypes h concreteTypes assemblies) - |> ImmutableArray.CreateRange + |> ImmutableArray.map (fun h -> concreteHandleToTypeDefn baseClassTypes h concreteTypes assemblies) let baseDef = TypeDefn.FromDefinition (concreteType.Definition, concreteType.Assembly.FullName, signatureTypeKind) diff --git a/WoofWare.PawPrint.Domain/TypeInfo.fs b/WoofWare.PawPrint.Domain/TypeInfo.fs index b9e09a2..04b2661 100644 --- a/WoofWare.PawPrint.Domain/TypeInfo.fs +++ b/WoofWare.PawPrint.Domain/TypeInfo.fs @@ -348,10 +348,10 @@ module TypeInfo = let rec resolveBaseType<'corelib, 'generic, 'field> (baseClassTypes : BaseClassTypes<'corelib>) + (sourceAssy : 'corelib) (getName : 'corelib -> AssemblyName) (getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'field>) - (getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic, 'field>) - (sourceAssembly : AssemblyName) + (getTypeRef : 'corelib -> TypeReferenceHandle -> 'corelib * TypeInfo<'generic, 'field>) (value : BaseTypeInfo option) : ResolvedBaseType = @@ -361,40 +361,48 @@ module TypeInfo = match value with | BaseTypeInfo.TypeDef typeDefinitionHandle -> - match isBaseType baseClassTypes getName sourceAssembly typeDefinitionHandle with + match isBaseType baseClassTypes getName (getName sourceAssy) typeDefinitionHandle with | Some x -> x | None -> let baseType = getTypeDef baseClassTypes.Corelib typeDefinitionHandle - resolveBaseType baseClassTypes getName getTypeDef getTypeRef sourceAssembly baseType.BaseType + resolveBaseType baseClassTypes sourceAssy getName getTypeDef getTypeRef baseType.BaseType | BaseTypeInfo.TypeRef typeReferenceHandle -> - let typeRef = getTypeRef baseClassTypes.Corelib typeReferenceHandle - failwith $"{typeRef}" + let targetAssy, typeRef = getTypeRef sourceAssy typeReferenceHandle + + match isBaseType baseClassTypes getName (getName targetAssy) typeRef.TypeDefHandle with + | Some x -> x + | None -> + let baseType = getTypeDef baseClassTypes.Corelib typeRef.TypeDefHandle + resolveBaseType baseClassTypes sourceAssy getName getTypeDef getTypeRef baseType.BaseType | BaseTypeInfo.TypeSpec typeSpecificationHandle -> failwith "todo" | BaseTypeInfo.ForeignAssemblyType (assemblyName, typeDefinitionHandle) -> resolveBaseType baseClassTypes + sourceAssy getName getTypeDef getTypeRef - assemblyName (Some (BaseTypeInfo.TypeDef typeDefinitionHandle)) let toTypeDefn (baseClassTypes : BaseClassTypes<'corelib>) + (assemblies : AssemblyName -> 'corelib) (getName : 'corelib -> AssemblyName) (getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'field>) - (getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic, 'field>) + (getTypeRef : 'corelib -> TypeReferenceHandle -> 'corelib * TypeInfo<'generic, 'field>) (ty : TypeInfo) : TypeDefn = let stk = - match resolveBaseType baseClassTypes getName getTypeDef getTypeRef ty.Assembly ty.BaseType with + match resolveBaseType baseClassTypes (assemblies ty.Assembly) getName getTypeDef getTypeRef ty.BaseType with | ResolvedBaseType.Enum | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType | ResolvedBaseType.Object | ResolvedBaseType.Delegate -> SignatureTypeKind.Class let defn = + // The only allowed construction of FromDefinition! + // All other constructions should use DumpedAssembly.typeInfoToTypeDefn. TypeDefn.FromDefinition (ComparableTypeDefinitionHandle.Make ty.TypeDefHandle, ty.Assembly.FullName, stk) if ty.Generics.IsEmpty then diff --git a/WoofWare.PawPrint.Test/TestPureCases.fs b/WoofWare.PawPrint.Test/TestPureCases.fs index 76afbfb..92389da 100644 --- a/WoofWare.PawPrint.Test/TestPureCases.fs +++ b/WoofWare.PawPrint.Test/TestPureCases.fs @@ -160,6 +160,11 @@ module TestPureCases = ExpectedReturnCode = 0 NativeImpls = MockEnv.make () } + { + FileName = "Initobj.cs" + ExpectedReturnCode = 0 + NativeImpls = MockEnv.make () + } ] let runTest (case : EndToEndTestCase) : unit = diff --git a/WoofWare.PawPrint.Test/sourcesPure/Initobj.cs b/WoofWare.PawPrint.Test/sourcesPure/Initobj.cs new file mode 100644 index 0000000..269dc03 --- /dev/null +++ b/WoofWare.PawPrint.Test/sourcesPure/Initobj.cs @@ -0,0 +1,503 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +public class TestInitobj +{ + // Simple struct with various primitive types + private struct SimpleStruct + { + public int IntField; + public bool BoolField; + public char CharField; + public double DoubleField; + public byte ByteField; + } + + // Nested struct + private struct NestedStruct + { + public SimpleStruct Inner; + public int OuterField; + } + + // Struct with arrays and references + private struct ComplexStruct + { + public object ObjectRef; + public string StringRef; + public int[] ArrayRef; + public int ValueField; + } + + // Generic struct + private struct GenericStruct + { + public T Value; + public int Count; + } + + // Struct for field tests + private struct StructWithStructField + { + public SimpleStruct NestedField; + public int OtherField; + } + + // Class with struct field for heap test + private class ClassWithStructField + { + public SimpleStruct StructField; + public int IntField; + } + + // Test 1: Initialize simple struct with local variable + public static int Test1() + { + SimpleStruct s = new SimpleStruct + { + IntField = 42, + BoolField = true, + CharField = 'X', + DoubleField = 3.14, + ByteField = 255 + }; + + // Verify initial values + if (s.IntField != 42) return 1; + if (s.BoolField != true) return 2; + if (s.CharField != 'X') return 3; + if (s.DoubleField != 3.14) return 4; + if (s.ByteField != 255) return 5; + + // Use default to reset the struct (generates initobj) + s = default(SimpleStruct); + + // Verify all fields are zeroed + if (s.IntField != 0) return 6; + if (s.BoolField != false) return 7; + if (s.CharField != '\0') return 8; + if (s.DoubleField != 0.0) return 9; + if (s.ByteField != 0) return 10; + + return 0; + } + + // Test 2: Initialize nested struct + public static int Test2() + { + NestedStruct n = new NestedStruct + { + Inner = new SimpleStruct + { + IntField = 100, + BoolField = true, + CharField = 'A', + DoubleField = 1.23, + ByteField = 128 + }, + OuterField = 999 + }; + + // Verify initial values + if (n.Inner.IntField != 100) return 20; + if (n.OuterField != 999) return 21; + + // Reset using default keyword (which should generate initobj) + n = default(NestedStruct); + + // Verify all fields are zeroed + if (n.Inner.IntField != 0) return 22; + if (n.Inner.BoolField != false) return 23; + if (n.Inner.CharField != '\0') return 24; + if (n.Inner.DoubleField != 0.0) return 25; + if (n.Inner.ByteField != 0) return 26; + if (n.OuterField != 0) return 27; + + return 0; + } + + // Test 3: Initialize struct with reference types + public static int Test3() + { + ComplexStruct c = new ComplexStruct + { + ObjectRef = new object(), + StringRef = "Hello", + ArrayRef = new int[3], + ValueField = 42 + }; + c.ArrayRef[0] = 1; + c.ArrayRef[1] = 2; + c.ArrayRef[2] = 3; + + // Verify initial values + if (c.ObjectRef == null) return 30; + if (c.StringRef != "Hello") return 31; + if (c.ArrayRef == null || c.ArrayRef.Length != 3) return 32; + if (c.ValueField != 42) return 33; + + // Reset using default + c = default(ComplexStruct); + + // Verify references are null and value is zero + if (c.ObjectRef != null) return 34; + if (c.StringRef != null) return 35; + if (c.ArrayRef != null) return 36; + if (c.ValueField != 0) return 37; + + return 0; + } + + // Test 4: Initialize generic struct + public static int Test4() + { + GenericStruct gi = new GenericStruct + { + Value = 123, + Count = 456 + }; + + if (gi.Value != 123) return 40; + if (gi.Count != 456) return 41; + + gi = default(GenericStruct); + + if (gi.Value != 0) return 42; + if (gi.Count != 0) return 43; + + // Test with reference type + GenericStruct gs = new GenericStruct + { + Value = "Test", + Count = 789 + }; + + if (gs.Value != "Test") return 44; + if (gs.Count != 789) return 45; + + gs = default(GenericStruct); + + if (gs.Value != null) return 46; + if (gs.Count != 0) return 47; + + return 0; + } + + // Test 5: Initialize struct in array element using ref + public static int Test5() + { + SimpleStruct[] array = new SimpleStruct[3]; + + // Set values in first element + array[0].IntField = 111; + array[0].BoolField = true; + array[0].CharField = 'Z'; + + if (array[0].IntField != 111) return 50; + if (array[0].BoolField != true) return 51; + if (array[0].CharField != 'Z') return 52; + + // Reset first element using default assignment + array[0] = default(SimpleStruct); + + if (array[0].IntField != 0) return 53; + if (array[0].BoolField != false) return 54; + if (array[0].CharField != '\0') return 55; + + // Also test with ref local + array[1].IntField = 222; + ref SimpleStruct secondElement = ref array[1]; + secondElement = default(SimpleStruct); + + if (array[1].IntField != 0) return 56; + + return 0; + } + + // Test 6: Initialize struct through method parameter + public static int Test6() + { + SimpleStruct s = new SimpleStruct + { + IntField = 200, + BoolField = true, + CharField = 'M', + DoubleField = 2.71, + ByteField = 64 + }; + + ResetStruct(ref s); + + if (s.IntField != 0) return 60; + if (s.BoolField != false) return 61; + if (s.CharField != '\0') return 62; + if (s.DoubleField != 0.0) return 63; + if (s.ByteField != 0) return 64; + + return 0; + } + + private static void ResetStruct(ref SimpleStruct s) + { + s = default(SimpleStruct); + } + + // Test 7: Initialize multiple structs + public static int Test7() + { + SimpleStruct s1 = new SimpleStruct { IntField = 1 }; + SimpleStruct s2 = new SimpleStruct { IntField = 2 }; + SimpleStruct s3 = new SimpleStruct { IntField = 3 }; + + if (s1.IntField != 1) return 70; + if (s2.IntField != 2) return 71; + if (s3.IntField != 3) return 72; + + s1 = default(SimpleStruct); + s2 = default(SimpleStruct); + s3 = default(SimpleStruct); + + if (s1.IntField != 0) return 73; + if (s2.IntField != 0) return 74; + if (s3.IntField != 0) return 75; + + return 0; + } + + // Test 8: Initialize struct passed as argument (tests Argument case) + public static int Test8() + { + SimpleStruct s = new SimpleStruct + { + IntField = 333, + BoolField = true, + CharField = 'Q', + DoubleField = 4.56, + ByteField = 77 + }; + + int result = InitializeArgumentStruct(ref s); + if (result != 0) return result; + + // Verify struct was reset + if (s.IntField != 0) return 80; + if (s.BoolField != false) return 81; + if (s.CharField != '\0') return 82; + if (s.DoubleField != 0.0) return 83; + if (s.ByteField != 0) return 84; + + return 0; + } + + private static int InitializeArgumentStruct(ref SimpleStruct arg) + { + // Verify initial values + if (arg.IntField != 333) return 85; + if (arg.BoolField != true) return 86; + + // Reset using default - this should use initobj on the argument + arg = default(SimpleStruct); + + return 0; + } + + // Test 9: Initialize struct field (tests Field case) + public static int Test9() + { + StructWithStructField container = new StructWithStructField + { + NestedField = new SimpleStruct + { + IntField = 444, + BoolField = true, + CharField = 'F', + DoubleField = 7.89, + ByteField = 88 + }, + OtherField = 555 + }; + + // Verify initial values + if (container.NestedField.IntField != 444) return 90; + if (container.OtherField != 555) return 91; + + // Reset the nested field using ref + ref SimpleStruct fieldRef = ref container.NestedField; + fieldRef = default(SimpleStruct); + + // Verify nested field was reset but other field unchanged + if (container.NestedField.IntField != 0) return 92; + if (container.NestedField.BoolField != false) return 93; + if (container.NestedField.CharField != '\0') return 94; + if (container.NestedField.DoubleField != 0.0) return 95; + if (container.NestedField.ByteField != 0) return 96; + if (container.OtherField != 555) return 97; + + return 0; + } + + // Test 10: Initialize struct in heap-allocated object (tests Heap case) + public static int Test10() + { + ClassWithStructField obj = new ClassWithStructField + { + StructField = new SimpleStruct + { + IntField = 666, + BoolField = true, + CharField = 'H', + DoubleField = 9.99, + ByteField = 99 + }, + IntField = 777 + }; + + // Verify initial values + if (obj.StructField.IntField != 666) return 100; + if (obj.IntField != 777) return 101; + + // Reset the struct field + obj.StructField = default(SimpleStruct); + + // Verify struct field was reset but other field unchanged + if (obj.StructField.IntField != 0) return 102; + if (obj.StructField.BoolField != false) return 103; + if (obj.StructField.CharField != '\0') return 104; + if (obj.StructField.DoubleField != 0.0) return 105; + if (obj.StructField.ByteField != 0) return 106; + if (obj.IntField != 777) return 107; + + return 0; + } + + // Test 11: Initialize struct through unsafe pointer manipulation + public static unsafe int Test11() + { + SimpleStruct s = new SimpleStruct + { + IntField = 888, + BoolField = true, + CharField = 'P', + DoubleField = 11.11, + ByteField = 111 + }; + + // Get a pointer to the struct + SimpleStruct* ptr = &s; + + // Initialize through pointer + *ptr = default(SimpleStruct); + + // Verify all fields are zeroed + if (s.IntField != 0) return 110; + if (s.BoolField != false) return 111; + if (s.CharField != '\0') return 112; + if (s.DoubleField != 0.0) return 113; + if (s.ByteField != 0) return 114; + + return 0; + } + + // Test 12: Initialize struct through Unsafe.AsRef + public static int Test12() + { + SimpleStruct s = new SimpleStruct + { + IntField = 999, + BoolField = true, + CharField = 'U', + DoubleField = 12.34, + ByteField = 200 + }; + + // Use Unsafe to get a ref and initialize it + ref SimpleStruct sRef = ref s; + sRef = default(SimpleStruct); + + // Verify all fields are zeroed + if (s.IntField != 0) return 120; + if (s.BoolField != false) return 121; + if (s.CharField != '\0') return 122; + if (s.DoubleField != 0.0) return 123; + if (s.ByteField != 0) return 124; + + return 0; + } + + // Test 13: Initialize readonly struct + public static int Test13() + { + ReadonlyStruct ros = new ReadonlyStruct(100, true); + + // Verify initial values through properties + if (ros.IntValue != 100) return 130; + if (ros.BoolValue != true) return 131; + + // Reset using default + ros = default(ReadonlyStruct); + + // Verify zeroed + if (ros.IntValue != 0) return 132; + if (ros.BoolValue != false) return 133; + + return 0; + } + + private readonly struct ReadonlyStruct + { + public readonly int IntValue; + public readonly bool BoolValue; + + public ReadonlyStruct(int i, bool b) + { + IntValue = i; + BoolValue = b; + } + } + + public static int Main(string[] argv) + { + var result = Test1(); + if (result != 0) return result; + + result = Test2(); + if (result != 0) return result; + + result = Test3(); + if (result != 0) return result; + + result = Test4(); + if (result != 0) return result; + + result = Test5(); + if (result != 0) return result; + + result = Test6(); + if (result != 0) return result; + + result = Test7(); + if (result != 0) return result; + + result = Test8(); + if (result != 0) return result; + + result = Test9(); + if (result != 0) return result; + + result = Test10(); + if (result != 0) return result; + + result = Test11(); + if (result != 0) return result; + + result = Test12(); + if (result != 0) return result; + + result = Test13(); + if (result != 0) return result; + + // All tests passed + return 0; + } +} diff --git a/WoofWare.PawPrint/BasicCliType.fs b/WoofWare.PawPrint/BasicCliType.fs index 36ea4f4..5b1dd53 100644 --- a/WoofWare.PawPrint/BasicCliType.fs +++ b/WoofWare.PawPrint/BasicCliType.fs @@ -139,6 +139,18 @@ module CliRuntimePointerSource = let a = ofManagedPointerSource a CliRuntimePointerSource.Field (a, ind) + let rec toManagedPointerSource (ptrSource : CliRuntimePointerSource) : ManagedPointerSource = + match ptrSource with + | CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, whichVar) -> + ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) + | CliRuntimePointerSource.Argument (sourceThread, methodFrame, whichVar) -> + ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) + | CliRuntimePointerSource.Heap managedHeapAddress -> ManagedPointerSource.Heap managedHeapAddress + | CliRuntimePointerSource.Null -> ManagedPointerSource.Null + | CliRuntimePointerSource.ArrayIndex (arr, ind) -> ManagedPointerSource.ArrayIndex (arr, ind) + | CliRuntimePointerSource.Field (a, ind) -> + let a = toManagedPointerSource a + ManagedPointerSource.Field (a, ind) type CliRuntimePointer = | Unmanaged of int64 diff --git a/WoofWare.PawPrint/EvalStack.fs b/WoofWare.PawPrint/EvalStack.fs index 2532aa7..df11f28 100644 --- a/WoofWare.PawPrint/EvalStack.fs +++ b/WoofWare.PawPrint/EvalStack.fs @@ -320,7 +320,7 @@ module EvalStackValue = | CliRuntimePointerSource.Heap addr -> EvalStackValue.ObjectRef addr | CliRuntimePointerSource.Null -> EvalStackValue.ManagedPointer ManagedPointerSource.Null | CliRuntimePointerSource.Field (source, fieldName) -> - ManagedPointerSource.Field (failwith "TODO", fieldName) + ManagedPointerSource.Field (CliRuntimePointerSource.toManagedPointerSource source, fieldName) |> EvalStackValue.ManagedPointer | CliType.ValueType fields -> // TODO: this is a bit dubious; we're being a bit sloppy with possibly-overlapping fields here diff --git a/WoofWare.PawPrint/IlMachineState.fs b/WoofWare.PawPrint/IlMachineState.fs index 94e66b8..ed61b08 100644 --- a/WoofWare.PawPrint/IlMachineState.fs +++ b/WoofWare.PawPrint/IlMachineState.fs @@ -284,7 +284,7 @@ module IlMachineState = (state : IlMachineState) : IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo = - match Assembly.resolveTypeRef state._LoadedAssemblies referencedInAssembly target typeGenericArgs with + match Assembly.resolveTypeRef state._LoadedAssemblies referencedInAssembly typeGenericArgs target with | TypeResolutionResult.Resolved (assy, typeDef) -> state, assy, typeDef | TypeResolutionResult.FirstLoadAssy loadFirst -> let state, _, _ = @@ -335,36 +335,8 @@ module IlMachineState = assy state - // If the resolved argument has generics, create a GenericInstantiation - // Otherwise, create a FromDefinition let preservedArg = - let baseType = - resolvedArg.BaseType - |> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies assy.Name - - let signatureTypeKind = - match baseType with - | ResolvedBaseType.Enum - | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType - | ResolvedBaseType.Object -> SignatureTypeKind.Class - | ResolvedBaseType.Delegate -> SignatureTypeKind.Class - - if resolvedArg.Generics.IsEmpty then - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make resolvedArg.TypeDefHandle, - assy.Name.FullName, - signatureTypeKind - ) - else - // Preserve the generic instantiation - let genericDef = - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make resolvedArg.TypeDefHandle, - assy.Name.FullName, - signatureTypeKind - ) - - TypeDefn.GenericInstantiation (genericDef, resolvedArg.Generics) + DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies resolvedArg args'.Add preservedArg @@ -448,25 +420,23 @@ module IlMachineState = // Convert ConcreteTypeHandle to TypeDefn let typeGenericArgsAsDefn = typeGenericArgs - |> Seq.map (fun handle -> + |> ImmutableArray.map (fun handle -> Concretization.concreteHandleToTypeDefn baseClassTypes handle state.ConcreteTypes state._LoadedAssemblies ) - |> ImmutableArray.CreateRange let methodGenericArgsAsDefn = methodGenericArgs - |> Seq.map (fun handle -> + |> ImmutableArray.map (fun handle -> Concretization.concreteHandleToTypeDefn baseClassTypes handle state.ConcreteTypes state._LoadedAssemblies ) - |> ImmutableArray.CreateRange resolveTypeFromDefn loggerFactory baseClassTypes sign typeGenericArgsAsDefn methodGenericArgsAsDefn assy state @@ -498,13 +468,13 @@ module IlMachineState = /// Concretize a ConcreteType to get a ConcreteTypeHandle for static field access let concretizeFieldDeclaringType (loggerFactory : ILoggerFactory) - (baseClassTypes : BaseClassTypes<'corelib>) + (baseClassTypes : BaseClassTypes) (declaringType : ConcreteType) (state : IlMachineState) : ConcreteTypeHandle * IlMachineState = // Create a concretization context from the current state - let ctx : TypeConcretization.ConcretizationContext<'corelib> = + let ctx : TypeConcretization.ConcretizationContext<_> = { InProgress = ImmutableDictionary.Empty ConcreteTypes = state.ConcreteTypes @@ -1435,6 +1405,48 @@ module IlMachineState = let getSyncBlock (addr : ManagedHeapAddress) (state : IlMachineState) : SyncBlock = state.ManagedHeap |> ManagedHeap.getSyncBlock addr + let getFieldValue (obj : ManagedPointerSource) (fieldName : string) (state : IlMachineState) : CliType = + match obj with + | ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) -> + getLocalVariable sourceThread methodFrame whichVar state + |> CliType.getField fieldName + | ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) -> failwith "todo" + | ManagedPointerSource.Heap addr -> + ManagedHeap.get addr state.ManagedHeap + |> AllocatedNonArrayObject.DereferenceField fieldName + | ManagedPointerSource.ArrayIndex (arr, index) -> getArrayValue arr index state |> CliType.getField fieldName + | ManagedPointerSource.Field (src, fieldName) -> failwith "todo" + | ManagedPointerSource.Null -> failwith "TODO: throw NRE" + + let setFieldValue + (obj : ManagedPointerSource) + (v : CliType) + (fieldName : string) + (state : IlMachineState) + : IlMachineState + = + match obj with + | ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) -> + let v = + getLocalVariable sourceThread methodFrame whichVar state + |> CliType.withFieldSet fieldName v + + state |> setLocalVariable sourceThread methodFrame whichVar v + | ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) -> failwith "todo" + | ManagedPointerSource.Heap addr -> + let newValue = + ManagedHeap.get addr state.ManagedHeap + |> AllocatedNonArrayObject.SetField fieldName v + + { state with + ManagedHeap = ManagedHeap.set addr newValue state.ManagedHeap + } + | ManagedPointerSource.ArrayIndex (arr, index) -> + let v = getArrayValue arr index state |> CliType.withFieldSet fieldName v + state |> setArrayValue arr v index + | ManagedPointerSource.Field (managedPointerSource, fieldName) -> failwith "todo" + | ManagedPointerSource.Null -> failwith "TODO: throw NRE" + let executeDelegateConstructor (instruction : MethodState) (state : IlMachineState) : IlMachineState = // We've been called with arguments already popped from the stack into local arguments. let constructing = instruction.Arguments.[0] @@ -1617,42 +1629,7 @@ module IlMachineState = : IlMachineState * TypeDefn = let defn = activeAssy.TypeDefs.[typeDef] - - let baseType = - defn.BaseType - |> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies defn.Assembly - - let signatureTypeKind = - match baseType with - | ResolvedBaseType.Enum - | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType - | ResolvedBaseType.Object -> SignatureTypeKind.Class - | ResolvedBaseType.Delegate -> SignatureTypeKind.Class - - let result = - if defn.Generics.IsEmpty then - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make defn.TypeDefHandle, - defn.Assembly.FullName, - signatureTypeKind - ) - else - // Preserve the generic instantiation by converting GenericParameters to TypeDefn.GenericTypeParameter - let genericDef = - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make defn.TypeDefHandle, - defn.Assembly.FullName, - signatureTypeKind - ) - - let genericArgs = - defn.Generics - |> Seq.mapi (fun i _ -> TypeDefn.GenericTypeParameter i) - |> ImmutableArray.CreateRange - - TypeDefn.GenericInstantiation (genericDef, genericArgs) - - state, result + state, DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies defn let lookupTypeRef (loggerFactory : ILoggerFactory) @@ -1680,25 +1657,4 @@ module IlMachineState = let state, assy, resolved = resolveTypeFromRef loggerFactory activeAssy ref typeGenerics state - let baseType = - resolved.BaseType - |> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies assy.Name - - let signatureTypeKind = - match baseType with - | ResolvedBaseType.Enum - | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType - | ResolvedBaseType.Object -> SignatureTypeKind.Class - | ResolvedBaseType.Delegate -> SignatureTypeKind.Class - - let result = - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make resolved.TypeDefHandle, - assy.Name.FullName, - signatureTypeKind - ) - - if resolved.Generics.IsEmpty then - state, result, assy - else - failwith "TODO: add generics" + state, DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies resolved, assy diff --git a/WoofWare.PawPrint/IlMachineStateExecution.fs b/WoofWare.PawPrint/IlMachineStateExecution.fs index db92d96..5029106 100644 --- a/WoofWare.PawPrint/IlMachineStateExecution.fs +++ b/WoofWare.PawPrint/IlMachineStateExecution.fs @@ -17,11 +17,7 @@ module IlMachineStateExecution = = match esv with | EvalStackValue.Int32 _ -> - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make baseClassTypes.Int32.TypeDefHandle, - baseClassTypes.Corelib.Name.FullName, - SignatureTypeKind.ValueType - ) + DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Int32 |> IlMachineState.concretizeType baseClassTypes state @@ -29,11 +25,7 @@ module IlMachineStateExecution = ImmutableArray.Empty ImmutableArray.Empty | EvalStackValue.Int64 _ -> - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make baseClassTypes.Int64.TypeDefHandle, - baseClassTypes.Corelib.Name.FullName, - SignatureTypeKind.ValueType - ) + DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Int64 |> IlMachineState.concretizeType baseClassTypes state @@ -42,11 +34,7 @@ module IlMachineStateExecution = ImmutableArray.Empty | EvalStackValue.NativeInt nativeIntSource -> failwith "todo" | EvalStackValue.Float _ -> - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make baseClassTypes.Double.TypeDefHandle, - baseClassTypes.Corelib.Name.FullName, - SignatureTypeKind.ValueType - ) + DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Double |> IlMachineState.concretizeType baseClassTypes state @@ -579,30 +567,8 @@ module IlMachineStateExecution = typeDef.Name ) - // TypeDef won't have any generics; it would be a TypeSpec if it did - // Create a TypeDefn from the TypeDef handle let baseTypeDefn = - let baseTypeDef = sourceAssembly.TypeDefs.[typeDefinitionHandle] - - let baseType = - baseTypeDef.BaseType - |> DumpedAssembly.resolveBaseType - baseClassTypes - state._LoadedAssemblies - sourceAssembly.Name - - let signatureTypeKind = - match baseType with - | ResolvedBaseType.Enum - | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType - | ResolvedBaseType.Object - | ResolvedBaseType.Delegate -> SignatureTypeKind.Class - - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make typeDefinitionHandle, - sourceAssembly.Name.FullName, - signatureTypeKind - ) + DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies typeDef // Concretize the base type let state, baseTypeHandle = @@ -640,22 +606,8 @@ module IlMachineStateExecution = // Create a TypeDefn from the resolved TypeRef let baseTypeDefn = - let baseType = - targetType.BaseType - |> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies assy.Name - - let signatureTypeKind = - match baseType with - | ResolvedBaseType.Enum - | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType - | ResolvedBaseType.Object - | ResolvedBaseType.Delegate -> SignatureTypeKind.Class - - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make targetType.TypeDefHandle, - assy.Name.FullName, - signatureTypeKind - ) + targetType + |> DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies // Concretize the base type let state, baseTypeHandle = diff --git a/WoofWare.PawPrint/ManagedHeap.fs b/WoofWare.PawPrint/ManagedHeap.fs index bcb6b60..68616dd 100644 --- a/WoofWare.PawPrint/ManagedHeap.fs +++ b/WoofWare.PawPrint/ManagedHeap.fs @@ -17,6 +17,29 @@ type AllocatedNonArrayObject = // TODO: this is wrong, it doesn't account for overlapping fields f.Fields |> List.find (fun f -> f.Name = name) |> _.Contents + static member SetField (name : string) (v : CliType) (f : AllocatedNonArrayObject) : AllocatedNonArrayObject = + // TODO: this is wrong, it doesn't account for overlapping fields + let contents = + { + Name = name + Contents = v + Offset = None + } + + { f with + Fields = + f.Fields + |> List.replaceWhere (fun f -> + if f.Name = name then + Some + { contents with + Offset = f.Offset + } + else + None + ) + } + type AllocatedArray = { Length : int @@ -125,6 +148,12 @@ module ManagedHeap = // TODO: arrays too heap.NonArrayObjects.[alloc] + let set (alloc : ManagedHeapAddress) (v : AllocatedNonArrayObject) (heap : ManagedHeap) : ManagedHeap = + // TODO: arrays too + { heap with + NonArrayObjects = heap.NonArrayObjects |> Map.add alloc v + } + let setArrayValue (alloc : ManagedHeapAddress) (offset : int) (v : CliType) (heap : ManagedHeap) : ManagedHeap = let newArrs = heap.Arrays diff --git a/WoofWare.PawPrint/Program.fs b/WoofWare.PawPrint/Program.fs index 8f8bb29..1d91ef5 100644 --- a/WoofWare.PawPrint/Program.fs +++ b/WoofWare.PawPrint/Program.fs @@ -16,11 +16,7 @@ module Program = : ManagedHeapAddress * IlMachineState = let state, stringType = - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make corelib.String.TypeDefHandle, - corelib.Corelib.Name.FullName, - SignatureTypeKind.Class - ) + DumpedAssembly.typeInfoToTypeDefn' corelib state._LoadedAssemblies corelib.String |> IlMachineState.concretizeType corelib state @@ -126,7 +122,7 @@ module Program = let rec go state = // Resolve the type reference to find which assembly it's in match - Assembly.resolveTypeRef state._LoadedAssemblies currentAssembly typeRef ImmutableArray.Empty + Assembly.resolveTypeRef state._LoadedAssemblies currentAssembly ImmutableArray.Empty typeRef with | TypeResolutionResult.FirstLoadAssy assyRef -> // Need to load this assembly first diff --git a/WoofWare.PawPrint/UnaryMetadataIlOp.fs b/WoofWare.PawPrint/UnaryMetadataIlOp.fs index 9162371..e167738 100644 --- a/WoofWare.PawPrint/UnaryMetadataIlOp.fs +++ b/WoofWare.PawPrint/UnaryMetadataIlOp.fs @@ -416,22 +416,10 @@ module internal UnaryMetadataIlOp = let activeAssy = state.ActiveAssembly thread let ty = activeAssy.TypeDefs.[td] - let baseTy = - DumpedAssembly.resolveBaseType - baseClassTypes - state._LoadedAssemblies - activeAssy.Name - ty.BaseType + let result = + DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies ty - let sigType = - match baseTy with - | ResolvedBaseType.Enum - | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType - | ResolvedBaseType.Object -> SignatureTypeKind.Class - | ResolvedBaseType.Delegate -> SignatureTypeKind.Class - - state, - TypeDefn.FromDefinition (ComparableTypeDefinitionHandle.Make td, activeAssy.Name.FullName, sigType) + state, result | MetadataToken.TypeSpecification handle -> state, state.ActiveAssembly(thread).TypeSpecs.[handle].Signature | MetadataToken.TypeReference handle -> @@ -443,22 +431,7 @@ module internal UnaryMetadataIlOp = ImmutableArray.Empty state - let baseTy = - DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies assy.Name resol.BaseType - - let sigType = - match baseTy with - | ResolvedBaseType.Enum - | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType - | ResolvedBaseType.Object -> SignatureTypeKind.Class - | ResolvedBaseType.Delegate -> SignatureTypeKind.Class - - state, - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make resol.TypeDefHandle, - assy.Name.FullName, - sigType - ) + state, DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies resol | m -> failwith $"unexpected metadata token {m} in IsInst" let state, targetConcreteType = @@ -770,8 +743,11 @@ module internal UnaryMetadataIlOp = IlMachineState.pushToEvalStack currentValue thread state | EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: raise NullReferenceException" - | EvalStackValue.ManagedPointer (ManagedPointerSource.Field _) -> - failwith "TODO: get a field on a field ptr" + | EvalStackValue.ManagedPointer (ManagedPointerSource.Field (src, fieldName)) -> + let currentValue = + IlMachineState.getFieldValue src fieldName state |> CliType.getField field.Name + + IlMachineState.pushToEvalStack currentValue thread state | EvalStackValue.UserDefinedValueType vt -> let result = vt |> EvalStackValueUserType.DereferenceField field.Name IlMachineState.pushToEvalStack' result thread state @@ -780,7 +756,43 @@ module internal UnaryMetadataIlOp = |> IlMachineState.advanceProgramCounter thread |> Tuple.withRight WhatWeDid.Executed - | Ldflda -> failwith "TODO: Ldflda unimplemented" + | Ldflda -> + let ptr, state = IlMachineState.popEvalStack thread state + + let ptr = + match ptr with + | Int32 _ + | Int64 _ + | Float _ -> failwith "expected pointer type" + | NativeInt nativeIntSource -> failwith "todo" + | ManagedPointer src -> src + | ObjectRef addr -> ManagedPointerSource.Heap addr + | UserDefinedValueType evalStackValueUserType -> failwith "todo" + + let state, field = + match metadataToken with + | MetadataToken.FieldDefinition f -> + let field = + activeAssy.Fields.[f] + |> FieldInfo.mapTypeGenerics (fun _ -> failwith "no generics allowed on FieldDefinition") + + state, field + | MetadataToken.MemberReference mr -> + let state, assyName, field, _ = + IlMachineState.resolveMember loggerFactory baseClassTypes thread activeAssy mr state + + match field with + | Choice1Of2 _method -> failwith "member reference was unexpectedly a method" + | Choice2Of2 field -> state, field + | t -> failwith $"Unexpectedly asked to load from a non-field: {t}" + + let result = + ManagedPointerSource.Field (ptr, field.Name) |> EvalStackValue.ManagedPointer + + state + |> IlMachineState.pushToEvalStack' result thread + |> IlMachineState.advanceProgramCounter thread + |> Tuple.withRight WhatWeDid.Executed | Ldsfld -> let state, field = match metadataToken with @@ -902,12 +914,7 @@ module internal UnaryMetadataIlOp = | _ -> failwith $"expected heap allocation for array, got {arr}" let elementType = - TypeInfo.toTypeDefn - baseClassTypes - _.Name - (fun x y -> x.TypeDefs.[y]) - (fun x y -> x.TypeRefs.[y] |> failwithf "%+A") - elementType + DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies elementType let state, zeroOfType = IlMachineState.cliTypeZeroOf @@ -976,7 +983,69 @@ module internal UnaryMetadataIlOp = IlMachineState.pushToEvalStack toPush thread state |> IlMachineState.advanceProgramCounter thread |> Tuple.withRight WhatWeDid.Executed - | Initobj -> failwith "TODO: Initobj unimplemented" + | Initobj -> + let popped, state = IlMachineState.popEvalStack thread state + let declaringTypeGenerics = currentMethod.DeclaringType.Generics + + let state, assy, targetType = + match metadataToken with + | MetadataToken.TypeDefinition defn -> + state, + activeAssy, + activeAssy.TypeDefs.[defn] + |> TypeInfo.mapGeneric (fun (p, _) -> TypeDefn.GenericTypeParameter p.SequenceNumber) + | MetadataToken.TypeSpecification spec -> + let state, assy, ty = + IlMachineState.resolveTypeFromSpecConcrete + loggerFactory + baseClassTypes + spec + activeAssy + declaringTypeGenerics + currentMethod.Generics + state + + state, assy, ty + | x -> failwith $"TODO: Ldelem element type resolution unimplemented for {x}" + + let targetType = + targetType + |> DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies + + let state, zeroOfType = + IlMachineState.cliTypeZeroOf + loggerFactory + baseClassTypes + assy + targetType + declaringTypeGenerics + ImmutableArray.Empty + state + + let state = + match popped with + | EvalStackValue.Int32 _ + | EvalStackValue.Int64 _ + | EvalStackValue.NativeInt _ + | EvalStackValue.Float _ -> failwith "unexpectedly not an address" + | EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr) + | EvalStackValue.ObjectRef addr -> failwith "todo" + | EvalStackValue.ManagedPointer src -> + match src with + | ManagedPointerSource.LocalVariable (thread, frame, var) -> + state |> IlMachineState.setLocalVariable thread frame var zeroOfType + | ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) -> failwith "todo" + | ManagedPointerSource.ArrayIndex (arr, index) -> + state |> IlMachineState.setArrayValue arr zeroOfType index + | ManagedPointerSource.Field (managedPointerSource, fieldName) -> + state |> IlMachineState.setFieldValue managedPointerSource zeroOfType fieldName + | ManagedPointerSource.Null -> failwith "runtime error: unexpectedly Initobj'ing null" + | ManagedPointerSource.Heap _ -> failwith "logic error" + | EvalStackValue.UserDefinedValueType evalStackValueUserType -> failwith "todo" + + state + |> IlMachineState.advanceProgramCounter thread + |> Tuple.withRight WhatWeDid.Executed | Ldsflda -> // TODO: check whether we should throw FieldAccessException @@ -1105,25 +1174,8 @@ module internal UnaryMetadataIlOp = methodGenerics state - let stk = - match - DumpedAssembly.resolveBaseType - baseClassTypes - state._LoadedAssemblies - assy.Name - typeDefn.BaseType - with - | ResolvedBaseType.ValueType - | ResolvedBaseType.Enum -> SignatureTypeKind.ValueType - | ResolvedBaseType.Delegate - | ResolvedBaseType.Object -> SignatureTypeKind.Class - let typeDefn = - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make typeDefn.TypeDefHandle, - assy.Name.FullName, - stk - ) + DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies typeDefn let state, handle = IlMachineState.concretizeType diff --git a/WoofWare.PawPrint/UnaryStringTokenIlOp.fs b/WoofWare.PawPrint/UnaryStringTokenIlOp.fs index 45dd607..4a5ec57 100644 --- a/WoofWare.PawPrint/UnaryStringTokenIlOp.fs +++ b/WoofWare.PawPrint/UnaryStringTokenIlOp.fs @@ -64,11 +64,7 @@ module internal UnaryStringTokenIlOp = ] let state, stringType = - TypeDefn.FromDefinition ( - ComparableTypeDefinitionHandle.Make baseClassTypes.String.TypeDefHandle, - baseClassTypes.Corelib.Name.FullName, - SignatureTypeKind.Class - ) + DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.String |> IlMachineState.concretizeType baseClassTypes state