mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-05 22:28:38 +00:00
Initobj (#114)
This commit is contained in:
@@ -423,8 +423,8 @@ module Assembly =
|
||||
let rec resolveTypeRef
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(referencedInAssembly : DumpedAssembly)
|
||||
(target : TypeRef)
|
||||
(genericArgs : ImmutableArray<TypeDefn>)
|
||||
(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<DumpedAssembly>)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(ti : TypeInfo<TypeDefn, TypeDefn>)
|
||||
=
|
||||
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<DumpedAssembly>)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(ti : TypeInfo<GenericParamFromMetadata, TypeDefn>)
|
||||
=
|
||||
ti
|
||||
|> TypeInfo.mapGeneric (fun (par, _) -> TypeDefn.GenericTypeParameter par.SequenceNumber)
|
||||
|> typeInfoToTypeDefn bct assemblies
|
||||
|
@@ -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<DumpedAssembly>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(assembly : AssemblyName)
|
||||
(typeGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(typeDefn : TypeDefn)
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
: ConcreteTypeHandle * ConcretizationContext<DumpedAssembly>
|
||||
=
|
||||
|
||||
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<DumpedAssembly>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(assembly : AssemblyName)
|
||||
@@ -713,7 +713,7 @@ module TypeConcretization =
|
||||
(methodGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(genericDef : TypeDefn)
|
||||
(args : ImmutableArray<TypeDefn>)
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
: ConcreteTypeHandle * ConcretizationContext<DumpedAssembly>
|
||||
=
|
||||
// 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<DumpedAssembly>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(assembly : AssemblyName)
|
||||
(typeArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
(types : ImmutableArray<TypeDefn>)
|
||||
: ImmutableArray<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<'corelib>
|
||||
: ImmutableArray<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<DumpedAssembly>
|
||||
=
|
||||
|
||||
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<DumpedAssembly>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(assembly : AssemblyName)
|
||||
(typeArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
(signature : TypeMethodSignature<TypeDefn>)
|
||||
: TypeMethodSignature<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<'corelib>
|
||||
: TypeMethodSignature<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<DumpedAssembly>
|
||||
=
|
||||
|
||||
// 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)
|
||||
|
@@ -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, TypeDefn>)
|
||||
: 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
|
||||
|
@@ -160,6 +160,11 @@ module TestPureCases =
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "Initobj.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
]
|
||||
|
||||
let runTest (case : EndToEndTestCase) : unit =
|
||||
|
503
WoofWare.PawPrint.Test/sourcesPure/Initobj.cs
Normal file
503
WoofWare.PawPrint.Test/sourcesPure/Initobj.cs
Normal file
@@ -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<T>
|
||||
{
|
||||
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<int> gi = new GenericStruct<int>
|
||||
{
|
||||
Value = 123,
|
||||
Count = 456
|
||||
};
|
||||
|
||||
if (gi.Value != 123) return 40;
|
||||
if (gi.Count != 456) return 41;
|
||||
|
||||
gi = default(GenericStruct<int>);
|
||||
|
||||
if (gi.Value != 0) return 42;
|
||||
if (gi.Count != 0) return 43;
|
||||
|
||||
// Test with reference type
|
||||
GenericStruct<string> gs = new GenericStruct<string>
|
||||
{
|
||||
Value = "Test",
|
||||
Count = 789
|
||||
};
|
||||
|
||||
if (gs.Value != "Test") return 44;
|
||||
if (gs.Count != 789) return 45;
|
||||
|
||||
gs = default(GenericStruct<string>);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -284,7 +284,7 @@ module IlMachineState =
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
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<TypeDefn> to get a ConcreteTypeHandle for static field access
|
||||
let concretizeFieldDeclaringType
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<'corelib>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(declaringType : ConcreteType<TypeDefn>)
|
||||
(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
|
||||
|
@@ -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 =
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user