9 Commits

Author SHA1 Message Date
Smaug123
55677a507b Revert 2025-08-24 20:43:06 +01:00
Smaug123
3930cc5fbb More 2025-08-24 20:40:52 +01:00
Smaug123
735449d4df Revert 2025-08-24 20:40:32 +01:00
Smaug123
6c73f14a4e Merge branch 'main' into generic-edge-cases 2025-08-24 20:39:27 +01:00
Patrick Stevens
4de0dbd816 Add another test and put real-version first (#116) 2025-08-24 19:38:43 +00:00
Smaug123
5bd0f779c5 Merge branch 'main' into generic-edge-cases 2025-08-24 20:27:48 +01:00
Smaug123
4e8c852b56 Merge branch 'main' into generic-edge-cases 2025-08-24 20:27:39 +01:00
Patrick Stevens
91aff34d1e Fix a TODO (#115) 2025-08-24 19:27:38 +00:00
Patrick Stevens
f9e186ba8f Initobj (#114) 2025-08-24 19:23:50 +00:00
19 changed files with 276 additions and 355 deletions

View File

@@ -423,8 +423,8 @@ module Assembly =
let rec resolveTypeRef let rec resolveTypeRef
(assemblies : ImmutableDictionary<string, DumpedAssembly>) (assemblies : ImmutableDictionary<string, DumpedAssembly>)
(referencedInAssembly : DumpedAssembly) (referencedInAssembly : DumpedAssembly)
(target : TypeRef)
(genericArgs : ImmutableArray<TypeDefn>) (genericArgs : ImmutableArray<TypeDefn>)
(target : TypeRef)
: TypeResolutionResult : TypeResolutionResult
= =
match target.ResolutionScope with match target.ResolutionScope with
@@ -495,7 +495,7 @@ module Assembly =
| None -> | None ->
match assy.TypeRef ns name with match assy.TypeRef ns name with
| Some typeRef -> resolveTypeRef assemblies assy typeRef genericArgs | Some typeRef -> resolveTypeRef assemblies assy genericArgs typeRef
| None -> | None ->
match assy.ExportedType (Some ns) name with match assy.ExportedType (Some ns) name with
@@ -532,7 +532,7 @@ module DumpedAssembly =
| Some (BaseTypeInfo.TypeRef r) -> | Some (BaseTypeInfo.TypeRef r) ->
let assy = loadedAssemblies.[source.FullName] let assy = loadedAssemblies.[source.FullName]
// TODO: generics // 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 _ -> | TypeResolutionResult.FirstLoadAssy _ ->
failwith failwith
"seems pretty unlikely that we could have constructed this object without loading its base type" "seems pretty unlikely that we could have constructed this object without loading its base type"
@@ -560,3 +560,35 @@ module DumpedAssembly =
| None -> ResolvedBaseType.Object | None -> ResolvedBaseType.Object
go source baseTypeInfo 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

View File

@@ -420,7 +420,7 @@ module TypeConcretization =
// First try to resolve without loading new assemblies // First try to resolve without loading new assemblies
let resolutionResult = let resolutionResult =
Assembly.resolveTypeRef ctx.LoadedAssemblies currentAssy typeRef ImmutableArray.Empty Assembly.resolveTypeRef ctx.LoadedAssemblies currentAssy ImmutableArray.Empty typeRef
match resolutionResult with match resolutionResult with
| TypeResolutionResult.Resolved (targetAssy, typeInfo) -> (targetAssy, typeInfo), ctx | TypeResolutionResult.Resolved (targetAssy, typeInfo) -> (targetAssy, typeInfo), ctx
@@ -437,7 +437,7 @@ module TypeConcretization =
// Now try to resolve again with the loaded assembly // Now try to resolve again with the loaded assembly
let resolutionResult2 = let resolutionResult2 =
Assembly.resolveTypeRef newCtx.LoadedAssemblies currentAssy typeRef ImmutableArray.Empty Assembly.resolveTypeRef newCtx.LoadedAssemblies currentAssy ImmutableArray.Empty typeRef
match resolutionResult2 with match resolutionResult2 with
| TypeResolutionResult.Resolved (targetAssy, typeInfo) -> (targetAssy, typeInfo), newCtx | TypeResolutionResult.Resolved (targetAssy, typeInfo) -> (targetAssy, typeInfo), newCtx
@@ -608,14 +608,14 @@ module TypeConcretization =
/// Concretize a type in a specific generic context /// Concretize a type in a specific generic context
let rec concretizeType let rec concretizeType
(ctx : ConcretizationContext<'corelib>) (ctx : ConcretizationContext<DumpedAssembly>)
(loadAssembly : (loadAssembly :
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly) AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
(assembly : AssemblyName) (assembly : AssemblyName)
(typeGenerics : ImmutableArray<ConcreteTypeHandle>) (typeGenerics : ImmutableArray<ConcreteTypeHandle>)
(methodGenerics : ImmutableArray<ConcreteTypeHandle>) (methodGenerics : ImmutableArray<ConcreteTypeHandle>)
(typeDefn : TypeDefn) (typeDefn : TypeDefn)
: ConcreteTypeHandle * ConcretizationContext<'corelib> : ConcreteTypeHandle * ConcretizationContext<DumpedAssembly>
= =
let key = (assembly, typeDefn) let key = (assembly, typeDefn)
@@ -705,7 +705,7 @@ module TypeConcretization =
| _ -> failwithf "TODO: Concretization of %A not implemented" typeDefn | _ -> failwithf "TODO: Concretization of %A not implemented" typeDefn
and private concretizeGenericInstantiation and private concretizeGenericInstantiation
(ctx : ConcretizationContext<'corelib>) (ctx : ConcretizationContext<DumpedAssembly>)
(loadAssembly : (loadAssembly :
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly) AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
(assembly : AssemblyName) (assembly : AssemblyName)
@@ -713,7 +713,7 @@ module TypeConcretization =
(methodGenerics : ImmutableArray<ConcreteTypeHandle>) (methodGenerics : ImmutableArray<ConcreteTypeHandle>)
(genericDef : TypeDefn) (genericDef : TypeDefn)
(args : ImmutableArray<TypeDefn>) (args : ImmutableArray<TypeDefn>)
: ConcreteTypeHandle * ConcretizationContext<'corelib> : ConcreteTypeHandle * ConcretizationContext<DumpedAssembly>
= =
// First, concretize all type arguments // First, concretize all type arguments
let argHandles, ctxAfterArgs = let argHandles, ctxAfterArgs =
@@ -864,14 +864,14 @@ module Concretization =
/// Helper to concretize an array of types /// Helper to concretize an array of types
let private concretizeTypeArray let private concretizeTypeArray
(ctx : TypeConcretization.ConcretizationContext<'corelib>) (ctx : TypeConcretization.ConcretizationContext<DumpedAssembly>)
(loadAssembly : (loadAssembly :
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly) AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
(assembly : AssemblyName) (assembly : AssemblyName)
(typeArgs : ImmutableArray<ConcreteTypeHandle>) (typeArgs : ImmutableArray<ConcreteTypeHandle>)
(methodArgs : ImmutableArray<ConcreteTypeHandle>) (methodArgs : ImmutableArray<ConcreteTypeHandle>)
(types : ImmutableArray<TypeDefn>) (types : ImmutableArray<TypeDefn>)
: ImmutableArray<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<'corelib> : ImmutableArray<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<DumpedAssembly>
= =
let handles = ImmutableArray.CreateBuilder types.Length let handles = ImmutableArray.CreateBuilder types.Length
@@ -888,14 +888,14 @@ module Concretization =
/// Helper to concretize a method signature /// Helper to concretize a method signature
let private concretizeMethodSignature let private concretizeMethodSignature
(ctx : TypeConcretization.ConcretizationContext<'corelib>) (ctx : TypeConcretization.ConcretizationContext<DumpedAssembly>)
(loadAssembly : (loadAssembly :
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly) AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
(assembly : AssemblyName) (assembly : AssemblyName)
(typeArgs : ImmutableArray<ConcreteTypeHandle>) (typeArgs : ImmutableArray<ConcreteTypeHandle>)
(methodArgs : ImmutableArray<ConcreteTypeHandle>) (methodArgs : ImmutableArray<ConcreteTypeHandle>)
(signature : TypeMethodSignature<TypeDefn>) (signature : TypeMethodSignature<TypeDefn>)
: TypeMethodSignature<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<'corelib> : TypeMethodSignature<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<DumpedAssembly>
= =
// Concretize return type // Concretize return type
@@ -1157,8 +1157,7 @@ module Concretization =
// Recursively convert generic arguments // Recursively convert generic arguments
let genericArgs = let genericArgs =
concreteType.Generics concreteType.Generics
|> Seq.map (fun h -> concreteHandleToTypeDefn baseClassTypes h concreteTypes assemblies) |> ImmutableArray.map (fun h -> concreteHandleToTypeDefn baseClassTypes h concreteTypes assemblies)
|> ImmutableArray.CreateRange
let baseDef = let baseDef =
TypeDefn.FromDefinition (concreteType.Definition, concreteType.Assembly.FullName, signatureTypeKind) TypeDefn.FromDefinition (concreteType.Definition, concreteType.Assembly.FullName, signatureTypeKind)

View File

@@ -348,10 +348,10 @@ module TypeInfo =
let rec resolveBaseType<'corelib, 'generic, 'field> let rec resolveBaseType<'corelib, 'generic, 'field>
(baseClassTypes : BaseClassTypes<'corelib>) (baseClassTypes : BaseClassTypes<'corelib>)
(sourceAssy : 'corelib)
(getName : 'corelib -> AssemblyName) (getName : 'corelib -> AssemblyName)
(getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'field>) (getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'field>)
(getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic, 'field>) (getTypeRef : 'corelib -> TypeReferenceHandle -> 'corelib * TypeInfo<'generic, 'field>)
(sourceAssembly : AssemblyName)
(value : BaseTypeInfo option) (value : BaseTypeInfo option)
: ResolvedBaseType : ResolvedBaseType
= =
@@ -361,40 +361,48 @@ module TypeInfo =
match value with match value with
| BaseTypeInfo.TypeDef typeDefinitionHandle -> | BaseTypeInfo.TypeDef typeDefinitionHandle ->
match isBaseType baseClassTypes getName sourceAssembly typeDefinitionHandle with match isBaseType baseClassTypes getName (getName sourceAssy) typeDefinitionHandle with
| Some x -> x | Some x -> x
| None -> | None ->
let baseType = getTypeDef baseClassTypes.Corelib typeDefinitionHandle 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 -> | BaseTypeInfo.TypeRef typeReferenceHandle ->
let typeRef = getTypeRef baseClassTypes.Corelib typeReferenceHandle let targetAssy, typeRef = getTypeRef sourceAssy typeReferenceHandle
failwith $"{typeRef}"
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.TypeSpec typeSpecificationHandle -> failwith "todo"
| BaseTypeInfo.ForeignAssemblyType (assemblyName, typeDefinitionHandle) -> | BaseTypeInfo.ForeignAssemblyType (assemblyName, typeDefinitionHandle) ->
resolveBaseType resolveBaseType
baseClassTypes baseClassTypes
sourceAssy
getName getName
getTypeDef getTypeDef
getTypeRef getTypeRef
assemblyName
(Some (BaseTypeInfo.TypeDef typeDefinitionHandle)) (Some (BaseTypeInfo.TypeDef typeDefinitionHandle))
let toTypeDefn let toTypeDefn
(baseClassTypes : BaseClassTypes<'corelib>) (baseClassTypes : BaseClassTypes<'corelib>)
(assemblies : AssemblyName -> 'corelib)
(getName : 'corelib -> AssemblyName) (getName : 'corelib -> AssemblyName)
(getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'field>) (getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'field>)
(getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic, 'field>) (getTypeRef : 'corelib -> TypeReferenceHandle -> 'corelib * TypeInfo<'generic, 'field>)
(ty : TypeInfo<TypeDefn, TypeDefn>) (ty : TypeInfo<TypeDefn, TypeDefn>)
: TypeDefn : TypeDefn
= =
let stk = 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.Enum
| ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType | ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType
| ResolvedBaseType.Object | ResolvedBaseType.Object
| ResolvedBaseType.Delegate -> SignatureTypeKind.Class | ResolvedBaseType.Delegate -> SignatureTypeKind.Class
let defn = 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) TypeDefn.FromDefinition (ComparableTypeDefinitionHandle.Make ty.TypeDefHandle, ty.Assembly.FullName, stk)
if ty.Generics.IsEmpty then if ty.Generics.IsEmpty then

View File

@@ -48,7 +48,7 @@ module TestPureCases =
} }
{ {
FileName = "ResizeArray.cs" FileName = "ResizeArray.cs"
ExpectedReturnCode = 109 ExpectedReturnCode = 114
NativeImpls = MockEnv.make () NativeImpls = MockEnv.make ()
} }
{ {
@@ -61,6 +61,16 @@ module TestPureCases =
ExpectedReturnCode = 0 ExpectedReturnCode = 0
NativeImpls = MockEnv.make () NativeImpls = MockEnv.make ()
} }
{
FileName = "AdvancedStructLayout.cs"
ExpectedReturnCode = 0
NativeImpls = MockEnv.make ()
}
{
FileName = "OverlappingStructs.cs"
ExpectedReturnCode = 0
NativeImpls = MockEnv.make ()
}
] ]
let cases : EndToEndTestCase list = let cases : EndToEndTestCase list =
@@ -183,11 +193,12 @@ module TestPureCases =
use peImage = new MemoryStream (image) use peImage = new MemoryStream (image)
try try
let realResult = RealRuntime.executeWithRealRuntime [||] image
realResult.ExitCode |> shouldEqual case.ExpectedReturnCode
let terminalState, terminatingThread = let terminalState, terminatingThread =
Program.run loggerFactory (Some case.FileName) peImage dotnetRuntimes case.NativeImpls [] Program.run loggerFactory (Some case.FileName) peImage dotnetRuntimes case.NativeImpls []
let realResult = RealRuntime.executeWithRealRuntime [||] image
let exitCode = let exitCode =
match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with
| [] -> failwith "expected program to return a value, but it returned void" | [] -> failwith "expected program to return a value, but it returned void"
@@ -198,7 +209,6 @@ module TestPureCases =
exitCode |> shouldEqual realResult.ExitCode exitCode |> shouldEqual realResult.ExitCode
exitCode |> shouldEqual case.ExpectedReturnCode
with _ -> with _ ->
for message in messages () do for message in messages () do
System.Console.Error.WriteLine $"{message}" System.Console.Error.WriteLine $"{message}"

View File

@@ -8,7 +8,7 @@ namespace HelloWorldApp
{ {
int[] array = new[] { 1, 2, 3 }; int[] array = new[] { 1, 2, 3 };
if (array.Sum() != 60) if (array.Sum() != 6)
{ {
return 1; return 1;
} }

View File

@@ -124,9 +124,12 @@ public class TestInitobj
{ {
ObjectRef = new object(), ObjectRef = new object(),
StringRef = "Hello", StringRef = "Hello",
ArrayRef = new int[] { 1, 2, 3 }, ArrayRef = new int[3],
ValueField = 42 ValueField = 42
}; };
c.ArrayRef[0] = 1;
c.ArrayRef[1] = 2;
c.ArrayRef[2] = 3;
// Verify initial values // Verify initial values
if (c.ObjectRef == null) return 30; if (c.ObjectRef == null) return 30;

View File

@@ -191,7 +191,7 @@ public class StructLayoutTests
static int TestStructPassing() static int TestStructPassing()
{ {
var s = new SequentialStruct { A = 500, B = 50, C = 5000 }; var s = new SequentialStruct { A = 500, B = 50, C = 5005 };
int result = ProcessSequential(s); int result = ProcessSequential(s);
if (result != 555) return 50; // 500 + 50 + 5 (C % 1000) if (result != 555) return 50; // 500 + 50 + 5 (C % 1000)

View File

@@ -273,3 +273,4 @@ public class TestUnsafeAs
return 0; return 0;
} }
} }

View File

@@ -139,6 +139,18 @@ module CliRuntimePointerSource =
let a = ofManagedPointerSource a let a = ofManagedPointerSource a
CliRuntimePointerSource.Field (a, ind) 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 = type CliRuntimePointer =
| Unmanaged of int64 | Unmanaged of int64

View File

@@ -320,7 +320,7 @@ module EvalStackValue =
| CliRuntimePointerSource.Heap addr -> EvalStackValue.ObjectRef addr | CliRuntimePointerSource.Heap addr -> EvalStackValue.ObjectRef addr
| CliRuntimePointerSource.Null -> EvalStackValue.ManagedPointer ManagedPointerSource.Null | CliRuntimePointerSource.Null -> EvalStackValue.ManagedPointer ManagedPointerSource.Null
| CliRuntimePointerSource.Field (source, fieldName) -> | CliRuntimePointerSource.Field (source, fieldName) ->
ManagedPointerSource.Field (failwith "TODO", fieldName) ManagedPointerSource.Field (CliRuntimePointerSource.toManagedPointerSource source, fieldName)
|> EvalStackValue.ManagedPointer |> EvalStackValue.ManagedPointer
| CliType.ValueType fields -> | CliType.ValueType fields ->
// TODO: this is a bit dubious; we're being a bit sloppy with possibly-overlapping fields here // TODO: this is a bit dubious; we're being a bit sloppy with possibly-overlapping fields here

View File

@@ -284,7 +284,7 @@ module IlMachineState =
(state : IlMachineState) (state : IlMachineState)
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn> : 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.Resolved (assy, typeDef) -> state, assy, typeDef
| TypeResolutionResult.FirstLoadAssy loadFirst -> | TypeResolutionResult.FirstLoadAssy loadFirst ->
let state, _, _ = let state, _, _ =
@@ -335,36 +335,8 @@ module IlMachineState =
assy assy
state state
// If the resolved argument has generics, create a GenericInstantiation
// Otherwise, create a FromDefinition
let preservedArg = let preservedArg =
let baseType = DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies resolvedArg
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)
args'.Add preservedArg args'.Add preservedArg
@@ -448,25 +420,23 @@ module IlMachineState =
// Convert ConcreteTypeHandle to TypeDefn // Convert ConcreteTypeHandle to TypeDefn
let typeGenericArgsAsDefn = let typeGenericArgsAsDefn =
typeGenericArgs typeGenericArgs
|> Seq.map (fun handle -> |> ImmutableArray.map (fun handle ->
Concretization.concreteHandleToTypeDefn Concretization.concreteHandleToTypeDefn
baseClassTypes baseClassTypes
handle handle
state.ConcreteTypes state.ConcreteTypes
state._LoadedAssemblies state._LoadedAssemblies
) )
|> ImmutableArray.CreateRange
let methodGenericArgsAsDefn = let methodGenericArgsAsDefn =
methodGenericArgs methodGenericArgs
|> Seq.map (fun handle -> |> ImmutableArray.map (fun handle ->
Concretization.concreteHandleToTypeDefn Concretization.concreteHandleToTypeDefn
baseClassTypes baseClassTypes
handle handle
state.ConcreteTypes state.ConcreteTypes
state._LoadedAssemblies state._LoadedAssemblies
) )
|> ImmutableArray.CreateRange
resolveTypeFromDefn loggerFactory baseClassTypes sign typeGenericArgsAsDefn methodGenericArgsAsDefn assy state resolveTypeFromDefn loggerFactory baseClassTypes sign typeGenericArgsAsDefn methodGenericArgsAsDefn assy state
@@ -546,13 +516,13 @@ module IlMachineState =
/// Concretize a ConcreteType<TypeDefn> to get a ConcreteTypeHandle for static field access /// Concretize a ConcreteType<TypeDefn> to get a ConcreteTypeHandle for static field access
let concretizeFieldDeclaringType let concretizeFieldDeclaringType
(loggerFactory : ILoggerFactory) (loggerFactory : ILoggerFactory)
(baseClassTypes : BaseClassTypes<'corelib>) (baseClassTypes : BaseClassTypes<DumpedAssembly>)
(declaringType : ConcreteType<TypeDefn>) (declaringType : ConcreteType<TypeDefn>)
(state : IlMachineState) (state : IlMachineState)
: ConcreteTypeHandle * IlMachineState : ConcreteTypeHandle * IlMachineState
= =
// Create a concretization context from the current state // Create a concretization context from the current state
let ctx : TypeConcretization.ConcretizationContext<'corelib> = let ctx : TypeConcretization.ConcretizationContext<_> =
{ {
InProgress = ImmutableDictionary.Empty InProgress = ImmutableDictionary.Empty
ConcreteTypes = state.ConcreteTypes ConcreteTypes = state.ConcreteTypes
@@ -1484,6 +1454,48 @@ module IlMachineState =
let getSyncBlock (addr : ManagedHeapAddress) (state : IlMachineState) : SyncBlock = let getSyncBlock (addr : ManagedHeapAddress) (state : IlMachineState) : SyncBlock =
state.ManagedHeap |> ManagedHeap.getSyncBlock addr 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 = let executeDelegateConstructor (instruction : MethodState) (state : IlMachineState) : IlMachineState =
// We've been called with arguments already popped from the stack into local arguments. // We've been called with arguments already popped from the stack into local arguments.
let constructing = instruction.Arguments.[0] let constructing = instruction.Arguments.[0]
@@ -1666,42 +1678,7 @@ module IlMachineState =
: IlMachineState * TypeDefn : IlMachineState * TypeDefn
= =
let defn = activeAssy.TypeDefs.[typeDef] let defn = activeAssy.TypeDefs.[typeDef]
state, DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies defn
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
let lookupTypeRef let lookupTypeRef
(loggerFactory : ILoggerFactory) (loggerFactory : ILoggerFactory)
@@ -1729,25 +1706,4 @@ module IlMachineState =
let state, assy, resolved = let state, assy, resolved =
resolveTypeFromRef loggerFactory activeAssy ref typeGenerics state resolveTypeFromRef loggerFactory activeAssy ref typeGenerics state
let baseType = state, DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies resolved, assy
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"

View File

@@ -17,11 +17,7 @@ module IlMachineStateExecution =
= =
match esv with match esv with
| EvalStackValue.Int32 _ -> | EvalStackValue.Int32 _ ->
TypeDefn.FromDefinition ( DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Int32
ComparableTypeDefinitionHandle.Make baseClassTypes.Int32.TypeDefHandle,
baseClassTypes.Corelib.Name.FullName,
SignatureTypeKind.ValueType
)
|> IlMachineState.concretizeType |> IlMachineState.concretizeType
baseClassTypes baseClassTypes
state state
@@ -29,11 +25,7 @@ module IlMachineStateExecution =
ImmutableArray.Empty ImmutableArray.Empty
ImmutableArray.Empty ImmutableArray.Empty
| EvalStackValue.Int64 _ -> | EvalStackValue.Int64 _ ->
TypeDefn.FromDefinition ( DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Int64
ComparableTypeDefinitionHandle.Make baseClassTypes.Int64.TypeDefHandle,
baseClassTypes.Corelib.Name.FullName,
SignatureTypeKind.ValueType
)
|> IlMachineState.concretizeType |> IlMachineState.concretizeType
baseClassTypes baseClassTypes
state state
@@ -42,11 +34,7 @@ module IlMachineStateExecution =
ImmutableArray.Empty ImmutableArray.Empty
| EvalStackValue.NativeInt nativeIntSource -> failwith "todo" | EvalStackValue.NativeInt nativeIntSource -> failwith "todo"
| EvalStackValue.Float _ -> | EvalStackValue.Float _ ->
TypeDefn.FromDefinition ( DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Double
ComparableTypeDefinitionHandle.Make baseClassTypes.Double.TypeDefHandle,
baseClassTypes.Corelib.Name.FullName,
SignatureTypeKind.ValueType
)
|> IlMachineState.concretizeType |> IlMachineState.concretizeType
baseClassTypes baseClassTypes
state state
@@ -579,30 +567,8 @@ module IlMachineStateExecution =
typeDef.Name 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 baseTypeDefn =
let baseTypeDef = sourceAssembly.TypeDefs.[typeDefinitionHandle] DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies typeDef
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
)
// Concretize the base type // Concretize the base type
let state, baseTypeHandle = let state, baseTypeHandle =
@@ -640,22 +606,8 @@ module IlMachineStateExecution =
// Create a TypeDefn from the resolved TypeRef // Create a TypeDefn from the resolved TypeRef
let baseTypeDefn = let baseTypeDefn =
let baseType = targetType
targetType.BaseType |> DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies
|> 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
)
// Concretize the base type // Concretize the base type
let state, baseTypeHandle = let state, baseTypeHandle =

View File

@@ -76,6 +76,7 @@ module Intrinsics =
| [ field ] -> go field.ContentsEval | [ field ] -> go field.ContentsEval
| _ -> failwith $"TODO: %O{vt}" | _ -> failwith $"TODO: %O{vt}"
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: throw NRE" | EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: throw NRE"
| EvalStackValue.ObjectRef addr
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr) -> Some addr | EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr) -> Some addr
| s -> failwith $"TODO: called with unrecognised arg %O{s}" | s -> failwith $"TODO: called with unrecognised arg %O{s}"
@@ -228,7 +229,10 @@ module Intrinsics =
let arg1 = ManagedHeap.get arg1 state.ManagedHeap let arg1 = ManagedHeap.get arg1 state.ManagedHeap
let arg2 = ManagedHeap.get arg2 state.ManagedHeap let arg2 = ManagedHeap.get arg2 state.ManagedHeap
if AllocatedNonArrayObject.DereferenceField "_firstChar" arg1 <> AllocatedNonArrayObject.DereferenceField "_firstChar" arg2 then if
AllocatedNonArrayObject.DereferenceField "_firstChar" arg1
<> AllocatedNonArrayObject.DereferenceField "_firstChar" arg2
then
state state
|> IlMachineState.pushToEvalStack (CliType.ofBool false) currentThread |> IlMachineState.pushToEvalStack (CliType.ofBool false) currentThread
|> IlMachineState.advanceProgramCounter currentThread |> IlMachineState.advanceProgramCounter currentThread

View File

@@ -17,6 +17,29 @@ type AllocatedNonArrayObject =
// TODO: this is wrong, it doesn't account for overlapping fields // TODO: this is wrong, it doesn't account for overlapping fields
f.Fields |> List.find (fun f -> f.Name = name) |> _.Contents 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 = type AllocatedArray =
{ {
Length : int Length : int
@@ -125,6 +148,12 @@ module ManagedHeap =
// TODO: arrays too // TODO: arrays too
heap.NonArrayObjects.[alloc] 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 setArrayValue (alloc : ManagedHeapAddress) (offset : int) (v : CliType) (heap : ManagedHeap) : ManagedHeap =
let newArrs = let newArrs =
heap.Arrays heap.Arrays

View File

@@ -112,7 +112,7 @@ module NullaryIlOp =
} }
| ManagedPointerSource.Heap managedHeapAddress -> failwith "todo" | ManagedPointerSource.Heap managedHeapAddress -> failwith "todo"
| ManagedPointerSource.ArrayIndex _ -> failwith "todo" | ManagedPointerSource.ArrayIndex _ -> failwith "todo"
| Field (managedPointerSource, fieldName) -> failwith "todo" | ManagedPointerSource.Field (managedPointerSource, fieldName) -> failwith "todo"
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo" | EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
let internal ldElem let internal ldElem

View File

@@ -16,11 +16,7 @@ module Program =
: ManagedHeapAddress * IlMachineState : ManagedHeapAddress * IlMachineState
= =
let state, stringType = let state, stringType =
TypeDefn.FromDefinition ( DumpedAssembly.typeInfoToTypeDefn' corelib state._LoadedAssemblies corelib.String
ComparableTypeDefinitionHandle.Make corelib.String.TypeDefHandle,
corelib.Corelib.Name.FullName,
SignatureTypeKind.Class
)
|> IlMachineState.concretizeType |> IlMachineState.concretizeType
corelib corelib
state state
@@ -126,7 +122,7 @@ module Program =
let rec go state = let rec go state =
// Resolve the type reference to find which assembly it's in // Resolve the type reference to find which assembly it's in
match match
Assembly.resolveTypeRef state._LoadedAssemblies currentAssembly typeRef ImmutableArray.Empty Assembly.resolveTypeRef state._LoadedAssemblies currentAssembly ImmutableArray.Empty typeRef
with with
| TypeResolutionResult.FirstLoadAssy assyRef -> | TypeResolutionResult.FirstLoadAssy assyRef ->
// Need to load this assembly first // Need to load this assembly first

View File

@@ -107,8 +107,8 @@ module internal UnaryConstIlOp =
| EvalStackValue.NativeInt i -> not (NativeIntSource.isZero i) | EvalStackValue.NativeInt i -> not (NativeIntSource.isZero i)
| EvalStackValue.Float f -> failwith "TODO: Brfalse_s float semantics undocumented" | EvalStackValue.Float f -> failwith "TODO: Brfalse_s float semantics undocumented"
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false | EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false
| EvalStackValue.ObjectRef _
| EvalStackValue.ManagedPointer _ -> true | EvalStackValue.ManagedPointer _ -> true
| EvalStackValue.ObjectRef _ -> failwith "TODO: Brfalse_s ObjectRef comparison unimplemented"
| EvalStackValue.UserDefinedValueType _ -> | EvalStackValue.UserDefinedValueType _ ->
failwith "TODO: Brfalse_s UserDefinedValueType comparison unimplemented" failwith "TODO: Brfalse_s UserDefinedValueType comparison unimplemented"
@@ -129,8 +129,8 @@ module internal UnaryConstIlOp =
| EvalStackValue.NativeInt i -> not (NativeIntSource.isZero i) | EvalStackValue.NativeInt i -> not (NativeIntSource.isZero i)
| EvalStackValue.Float f -> failwith "TODO: Brtrue_s float semantics undocumented" | EvalStackValue.Float f -> failwith "TODO: Brtrue_s float semantics undocumented"
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false | EvalStackValue.ManagedPointer ManagedPointerSource.Null -> false
| EvalStackValue.ManagedPointer _ | EvalStackValue.ObjectRef _
| EvalStackValue.ObjectRef _ -> true | EvalStackValue.ManagedPointer _ -> true
| EvalStackValue.UserDefinedValueType _ -> | EvalStackValue.UserDefinedValueType _ ->
failwith "TODO: Brtrue_s UserDefinedValueType comparison unimplemented" failwith "TODO: Brtrue_s UserDefinedValueType comparison unimplemented"
@@ -422,7 +422,7 @@ module internal UnaryConstIlOp =
| EvalStackValue.Float v1, _ -> failwith $"invalid comparison, {v1} with {value2}" | EvalStackValue.Float v1, _ -> failwith $"invalid comparison, {v1} with {value2}"
| EvalStackValue.NativeInt v1, EvalStackValue.NativeInt v2 -> v1 <> v2 | EvalStackValue.NativeInt v1, EvalStackValue.NativeInt v2 -> v1 <> v2
| EvalStackValue.ManagedPointer ptr1, EvalStackValue.ManagedPointer ptr2 -> ptr1 <> ptr2 | EvalStackValue.ManagedPointer ptr1, EvalStackValue.ManagedPointer ptr2 -> ptr1 <> ptr2
| EvalStackValue.ObjectRef p1, EvalStackValue.ObjectRef p2 -> p1 <> p2 | EvalStackValue.ObjectRef ptr1, EvalStackValue.ObjectRef ptr2 -> ptr1 <> ptr2
| _, _ -> failwith $"TODO {value1} {value2} (see table III.4)" | _, _ -> failwith $"TODO {value1} {value2} (see table III.4)"
state state

View File

@@ -455,22 +455,10 @@ module internal UnaryMetadataIlOp =
let activeAssy = state.ActiveAssembly thread let activeAssy = state.ActiveAssembly thread
let ty = activeAssy.TypeDefs.[td] let ty = activeAssy.TypeDefs.[td]
let baseTy = let result =
DumpedAssembly.resolveBaseType DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies ty
baseClassTypes
state._LoadedAssemblies
activeAssy.Name
ty.BaseType
let sigType = state, result
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)
| MetadataToken.TypeSpecification handle -> | MetadataToken.TypeSpecification handle ->
state, state.ActiveAssembly(thread).TypeSpecs.[handle].Signature state, state.ActiveAssembly(thread).TypeSpecs.[handle].Signature
| MetadataToken.TypeReference handle -> | MetadataToken.TypeReference handle ->
@@ -482,22 +470,7 @@ module internal UnaryMetadataIlOp =
ImmutableArray.Empty ImmutableArray.Empty
state state
let baseTy = state, DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies resol
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
)
| m -> failwith $"unexpected metadata token {m} in IsInst" | m -> failwith $"unexpected metadata token {m} in IsInst"
let state, targetConcreteType = let state, targetConcreteType =
@@ -515,6 +488,7 @@ module internal UnaryMetadataIlOp =
// null IsInstance check always succeeds and results in a null reference // null IsInstance check always succeeds and results in a null reference
EvalStackValue.ManagedPointer ManagedPointerSource.Null EvalStackValue.ManagedPointer ManagedPointerSource.Null
| EvalStackValue.ManagedPointer (ManagedPointerSource.LocalVariable _) -> failwith "TODO" | EvalStackValue.ManagedPointer (ManagedPointerSource.LocalVariable _) -> failwith "TODO"
| EvalStackValue.ObjectRef addr
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr) -> | EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr) ->
match state.ManagedHeap.NonArrayObjects.TryGetValue addr with match state.ManagedHeap.NonArrayObjects.TryGetValue addr with
| true, v -> | true, v ->
@@ -822,8 +796,11 @@ module internal UnaryMetadataIlOp =
IlMachineState.pushToEvalStack currentValue thread state IlMachineState.pushToEvalStack currentValue thread state
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> | EvalStackValue.ManagedPointer ManagedPointerSource.Null ->
failwith "TODO: raise NullReferenceException" failwith "TODO: raise NullReferenceException"
| EvalStackValue.ManagedPointer (ManagedPointerSource.Field _) -> | EvalStackValue.ManagedPointer (ManagedPointerSource.Field (src, fieldName)) ->
failwith "TODO: get a field on a field ptr" let currentValue =
IlMachineState.getFieldValue src fieldName state |> CliType.getField field.Name
IlMachineState.pushToEvalStack currentValue thread state
| EvalStackValue.UserDefinedValueType vt -> | EvalStackValue.UserDefinedValueType vt ->
let result = vt |> EvalStackValueUserType.DereferenceField field.Name let result = vt |> EvalStackValueUserType.DereferenceField field.Name
@@ -834,70 +811,51 @@ module internal UnaryMetadataIlOp =
|> Tuple.withRight WhatWeDid.Executed |> Tuple.withRight WhatWeDid.Executed
| Ldflda -> | 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 = let state, field =
match metadataToken with match metadataToken with
| MetadataToken.FieldDefinition f -> | MetadataToken.FieldDefinition f ->
let field = activeAssy.Fields.[f] let field =
// Map the field to have TypeDefn type parameters activeAssy.Fields.[f]
let mappedField = |> FieldInfo.mapTypeGenerics (fun _ -> failwith "no generics allowed on FieldDefinition")
field |> FieldInfo.mapTypeGenerics (fun i _ -> TypeDefn.GenericTypeParameter i)
state, mappedField state, field
| MetadataToken.MemberReference m -> | MetadataToken.MemberReference mr ->
let state, _, resolved, _ = let state, assyName, field, _ =
// TODO: generics
IlMachineState.resolveMember IlMachineState.resolveMember
loggerFactory loggerFactory
baseClassTypes baseClassTypes
thread thread
activeAssy activeAssy
ImmutableArray.Empty ImmutableArray.Empty
m mr
state state
match resolved with match field with
| Choice1Of2 _method -> failwith "member reference was unexpectedly a method"
| Choice2Of2 field -> state, field | Choice2Of2 field -> state, field
| Choice1Of2 _ -> failwith "Expected field in Ldflda but got method" | t -> failwith $"Unexpectedly asked to load from a non-field: {t}"
| _ -> failwith $"Unexpected in Ldflda: {metadataToken}"
let source, state = IlMachineState.popEvalStack thread state let result =
ManagedPointerSource.Field (ptr, field.Name) |> EvalStackValue.ManagedPointer
// Ldflda needs to return a pointer to the field within the object/struct
let toPush =
match source with
| EvalStackValue.ObjectRef heapAddr ->
// For object references, we need to create a pointer to the field
// TODO: The current ManagedPointerSource doesn't have a case for field pointers
// We're using Heap pointer for now, but this doesn't capture the field offset
// This will need to be enhanced to support field-specific pointers
ManagedPointerSource.Heap heapAddr |> EvalStackValue.ManagedPointer
| EvalStackValue.ManagedPointer ptr ->
// If we already have a managed pointer, we need to handle field access
// through that pointer. For now, return the same pointer type
// TODO: This needs to track the field offset within the pointed-to object
match ptr with
| ManagedPointerSource.Null -> failwith "TODO: NullReferenceException in Ldflda"
| _ -> ptr |> EvalStackValue.ManagedPointer
| EvalStackValue.NativeInt (NativeIntSource.ManagedPointer ptr) ->
// Unmanaged pointer input produces unmanaged pointer output
// TODO: This also needs field offset tracking
match ptr with
| ManagedPointerSource.Null -> failwith "TODO: NullReferenceException in Ldflda"
| _ -> ptr |> NativeIntSource.ManagedPointer |> EvalStackValue.NativeInt
| EvalStackValue.NativeInt (NativeIntSource.Verbatim _) ->
// Native int that's not from a managed pointer
// This represents an unmanaged pointer scenario
failwith "TODO: Ldflda with unmanaged pointer - not allowed in verifiable code"
| EvalStackValue.UserDefinedValueType vt ->
// For value types on the stack, we need to store them somewhere
// and return a pointer to the field
// This is complex because we need to materialize the value type
failwith "TODO: Ldflda on value type - need to allocate temporary storage and create field pointer"
| _ -> failwith $"unexpected Ldflda source: {source}"
state state
|> IlMachineState.pushToEvalStack' toPush thread |> IlMachineState.pushToEvalStack' result thread
|> IlMachineState.advanceProgramCounter thread |> IlMachineState.advanceProgramCounter thread
|> Tuple.withRight WhatWeDid.Executed |> Tuple.withRight WhatWeDid.Executed
| Ldsfld -> | Ldsfld ->
let state, field = let state, field =
match metadataToken with match metadataToken with
@@ -1026,12 +984,7 @@ module internal UnaryMetadataIlOp =
| _ -> failwith $"expected heap allocation for array, got {arr}" | _ -> failwith $"expected heap allocation for array, got {arr}"
let elementType = let elementType =
TypeInfo.toTypeDefn DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies elementType
baseClassTypes
_.Name
(fun x y -> x.TypeDefs.[y])
(fun x y -> x.TypeRefs.[y] |> failwithf "%+A")
elementType
let state, zeroOfType = let state, zeroOfType =
IlMachineState.cliTypeZeroOf IlMachineState.cliTypeZeroOf
@@ -1100,12 +1053,18 @@ module internal UnaryMetadataIlOp =
IlMachineState.pushToEvalStack toPush thread state IlMachineState.pushToEvalStack toPush thread state
|> IlMachineState.advanceProgramCounter thread |> IlMachineState.advanceProgramCounter thread
|> Tuple.withRight WhatWeDid.Executed |> Tuple.withRight WhatWeDid.Executed
| Initobj -> | Initobj ->
let addr, state = IlMachineState.popEvalStack thread state let popped, state = IlMachineState.popEvalStack thread state
let declaringTypeGenerics = currentMethod.DeclaringType.Generics let declaringTypeGenerics = currentMethod.DeclaringType.Generics
let state, assy, ty = let state, assy, targetType =
match metadataToken with match metadataToken with
| MetadataToken.TypeDefinition defn ->
state,
activeAssy,
activeAssy.TypeDefs.[defn]
|> TypeInfo.mapGeneric (fun (p, _) -> TypeDefn.GenericTypeParameter p.SequenceNumber)
| MetadataToken.TypeSpecification spec -> | MetadataToken.TypeSpecification spec ->
let state, assy, ty = let state, assy, ty =
IlMachineState.resolveTypeFromSpecConcrete IlMachineState.resolveTypeFromSpecConcrete
@@ -1118,68 +1077,47 @@ module internal UnaryMetadataIlOp =
state state
state, assy, ty state, assy, ty
| MetadataToken.TypeDefinition defn -> | x -> failwith $"TODO: Ldelem element type resolution unimplemented for {x}"
let state, assy, ty =
IlMachineState.resolveTypeFromDefnConcrete
loggerFactory
baseClassTypes
defn
activeAssy
declaringTypeGenerics
currentMethod.Generics
state
state, assy, ty let targetType =
| x -> failwith $"unexpected in Initobj: %O{x}" targetType
|> DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies
let state, zeroOfType =
IlMachineState.cliTypeZeroOf
loggerFactory
baseClassTypes
assy
targetType
declaringTypeGenerics
ImmutableArray.Empty
state
let state = let state =
match addr with 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 -> | EvalStackValue.ManagedPointer src ->
match src with match src with
| ManagedPointerSource.Null -> failwith "TODO: probably NRE here"
| ManagedPointerSource.Heap _ -> failwith "TODO: heap"
| ManagedPointerSource.LocalVariable (thread, frame, var) -> | ManagedPointerSource.LocalVariable (thread, frame, var) ->
// Create zero-initialized fields based on the type info state |> IlMachineState.setLocalVariable thread frame var zeroOfType
let state, zeroFields = | ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) -> failwith "todo"
((state, []), ty.Fields) | ManagedPointerSource.ArrayIndex (arr, index) ->
||> List.fold (fun (state, acc) field -> state |> IlMachineState.setArrayValue arr zeroOfType index
// Concretize the field type | ManagedPointerSource.Field (managedPointerSource, fieldName) ->
let state, fieldHandle = state |> IlMachineState.setFieldValue managedPointerSource zeroOfType fieldName
IlMachineState.concretizeType | ManagedPointerSource.Null -> failwith "runtime error: unexpectedly Initobj'ing null"
baseClassTypes | ManagedPointerSource.Heap _ -> failwith "logic error"
state | EvalStackValue.UserDefinedValueType evalStackValueUserType -> failwith "todo"
assy.Name
declaringTypeGenerics
currentMethod.Generics
field.Signature
// Get zero value for the field type
let zero, state =
IlMachineState.cliTypeZeroOfHandle state baseClassTypes fieldHandle
let field =
{
Name = field.Name
Contents = zero
Offset = field.Offset
}
state, field :: acc
)
|> fun (state, fields) -> state, List.rev fields
// Create the value type with zero-initialized fields
let newValue = zeroFields |> CliValueType.OfFields |> CliType.ValueType
state |> IlMachineState.setLocalVariable thread frame var newValue
| ManagedPointerSource.Argument (thread, frame, arg) -> failwith "TODO: Argument"
| ManagedPointerSource.ArrayIndex (arr, index) -> failwith "todo: array index"
| Field (managedPointerSource, fieldName) -> failwith "todo"
| addr -> failwith $"Bad address in Initobj: {addr}"
state state
|> IlMachineState.advanceProgramCounter thread |> IlMachineState.advanceProgramCounter thread
|> Tuple.withRight WhatWeDid.Executed |> Tuple.withRight WhatWeDid.Executed
| Ldsflda -> | Ldsflda ->
// TODO: check whether we should throw FieldAccessException // TODO: check whether we should throw FieldAccessException
@@ -1342,25 +1280,8 @@ module internal UnaryMetadataIlOp =
methodGenerics methodGenerics
state 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 = let typeDefn =
TypeDefn.FromDefinition ( DumpedAssembly.typeInfoToTypeDefn baseClassTypes state._LoadedAssemblies typeDefn
ComparableTypeDefinitionHandle.Make typeDefn.TypeDefHandle,
assy.Name.FullName,
stk
)
let state, handle = let state, handle =
IlMachineState.concretizeType IlMachineState.concretizeType
@@ -1419,7 +1340,9 @@ module internal UnaryMetadataIlOp =
IlMachineState.pushToEvalStack (CliType.ValueType vt) thread state IlMachineState.pushToEvalStack (CliType.ValueType vt) thread state
| MetadataToken.TypeDefinition h -> | MetadataToken.TypeDefinition h ->
let state, typeDefn = IlMachineState.lookupTypeDefn baseClassTypes state activeAssy h let state, typeDefn =
IlMachineState.lookupTypeDefn baseClassTypes state activeAssy h
handleTypeToken typeDefn state handleTypeToken typeDefn state
| _ -> failwith $"Unexpected metadata token %O{metadataToken} in LdToken" | _ -> failwith $"Unexpected metadata token %O{metadataToken} in LdToken"

View File

@@ -64,11 +64,7 @@ module internal UnaryStringTokenIlOp =
] ]
let state, stringType = let state, stringType =
TypeDefn.FromDefinition ( DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.String
ComparableTypeDefinitionHandle.Make baseClassTypes.String.TypeDefHandle,
baseClassTypes.Corelib.Name.FullName,
SignatureTypeKind.Class
)
|> IlMachineState.concretizeType |> IlMachineState.concretizeType
baseClassTypes baseClassTypes
state state