mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-12-14 21:45:39 +00:00
Progress towards the GenericEdgeCases test (#96)
This commit is contained in:
@@ -565,6 +565,7 @@ module DumpedAssembly =
|
||||
(bct : BaseClassTypes<DumpedAssembly>)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(ti : TypeInfo<TypeDefn, TypeDefn>)
|
||||
: TypeDefn
|
||||
=
|
||||
ti
|
||||
|> TypeInfo.toTypeDefn
|
||||
|
||||
@@ -183,6 +183,24 @@ module ConcreteActivePatterns =
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|ConcreteGenericArray|_|)
|
||||
(concreteTypes : AllConcreteTypes)
|
||||
(eltType : ConcreteTypeHandle)
|
||||
(handle : ConcreteTypeHandle)
|
||||
=
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Concrete id ->
|
||||
match concreteTypes.Mapping |> Map.tryFind id with
|
||||
| Some ct when
|
||||
ct.Assembly.Name = "System.Private.CoreLib"
|
||||
&& ct.Namespace = "System"
|
||||
&& ct.Name = "Array"
|
||||
&& Seq.tryExactlyOne ct.Generics = Some eltType
|
||||
->
|
||||
Some ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
let (|ConcreteObj|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) : unit option =
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Concrete id ->
|
||||
@@ -302,6 +320,23 @@ module ConcreteActivePatterns =
|
||||
| None -> None
|
||||
| _ -> None
|
||||
|
||||
let (|ConcreteUInt32|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) : unit option =
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Concrete id ->
|
||||
match concreteTypes.Mapping |> Map.tryFind id with
|
||||
| Some ct ->
|
||||
if
|
||||
ct.Assembly.Name = "System.Private.CoreLib"
|
||||
&& ct.Namespace = "System"
|
||||
&& ct.Name = "UInt32"
|
||||
&& ct.Generics.IsEmpty
|
||||
then
|
||||
Some ()
|
||||
else
|
||||
None
|
||||
| None -> None
|
||||
| _ -> None
|
||||
|
||||
let (|ConcreteSingle|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) : unit option =
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Concrete id ->
|
||||
@@ -331,6 +366,13 @@ module ConcreteActivePatterns =
|
||||
| ConcreteTypeHandle.Pointer inner -> Some inner
|
||||
| _ -> None
|
||||
|
||||
type IAssemblyLoad =
|
||||
abstract LoadAssembly :
|
||||
loadedAssemblies : ImmutableDictionary<string, DumpedAssembly> ->
|
||||
referencedIn : AssemblyName ->
|
||||
handle : AssemblyReferenceHandle ->
|
||||
ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module TypeConcretization =
|
||||
|
||||
@@ -406,8 +448,7 @@ module TypeConcretization =
|
||||
|
||||
// Helper function for assembly loading with retry pattern
|
||||
let private loadAssemblyAndResolveTypeRef
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(loadAssembly : IAssemblyLoad)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(currentAssembly : AssemblyName)
|
||||
(typeRef : TypeRef)
|
||||
@@ -428,7 +469,8 @@ module TypeConcretization =
|
||||
// Need to load the assembly
|
||||
match typeRef.ResolutionScope with
|
||||
| TypeRefResolutionScope.Assembly assyRef ->
|
||||
let newAssemblies, _ = loadAssembly currentAssembly assyRef
|
||||
let newAssemblies, _ =
|
||||
loadAssembly.LoadAssembly ctx.LoadedAssemblies currentAssembly assyRef
|
||||
|
||||
let newCtx =
|
||||
{ ctx with
|
||||
@@ -584,8 +626,7 @@ module TypeConcretization =
|
||||
ImmutableArray.Empty // No generic parameters
|
||||
|
||||
let private concretizeTypeReference
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(loadAssembly : IAssemblyLoad)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(currentAssembly : AssemblyName)
|
||||
(typeRef : TypeRef)
|
||||
@@ -609,8 +650,7 @@ module TypeConcretization =
|
||||
/// Concretize a type in a specific generic context
|
||||
let rec concretizeType
|
||||
(ctx : ConcretizationContext<DumpedAssembly>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(loadAssembly : IAssemblyLoad)
|
||||
(assembly : AssemblyName)
|
||||
(typeGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
@@ -706,8 +746,7 @@ module TypeConcretization =
|
||||
|
||||
and private concretizeGenericInstantiation
|
||||
(ctx : ConcretizationContext<DumpedAssembly>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(loadAssembly : IAssemblyLoad)
|
||||
(assembly : AssemblyName)
|
||||
(typeGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
@@ -786,7 +825,8 @@ module TypeConcretization =
|
||||
|
||||
| false, _ ->
|
||||
// Need to load the assembly
|
||||
let newAssemblies, loadedAssy = loadAssembly assembly assyRef
|
||||
let newAssemblies, loadedAssy =
|
||||
loadAssembly.LoadAssembly ctx.LoadedAssemblies assembly assyRef
|
||||
|
||||
let ctxWithNewAssy =
|
||||
{ ctxAfterArgs with
|
||||
@@ -865,8 +905,7 @@ module Concretization =
|
||||
/// Helper to concretize an array of types
|
||||
let private concretizeTypeArray
|
||||
(ctx : TypeConcretization.ConcretizationContext<DumpedAssembly>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(loadAssembly : IAssemblyLoad)
|
||||
(assembly : AssemblyName)
|
||||
(typeArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
@@ -889,8 +928,7 @@ module Concretization =
|
||||
/// Helper to concretize a method signature
|
||||
let private concretizeMethodSignature
|
||||
(ctx : TypeConcretization.ConcretizationContext<DumpedAssembly>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(loadAssembly : IAssemblyLoad)
|
||||
(assembly : AssemblyName)
|
||||
(typeArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
@@ -926,8 +964,7 @@ module Concretization =
|
||||
|
||||
/// Helper to ensure base type assembly is loaded
|
||||
let rec private ensureBaseTypeAssembliesLoaded
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(loadAssembly : IAssemblyLoad)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(assyName : AssemblyName)
|
||||
(baseTypeInfo : BaseTypeInfo option)
|
||||
@@ -947,7 +984,7 @@ module Concretization =
|
||||
| true, _ -> assemblies
|
||||
| false, _ ->
|
||||
// Need to load the assembly - pass the assembly that contains the reference
|
||||
let newAssemblies, _ = loadAssembly assy.Name assyRef
|
||||
let newAssemblies, _ = loadAssembly.LoadAssembly assemblies assy.Name assyRef
|
||||
newAssemblies
|
||||
| _ -> assemblies
|
||||
| Some (BaseTypeInfo.TypeDef _)
|
||||
@@ -957,8 +994,7 @@ module Concretization =
|
||||
/// Concretize a method's signature and body
|
||||
let concretizeMethod
|
||||
(ctx : AllConcreteTypes)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(loadAssembly : IAssemblyLoad)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(baseTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(method : WoofWare.PawPrint.MethodInfo<'ty, GenericParamFromMetadata, TypeDefn>)
|
||||
|
||||
@@ -22,12 +22,17 @@ module TestPureCases =
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "InitializeArray.cs"
|
||||
FileName = "OverlappingStructs.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "GenericEdgeCases.cs"
|
||||
FileName = "AdvancedStructLayout.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "InitializeArray.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
@@ -57,12 +62,7 @@ module TestPureCases =
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "AdvancedStructLayout.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "OverlappingStructs.cs"
|
||||
FileName = "GenericEdgeCases.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
@@ -80,6 +80,11 @@ module TestPureCases =
|
||||
ExpectedReturnCode = 1
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "Initobj.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "TestShl.cs"
|
||||
ExpectedReturnCode = 0
|
||||
@@ -165,11 +170,6 @@ module TestPureCases =
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
{
|
||||
FileName = "Initobj.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
}
|
||||
]
|
||||
|
||||
let runTest (case : EndToEndTestCase) : unit =
|
||||
|
||||
@@ -54,7 +54,7 @@ module AbstractMachine =
|
||||
// We've been instructed to run a delegate.
|
||||
let delegateToRunAddr =
|
||||
match instruction.Arguments.[0] with
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.Heap addr))
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed (ManagedPointerSource.Heap addr))
|
||||
| CliType.ObjectRef (Some addr) -> addr
|
||||
| _ -> failwith "expected a managed object ref to delegate"
|
||||
|
||||
@@ -222,5 +222,5 @@ module AbstractMachine =
|
||||
|> ExecutionResult.Stepped
|
||||
| IlOp.Switch immutableArray -> failwith "TODO: Switch unimplemented"
|
||||
| IlOp.UnaryStringToken (unaryStringTokenIlOp, stringHandle) ->
|
||||
UnaryStringTokenIlOp.execute baseClassTypes unaryStringTokenIlOp stringHandle state thread
|
||||
UnaryStringTokenIlOp.execute loggerFactory baseClassTypes unaryStringTokenIlOp stringHandle state thread
|
||||
|> ExecutionResult.Stepped
|
||||
|
||||
@@ -43,6 +43,7 @@ type ManagedPointerSource =
|
||||
| ArrayIndex of arr : ManagedHeapAddress * index : int
|
||||
| Field of ManagedPointerSource * fieldName : string
|
||||
| Null
|
||||
| InterpretedAsType of ManagedPointerSource * ConcreteType<ConcreteTypeHandle>
|
||||
|
||||
override this.ToString () =
|
||||
match this with
|
||||
@@ -54,6 +55,7 @@ type ManagedPointerSource =
|
||||
$"<argument %i{var} in method frame %i{method} of thread %O{source}>"
|
||||
| ManagedPointerSource.ArrayIndex (arr, index) -> $"<index %i{index} of array %O{arr}>"
|
||||
| ManagedPointerSource.Field (source, name) -> $"<field %s{name} of %O{source}>"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> $"<%O{src} as %s{ty.Namespace}.%s{ty.Name}>"
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type UnsignedNativeIntSource =
|
||||
@@ -115,46 +117,9 @@ type CliNumericType =
|
||||
| Float32 of float32
|
||||
| Float64 of float
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
type CliRuntimePointerSource =
|
||||
| LocalVariable of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
||||
| Argument of sourceThread : ThreadId * methodFrame : int * whichVar : uint16
|
||||
| Field of source : CliRuntimePointerSource * fieldName : string
|
||||
| Heap of ManagedHeapAddress
|
||||
| ArrayIndex of arr : ManagedHeapAddress * index : int
|
||||
| Null
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module CliRuntimePointerSource =
|
||||
let rec ofManagedPointerSource (ptrSource : ManagedPointerSource) : CliRuntimePointerSource =
|
||||
match ptrSource with
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, whichVar)
|
||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
||||
CliRuntimePointerSource.Argument (sourceThread, methodFrame, whichVar)
|
||||
| ManagedPointerSource.Heap managedHeapAddress -> CliRuntimePointerSource.Heap managedHeapAddress
|
||||
| ManagedPointerSource.Null -> CliRuntimePointerSource.Null
|
||||
| ManagedPointerSource.ArrayIndex (arr, ind) -> CliRuntimePointerSource.ArrayIndex (arr, ind)
|
||||
| ManagedPointerSource.Field (a, ind) ->
|
||||
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
|
||||
| Managed of CliRuntimePointerSource
|
||||
| Managed of ManagedPointerSource
|
||||
|
||||
/// This is the kind of type that can be stored in arguments, local variables, statics, array elements, fields.
|
||||
type CliType =
|
||||
@@ -257,7 +222,7 @@ module CliType =
|
||||
| PrimitiveType.IntPtr ->
|
||||
{
|
||||
Name = "_value"
|
||||
Contents = CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null)
|
||||
Contents = CliType.RuntimePointer (CliRuntimePointer.Managed ManagedPointerSource.Null)
|
||||
Offset = Some 0
|
||||
}
|
||||
|> List.singleton
|
||||
@@ -266,7 +231,7 @@ module CliType =
|
||||
| PrimitiveType.UIntPtr ->
|
||||
{
|
||||
Name = "_value"
|
||||
Contents = CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null)
|
||||
Contents = CliType.RuntimePointer (CliRuntimePointer.Managed ManagedPointerSource.Null)
|
||||
Offset = Some 0
|
||||
}
|
||||
|> List.singleton
|
||||
@@ -296,7 +261,7 @@ module CliType =
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Byref _ ->
|
||||
// Byref types are managed references - the zero value is a null reference
|
||||
CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null), concreteTypes
|
||||
CliType.RuntimePointer (CliRuntimePointer.Managed ManagedPointerSource.Null), concreteTypes
|
||||
|
||||
| ConcreteTypeHandle.Pointer _ ->
|
||||
// Pointer types are unmanaged pointers - the zero value is a null pointer
|
||||
@@ -460,20 +425,22 @@ module CliType =
|
||||
// The field type might reference generic parameters of the declaring type
|
||||
let methodGenerics = ImmutableArray.Empty // Fields don't have method generics
|
||||
|
||||
let loadAssembly
|
||||
(assyName : AssemblyName)
|
||||
(ref : AssemblyReferenceHandle)
|
||||
: ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly
|
||||
=
|
||||
match assemblies.TryGetValue assyName.FullName with
|
||||
| true, currentAssy ->
|
||||
let targetAssyRef = currentAssy.AssemblyReferences.[ref]
|
||||
let loadAssembly =
|
||||
{ new IAssemblyLoad with
|
||||
member _.LoadAssembly loaded assyName ref =
|
||||
match loaded.TryGetValue assyName.FullName with
|
||||
| true, currentAssy ->
|
||||
let targetAssyRef = currentAssy.AssemblyReferences.[ref]
|
||||
|
||||
match assemblies.TryGetValue targetAssyRef.Name.FullName with
|
||||
| true, targetAssy -> assemblies, targetAssy
|
||||
| false, _ ->
|
||||
failwithf "Assembly %s not loaded when trying to resolve reference" targetAssyRef.Name.FullName
|
||||
| false, _ -> failwithf "Current assembly %s not loaded when trying to resolve reference" assyName.FullName
|
||||
match loaded.TryGetValue targetAssyRef.Name.FullName with
|
||||
| true, targetAssy -> loaded, targetAssy
|
||||
| false, _ ->
|
||||
failwithf
|
||||
"Assembly %s not loaded when trying to resolve reference"
|
||||
targetAssyRef.Name.FullName
|
||||
| false, _ ->
|
||||
failwithf "Current assembly %s not loaded when trying to resolve reference" assyName.FullName
|
||||
}
|
||||
|
||||
let handle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
|
||||
@@ -6,6 +6,7 @@ type IArithmeticOperation =
|
||||
abstract Int32Int32 : int32 -> int32 -> int32
|
||||
abstract Int64Int64 : int64 -> int64 -> int64
|
||||
abstract FloatFloat : float -> float -> float
|
||||
abstract NativeIntNativeInt : nativeint -> nativeint -> nativeint
|
||||
abstract Name : string
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
@@ -15,6 +16,7 @@ module ArithmeticOperation =
|
||||
member _.Int32Int32 a b = (# "add" a b : int32 #)
|
||||
member _.Int64Int64 a b = (# "add" a b : int64 #)
|
||||
member _.FloatFloat a b = (# "add" a b : float #)
|
||||
member _.NativeIntNativeInt a b = (# "add" a b : nativeint #)
|
||||
member _.Name = "add"
|
||||
}
|
||||
|
||||
@@ -23,6 +25,7 @@ module ArithmeticOperation =
|
||||
member _.Int32Int32 a b = (# "sub" a b : int32 #)
|
||||
member _.Int64Int64 a b = (# "sub" a b : int64 #)
|
||||
member _.FloatFloat a b = (# "sub" a b : float #)
|
||||
member _.NativeIntNativeInt a b = (# "sub" a b : nativeint #)
|
||||
member _.Name = "sub"
|
||||
}
|
||||
|
||||
@@ -31,9 +34,19 @@ module ArithmeticOperation =
|
||||
member _.Int32Int32 a b = (# "mul" a b : int32 #)
|
||||
member _.Int64Int64 a b = (# "mul" a b : int64 #)
|
||||
member _.FloatFloat a b = (# "mul" a b : float #)
|
||||
member _.NativeIntNativeInt a b = (# "mul" a b : nativeint #)
|
||||
member _.Name = "mul"
|
||||
}
|
||||
|
||||
let mulOvf =
|
||||
{ new IArithmeticOperation with
|
||||
member _.Int32Int32 a b = (# "mul.ovf" a b : int32 #)
|
||||
member _.Int64Int64 a b = (# "mul.ovf" a b : int64 #)
|
||||
member _.FloatFloat a b = (# "mul.ovf" a b : float #)
|
||||
member _.NativeIntNativeInt a b = (# "mul.ovf" a b : nativeint #)
|
||||
member _.Name = "mul_ovf"
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module BinaryArithmetic =
|
||||
let execute (op : IArithmeticOperation) (val1 : EvalStackValue) (val2 : EvalStackValue) : EvalStackValue =
|
||||
@@ -45,7 +58,21 @@ module BinaryArithmetic =
|
||||
| EvalStackValue.Int32 val1, EvalStackValue.ObjectRef val2 -> failwith "" |> EvalStackValue.ObjectRef
|
||||
| EvalStackValue.Int64 val1, EvalStackValue.Int64 val2 -> op.Int64Int64 val1 val2 |> EvalStackValue.Int64
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.Int32 val2 -> failwith "" |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.NativeInt val2 -> failwith "" |> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.NativeInt val2 ->
|
||||
let val1 =
|
||||
match val1 with
|
||||
| NativeIntSource.Verbatim n -> nativeint<int64> n
|
||||
| v -> failwith $"refusing to multiply non-verbatim native int %O{v}"
|
||||
|
||||
let val2 =
|
||||
match val2 with
|
||||
| NativeIntSource.Verbatim n -> nativeint<int64> n
|
||||
| v -> failwith $"refusing to multiply non-verbatim native int %O{v}"
|
||||
|
||||
op.NativeIntNativeInt val1 val2
|
||||
|> int64<nativeint>
|
||||
|> NativeIntSource.Verbatim
|
||||
|> EvalStackValue.NativeInt
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.ManagedPointer val2 ->
|
||||
failwith "" |> EvalStackValue.ManagedPointer
|
||||
| EvalStackValue.NativeInt val1, EvalStackValue.ObjectRef val2 -> failwith "" |> EvalStackValue.ObjectRef
|
||||
|
||||
@@ -8,8 +8,6 @@ type EvalStackValue =
|
||||
| Float of float
|
||||
| ManagedPointer of ManagedPointerSource
|
||||
| ObjectRef of ManagedHeapAddress
|
||||
// Fraser thinks this isn't really a thing in CoreCLR
|
||||
// | TransientPointer of TransientPointerSource
|
||||
| UserDefinedValueType of EvalStackValueUserType
|
||||
|
||||
override this.ToString () =
|
||||
@@ -137,7 +135,20 @@ module EvalStackValue =
|
||||
match popped.Fields with
|
||||
| [] -> failwith "unexpectedly empty"
|
||||
| [ popped ] -> toCliTypeCoerced target popped.ContentsEval
|
||||
| _ -> failwith $"TODO: %O{target}"
|
||||
| fields ->
|
||||
match fields.[0].Offset with
|
||||
| None -> failwith "TODO"
|
||||
| Some _ ->
|
||||
let fields =
|
||||
fields
|
||||
|> List.map (fun f ->
|
||||
match f.Offset with
|
||||
| None -> failwith "unexpectedly got a field which didn't have an offset"
|
||||
| Some offset -> offset, f
|
||||
)
|
||||
|> List.sortBy fst
|
||||
|
||||
failwith "TODO"
|
||||
| i -> failwith $"TODO: %O{i}"
|
||||
| CliNumericType.Int64 _ ->
|
||||
match popped with
|
||||
@@ -191,11 +202,9 @@ module EvalStackValue =
|
||||
| CliType.ObjectRef _ ->
|
||||
match popped with
|
||||
| EvalStackValue.ManagedPointer ptrSource ->
|
||||
CliRuntimePointerSource.ofManagedPointerSource ptrSource
|
||||
|> CliRuntimePointer.Managed
|
||||
|> CliType.RuntimePointer
|
||||
ptrSource |> CliRuntimePointer.Managed |> CliType.RuntimePointer
|
||||
| EvalStackValue.ObjectRef ptr ->
|
||||
CliRuntimePointerSource.Heap ptr
|
||||
ManagedPointerSource.Heap ptr
|
||||
|> CliRuntimePointer.Managed
|
||||
|> CliType.RuntimePointer
|
||||
| EvalStackValue.NativeInt nativeIntSource ->
|
||||
@@ -224,22 +233,16 @@ module EvalStackValue =
|
||||
| i -> failwith $"TODO: %O{i}"
|
||||
| CliType.RuntimePointer _ ->
|
||||
match popped with
|
||||
| EvalStackValue.ManagedPointer src ->
|
||||
CliRuntimePointerSource.ofManagedPointerSource src
|
||||
|> CliRuntimePointer.Managed
|
||||
|> CliType.RuntimePointer
|
||||
| EvalStackValue.ManagedPointer src -> src |> CliRuntimePointer.Managed |> CliType.RuntimePointer
|
||||
| EvalStackValue.NativeInt intSrc ->
|
||||
match intSrc with
|
||||
| NativeIntSource.Verbatim i -> CliType.RuntimePointer (CliRuntimePointer.Unmanaged i)
|
||||
| NativeIntSource.ManagedPointer src ->
|
||||
CliRuntimePointerSource.ofManagedPointerSource src
|
||||
|> CliRuntimePointer.Managed
|
||||
|> CliType.RuntimePointer
|
||||
| NativeIntSource.ManagedPointer src -> src |> CliRuntimePointer.Managed |> CliType.RuntimePointer
|
||||
| NativeIntSource.FunctionPointer methodInfo ->
|
||||
CliType.Numeric (CliNumericType.NativeInt (NativeIntSource.FunctionPointer methodInfo))
|
||||
| NativeIntSource.TypeHandlePtr int64 -> failwith "todo"
|
||||
| EvalStackValue.ObjectRef addr ->
|
||||
CliRuntimePointerSource.Heap addr
|
||||
ManagedPointerSource.Heap addr
|
||||
|> CliRuntimePointer.Managed
|
||||
|> CliType.RuntimePointer
|
||||
| _ -> failwith $"TODO: %O{popped}"
|
||||
@@ -307,21 +310,7 @@ module EvalStackValue =
|
||||
| CliType.RuntimePointer ptr ->
|
||||
match ptr with
|
||||
| CliRuntimePointer.Unmanaged ptrInt -> NativeIntSource.Verbatim ptrInt |> EvalStackValue.NativeInt
|
||||
| CliRuntimePointer.Managed ptr ->
|
||||
match ptr with
|
||||
| CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, var) ->
|
||||
ManagedPointerSource.LocalVariable (sourceThread, methodFrame, var)
|
||||
|> EvalStackValue.ManagedPointer
|
||||
| CliRuntimePointerSource.ArrayIndex (arr, ind) ->
|
||||
ManagedPointerSource.ArrayIndex (arr, ind) |> EvalStackValue.ManagedPointer
|
||||
| CliRuntimePointerSource.Argument (sourceThread, methodFrame, var) ->
|
||||
ManagedPointerSource.Argument (sourceThread, methodFrame, var)
|
||||
|> EvalStackValue.ManagedPointer
|
||||
| CliRuntimePointerSource.Heap addr -> EvalStackValue.ObjectRef addr
|
||||
| CliRuntimePointerSource.Null -> EvalStackValue.ManagedPointer ManagedPointerSource.Null
|
||||
| CliRuntimePointerSource.Field (source, fieldName) ->
|
||||
ManagedPointerSource.Field (CliRuntimePointerSource.toManagedPointerSource source, fieldName)
|
||||
|> EvalStackValue.ManagedPointer
|
||||
| CliRuntimePointer.Managed ptr -> ptr |> EvalStackValue.ManagedPointer
|
||||
| CliType.ValueType fields ->
|
||||
// TODO: this is a bit dubious; we're being a bit sloppy with possibly-overlapping fields here
|
||||
fields.Fields
|
||||
|
||||
@@ -173,6 +173,7 @@ module EvalStackValueComparisons =
|
||||
| ManagedPointerSource.LocalVariable _
|
||||
| ManagedPointerSource.Argument _ -> false
|
||||
| ManagedPointerSource.ArrayIndex (arr, index) -> failwith "todo"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> failwith "todo"
|
||||
| EvalStackValue.ObjectRef _, _ -> failwith $"bad ceq: ObjectRef vs {var2}"
|
||||
| EvalStackValue.ManagedPointer var1, EvalStackValue.ManagedPointer var2 -> var1 = var2
|
||||
| EvalStackValue.ManagedPointer var1, EvalStackValue.NativeInt var2 ->
|
||||
|
||||
@@ -89,6 +89,7 @@ module System_Threading_Monitor =
|
||||
| ManagedPointerSource.Heap addr -> failwith "todo: managed heap"
|
||||
| ManagedPointerSource.ArrayIndex _ -> failwith "todo: array index"
|
||||
| ManagedPointerSource.Field (managedPointerSource, fieldName) -> failwith "todo"
|
||||
| ManagedPointerSource.InterpretedAsType _ -> failwith "TODO"
|
||||
|
||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||
|
||||
|
||||
@@ -149,7 +149,73 @@ type StateLoadResult =
|
||||
module IlMachineState =
|
||||
type private Dummy = class end
|
||||
|
||||
let private loadAssembly'
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(dotnetRuntimeDirs : string seq)
|
||||
(referencedInAssembly : DumpedAssembly)
|
||||
(r : AssemblyReferenceHandle)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
=
|
||||
let assemblyRef = referencedInAssembly.AssemblyReferences.[r]
|
||||
let assemblyName = assemblyRef.Name
|
||||
|
||||
match assemblies.TryGetValue assemblyName.FullName with
|
||||
| true, v -> v, assemblyName
|
||||
| false, _ ->
|
||||
let logger = loggerFactory.CreateLogger typeof<Dummy>.DeclaringType
|
||||
|
||||
let assy =
|
||||
dotnetRuntimeDirs
|
||||
|> Seq.choose (fun dir ->
|
||||
let file = Path.Combine (dir, assemblyName.Name + ".dll")
|
||||
|
||||
try
|
||||
use f = File.OpenRead file
|
||||
logger.LogInformation ("Loading assembly from file {AssemblyFileLoadPath}", file)
|
||||
Assembly.read loggerFactory (Some file) f |> Some
|
||||
with :? FileNotFoundException ->
|
||||
None
|
||||
)
|
||||
|> Seq.toList
|
||||
|
||||
match assy |> List.tryHead with
|
||||
| None -> failwith $"Could not find a readable DLL in any runtime dir with name %s{assemblyName.Name}.dll"
|
||||
| Some assy -> assy, assemblyName
|
||||
|
||||
/// <summary>
|
||||
/// Create a new IlMachineState which has loaded the given assembly.
|
||||
/// This involves reading assemblies from the disk and doing a complete parse of them, so it might be quite slow!
|
||||
///
|
||||
/// This function doesn't do anything if the referenced assembly has already been loaded.
|
||||
/// </summary>
|
||||
/// <param name="loggerFactory">LoggerFactory into which to emit logs.</param>
|
||||
/// <param name="referencedInAssembly">The assembly which contains an AssemblyReference which causes us to want to load a new assembly.</param>
|
||||
/// <param name="r">The AssemblyReferenceHandle pointing at an assembly we want to load. *Important*: this is an AssemblyReferenceHandle from <c>referencedInAssembly</c>; in general, AssemblyReferenceHandles are only well-defined if you know what assembly they were defined in.</param>
|
||||
/// <param name="state">The immutable state to augment with the new assembly.</param>
|
||||
let loadAssembly
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(referencedInAssembly : DumpedAssembly)
|
||||
(r : AssemblyReferenceHandle)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * AssemblyName
|
||||
=
|
||||
let dumped, assy =
|
||||
loadAssembly' loggerFactory state.DotnetRuntimeDirs referencedInAssembly r state._LoadedAssemblies
|
||||
|
||||
state.WithLoadedAssembly assy dumped, dumped, assy
|
||||
|
||||
let private loader (loggerFactory : ILoggerFactory) (state : IlMachineState) : IAssemblyLoad =
|
||||
{ new IAssemblyLoad with
|
||||
member _.LoadAssembly loaded assyName ref =
|
||||
let targetAssy, name =
|
||||
loadAssembly' loggerFactory state.DotnetRuntimeDirs loaded.[assyName.FullName] ref loaded
|
||||
|
||||
let newAssys = loaded.SetItem (name.FullName, targetAssy)
|
||||
newAssys, targetAssy
|
||||
}
|
||||
|
||||
let concretizeType
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(state : IlMachineState)
|
||||
(declaringAssembly : AssemblyName)
|
||||
@@ -169,14 +235,7 @@ module IlMachineState =
|
||||
let handle, ctx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun assyName ref ->
|
||||
let currentAssy = state.LoadedAssembly assyName |> Option.get
|
||||
|
||||
let targetAssy =
|
||||
currentAssy.AssemblyReferences.[ref].Name |> state.LoadedAssembly |> Option.get
|
||||
|
||||
state._LoadedAssemblies, targetAssy
|
||||
)
|
||||
(loader loggerFactory state)
|
||||
declaringAssembly
|
||||
typeGenerics
|
||||
methodGenerics
|
||||
@@ -190,51 +249,6 @@ module IlMachineState =
|
||||
|
||||
state, handle
|
||||
|
||||
/// <summary>
|
||||
/// Create a new IlMachineState which has loaded the given assembly.
|
||||
/// This involves reading assemblies from the disk and doing a complete parse of them, so it might be quite slow!
|
||||
///
|
||||
/// This function doesn't do anything if the referenced assembly has already been loaded.
|
||||
/// </summary>
|
||||
/// <param name="loggerFactory">LoggerFactory into which to emit logs.</param>
|
||||
/// <param name="referencedInAssembly">The assembly which contains an AssemblyReference which causes us to want to load a new assembly.</param>
|
||||
/// <param name="r">The AssemblyReferenceHandle pointing at an assembly we want to load. *Important*: this is an AssemblyReferenceHandle from <c>referencedInAssembly</c>; in general, AssemblyReferenceHandles are only well-defined if you know what assembly they were defined in.</param>
|
||||
/// <param name="state">The immutable state to augment with the new assembly.</param>
|
||||
let loadAssembly
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(referencedInAssembly : DumpedAssembly)
|
||||
(r : AssemblyReferenceHandle)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * AssemblyName
|
||||
=
|
||||
let assemblyRef = referencedInAssembly.AssemblyReferences.[r]
|
||||
let assemblyName = assemblyRef.Name
|
||||
|
||||
match state.LoadedAssembly assemblyName with
|
||||
| Some v -> state, v, assemblyName
|
||||
| None ->
|
||||
let logger = loggerFactory.CreateLogger typeof<Dummy>.DeclaringType
|
||||
|
||||
let assy =
|
||||
state.DotnetRuntimeDirs
|
||||
|> Seq.choose (fun dir ->
|
||||
let file = Path.Combine (dir, assemblyName.Name + ".dll")
|
||||
|
||||
try
|
||||
use f = File.OpenRead file
|
||||
logger.LogInformation ("Loading assembly from file {AssemblyFileLoadPath}", file)
|
||||
Assembly.read loggerFactory (Some file) f |> Some
|
||||
with :? FileNotFoundException ->
|
||||
None
|
||||
)
|
||||
|> Seq.toList
|
||||
|
||||
match assy |> List.tryHead with
|
||||
| None -> failwith $"Could not find a readable DLL in any runtime dir with name %s{assemblyName.Name}.dll"
|
||||
| Some assy ->
|
||||
|
||||
state.WithLoadedAssembly assemblyName assy, assy, assemblyName
|
||||
|
||||
let rec internal resolveTypeFromName
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(ns : string option)
|
||||
@@ -440,6 +454,54 @@ module IlMachineState =
|
||||
|
||||
resolveTypeFromDefn loggerFactory baseClassTypes sign typeGenericArgsAsDefn methodGenericArgsAsDefn assy state
|
||||
|
||||
/// Resolve a TypeDefinition using concrete type handles from execution context
|
||||
let resolveTypeFromDefnConcrete
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : TypeDefinitionHandle)
|
||||
(assy : DumpedAssembly)
|
||||
(typeGenericArgs : ConcreteTypeHandle ImmutableArray)
|
||||
(methodGenericArgs : ConcreteTypeHandle ImmutableArray)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
let typeDef = assy.TypeDefs.[ty]
|
||||
|
||||
// Convert ConcreteTypeHandle to TypeDefn for the generics
|
||||
let typeGenericArgsAsDefn =
|
||||
typeGenericArgs
|
||||
|> Seq.map (fun handle ->
|
||||
Concretization.concreteHandleToTypeDefn
|
||||
baseClassTypes
|
||||
handle
|
||||
state.ConcreteTypes
|
||||
state._LoadedAssemblies
|
||||
)
|
||||
|> ImmutableArray.CreateRange
|
||||
|
||||
let methodGenericArgsAsDefn =
|
||||
methodGenericArgs
|
||||
|> Seq.map (fun handle ->
|
||||
Concretization.concreteHandleToTypeDefn
|
||||
baseClassTypes
|
||||
handle
|
||||
state.ConcreteTypes
|
||||
state._LoadedAssemblies
|
||||
)
|
||||
|> ImmutableArray.CreateRange
|
||||
|
||||
// Map the type definition's generics using the provided type generic arguments
|
||||
let resolvedTypeDef =
|
||||
typeDef
|
||||
|> TypeInfo.mapGeneric (fun (param, _) ->
|
||||
if param.SequenceNumber < typeGenericArgsAsDefn.Length then
|
||||
typeGenericArgsAsDefn.[param.SequenceNumber]
|
||||
else
|
||||
failwithf "Generic type parameter %d out of range" param.SequenceNumber
|
||||
)
|
||||
|
||||
state, assy, resolvedTypeDef
|
||||
|
||||
/// Get zero value for a type that's already been concretized
|
||||
let cliTypeZeroOfHandle
|
||||
(state : IlMachineState)
|
||||
@@ -482,26 +544,6 @@ module IlMachineState =
|
||||
BaseTypes = baseClassTypes
|
||||
}
|
||||
|
||||
// Helper function to get assembly from reference
|
||||
let loadAssembly
|
||||
(currentAssembly : AssemblyName)
|
||||
(assyRef : AssemblyReferenceHandle)
|
||||
: ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly
|
||||
=
|
||||
let assyToLoad =
|
||||
match state.LoadedAssembly currentAssembly with
|
||||
| Some assy -> assy
|
||||
| None -> failwithf "Assembly %s not loaded" currentAssembly.FullName
|
||||
|
||||
let referencedAssy = assyToLoad.AssemblyReferences.[assyRef]
|
||||
|
||||
match state.LoadedAssembly referencedAssy.Name with
|
||||
| Some assy -> state._LoadedAssemblies, assy
|
||||
| None ->
|
||||
// Need to load the assembly
|
||||
let newState, loadedAssy, _ = loadAssembly loggerFactory assyToLoad assyRef state
|
||||
newState._LoadedAssemblies, loadedAssy
|
||||
|
||||
// Concretize each generic argument first
|
||||
let mutable currentCtx = ctx
|
||||
let genericHandles = ImmutableArray.CreateBuilder declaringType.Generics.Length
|
||||
@@ -510,7 +552,7 @@ module IlMachineState =
|
||||
let handle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
currentCtx
|
||||
loadAssembly
|
||||
(loader loggerFactory state)
|
||||
declaringType.Assembly
|
||||
ImmutableArray.Empty // No type generics in this context
|
||||
ImmutableArray.Empty // No method generics in this context
|
||||
@@ -522,12 +564,13 @@ module IlMachineState =
|
||||
// Now we need to concretize the type definition itself
|
||||
// If it's a non-generic type, we can use concretizeTypeDefinition directly
|
||||
if declaringType.Generics.IsEmpty then
|
||||
let handle, newCtx =
|
||||
let handle, currentCtx =
|
||||
TypeConcretization.concretizeTypeDefinition currentCtx declaringType.Assembly declaringType.Definition
|
||||
|
||||
let newState =
|
||||
{ state with
|
||||
ConcreteTypes = newCtx.ConcreteTypes
|
||||
ConcreteTypes = currentCtx.ConcreteTypes
|
||||
_LoadedAssemblies = currentCtx.LoadedAssemblies
|
||||
}
|
||||
|
||||
handle, newState
|
||||
@@ -583,7 +626,7 @@ module IlMachineState =
|
||||
state.WithLoadedAssembly assy.Name assy
|
||||
|
||||
let state, handle =
|
||||
concretizeType baseClassTypes state assy.Name typeGenerics methodGenerics ty
|
||||
concretizeType loggerFactory baseClassTypes state assy.Name typeGenerics methodGenerics ty
|
||||
|
||||
// Now get the zero value
|
||||
let zero, state = cliTypeZeroOfHandle state baseClassTypes handle
|
||||
@@ -759,22 +802,7 @@ module IlMachineState =
|
||||
let concretizedMethod, newConcreteTypes, newAssemblies =
|
||||
Concretization.concretizeMethod
|
||||
state.ConcreteTypes
|
||||
(fun assyName ref ->
|
||||
match state.LoadedAssembly assyName with
|
||||
| Some currentAssy ->
|
||||
let targetAssyRef = currentAssy.AssemblyReferences.[ref]
|
||||
|
||||
match state.LoadedAssembly targetAssyRef.Name with
|
||||
| Some _ ->
|
||||
// Assembly already loaded, return existing state
|
||||
state._LoadedAssemblies, state._LoadedAssemblies.[targetAssyRef.Name.FullName]
|
||||
| None ->
|
||||
// Need to load the assembly
|
||||
let newState, loadedAssy, _ = loadAssembly loggerFactory currentAssy ref state
|
||||
newState._LoadedAssemblies, loadedAssy
|
||||
| None ->
|
||||
failwithf "Current assembly %s not loaded when trying to resolve reference" assyName.FullName
|
||||
)
|
||||
(loader loggerFactory state)
|
||||
state._LoadedAssemblies
|
||||
baseClassTypes
|
||||
methodToCall
|
||||
@@ -820,6 +848,7 @@ module IlMachineState =
|
||||
for i = 0 to generics.Length - 1 do
|
||||
let state2, handle =
|
||||
concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
callingAssembly
|
||||
@@ -875,14 +904,7 @@ module IlMachineState =
|
||||
let handle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun assyName ref ->
|
||||
let currentAssy = state.LoadedAssembly assyName |> Option.get
|
||||
|
||||
let targetAssy =
|
||||
currentAssy.AssemblyReferences.[ref].Name |> state.LoadedAssembly |> Option.get
|
||||
|
||||
state._LoadedAssemblies, targetAssy
|
||||
)
|
||||
(loader loggerFactory state)
|
||||
(state.ActiveAssembly thread).Name
|
||||
ImmutableArray.Empty // No type generics for the concretization context
|
||||
ImmutableArray.Empty // No method generics for the concretization context
|
||||
@@ -893,6 +915,7 @@ module IlMachineState =
|
||||
state <-
|
||||
{ state with
|
||||
ConcreteTypes = newCtx.ConcreteTypes
|
||||
_LoadedAssemblies = newCtx.LoadedAssemblies
|
||||
}
|
||||
|
||||
handles.ToImmutable (), state
|
||||
@@ -997,14 +1020,7 @@ module IlMachineState =
|
||||
let declaringHandle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun assyName ref ->
|
||||
let currentAssy = state.LoadedAssembly assyName |> Option.get
|
||||
|
||||
let targetAssy =
|
||||
currentAssy.AssemblyReferences.[ref].Name |> state.LoadedAssembly |> Option.get
|
||||
|
||||
state._LoadedAssemblies, targetAssy
|
||||
)
|
||||
(loader loggerFactory state)
|
||||
field.DeclaringType.Assembly
|
||||
contextTypeGenerics
|
||||
contextMethodGenerics
|
||||
@@ -1190,6 +1206,7 @@ module IlMachineState =
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(currentThread : ThreadId)
|
||||
(assy : DumpedAssembly)
|
||||
(genericMethodTypeArgs : ImmutableArray<ConcreteTypeHandle>)
|
||||
(m : MemberReferenceHandle)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState *
|
||||
@@ -1253,6 +1270,7 @@ module IlMachineState =
|
||||
// TODO: generics?
|
||||
let state, t =
|
||||
concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
targetType.Assembly
|
||||
@@ -1270,6 +1288,7 @@ module IlMachineState =
|
||||
// Concretize the field signature from the member reference
|
||||
let state, concreteFieldSig =
|
||||
concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
(state.ActiveAssembly(currentThread).Name)
|
||||
@@ -1287,6 +1306,7 @@ module IlMachineState =
|
||||
// Concretize the field's signature for comparison
|
||||
let state, fieldSigConcrete =
|
||||
concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
assy.Name
|
||||
@@ -1324,11 +1344,12 @@ module IlMachineState =
|
||||
state
|
||||
(fun state ty ->
|
||||
concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
(state.ActiveAssembly(currentThread).Name)
|
||||
concreteExtractedTypeArgs
|
||||
ImmutableArray.Empty
|
||||
genericMethodTypeArgs
|
||||
ty
|
||||
)
|
||||
|
||||
@@ -1341,11 +1362,12 @@ module IlMachineState =
|
||||
state
|
||||
(fun state ty ->
|
||||
concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
assy.Name
|
||||
concreteExtractedTypeArgs
|
||||
ImmutableArray.Empty
|
||||
genericMethodTypeArgs
|
||||
ty
|
||||
)
|
||||
|
||||
@@ -1417,6 +1439,7 @@ module IlMachineState =
|
||||
| ManagedPointerSource.ArrayIndex (arr, index) -> getArrayValue arr index state |> CliType.getField fieldName
|
||||
| ManagedPointerSource.Field (src, fieldName) -> failwith "todo"
|
||||
| ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> failwith "TODO"
|
||||
|
||||
let setFieldValue
|
||||
(obj : ManagedPointerSource)
|
||||
@@ -1446,6 +1469,7 @@ module IlMachineState =
|
||||
state |> setArrayValue arr v index
|
||||
| ManagedPointerSource.Field (managedPointerSource, fieldName) -> failwith "todo"
|
||||
| ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> failwith "TODO"
|
||||
|
||||
let executeDelegateConstructor (instruction : MethodState) (state : IlMachineState) : IlMachineState =
|
||||
// We've been called with arguments already popped from the stack into local arguments.
|
||||
@@ -1455,17 +1479,17 @@ module IlMachineState =
|
||||
|
||||
let targetObj =
|
||||
match targetObj with
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.Heap target))
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed (ManagedPointerSource.Heap target))
|
||||
| CliType.ObjectRef (Some target) -> Some target
|
||||
| CliType.ObjectRef None
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null) -> None
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed ManagedPointerSource.Null) -> None
|
||||
| _ -> failwith $"Unexpected target type for delegate: {targetObj}"
|
||||
|
||||
let constructing =
|
||||
match constructing with
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null)
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed ManagedPointerSource.Null)
|
||||
| CliType.ObjectRef None -> failwith "unexpectedly constructing the null delegate"
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.Heap target))
|
||||
| CliType.RuntimePointer (CliRuntimePointer.Managed (ManagedPointerSource.Heap target))
|
||||
| CliType.ObjectRef (Some target) -> target
|
||||
| _ -> failwith $"Unexpectedly not constructing a managed object: {constructing}"
|
||||
|
||||
@@ -1507,6 +1531,7 @@ module IlMachineState =
|
||||
|
||||
/// Returns the type handle and an allocated System.RuntimeType.
|
||||
let getOrAllocateType
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(defn : ConcreteTypeHandle)
|
||||
(state : IlMachineState)
|
||||
@@ -1518,7 +1543,13 @@ module IlMachineState =
|
||||
baseClassTypes.Corelib.Name.FullName,
|
||||
SignatureTypeKind.Class
|
||||
)
|
||||
|> concretizeType baseClassTypes state baseClassTypes.Corelib.Name ImmutableArray.Empty ImmutableArray.Empty
|
||||
|> concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
baseClassTypes.Corelib.Name
|
||||
ImmutableArray.Empty
|
||||
ImmutableArray.Empty
|
||||
|
||||
let result, reg, state =
|
||||
TypeHandleRegistry.getOrAllocate
|
||||
@@ -1562,7 +1593,13 @@ module IlMachineState =
|
||||
baseClassTypes.Corelib.Name.FullName,
|
||||
SignatureTypeKind.Class
|
||||
)
|
||||
|> concretizeType baseClassTypes state baseClassTypes.Corelib.Name ImmutableArray.Empty ImmutableArray.Empty
|
||||
|> concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
baseClassTypes.Corelib.Name
|
||||
ImmutableArray.Empty
|
||||
ImmutableArray.Empty
|
||||
|
||||
let result, reg, state =
|
||||
FieldHandleRegistry.getOrAllocate
|
||||
@@ -1620,6 +1657,7 @@ module IlMachineState =
|
||||
match obj with
|
||||
| CliType.ValueType vt -> vt |> CliValueType.DereferenceField name
|
||||
| v -> failwith $"could not find field {name} on object {v}"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> failwith "TODO"
|
||||
|
||||
let lookupTypeDefn
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
|
||||
@@ -10,6 +10,7 @@ open Microsoft.Extensions.Logging
|
||||
[<RequireQualifiedAccess>]
|
||||
module IlMachineStateExecution =
|
||||
let getTypeOfObj
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(state : IlMachineState)
|
||||
(esv : EvalStackValue)
|
||||
@@ -19,6 +20,7 @@ module IlMachineStateExecution =
|
||||
| EvalStackValue.Int32 _ ->
|
||||
DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Int32
|
||||
|> IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
baseClassTypes.Corelib.Name
|
||||
@@ -27,6 +29,7 @@ module IlMachineStateExecution =
|
||||
| EvalStackValue.Int64 _ ->
|
||||
DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Int64
|
||||
|> IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
baseClassTypes.Corelib.Name
|
||||
@@ -36,6 +39,7 @@ module IlMachineStateExecution =
|
||||
| EvalStackValue.Float _ ->
|
||||
DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.Double
|
||||
|> IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
baseClassTypes.Corelib.Name
|
||||
@@ -51,6 +55,7 @@ module IlMachineStateExecution =
|
||||
| ManagedPointerSource.ArrayIndex (arr, index) -> failwith "todo"
|
||||
| ManagedPointerSource.Null -> failwith "todo"
|
||||
| ManagedPointerSource.Field (managedPointerSource, fieldName) -> failwith "todo"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> failwith "todo"
|
||||
| EvalStackValue.ObjectRef addr ->
|
||||
let o = ManagedHeap.get addr state.ManagedHeap
|
||||
state, o.ConcreteType
|
||||
@@ -113,16 +118,13 @@ module IlMachineStateExecution =
|
||||
|
||||
match
|
||||
if isIntrinsic then
|
||||
Intrinsics.call baseClassTypes methodToCall thread state
|
||||
Intrinsics.call loggerFactory baseClassTypes methodToCall thread state
|
||||
else
|
||||
None
|
||||
with
|
||||
| Some result -> result
|
||||
| None ->
|
||||
|
||||
if methodToCall.Name = "GetValue" then
|
||||
printfn ""
|
||||
|
||||
// Get zero values for all parameters
|
||||
let state, argZeroObjects =
|
||||
((state, []), methodToCall.Signature.ParameterTypes)
|
||||
@@ -156,7 +158,8 @@ module IlMachineStateExecution =
|
||||
| None -> failwith "unexpectedly no `this` on the eval stack of instance method"
|
||||
| Some this -> this
|
||||
|
||||
let state, callingObjTyHandle = getTypeOfObj baseClassTypes state callingObj
|
||||
let state, callingObjTyHandle =
|
||||
getTypeOfObj loggerFactory baseClassTypes state callingObj
|
||||
|
||||
let callingObjTy =
|
||||
let ty =
|
||||
@@ -200,6 +203,7 @@ module IlMachineStateExecution =
|
||||
let state, retType =
|
||||
meth.Signature.ReturnType
|
||||
|> IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
meth.DeclaringType.Assembly
|
||||
@@ -211,6 +215,7 @@ module IlMachineStateExecution =
|
||||
||> Seq.mapFold (fun state ty ->
|
||||
ty
|
||||
|> IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
meth.DeclaringType.Assembly
|
||||
@@ -407,7 +412,7 @@ module IlMachineStateExecution =
|
||||
// where Newobj puts the object pointer on top
|
||||
let thisArg, newState =
|
||||
popAndCoerceArg
|
||||
(CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null))
|
||||
(CliType.RuntimePointer (CliRuntimePointer.Managed ManagedPointerSource.Null))
|
||||
currentState
|
||||
|
||||
currentState <- newState
|
||||
@@ -430,7 +435,7 @@ module IlMachineStateExecution =
|
||||
|
||||
let thisArg, newState =
|
||||
popAndCoerceArg
|
||||
(CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null))
|
||||
(CliType.RuntimePointer (CliRuntimePointer.Managed ManagedPointerSource.Null))
|
||||
currentState
|
||||
|
||||
args.Add thisArg
|
||||
@@ -573,6 +578,7 @@ module IlMachineStateExecution =
|
||||
// Concretize the base type
|
||||
let state, baseTypeHandle =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
sourceAssembly.Name
|
||||
@@ -612,6 +618,7 @@ module IlMachineStateExecution =
|
||||
// Concretize the base type
|
||||
let state, baseTypeHandle =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
sourceAssembly.Name
|
||||
@@ -663,6 +670,7 @@ module IlMachineStateExecution =
|
||||
state
|
||||
(fun state typeDefn ->
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
concreteType.Assembly
|
||||
@@ -687,6 +695,7 @@ module IlMachineStateExecution =
|
||||
||> Seq.fold (fun (state, acc) typeDefn ->
|
||||
let state, handle =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
concreteType.Assembly
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
open System
|
||||
open System.Collections.Immutable
|
||||
open Microsoft.Extensions.Logging
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Intrinsics =
|
||||
@@ -14,10 +16,97 @@ module Intrinsics =
|
||||
"System.Private.CoreLib", "ArgumentNullException", "ThrowIfNull"
|
||||
// https://github.com/dotnet/runtime/blob/ec11903827fc28847d775ba17e0cd1ff56cfbc2e/src/coreclr/System.Private.CoreLib/src/System/Type.CoreCLR.cs#L82
|
||||
"System.Private.CoreLib", "Type", "GetTypeFromHandle"
|
||||
// https://github.com/dotnet/runtime/blob/108fa7856efcfd39bc991c2d849eabbf7ba5989c/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs#L161
|
||||
"System.Private.CoreLib", "ReadOnlySpan`1", "get_Length"
|
||||
// https://github.com/dotnet/runtime/blob/9e5e6aa7bc36aeb2a154709a9d1192030c30a2ef/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs#L153
|
||||
"System.Private.CoreLib", "RuntimeHelpers", "CreateSpan"
|
||||
// https://github.com/dotnet/runtime/blob/d258af50034c192bf7f0a18856bf83d2903d98ae/src/libraries/System.Private.CoreLib/src/System/Math.cs#L127
|
||||
// https://github.com/dotnet/runtime/blob/d258af50034c192bf7f0a18856bf83d2903d98ae/src/libraries/System.Private.CoreLib/src/System/Math.cs#L137
|
||||
"System.Private.CoreLib", "Math", "Abs"
|
||||
// https://github.com/dotnet/runtime/blob/d258af50034c192bf7f0a18856bf83d2903d98ae/src/libraries/System.Private.CoreLib/src/System/Math.cs#L965C10-L1062C19
|
||||
"System.Private.CoreLib", "Math", "Max"
|
||||
// https://github.com/dotnet/runtime/blob/d258af50034c192bf7f0a18856bf83d2903d98ae/src/libraries/System.Private.CoreLib/src/System/Buffer.cs#L150
|
||||
"System.Private.CoreLib", "Buffer", "Memmove"
|
||||
]
|
||||
|> Set.ofList
|
||||
|
||||
type private RefTypeProcessingStatus =
|
||||
| InProgress
|
||||
| Completed of bool
|
||||
|
||||
let rec private containsRefType
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(state : IlMachineState)
|
||||
(seenSoFar : ImmutableDictionary<TypeInfo<TypeDefn, TypeDefn>, RefTypeProcessingStatus>)
|
||||
(td : TypeInfo<TypeDefn, TypeDefn>)
|
||||
: IlMachineState * ImmutableDictionary<_, RefTypeProcessingStatus> * bool
|
||||
=
|
||||
match seenSoFar.TryGetValue td with
|
||||
| true, InProgress ->
|
||||
// We've hit a cycle. Optimistically assume this path does not introduce a reference type.
|
||||
// If another path finds a reference type, its 'true' will override this.
|
||||
state, seenSoFar, false
|
||||
| true, Completed v ->
|
||||
// We've already calculated this; return the memoized result.
|
||||
state, seenSoFar, v
|
||||
| false, _ ->
|
||||
// Check if this type itself is a reference type.
|
||||
let baseType =
|
||||
td.BaseType
|
||||
|> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies td.Assembly
|
||||
|
||||
match baseType with
|
||||
| ResolvedBaseType.Delegate
|
||||
| ResolvedBaseType.Object ->
|
||||
// Short-circuit: if the type itself is a reference type, we're done.
|
||||
let seenSoFar = seenSoFar.Add (td, Completed true)
|
||||
state, seenSoFar, true
|
||||
| ResolvedBaseType.Enum
|
||||
| ResolvedBaseType.ValueType ->
|
||||
// It's a value type, so we must check its fields.
|
||||
// Mark as in progress before recursing.
|
||||
let seenSoFarWithInProgress = seenSoFar.Add (td, InProgress)
|
||||
|
||||
let stateAfterFieldResolution, nonStaticFields =
|
||||
((state, []), td.Fields)
|
||||
||> List.fold (fun (currentState, acc) field ->
|
||||
if field.IsStatic then
|
||||
currentState, acc
|
||||
else
|
||||
// TODO: generics
|
||||
let newState, _, info =
|
||||
IlMachineState.resolveTypeFromDefn
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
field.Signature
|
||||
ImmutableArray.Empty
|
||||
ImmutableArray.Empty
|
||||
(currentState.LoadedAssembly (td.Assembly) |> Option.get)
|
||||
currentState
|
||||
|
||||
newState, info :: acc
|
||||
)
|
||||
|
||||
// Recurse through the fields, correctly propagating state.
|
||||
let finalState, finalSeenSoFar, fieldsContainRefType =
|
||||
((stateAfterFieldResolution, seenSoFarWithInProgress, false), nonStaticFields)
|
||||
||> List.fold (fun (currentState, currentSeenSoFar, currentResult) field ->
|
||||
if currentResult then
|
||||
(currentState, currentSeenSoFar, true) // Short-circuit
|
||||
else
|
||||
let newState, newSeenSoFar, fieldResult =
|
||||
containsRefType loggerFactory baseClassTypes currentState currentSeenSoFar field
|
||||
|
||||
(newState, newSeenSoFar, currentResult || fieldResult)
|
||||
)
|
||||
|
||||
// Mark as completed with the final result before returning.
|
||||
let finalSeenSoFar = finalSeenSoFar.SetItem (td, Completed fieldsContainRefType)
|
||||
finalState, finalSeenSoFar, fieldsContainRefType
|
||||
|
||||
let call
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<_>)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<ConcreteTypeHandle, ConcreteTypeHandle, ConcreteTypeHandle>)
|
||||
(currentThread : ThreadId)
|
||||
@@ -99,21 +188,7 @@ module Intrinsics =
|
||||
|
||||
let toPush =
|
||||
match arg with
|
||||
| EvalStackValue.ManagedPointer ptr ->
|
||||
match ptr with
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
CliRuntimePointer.Managed (
|
||||
CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, whichVar)
|
||||
)
|
||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
||||
CliRuntimePointer.Managed (
|
||||
CliRuntimePointerSource.Argument (sourceThread, methodFrame, whichVar)
|
||||
)
|
||||
| ManagedPointerSource.Heap managedHeapAddress ->
|
||||
CliRuntimePointer.Managed (CliRuntimePointerSource.Heap managedHeapAddress)
|
||||
| ManagedPointerSource.Null -> failwith "todo"
|
||||
| ManagedPointerSource.ArrayIndex _ -> failwith "TODO"
|
||||
| ManagedPointerSource.Field _ -> failwith "TODO"
|
||||
| EvalStackValue.ManagedPointer ptr -> CliRuntimePointer.Managed ptr
|
||||
| x -> failwith $"TODO: Unsafe.AsPointer(%O{x})"
|
||||
|
||||
IlMachineState.pushToEvalStack (CliType.RuntimePointer toPush) currentThread state
|
||||
@@ -185,6 +260,44 @@ module Intrinsics =
|
||||
| EvalStackValue.Float f -> BitConverter.DoubleToInt64Bits f |> EvalStackValue.Int64
|
||||
| _ -> failwith "TODO"
|
||||
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' result currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Some
|
||||
| "System.Private.CoreLib", "BitConverter", "SingleToUInt32Bits" ->
|
||||
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||
| [ ConcreteSingle state.ConcreteTypes ], ConcreteUInt32 state.ConcreteTypes -> ()
|
||||
| _ -> failwith "bad signature BitConverter.SingleToUInt32Bits"
|
||||
|
||||
let arg, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let result =
|
||||
match arg with
|
||||
| EvalStackValue.Float f ->
|
||||
BitConverter.SingleToUInt32Bits (float32<float> f)
|
||||
|> int<uint32>
|
||||
|> EvalStackValue.Int32
|
||||
| _ -> failwith "TODO"
|
||||
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' result currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Some
|
||||
| "System.Private.CoreLib", "BitConverter", "UInt32BitsToSingle" ->
|
||||
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||
| [ ConcreteUInt32 state.ConcreteTypes ], ConcreteSingle state.ConcreteTypes -> ()
|
||||
| _ -> failwith "bad signature BitConverter.UInt32BitsToSingle"
|
||||
|
||||
let arg, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let result =
|
||||
match arg with
|
||||
| EvalStackValue.Int32 f ->
|
||||
BitConverter.UInt32BitsToSingle (uint32<int> f)
|
||||
|> float<float32>
|
||||
|> EvalStackValue.Float
|
||||
| _ -> failwith "TODO"
|
||||
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' result currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
@@ -299,15 +412,46 @@ module Intrinsics =
|
||||
| [], ConcreteBool state.ConcreteTypes -> ()
|
||||
| _ -> failwith "bad signature for System.Private.CoreLib.RuntimeHelpers.IsReferenceOrContainsReference"
|
||||
|
||||
let generic =
|
||||
AllConcreteTypes.lookup (Seq.exactlyOne methodToCall.Generics) state.ConcreteTypes
|
||||
let arg = Seq.exactlyOne methodToCall.Generics
|
||||
|
||||
let generic =
|
||||
match generic with
|
||||
| None -> failwith "somehow have not already concretised type in IsReferenceOrContainsReferences"
|
||||
| Some generic -> generic
|
||||
let state, result =
|
||||
// Some types appear circular, because they're hardcoded in the runtime. We have to special-case them.
|
||||
match arg with
|
||||
| ConcreteChar state.ConcreteTypes -> state, false
|
||||
| _ ->
|
||||
|
||||
failwith $"TODO: do the thing on %O{generic}"
|
||||
let generic = AllConcreteTypes.lookup arg state.ConcreteTypes
|
||||
|
||||
let generic =
|
||||
match generic with
|
||||
| None -> failwith "somehow have not already concretised type in IsReferenceOrContainsReferences"
|
||||
| Some generic -> generic
|
||||
|
||||
let td =
|
||||
state.LoadedAssembly generic.Assembly
|
||||
|> Option.get
|
||||
|> fun a -> a.TypeDefs.[generic.Definition.Get]
|
||||
|
||||
let baseType =
|
||||
td.BaseType
|
||||
|> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies generic.Assembly
|
||||
|
||||
match baseType with
|
||||
| ResolvedBaseType.Enum
|
||||
| ResolvedBaseType.ValueType ->
|
||||
td
|
||||
|> TypeInfo.mapGeneric (fun (par, _) -> TypeDefn.GenericTypeParameter par.SequenceNumber)
|
||||
|> containsRefType loggerFactory baseClassTypes state ImmutableDictionary.Empty
|
||||
|> fun (state, _, result) -> state, result
|
||||
| ResolvedBaseType.Object
|
||||
| ResolvedBaseType.Delegate -> state, true
|
||||
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack (CliType.ofBool result) currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
Some state
|
||||
| "System.Private.CoreLib", "RuntimeHelpers", "InitializeArray" ->
|
||||
// https://github.com/dotnet/runtime/blob/9e5e6aa7bc36aeb2a154709a9d1192030c30a2ef/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs#L18
|
||||
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||
@@ -319,11 +463,110 @@ module Intrinsics =
|
||||
failwith "TODO: if arg1 contains null handle, throw ArgumentException"
|
||||
|
||||
failwith "TODO: array initialization"
|
||||
| "System.Private.CoreLib", "Unsafe", "As" ->
|
||||
// https://github.com/dotnet/runtime/blob/721fdf6dcb032da1f883d30884e222e35e3d3c99/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs#L64
|
||||
let inputType, retType =
|
||||
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||
| [ input ], ret -> input, ret
|
||||
| _ -> failwith "bad signature Unsafe.As"
|
||||
|
||||
let from, to_ =
|
||||
match Seq.toList methodToCall.Generics with
|
||||
| [ from ; to_ ] -> from, to_
|
||||
| _ -> failwith "bad generics"
|
||||
|
||||
if ConcreteTypeHandle.Byref to_ <> retType then
|
||||
failwith "bad return type"
|
||||
|
||||
if ConcreteTypeHandle.Byref from <> inputType then
|
||||
failwith "bad input type"
|
||||
|
||||
let from =
|
||||
match AllConcreteTypes.lookup from state.ConcreteTypes with
|
||||
| None -> failwith "somehow have not concretised input type"
|
||||
| Some t -> t
|
||||
|
||||
let to_ =
|
||||
match AllConcreteTypes.lookup to_ state.ConcreteTypes with
|
||||
| None -> failwith "somehow have not concretised ret type"
|
||||
| Some t -> t
|
||||
|
||||
let inputAddr, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let ptr =
|
||||
match inputAddr with
|
||||
| EvalStackValue.Int32 _
|
||||
| EvalStackValue.Int64 _
|
||||
| EvalStackValue.Float _ -> failwith "expected pointer type"
|
||||
| EvalStackValue.NativeInt nativeIntSource -> failwith "todo"
|
||||
| EvalStackValue.ManagedPointer src ->
|
||||
ManagedPointerSource.InterpretedAsType (src, to_)
|
||||
|> EvalStackValue.ManagedPointer
|
||||
| EvalStackValue.ObjectRef addr ->
|
||||
ManagedPointerSource.InterpretedAsType (ManagedPointerSource.Heap addr, to_)
|
||||
|> EvalStackValue.ManagedPointer
|
||||
| EvalStackValue.UserDefinedValueType evalStackValueUserType -> failwith "todo"
|
||||
|
||||
let state =
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' ptr currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
Some state
|
||||
| "System.Private.CoreLib", "Unsafe", "SizeOf" ->
|
||||
// https://github.com/dotnet/runtime/blob/721fdf6dcb032da1f883d30884e222e35e3d3c99/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs#L51
|
||||
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||
| [], ConcreteInt32 state.ConcreteTypes -> ()
|
||||
| _ -> failwith "bad signature Unsafe.SizeOf"
|
||||
|
||||
let ty =
|
||||
match Seq.toList methodToCall.Generics with
|
||||
| [ ty ] -> ty
|
||||
| _ -> failwith "bad generics"
|
||||
|
||||
let zero, state = IlMachineState.cliTypeZeroOfHandle state baseClassTypes ty
|
||||
|
||||
let size = CliType.sizeOf zero
|
||||
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack (CliType.Numeric (CliNumericType.Int32 size)) currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Some
|
||||
| "System.Private.CoreLib", "RuntimeHelpers", "CreateSpan" ->
|
||||
// https://github.com/dotnet/runtime/blob/9e5e6aa7bc36aeb2a154709a9d1192030c30a2ef/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs#L153
|
||||
None
|
||||
| "System.Private.CoreLib", "Type", "op_Equality" ->
|
||||
// https://github.com/dotnet/runtime/blob/ec11903827fc28847d775ba17e0cd1ff56cfbc2e/src/libraries/System.Private.CoreLib/src/System/Type.cs#L703
|
||||
None
|
||||
| "System.Private.CoreLib", "MemoryMarshal", "GetArrayDataReference" ->
|
||||
// https://github.com/dotnet/runtime/blob/d258af50034c192bf7f0a18856bf83d2903d98ae/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.CoreCLR.cs#L20
|
||||
let generic = Seq.exactlyOne methodToCall.Generics
|
||||
|
||||
match methodToCall.Signature.ParameterTypes, methodToCall.Signature.ReturnType with
|
||||
| [ ConcreteGenericArray state.ConcreteTypes generic ], ConcreteByref t when t = generic -> ()
|
||||
| _ -> failwith "bad signature MemoryMarshal.GetArrayDataReference"
|
||||
|
||||
let arr, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let toPush =
|
||||
match arr with
|
||||
| EvalStackValue.Int32 _
|
||||
| EvalStackValue.Int64 _
|
||||
| EvalStackValue.Float _ -> failwith "expected reference"
|
||||
| EvalStackValue.NativeInt nativeIntSource -> failwith "todo"
|
||||
| EvalStackValue.ObjectRef addr
|
||||
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr) ->
|
||||
if not (state.ManagedHeap.Arrays.ContainsKey addr) then
|
||||
failwith "array not found"
|
||||
|
||||
EvalStackValue.ManagedPointer (ManagedPointerSource.ArrayIndex (addr, 0))
|
||||
| EvalStackValue.UserDefinedValueType evalStackValueUserType -> failwith "todo"
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: raise NRE"
|
||||
| EvalStackValue.ManagedPointer _ -> failwith "todo"
|
||||
|
||||
state
|
||||
|> IlMachineState.pushToEvalStack' toPush currentThread
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Some
|
||||
| a, b, c -> failwith $"TODO: implement JIT intrinsic {a}.{b}.{c}"
|
||||
|> Option.map (fun s -> s.WithThreadSwitchedToAssembly callerAssy currentThread |> fst)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
open System
|
||||
open Microsoft.Extensions.Logging
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
@@ -81,6 +82,7 @@ module NullaryIlOp =
|
||||
| EvalStackValue.ManagedPointer src ->
|
||||
match src with
|
||||
| ManagedPointerSource.Null -> failwith "TODO: throw NullReferenceException"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> failwith "TODO"
|
||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
||||
failwith "unexpected - can we really write to an argument?"
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
@@ -461,7 +463,25 @@ module NullaryIlOp =
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
|> ExecutionResult.Stepped
|
||||
| Mul_ovf -> failwith "TODO: Mul_ovf unimplemented"
|
||||
| Mul_ovf ->
|
||||
let val1, state = IlMachineState.popEvalStack currentThread state
|
||||
let val2, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let result =
|
||||
try
|
||||
BinaryArithmetic.execute ArithmeticOperation.mulOvf val1 val2 |> Ok
|
||||
with :? OverflowException as e ->
|
||||
Error e
|
||||
|
||||
let state =
|
||||
match result with
|
||||
| Ok result -> state |> IlMachineState.pushToEvalStack' result currentThread
|
||||
| Error excToThrow -> failwith "TODO: throw OverflowException"
|
||||
|
||||
state
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
|> ExecutionResult.Stepped
|
||||
| Mul_ovf_un -> failwith "TODO: Mul_ovf_un unimplemented"
|
||||
| Div -> failwith "TODO: Div unimplemented"
|
||||
| Div_un -> failwith "TODO: Div_un unimplemented"
|
||||
@@ -909,6 +929,7 @@ module NullaryIlOp =
|
||||
(EvalStackValue.toCliTypeCoerced (CliType.ObjectRef None) value)
|
||||
index
|
||||
| ManagedPointerSource.Field _ -> failwith "TODO"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> failwith "TODO"
|
||||
| addr -> failwith $"TODO: {addr}"
|
||||
|
||||
let state = state |> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
@@ -10,6 +10,7 @@ open Microsoft.Extensions.Logging
|
||||
module Program =
|
||||
/// Returns the pointer to the resulting array on the heap.
|
||||
let allocateArgs
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(args : string list)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(state : IlMachineState)
|
||||
@@ -18,6 +19,7 @@ module Program =
|
||||
let state, stringType =
|
||||
DumpedAssembly.typeInfoToTypeDefn' corelib state._LoadedAssemblies corelib.String
|
||||
|> IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
corelib
|
||||
state
|
||||
corelib.Corelib.Name
|
||||
@@ -285,7 +287,7 @@ module Program =
|
||||
let arrayAllocation, state =
|
||||
match mainMethodFromMetadata.Signature.ParameterTypes |> Seq.toList with
|
||||
| [ TypeDefn.OneDimensionalArrayLowerBoundZero (TypeDefn.PrimitiveType PrimitiveType.String) ] ->
|
||||
allocateArgs argv baseClassTypes state
|
||||
allocateArgs loggerFactory argv baseClassTypes state
|
||||
| _ -> failwith "Main method must take an array of strings; other signatures not yet implemented"
|
||||
|
||||
match mainMethodFromMetadata.Signature.ReturnType with
|
||||
|
||||
@@ -28,6 +28,24 @@ module internal UnaryMetadataIlOp =
|
||||
| MetadataToken.MethodSpecification h ->
|
||||
let spec = activeAssy.MethodSpecs.[h]
|
||||
|
||||
let state, methodGenerics =
|
||||
((state, []), spec.Signature)
|
||||
||> Seq.fold (fun (state, acc) typeDefn ->
|
||||
let state, concreteType =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
(state.ActiveAssembly thread).Name
|
||||
currentMethod.DeclaringType.Generics
|
||||
currentMethod.Generics
|
||||
typeDefn
|
||||
|
||||
state, concreteType :: acc
|
||||
)
|
||||
|
||||
let methodGenerics = List.rev methodGenerics |> ImmutableArray.CreateRange
|
||||
|
||||
match spec.Method with
|
||||
| MetadataToken.MethodDef token ->
|
||||
let method =
|
||||
@@ -44,6 +62,7 @@ module internal UnaryMetadataIlOp =
|
||||
baseClassTypes
|
||||
thread
|
||||
(state.ActiveAssembly thread)
|
||||
methodGenerics
|
||||
ref
|
||||
state
|
||||
|
||||
@@ -58,6 +77,7 @@ module internal UnaryMetadataIlOp =
|
||||
baseClassTypes
|
||||
thread
|
||||
(state.ActiveAssembly thread)
|
||||
currentMethod.DeclaringType.Generics
|
||||
h
|
||||
state
|
||||
|
||||
@@ -114,6 +134,24 @@ module internal UnaryMetadataIlOp =
|
||||
| MetadataToken.MethodSpecification h ->
|
||||
let spec = activeAssy.MethodSpecs.[h]
|
||||
|
||||
let state, methodGenerics =
|
||||
((state, []), spec.Signature)
|
||||
||> Seq.fold (fun (state, acc) typeDefn ->
|
||||
let state, concreteType =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
(state.ActiveAssembly thread).Name
|
||||
currentMethod.DeclaringType.Generics
|
||||
ImmutableArray.Empty
|
||||
typeDefn
|
||||
|
||||
state, concreteType :: acc
|
||||
)
|
||||
|
||||
let methodGenerics = List.rev methodGenerics |> ImmutableArray.CreateRange
|
||||
|
||||
match spec.Method with
|
||||
| MetadataToken.MethodDef token ->
|
||||
let method =
|
||||
@@ -128,6 +166,7 @@ module internal UnaryMetadataIlOp =
|
||||
baseClassTypes
|
||||
thread
|
||||
(state.ActiveAssembly thread)
|
||||
methodGenerics
|
||||
ref
|
||||
state
|
||||
|
||||
@@ -142,6 +181,7 @@ module internal UnaryMetadataIlOp =
|
||||
baseClassTypes
|
||||
thread
|
||||
(state.ActiveAssembly thread)
|
||||
ImmutableArray.Empty
|
||||
h
|
||||
state
|
||||
|
||||
@@ -203,6 +243,7 @@ module internal UnaryMetadataIlOp =
|
||||
baseClassTypes
|
||||
thread
|
||||
(state.ActiveAssembly thread)
|
||||
ImmutableArray.Empty
|
||||
mr
|
||||
state
|
||||
|
||||
@@ -436,6 +477,7 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
let state, targetConcreteType =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
activeAssy.Name
|
||||
@@ -481,7 +523,14 @@ module internal UnaryMetadataIlOp =
|
||||
state, field
|
||||
| MetadataToken.MemberReference mr ->
|
||||
let state, _, field, _ =
|
||||
IlMachineState.resolveMember loggerFactory baseClassTypes thread activeAssy mr state
|
||||
IlMachineState.resolveMember
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
thread
|
||||
activeAssy
|
||||
ImmutableArray.Empty
|
||||
mr
|
||||
state
|
||||
|
||||
match field with
|
||||
| Choice1Of2 _method -> failwith "member reference was unexpectedly a method"
|
||||
@@ -498,6 +547,7 @@ module internal UnaryMetadataIlOp =
|
||||
)
|
||||
|
||||
let valueToStore, state = IlMachineState.popEvalStack thread state
|
||||
let currentObj, state = IlMachineState.popEvalStack thread state
|
||||
|
||||
let state, declaringTypeHandle, typeGenerics =
|
||||
IlMachineState.concretizeFieldForExecution loggerFactory baseClassTypes thread field state
|
||||
@@ -514,8 +564,6 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
let valueToStore = EvalStackValue.toCliTypeCoerced zero valueToStore
|
||||
|
||||
let currentObj, state = IlMachineState.popEvalStack thread state
|
||||
|
||||
if field.Attributes.HasFlag FieldAttributes.Static then
|
||||
let state =
|
||||
IlMachineState.setStatic declaringTypeHandle field.Name valueToStore state
|
||||
@@ -576,6 +624,7 @@ module internal UnaryMetadataIlOp =
|
||||
state |> IlMachineState.setArrayValue arr newValue index
|
||||
| EvalStackValue.ManagedPointer (ManagedPointerSource.Field (managedPointerSource, fieldName)) ->
|
||||
failwith "todo"
|
||||
| EvalStackValue.ManagedPointer (ManagedPointerSource.InterpretedAsType (src, ty)) -> failwith "todo"
|
||||
| EvalStackValue.UserDefinedValueType _ -> failwith "todo"
|
||||
|
||||
state
|
||||
@@ -601,6 +650,7 @@ module internal UnaryMetadataIlOp =
|
||||
baseClassTypes
|
||||
thread
|
||||
(state.ActiveAssembly thread)
|
||||
ImmutableArray.Empty
|
||||
mr
|
||||
state
|
||||
|
||||
@@ -660,7 +710,14 @@ module internal UnaryMetadataIlOp =
|
||||
state, field
|
||||
| MetadataToken.MemberReference mr ->
|
||||
let state, assyName, field, _ =
|
||||
IlMachineState.resolveMember loggerFactory baseClassTypes thread activeAssy mr state
|
||||
IlMachineState.resolveMember
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
thread
|
||||
activeAssy
|
||||
ImmutableArray.Empty
|
||||
mr
|
||||
state
|
||||
|
||||
match field with
|
||||
| Choice1Of2 _method -> failwith "member reference was unexpectedly a method"
|
||||
@@ -748,8 +805,10 @@ module internal UnaryMetadataIlOp =
|
||||
IlMachineState.getFieldValue src fieldName state |> CliType.getField field.Name
|
||||
|
||||
IlMachineState.pushToEvalStack currentValue thread state
|
||||
| EvalStackValue.ManagedPointer (ManagedPointerSource.InterpretedAsType (src, ty)) -> failwith "TODO"
|
||||
| EvalStackValue.UserDefinedValueType vt ->
|
||||
let result = vt |> EvalStackValueUserType.DereferenceField field.Name
|
||||
|
||||
IlMachineState.pushToEvalStack' result thread state
|
||||
|
||||
state
|
||||
@@ -779,7 +838,15 @@ module internal UnaryMetadataIlOp =
|
||||
state, field
|
||||
| MetadataToken.MemberReference mr ->
|
||||
let state, assyName, field, _ =
|
||||
IlMachineState.resolveMember loggerFactory baseClassTypes thread activeAssy mr state
|
||||
// TODO: generics
|
||||
IlMachineState.resolveMember
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
thread
|
||||
activeAssy
|
||||
ImmutableArray.Empty
|
||||
mr
|
||||
state
|
||||
|
||||
match field with
|
||||
| Choice1Of2 _method -> failwith "member reference was unexpectedly a method"
|
||||
@@ -793,6 +860,7 @@ module internal UnaryMetadataIlOp =
|
||||
|> IlMachineState.pushToEvalStack' result thread
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
|
||||
| Ldsfld ->
|
||||
let state, field =
|
||||
match metadataToken with
|
||||
@@ -807,7 +875,14 @@ module internal UnaryMetadataIlOp =
|
||||
state, field
|
||||
| MetadataToken.MemberReference mr ->
|
||||
let state, _, field, _ =
|
||||
IlMachineState.resolveMember loggerFactory baseClassTypes thread activeAssy mr state
|
||||
IlMachineState.resolveMember
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
thread
|
||||
activeAssy
|
||||
ImmutableArray.Empty
|
||||
mr
|
||||
state
|
||||
|
||||
match field with
|
||||
| Choice1Of2 _method -> failwith "member reference was unexpectedly a method"
|
||||
@@ -983,6 +1058,7 @@ module internal UnaryMetadataIlOp =
|
||||
IlMachineState.pushToEvalStack toPush thread state
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
|
||||
| Initobj ->
|
||||
let popped, state = IlMachineState.popEvalStack thread state
|
||||
let declaringTypeGenerics = currentMethod.DeclaringType.Generics
|
||||
@@ -1040,12 +1116,14 @@ module internal UnaryMetadataIlOp =
|
||||
| ManagedPointerSource.Field (managedPointerSource, fieldName) ->
|
||||
state |> IlMachineState.setFieldValue managedPointerSource zeroOfType fieldName
|
||||
| ManagedPointerSource.Null -> failwith "runtime error: unexpectedly Initobj'ing null"
|
||||
| ManagedPointerSource.InterpretedAsType (src, ty) -> failwith "TODO"
|
||||
| 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
|
||||
@@ -1067,30 +1145,31 @@ module internal UnaryMetadataIlOp =
|
||||
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
||||
| NothingToDo state ->
|
||||
|
||||
if TypeDefn.isManaged field.Signature then
|
||||
match IlMachineState.getStatic declaringTypeHandle field.Name state with
|
||||
| Some v ->
|
||||
IlMachineState.pushToEvalStack v thread state
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| None ->
|
||||
// Field is not yet initialised
|
||||
let state, zero =
|
||||
IlMachineState.cliTypeZeroOf
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
activeAssy
|
||||
field.Signature
|
||||
typeGenerics
|
||||
ImmutableArray.Empty // field can't have its own generics
|
||||
state
|
||||
// TODO: if field type is unmanaged, push an unmanaged pointer
|
||||
// TODO: Note that field may be a static global with an assigned relative virtual address
|
||||
// (the offset of the field from the base address at which its containing PE file is loaded into memory)
|
||||
// where the memory is unmanaged.
|
||||
match IlMachineState.getStatic declaringTypeHandle field.Name state with
|
||||
| Some v ->
|
||||
IlMachineState.pushToEvalStack v thread state
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| None ->
|
||||
// Field is not yet initialised
|
||||
let state, zero =
|
||||
IlMachineState.cliTypeZeroOf
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
activeAssy
|
||||
field.Signature
|
||||
typeGenerics
|
||||
ImmutableArray.Empty // field can't have its own generics
|
||||
state
|
||||
|
||||
IlMachineState.setStatic declaringTypeHandle field.Name zero state
|
||||
|> IlMachineState.pushToEvalStack (CliType.ObjectRef None) thread
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
else
|
||||
failwith "TODO: Ldsflda - push unmanaged pointer"
|
||||
IlMachineState.setStatic declaringTypeHandle field.Name zero state
|
||||
|> IlMachineState.pushToEvalStack (CliType.ObjectRef None) thread
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
|
||||
| Ldftn ->
|
||||
let method, methodGenerics =
|
||||
@@ -1142,6 +1221,42 @@ module internal UnaryMetadataIlOp =
|
||||
| Stobj -> failwith "TODO: Stobj unimplemented"
|
||||
| Constrained -> failwith "TODO: Constrained unimplemented"
|
||||
| Ldtoken ->
|
||||
// Helper function to handle type tokens and create RuntimeTypeHandle
|
||||
let handleTypeToken (typeDefn : TypeDefn) (state : IlMachineState) : IlMachineState =
|
||||
let ty = baseClassTypes.RuntimeTypeHandle
|
||||
let field = ty.Fields |> List.exactlyOne
|
||||
|
||||
if field.Name <> "m_type" then
|
||||
failwith $"unexpected field name ${field.Name} for BCL type RuntimeTypeHandle"
|
||||
|
||||
let methodGenerics = currentMethod.Generics
|
||||
let typeGenerics = currentMethod.DeclaringType.Generics
|
||||
|
||||
let state, handle =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
activeAssy.Name
|
||||
typeGenerics
|
||||
methodGenerics
|
||||
typeDefn
|
||||
|
||||
let alloc, state =
|
||||
IlMachineState.getOrAllocateType loggerFactory baseClassTypes handle state
|
||||
|
||||
let vt =
|
||||
// https://github.com/dotnet/runtime/blob/2b21c73fa2c32fa0195e4a411a435dda185efd08/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs#L92
|
||||
{
|
||||
Name = "m_type"
|
||||
Contents = CliType.ObjectRef (Some alloc)
|
||||
Offset = None
|
||||
}
|
||||
|> List.singleton
|
||||
|> CliValueType.OfFields
|
||||
|
||||
IlMachineState.pushToEvalStack (CliType.ValueType vt) thread state
|
||||
|
||||
let state =
|
||||
match metadataToken with
|
||||
| MetadataToken.FieldDefinition h ->
|
||||
@@ -1179,6 +1294,7 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
let state, handle =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
assy.Name
|
||||
@@ -1186,7 +1302,8 @@ module internal UnaryMetadataIlOp =
|
||||
methodGenerics
|
||||
typeDefn
|
||||
|
||||
let alloc, state = IlMachineState.getOrAllocateType baseClassTypes handle state
|
||||
let alloc, state =
|
||||
IlMachineState.getOrAllocateType loggerFactory baseClassTypes handle state
|
||||
|
||||
let vt =
|
||||
{
|
||||
@@ -1214,6 +1331,7 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
let state, handle =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
assy.Name
|
||||
@@ -1221,7 +1339,8 @@ module internal UnaryMetadataIlOp =
|
||||
methodGenerics
|
||||
typeDefn
|
||||
|
||||
let alloc, state = IlMachineState.getOrAllocateType baseClassTypes handle state
|
||||
let alloc, state =
|
||||
IlMachineState.getOrAllocateType loggerFactory baseClassTypes handle state
|
||||
|
||||
let vt =
|
||||
{
|
||||
@@ -1234,40 +1353,10 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
IlMachineState.pushToEvalStack (CliType.ValueType vt) thread state
|
||||
| MetadataToken.TypeDefinition h ->
|
||||
let ty = baseClassTypes.RuntimeTypeHandle
|
||||
let field = ty.Fields |> List.exactlyOne
|
||||
|
||||
if field.Name <> "m_type" then
|
||||
failwith $"unexpected field name ${field.Name} for BCL type RuntimeTypeHandle"
|
||||
|
||||
let methodGenerics = currentMethod.Generics
|
||||
|
||||
let typeGenerics = currentMethod.DeclaringType.Generics
|
||||
|
||||
let state, typeDefn =
|
||||
IlMachineState.lookupTypeDefn baseClassTypes state activeAssy h
|
||||
|
||||
let state, handle =
|
||||
IlMachineState.concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
activeAssy.Name
|
||||
typeGenerics
|
||||
methodGenerics
|
||||
typeDefn
|
||||
|
||||
let alloc, state = IlMachineState.getOrAllocateType baseClassTypes handle state
|
||||
|
||||
let vt =
|
||||
{
|
||||
Name = "m_type"
|
||||
Contents = CliType.ObjectRef (Some alloc)
|
||||
Offset = None
|
||||
}
|
||||
|> List.singleton
|
||||
|> CliValueType.OfFields
|
||||
|
||||
IlMachineState.pushToEvalStack (CliType.ValueType vt) thread state
|
||||
handleTypeToken typeDefn state
|
||||
| _ -> failwith $"Unexpected metadata token %O{metadataToken} in LdToken"
|
||||
|
||||
state
|
||||
@@ -1289,10 +1378,12 @@ module internal UnaryMetadataIlOp =
|
||||
activeAssy
|
||||
currentMethod.DeclaringType.Generics
|
||||
ref
|
||||
| MetadataToken.TypeSpecification spec -> state, activeAssy.TypeSpecs.[spec].Signature, activeAssy
|
||||
| _ -> failwith $"unexpected token {metadataToken} in Sizeof"
|
||||
|
||||
let state, typeHandle =
|
||||
IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
assy.Name
|
||||
|
||||
@@ -2,12 +2,13 @@ namespace WoofWare.PawPrint
|
||||
|
||||
open System.Collections.Immutable
|
||||
open System.Reflection
|
||||
open System.Reflection.Metadata
|
||||
open Microsoft.Extensions.Logging
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
|
||||
module internal UnaryStringTokenIlOp =
|
||||
let execute
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(op : UnaryStringTokenIlOp)
|
||||
(sh : StringToken)
|
||||
@@ -66,6 +67,7 @@ module internal UnaryStringTokenIlOp =
|
||||
let state, stringType =
|
||||
DumpedAssembly.typeInfoToTypeDefn' baseClassTypes state._LoadedAssemblies baseClassTypes.String
|
||||
|> IlMachineState.concretizeType
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
state
|
||||
baseClassTypes.Corelib.Name
|
||||
|
||||
Reference in New Issue
Block a user