mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-12 17:18:40 +00:00
Track generics at runtime (#32)
This commit is contained in:
@@ -5,6 +5,7 @@ open System.IO
|
|||||||
open FsUnitTyped
|
open FsUnitTyped
|
||||||
open NUnit.Framework
|
open NUnit.Framework
|
||||||
open WoofWare.PawPrint
|
open WoofWare.PawPrint
|
||||||
|
open WoofWare.PawPrint.ExternImplementations
|
||||||
open WoofWare.PawPrint.Test
|
open WoofWare.PawPrint.Test
|
||||||
open WoofWare.DotnetRuntimeLocator
|
open WoofWare.DotnetRuntimeLocator
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ module TestBasicLock =
|
|||||||
let dotnetRuntimes =
|
let dotnetRuntimes =
|
||||||
DotnetRuntime.SelectForDll assy.Location |> ImmutableArray.CreateRange
|
DotnetRuntime.SelectForDll assy.Location |> ImmutableArray.CreateRange
|
||||||
|
|
||||||
let impls = MockEnv.make ()
|
let impls = NativeImpls.PassThru ()
|
||||||
|
|
||||||
use peImage = new MemoryStream (image)
|
use peImage = new MemoryStream (image)
|
||||||
|
|
||||||
|
@@ -41,7 +41,7 @@ module TestCases =
|
|||||||
{
|
{
|
||||||
FileName = "WriteLine.cs"
|
FileName = "WriteLine.cs"
|
||||||
ExpectedReturnCode = 1
|
ExpectedReturnCode = 1
|
||||||
NativeImpls = MockEnv.make ()
|
NativeImpls = NativeImpls.PassThru ()
|
||||||
LocalVariablesOfMain = []
|
LocalVariablesOfMain = []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@@ -6,6 +6,7 @@ open System.IO
|
|||||||
open FsUnitTyped
|
open FsUnitTyped
|
||||||
open NUnit.Framework
|
open NUnit.Framework
|
||||||
open WoofWare.PawPrint
|
open WoofWare.PawPrint
|
||||||
|
open WoofWare.PawPrint.ExternImplementations
|
||||||
open WoofWare.PawPrint.Test
|
open WoofWare.PawPrint.Test
|
||||||
open WoofWare.DotnetRuntimeLocator
|
open WoofWare.DotnetRuntimeLocator
|
||||||
|
|
||||||
@@ -15,14 +16,14 @@ module TestHelloWorld =
|
|||||||
|
|
||||||
[<Test ; Explicit "This test doesn't run yet">]
|
[<Test ; Explicit "This test doesn't run yet">]
|
||||||
let ``Can run Hello World`` () : unit =
|
let ``Can run Hello World`` () : unit =
|
||||||
let source = Assembly.getEmbeddedResourceAsString "HelloWorld.cs" assy
|
let source = Assembly.getEmbeddedResourceAsString "WriteLine.cs" assy
|
||||||
let image = Roslyn.compile [ source ]
|
let image = Roslyn.compile [ source ]
|
||||||
let messages, loggerFactory = LoggerFactory.makeTest ()
|
let messages, loggerFactory = LoggerFactory.makeTest ()
|
||||||
|
|
||||||
let dotnetRuntimes =
|
let dotnetRuntimes =
|
||||||
DotnetRuntime.SelectForDll assy.Location |> ImmutableArray.CreateRange
|
DotnetRuntime.SelectForDll assy.Location |> ImmutableArray.CreateRange
|
||||||
|
|
||||||
let impls = MockEnv.make ()
|
let impls = NativeImpls.PassThru ()
|
||||||
|
|
||||||
try
|
try
|
||||||
use peImage = new MemoryStream (image)
|
use peImage = new MemoryStream (image)
|
||||||
|
@@ -22,10 +22,11 @@ module AbstractMachine =
|
|||||||
match instruction.ExecutingMethod.Instructions with
|
match instruction.ExecutingMethod.Instructions with
|
||||||
| None ->
|
| None ->
|
||||||
let targetAssy =
|
let targetAssy =
|
||||||
state.LoadedAssembly (snd instruction.ExecutingMethod.DeclaringType)
|
state.LoadedAssembly instruction.ExecutingMethod.DeclaringType.Assembly
|
||||||
|> Option.get
|
|> Option.get
|
||||||
|
|
||||||
let targetType = targetAssy.TypeDefs.[fst instruction.ExecutingMethod.DeclaringType]
|
let targetType =
|
||||||
|
targetAssy.TypeDefs.[instruction.ExecutingMethod.DeclaringType.Definition.Get]
|
||||||
|
|
||||||
let outcome =
|
let outcome =
|
||||||
match
|
match
|
||||||
@@ -80,10 +81,10 @@ module AbstractMachine =
|
|||||||
| true, executingInstruction ->
|
| true, executingInstruction ->
|
||||||
|
|
||||||
let executingInType =
|
let executingInType =
|
||||||
match state.LoadedAssembly (snd instruction.ExecutingMethod.DeclaringType) with
|
match state.LoadedAssembly instruction.ExecutingMethod.DeclaringType.Assembly with
|
||||||
| None -> "<unloaded assembly>"
|
| None -> "<unloaded assembly>"
|
||||||
| Some assy ->
|
| Some assy ->
|
||||||
match assy.TypeDefs.TryGetValue (fst instruction.ExecutingMethod.DeclaringType) with
|
match assy.TypeDefs.TryGetValue instruction.ExecutingMethod.DeclaringType.Definition.Get with
|
||||||
| true, v -> v.Name
|
| true, v -> v.Name
|
||||||
| false, _ -> "<unrecognised type>"
|
| false, _ -> "<unrecognised type>"
|
||||||
|
|
||||||
|
@@ -61,7 +61,7 @@ type DumpedAssembly =
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dictionary of all method definitions in this assembly, keyed by their handle.
|
/// Dictionary of all method definitions in this assembly, keyed by their handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Methods : IReadOnlyDictionary<MethodDefinitionHandle, WoofWare.PawPrint.MethodInfo>
|
Methods : IReadOnlyDictionary<MethodDefinitionHandle, WoofWare.PawPrint.MethodInfo<FakeUnit>>
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dictionary of all member references in this assembly, keyed by their handle.
|
/// Dictionary of all member references in this assembly, keyed by their handle.
|
||||||
|
@@ -144,7 +144,7 @@ module CliType =
|
|||||||
match signatureTypeKind with
|
match signatureTypeKind with
|
||||||
| SignatureTypeKind.Unknown -> failwith "todo"
|
| SignatureTypeKind.Unknown -> failwith "todo"
|
||||||
| SignatureTypeKind.ValueType ->
|
| SignatureTypeKind.ValueType ->
|
||||||
let typeDef = assy.TypeDefs.[typeDefinitionHandle]
|
let typeDef = assy.TypeDefs.[typeDefinitionHandle.Get]
|
||||||
|
|
||||||
let fields =
|
let fields =
|
||||||
typeDef.Fields
|
typeDef.Fields
|
||||||
|
36
WoofWare.PawPrint/ComparableSignatureHeader.fs
Normal file
36
WoofWare.PawPrint/ComparableSignatureHeader.fs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
namespace WoofWare.PawPrint
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Reflection.Metadata
|
||||||
|
|
||||||
|
[<CustomEquality>]
|
||||||
|
[<CustomComparison>]
|
||||||
|
type ComparableSignatureHeader =
|
||||||
|
private
|
||||||
|
{
|
||||||
|
_Inner : SignatureHeader
|
||||||
|
}
|
||||||
|
|
||||||
|
member this.Get = this._Inner
|
||||||
|
|
||||||
|
override this.Equals (other : obj) =
|
||||||
|
match other with
|
||||||
|
| :? ComparableSignatureHeader as other -> this._Inner.RawValue = other._Inner.RawValue
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
override this.GetHashCode () = this._Inner.RawValue.GetHashCode ()
|
||||||
|
|
||||||
|
interface IComparable<ComparableSignatureHeader> with
|
||||||
|
member this.CompareTo (other : ComparableSignatureHeader) =
|
||||||
|
this._Inner.RawValue.CompareTo other._Inner.RawValue
|
||||||
|
|
||||||
|
interface IComparable with
|
||||||
|
member this.CompareTo (other : obj) =
|
||||||
|
match other with
|
||||||
|
| :? ComparableSignatureHeader as other -> (this :> IComparable<ComparableSignatureHeader>).CompareTo other
|
||||||
|
| _ -> failwith "invalid comparison"
|
||||||
|
|
||||||
|
static member Make x : ComparableSignatureHeader =
|
||||||
|
{
|
||||||
|
_Inner = x
|
||||||
|
}
|
37
WoofWare.PawPrint/ComparableTypeDefinitionHandle.fs
Normal file
37
WoofWare.PawPrint/ComparableTypeDefinitionHandle.fs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
namespace WoofWare.PawPrint
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Reflection.Metadata
|
||||||
|
|
||||||
|
[<CustomEquality>]
|
||||||
|
[<CustomComparison>]
|
||||||
|
type ComparableTypeDefinitionHandle =
|
||||||
|
private
|
||||||
|
{
|
||||||
|
_Inner : TypeDefinitionHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
override this.Equals (other) =
|
||||||
|
match other with
|
||||||
|
| :? ComparableTypeDefinitionHandle as other -> this._Inner.GetHashCode () = other._Inner.GetHashCode ()
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
override this.GetHashCode () : int = this._Inner.GetHashCode ()
|
||||||
|
|
||||||
|
interface IComparable<ComparableTypeDefinitionHandle> with
|
||||||
|
member this.CompareTo (other : ComparableTypeDefinitionHandle) : int =
|
||||||
|
this._Inner.GetHashCode().CompareTo (other._Inner.GetHashCode ())
|
||||||
|
|
||||||
|
interface IComparable with
|
||||||
|
member this.CompareTo (other : obj) : int =
|
||||||
|
match other with
|
||||||
|
| :? ComparableTypeDefinitionHandle as other ->
|
||||||
|
(this :> IComparable<ComparableTypeDefinitionHandle>).CompareTo other
|
||||||
|
| _ -> failwith "invalid comparison"
|
||||||
|
|
||||||
|
static member Make (h : TypeDefinitionHandle) =
|
||||||
|
{
|
||||||
|
_Inner = h
|
||||||
|
}
|
||||||
|
|
||||||
|
member this.Get = this._Inner
|
93
WoofWare.PawPrint/ConcreteType.fs
Normal file
93
WoofWare.PawPrint/ConcreteType.fs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
namespace WoofWare.PawPrint
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Reflection
|
||||||
|
open System.Reflection.Metadata
|
||||||
|
|
||||||
|
type FakeUnit = private | FakeUnit
|
||||||
|
|
||||||
|
/// A type which has been concretised, runtime-representable, etc.
|
||||||
|
[<CustomEquality>]
|
||||||
|
[<CustomComparison>]
|
||||||
|
type ConcreteType<'typeGeneric when 'typeGeneric : comparison and 'typeGeneric :> IComparable<'typeGeneric>> =
|
||||||
|
private
|
||||||
|
{
|
||||||
|
_AssemblyName : AssemblyName
|
||||||
|
_Definition : ComparableTypeDefinitionHandle
|
||||||
|
_Generics : 'typeGeneric list
|
||||||
|
}
|
||||||
|
|
||||||
|
member this.Assembly : AssemblyName = this._AssemblyName
|
||||||
|
member this.Definition : ComparableTypeDefinitionHandle = this._Definition
|
||||||
|
member this.Generics : 'typeGeneric list = this._Generics
|
||||||
|
|
||||||
|
override this.Equals (other : obj) : bool =
|
||||||
|
match other with
|
||||||
|
| :? ConcreteType<'typeGeneric> as other ->
|
||||||
|
this._Generics = other._Generics
|
||||||
|
&& this._Definition = other._Definition
|
||||||
|
&& this._AssemblyName.FullName = other._AssemblyName.FullName
|
||||||
|
| _ -> false
|
||||||
|
|
||||||
|
override this.GetHashCode () : int =
|
||||||
|
hash (this._AssemblyName.FullName, this._Definition, this._Generics)
|
||||||
|
|
||||||
|
interface IComparable<ConcreteType<'typeGeneric>> with
|
||||||
|
member this.CompareTo (other : ConcreteType<'typeGeneric>) : int =
|
||||||
|
let comp = this._AssemblyName.FullName.CompareTo other._AssemblyName.FullName
|
||||||
|
|
||||||
|
if comp = 0 then
|
||||||
|
let comp =
|
||||||
|
(this._Definition :> IComparable<ComparableTypeDefinitionHandle>).CompareTo other._Definition
|
||||||
|
|
||||||
|
if comp = 0 then
|
||||||
|
let thisGen = (this._Generics : 'typeGeneric list) :> IComparable<'typeGeneric list>
|
||||||
|
thisGen.CompareTo other._Generics
|
||||||
|
else
|
||||||
|
comp
|
||||||
|
else
|
||||||
|
comp
|
||||||
|
|
||||||
|
interface IComparable with
|
||||||
|
member this.CompareTo other =
|
||||||
|
match other with
|
||||||
|
| :? ConcreteType<'typeGeneric> as other ->
|
||||||
|
(this :> IComparable<ConcreteType<'typeGeneric>>).CompareTo other
|
||||||
|
| _ -> failwith "bad comparison"
|
||||||
|
|
||||||
|
type RuntimeConcreteType = ConcreteType<TypeDefn>
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module ConcreteType =
|
||||||
|
let make (assemblyName : AssemblyName) (defn : TypeDefinitionHandle) (generics : TypeDefn list) =
|
||||||
|
{
|
||||||
|
_AssemblyName = assemblyName
|
||||||
|
_Definition = ComparableTypeDefinitionHandle.Make defn
|
||||||
|
_Generics = generics
|
||||||
|
}
|
||||||
|
|
||||||
|
let make'
|
||||||
|
(assemblyName : AssemblyName)
|
||||||
|
(defn : TypeDefinitionHandle)
|
||||||
|
(genericParamCount : int)
|
||||||
|
: ConcreteType<FakeUnit>
|
||||||
|
=
|
||||||
|
{
|
||||||
|
_AssemblyName = assemblyName
|
||||||
|
_Definition = ComparableTypeDefinitionHandle.Make defn
|
||||||
|
_Generics = List.replicate genericParamCount FakeUnit.FakeUnit
|
||||||
|
}
|
||||||
|
|
||||||
|
let mapGeneric<'a, 'b
|
||||||
|
when 'a : comparison and 'a :> IComparable<'a> and 'b : equality and 'b : comparison and 'b :> IComparable<'b>>
|
||||||
|
(f : int -> 'a -> 'b)
|
||||||
|
(x : ConcreteType<'a>)
|
||||||
|
: ConcreteType<'b>
|
||||||
|
=
|
||||||
|
let generics = x._Generics |> List.mapi f
|
||||||
|
|
||||||
|
{
|
||||||
|
_AssemblyName = x._AssemblyName
|
||||||
|
_Definition = x._Definition
|
||||||
|
_Generics = generics
|
||||||
|
}
|
@@ -75,7 +75,10 @@ module EvalStackValue =
|
|||||||
| CliNumericType.Int64 int64 -> failwith "todo"
|
| CliNumericType.Int64 int64 -> failwith "todo"
|
||||||
| CliNumericType.NativeInt int64 -> failwith "todo"
|
| CliNumericType.NativeInt int64 -> failwith "todo"
|
||||||
| CliNumericType.NativeFloat f -> failwith "todo"
|
| CliNumericType.NativeFloat f -> failwith "todo"
|
||||||
| CliNumericType.Int8 b -> failwith "todo"
|
| CliNumericType.Int8 _ ->
|
||||||
|
match popped with
|
||||||
|
| EvalStackValue.Int32 i -> CliType.Numeric (CliNumericType.Int8 (i % 256 |> int8))
|
||||||
|
| i -> failwith $"TODO: %O{i}"
|
||||||
| CliNumericType.Int16 s -> failwith "todo"
|
| CliNumericType.Int16 s -> failwith "todo"
|
||||||
| CliNumericType.UInt8 b -> failwith "todo"
|
| CliNumericType.UInt8 b -> failwith "todo"
|
||||||
| CliNumericType.UInt16 s -> failwith "todo"
|
| CliNumericType.UInt16 s -> failwith "todo"
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
namespace WoofWare.PawPrint
|
namespace WoofWare.PawPrint
|
||||||
|
|
||||||
|
open System
|
||||||
open System.Collections.Immutable
|
open System.Collections.Immutable
|
||||||
open System.IO
|
open System.IO
|
||||||
open System.Reflection
|
open System.Reflection
|
||||||
@@ -21,16 +22,12 @@ type IlMachineState =
|
|||||||
_LoadedAssemblies : ImmutableDictionary<string, DumpedAssembly>
|
_LoadedAssemblies : ImmutableDictionary<string, DumpedAssembly>
|
||||||
/// Tracks initialization state of types across assemblies
|
/// Tracks initialization state of types across assemblies
|
||||||
TypeInitTable : TypeInitTable
|
TypeInitTable : TypeInitTable
|
||||||
Statics : ImmutableDictionary<TypeDefinitionHandle * AssemblyName, ImmutableDictionary<string, CliType>>
|
/// For each type, specialised to each set of generic args, a map of string field name to static value contained therein.
|
||||||
|
Statics : ImmutableDictionary<RuntimeConcreteType, ImmutableDictionary<string, CliType>>
|
||||||
DotnetRuntimeDirs : string ImmutableArray
|
DotnetRuntimeDirs : string ImmutableArray
|
||||||
}
|
}
|
||||||
|
|
||||||
member this.SetStatic
|
member this.SetStatic (ty : RuntimeConcreteType) (field : string) (value : CliType) : IlMachineState =
|
||||||
(ty : TypeDefinitionHandle * AssemblyName)
|
|
||||||
(field : string)
|
|
||||||
(value : CliType)
|
|
||||||
: IlMachineState
|
|
||||||
=
|
|
||||||
let statics =
|
let statics =
|
||||||
match this.Statics.TryGetValue ty with
|
match this.Statics.TryGetValue ty with
|
||||||
| false, _ -> this.Statics.Add (ty, ImmutableDictionary.Create().Add (field, value))
|
| false, _ -> this.Statics.Add (ty, ImmutableDictionary.Create().Add (field, value))
|
||||||
@@ -40,31 +37,29 @@ type IlMachineState =
|
|||||||
Statics = statics
|
Statics = statics
|
||||||
}
|
}
|
||||||
|
|
||||||
member this.WithTypeBeginInit (thread : ThreadId) (handle : TypeDefinitionHandle, assy : AssemblyName) =
|
member this.WithTypeBeginInit (thread : ThreadId) (ty : RuntimeConcreteType) =
|
||||||
this.Logger.LogDebug (
|
this.Logger.LogDebug (
|
||||||
"Beginning initialisation of type {TypeName}, handle {TypeDefinitionHandle} from assy {AssemblyHash}",
|
"Beginning initialisation of type {s_Assembly}.{TypeName}, handle {TypeDefinitionHandle}",
|
||||||
this.LoadedAssembly(assy).Value.TypeDefs.[handle].Name,
|
ty.Assembly.FullName,
|
||||||
handle.GetHashCode (),
|
this.LoadedAssembly(ty.Assembly).Value.TypeDefs.[ty.Definition.Get].Name,
|
||||||
assy.GetHashCode ()
|
ty.Definition.Get.GetHashCode ()
|
||||||
)
|
)
|
||||||
|
|
||||||
let typeInitTable =
|
let typeInitTable = this.TypeInitTable |> TypeInitTable.beginInitialising thread ty
|
||||||
this.TypeInitTable |> TypeInitTable.beginInitialising thread (handle, assy)
|
|
||||||
|
|
||||||
{ this with
|
{ this with
|
||||||
TypeInitTable = typeInitTable
|
TypeInitTable = typeInitTable
|
||||||
}
|
}
|
||||||
|
|
||||||
member this.WithTypeEndInit (thread : ThreadId) (handle : TypeDefinitionHandle, assy : AssemblyName) =
|
member this.WithTypeEndInit (thread : ThreadId) (ty : RuntimeConcreteType) =
|
||||||
this.Logger.LogDebug (
|
this.Logger.LogDebug (
|
||||||
"Marking complete initialisation of type {TypeName}, handle {TypeDefinitionHandle} from assy {AssemblyHash}",
|
"Marking complete initialisation of type {s_Assembly}.{TypeName}, handle {TypeDefinitionHandle}",
|
||||||
this.LoadedAssembly(assy).Value.TypeDefs.[handle].Name,
|
ty.Assembly.FullName,
|
||||||
handle.GetHashCode (),
|
this.LoadedAssembly(ty.Assembly).Value.TypeDefs.[ty.Definition.Get].Name,
|
||||||
assy.GetHashCode ()
|
ty.Definition.Get.GetHashCode ()
|
||||||
)
|
)
|
||||||
|
|
||||||
let typeInitTable =
|
let typeInitTable = this.TypeInitTable |> TypeInitTable.markInitialised thread ty
|
||||||
this.TypeInitTable |> TypeInitTable.markInitialised thread (handle, assy)
|
|
||||||
|
|
||||||
{ this with
|
{ this with
|
||||||
TypeInitTable = typeInitTable
|
TypeInitTable = typeInitTable
|
||||||
@@ -75,11 +70,13 @@ type IlMachineState =
|
|||||||
_LoadedAssemblies = this._LoadedAssemblies.Add (name.FullName, value)
|
_LoadedAssemblies = this._LoadedAssemblies.Add (name.FullName, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
member this.LoadedAssembly (name : AssemblyName) : DumpedAssembly option =
|
member this.LoadedAssembly' (fullName : string) : DumpedAssembly option =
|
||||||
match this._LoadedAssemblies.TryGetValue name.FullName with
|
match this._LoadedAssemblies.TryGetValue fullName with
|
||||||
| false, _ -> None
|
| false, _ -> None
|
||||||
| true, v -> Some v
|
| true, v -> Some v
|
||||||
|
|
||||||
|
member this.LoadedAssembly (name : AssemblyName) : DumpedAssembly option = this.LoadedAssembly' name.FullName
|
||||||
|
|
||||||
/// Returns also the original assembly name.
|
/// Returns also the original assembly name.
|
||||||
member this.WithThreadSwitchedToAssembly (assy : AssemblyName) (thread : ThreadId) : IlMachineState * AssemblyName =
|
member this.WithThreadSwitchedToAssembly (assy : AssemblyName) (thread : ThreadId) : IlMachineState * AssemblyName =
|
||||||
let mutable existing = Unchecked.defaultof<AssemblyName>
|
let mutable existing = Unchecked.defaultof<AssemblyName>
|
||||||
@@ -263,7 +260,7 @@ module IlMachineState =
|
|||||||
| None ->
|
| None ->
|
||||||
|
|
||||||
state, assy, generic, Some args
|
state, assy, generic, Some args
|
||||||
| TypeDefn.FromDefinition (defn, _typeKind) -> state, assy, assy.TypeDefs.[defn], None
|
| TypeDefn.FromDefinition (defn, _typeKind) -> state, assy, assy.TypeDefs.[defn.Get], None
|
||||||
| s -> failwith $"TODO: resolveTypeFromDefn unimplemented for {s}"
|
| s -> failwith $"TODO: resolveTypeFromDefn unimplemented for {s}"
|
||||||
|
|
||||||
let resolveTypeFromSpec
|
let resolveTypeFromSpec
|
||||||
@@ -303,11 +300,11 @@ module IlMachineState =
|
|||||||
|
|
||||||
let callMethod
|
let callMethod
|
||||||
(loggerFactory : ILoggerFactory)
|
(loggerFactory : ILoggerFactory)
|
||||||
(wasInitialising : (TypeDefinitionHandle * AssemblyName) option)
|
(wasInitialising : RuntimeConcreteType option)
|
||||||
(wasConstructing : ManagedHeapAddress option)
|
(wasConstructing : ManagedHeapAddress option)
|
||||||
(wasClassConstructor : bool)
|
(wasClassConstructor : bool)
|
||||||
(generics : ImmutableArray<TypeDefn> option)
|
(methodGenerics : ImmutableArray<TypeDefn> option)
|
||||||
(methodToCall : WoofWare.PawPrint.MethodInfo)
|
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||||
(thread : ThreadId)
|
(thread : ThreadId)
|
||||||
(threadState : ThreadState)
|
(threadState : ThreadState)
|
||||||
(state : IlMachineState)
|
(state : IlMachineState)
|
||||||
@@ -321,7 +318,7 @@ module IlMachineState =
|
|||||||
loggerFactory
|
loggerFactory
|
||||||
(state.ActiveAssembly thread)
|
(state.ActiveAssembly thread)
|
||||||
ty
|
ty
|
||||||
(generics |> Option.defaultValue ImmutableArray.Empty)
|
(methodGenerics |> Option.defaultValue ImmutableArray.Empty)
|
||||||
state
|
state
|
||||||
|
|
||||||
state, zero :: zeros
|
state, zero :: zeros
|
||||||
@@ -353,6 +350,7 @@ module IlMachineState =
|
|||||||
state._LoadedAssemblies
|
state._LoadedAssemblies
|
||||||
(state.ActiveAssembly thread)
|
(state.ActiveAssembly thread)
|
||||||
methodToCall
|
methodToCall
|
||||||
|
methodGenerics
|
||||||
(args.ToImmutable ())
|
(args.ToImmutable ())
|
||||||
(Some
|
(Some
|
||||||
{
|
{
|
||||||
@@ -369,7 +367,7 @@ module IlMachineState =
|
|||||||
let state, _, _ =
|
let state, _, _ =
|
||||||
loadAssembly
|
loadAssembly
|
||||||
loggerFactory
|
loggerFactory
|
||||||
(state.LoadedAssembly (snd methodToCall.DeclaringType) |> Option.get)
|
(state.LoadedAssembly methodToCall.DeclaringType.Assembly |> Option.get)
|
||||||
toLoad.Handle
|
toLoad.Handle
|
||||||
state
|
state
|
||||||
|
|
||||||
@@ -413,6 +411,7 @@ module IlMachineState =
|
|||||||
state._LoadedAssemblies
|
state._LoadedAssemblies
|
||||||
(state.ActiveAssembly thread)
|
(state.ActiveAssembly thread)
|
||||||
methodToCall
|
methodToCall
|
||||||
|
methodGenerics
|
||||||
(args.ToImmutable ())
|
(args.ToImmutable ())
|
||||||
(Some
|
(Some
|
||||||
{
|
{
|
||||||
@@ -429,7 +428,7 @@ module IlMachineState =
|
|||||||
let state, _, _ =
|
let state, _, _ =
|
||||||
loadAssembly
|
loadAssembly
|
||||||
loggerFactory
|
loggerFactory
|
||||||
(state.LoadedAssembly (snd methodToCall.DeclaringType) |> Option.get)
|
(state.LoadedAssembly methodToCall.DeclaringType.Assembly |> Option.get)
|
||||||
toLoad.Handle
|
toLoad.Handle
|
||||||
state
|
state
|
||||||
|
|
||||||
@@ -453,18 +452,14 @@ module IlMachineState =
|
|||||||
|
|
||||||
let rec loadClass
|
let rec loadClass
|
||||||
(loggerFactory : ILoggerFactory)
|
(loggerFactory : ILoggerFactory)
|
||||||
(typeDefHandle : TypeDefinitionHandle)
|
(ty : RuntimeConcreteType)
|
||||||
(assemblyName : AssemblyName)
|
|
||||||
(currentThread : ThreadId)
|
(currentThread : ThreadId)
|
||||||
(state : IlMachineState)
|
(state : IlMachineState)
|
||||||
: StateLoadResult
|
: StateLoadResult
|
||||||
=
|
=
|
||||||
if typeDefHandle.IsNil then
|
|
||||||
failwith "Called `loadClass` with a nil typedef"
|
|
||||||
|
|
||||||
let logger = loggerFactory.CreateLogger "LoadClass"
|
let logger = loggerFactory.CreateLogger "LoadClass"
|
||||||
|
|
||||||
match TypeInitTable.tryGet (typeDefHandle, assemblyName) state.TypeInitTable with
|
match TypeInitTable.tryGet ty state.TypeInitTable with
|
||||||
| Some TypeInitState.Initialized ->
|
| Some TypeInitState.Initialized ->
|
||||||
// Type already initialized; nothing to do
|
// Type already initialized; nothing to do
|
||||||
StateLoadResult.NothingToDo state
|
StateLoadResult.NothingToDo state
|
||||||
@@ -480,19 +475,19 @@ module IlMachineState =
|
|||||||
// We have work to do!
|
// We have work to do!
|
||||||
|
|
||||||
let state, origAssyName =
|
let state, origAssyName =
|
||||||
state.WithThreadSwitchedToAssembly assemblyName currentThread
|
state.WithThreadSwitchedToAssembly ty.Assembly currentThread
|
||||||
|
|
||||||
let sourceAssembly = state.LoadedAssembly assemblyName |> Option.get
|
let sourceAssembly = state.LoadedAssembly ty.Assembly |> Option.get
|
||||||
|
|
||||||
let typeDef =
|
let typeDef =
|
||||||
match sourceAssembly.TypeDefs.TryGetValue typeDefHandle with
|
match sourceAssembly.TypeDefs.TryGetValue ty.Definition.Get with
|
||||||
| false, _ -> failwith $"Failed to find type definition {typeDefHandle} in {assemblyName.Name}"
|
| false, _ -> failwith $"Failed to find type definition {ty.Definition.Get} in {ty.Assembly.FullName}"
|
||||||
| true, v -> v
|
| true, v -> v
|
||||||
|
|
||||||
logger.LogDebug ("Resolving type {TypeDefNamespace}.{TypeDefName}", typeDef.Namespace, typeDef.Name)
|
logger.LogDebug ("Resolving type {TypeDefNamespace}.{TypeDefName}", typeDef.Namespace, typeDef.Name)
|
||||||
|
|
||||||
// First mark as in-progress to detect cycles
|
// First mark as in-progress to detect cycles
|
||||||
let state = state.WithTypeBeginInit currentThread (typeDefHandle, assemblyName)
|
let state = state.WithTypeBeginInit currentThread ty
|
||||||
|
|
||||||
// Check if the type has a base type that needs initialization
|
// Check if the type has a base type that needs initialization
|
||||||
let firstDoBaseClass =
|
let firstDoBaseClass =
|
||||||
@@ -500,17 +495,17 @@ module IlMachineState =
|
|||||||
| Some baseTypeInfo ->
|
| Some baseTypeInfo ->
|
||||||
// Determine if base type is in the same or different assembly
|
// Determine if base type is in the same or different assembly
|
||||||
match baseTypeInfo with
|
match baseTypeInfo with
|
||||||
| ForeignAssemblyType (baseAssemblyName, baseTypeHandle) ->
|
| ForeignAssemblyType _ -> failwith "TODO"
|
||||||
logger.LogDebug (
|
//logger.LogDebug (
|
||||||
"Resolved base type of {TypeDefNamespace}.{TypeDefName} to foreign assembly {ForeignAssemblyName}",
|
// "Resolved base type of {TypeDefNamespace}.{TypeDefName} to foreign assembly {ForeignAssemblyName}",
|
||||||
typeDef.Namespace,
|
// typeDef.Namespace,
|
||||||
typeDef.Name,
|
// typeDef.Name,
|
||||||
baseAssemblyName.Name
|
// baseAssemblyName.Name
|
||||||
)
|
//)
|
||||||
|
|
||||||
match loadClass loggerFactory baseTypeHandle baseAssemblyName currentThread state with
|
//match loadClass loggerFactory baseTypeHandle baseAssemblyName currentThread state with
|
||||||
| FirstLoadThis state -> Error state
|
//| FirstLoadThis state -> Error state
|
||||||
| NothingToDo state -> Ok state
|
//| NothingToDo state -> Ok state
|
||||||
| TypeDef typeDefinitionHandle ->
|
| TypeDef typeDefinitionHandle ->
|
||||||
logger.LogDebug (
|
logger.LogDebug (
|
||||||
"Resolved base type of {TypeDefNamespace}.{TypeDefName} to this assembly, typedef",
|
"Resolved base type of {TypeDefNamespace}.{TypeDefName} to this assembly, typedef",
|
||||||
@@ -518,7 +513,10 @@ module IlMachineState =
|
|||||||
typeDef.Name
|
typeDef.Name
|
||||||
)
|
)
|
||||||
|
|
||||||
match loadClass loggerFactory typeDefinitionHandle assemblyName currentThread state with
|
// TypeDef won't have any generics; it would be a TypeSpec if it did
|
||||||
|
let ty = ConcreteType.make ty.Assembly typeDefinitionHandle []
|
||||||
|
|
||||||
|
match loadClass loggerFactory ty currentThread state with
|
||||||
| FirstLoadThis state -> Error state
|
| FirstLoadThis state -> Error state
|
||||||
| NothingToDo state -> Ok state
|
| NothingToDo state -> Ok state
|
||||||
| TypeRef typeReferenceHandle ->
|
| TypeRef typeReferenceHandle ->
|
||||||
@@ -534,7 +532,10 @@ module IlMachineState =
|
|||||||
targetType.Name
|
targetType.Name
|
||||||
)
|
)
|
||||||
|
|
||||||
match loadClass loggerFactory targetType.TypeDefHandle assy.Name currentThread state with
|
// TypeRef won't have any generics; it would be a TypeSpec if it did
|
||||||
|
let ty = ConcreteType.make assy.Name targetType.TypeDefHandle []
|
||||||
|
|
||||||
|
match loadClass loggerFactory ty currentThread state with
|
||||||
| FirstLoadThis state -> Error state
|
| FirstLoadThis state -> Error state
|
||||||
| NothingToDo state -> Ok state
|
| NothingToDo state -> Ok state
|
||||||
| TypeSpec typeSpecificationHandle -> failwith "TODO: TypeSpec base type loading unimplemented"
|
| TypeSpec typeSpecificationHandle -> failwith "TODO: TypeSpec base type loading unimplemented"
|
||||||
@@ -552,20 +553,23 @@ module IlMachineState =
|
|||||||
|> List.tryFind (fun method -> method.Name = ".cctor" && method.IsStatic && method.Parameters.IsEmpty)
|
|> List.tryFind (fun method -> method.Name = ".cctor" && method.IsStatic && method.Parameters.IsEmpty)
|
||||||
|
|
||||||
match cctor with
|
match cctor with
|
||||||
| Some ctorMethod ->
|
| Some cctorMethod ->
|
||||||
// Call the class constructor! Note that we *don't* use `callMethodInActiveAssembly`, because that
|
// Call the class constructor! Note that we *don't* use `callMethodInActiveAssembly`, because that
|
||||||
// performs class loading, but we're already in the middle of loading this class.
|
// performs class loading, but we're already in the middle of loading this class.
|
||||||
// TODO: factor out the common bit.
|
// TODO: factor out the common bit.
|
||||||
let currentThreadState = state.ThreadState.[currentThread]
|
let currentThreadState = state.ThreadState.[currentThread]
|
||||||
|
|
||||||
|
let cctorMethod =
|
||||||
|
cctorMethod |> MethodInfo.mapTypeGenerics (fun i _ -> ty.Generics.[i])
|
||||||
|
|
||||||
callMethod
|
callMethod
|
||||||
loggerFactory
|
loggerFactory
|
||||||
(Some (typeDefHandle, assemblyName))
|
(Some ty)
|
||||||
None
|
None
|
||||||
true
|
true
|
||||||
// constructor is surely not generic
|
// constructor is surely not generic
|
||||||
None
|
None
|
||||||
ctorMethod
|
cctorMethod
|
||||||
currentThread
|
currentThread
|
||||||
currentThreadState
|
currentThreadState
|
||||||
state
|
state
|
||||||
@@ -573,7 +577,7 @@ module IlMachineState =
|
|||||||
| None ->
|
| None ->
|
||||||
// No constructor, just continue.
|
// No constructor, just continue.
|
||||||
// Mark the type as initialized.
|
// Mark the type as initialized.
|
||||||
let state = state.WithTypeEndInit currentThread (typeDefHandle, assemblyName)
|
let state = state.WithTypeEndInit currentThread ty
|
||||||
|
|
||||||
// Restore original assembly context if needed
|
// Restore original assembly context if needed
|
||||||
state.WithThreadSwitchedToAssembly origAssyName currentThread
|
state.WithThreadSwitchedToAssembly origAssyName currentThread
|
||||||
@@ -583,13 +587,13 @@ module IlMachineState =
|
|||||||
let ensureTypeInitialised
|
let ensureTypeInitialised
|
||||||
(loggerFactory : ILoggerFactory)
|
(loggerFactory : ILoggerFactory)
|
||||||
(thread : ThreadId)
|
(thread : ThreadId)
|
||||||
(ty : TypeDefinitionHandle * AssemblyName)
|
(ty : RuntimeConcreteType)
|
||||||
(state : IlMachineState)
|
(state : IlMachineState)
|
||||||
: IlMachineState * WhatWeDid
|
: IlMachineState * WhatWeDid
|
||||||
=
|
=
|
||||||
match TypeInitTable.tryGet ty state.TypeInitTable with
|
match TypeInitTable.tryGet ty state.TypeInitTable with
|
||||||
| None ->
|
| None ->
|
||||||
match loadClass loggerFactory (fst ty) (snd ty) thread state with
|
match loadClass loggerFactory ty thread state with
|
||||||
| NothingToDo state -> state, WhatWeDid.Executed
|
| NothingToDo state -> state, WhatWeDid.Executed
|
||||||
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
||||||
| Some TypeInitState.Initialized -> state, WhatWeDid.Executed
|
| Some TypeInitState.Initialized -> state, WhatWeDid.Executed
|
||||||
@@ -603,8 +607,8 @@ module IlMachineState =
|
|||||||
let callMethodInActiveAssembly
|
let callMethodInActiveAssembly
|
||||||
(loggerFactory : ILoggerFactory)
|
(loggerFactory : ILoggerFactory)
|
||||||
(thread : ThreadId)
|
(thread : ThreadId)
|
||||||
(generics : TypeDefn ImmutableArray option)
|
(methodGenerics : TypeDefn ImmutableArray option)
|
||||||
(methodToCall : WoofWare.PawPrint.MethodInfo)
|
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||||
(weAreConstructingObj : ManagedHeapAddress option)
|
(weAreConstructingObj : ManagedHeapAddress option)
|
||||||
(state : IlMachineState)
|
(state : IlMachineState)
|
||||||
: IlMachineState * WhatWeDid
|
: IlMachineState * WhatWeDid
|
||||||
@@ -616,7 +620,16 @@ module IlMachineState =
|
|||||||
|
|
||||||
match typeInit with
|
match typeInit with
|
||||||
| WhatWeDid.Executed ->
|
| WhatWeDid.Executed ->
|
||||||
callMethod loggerFactory None weAreConstructingObj false generics methodToCall thread threadState state,
|
callMethod
|
||||||
|
loggerFactory
|
||||||
|
None
|
||||||
|
weAreConstructingObj
|
||||||
|
false
|
||||||
|
methodGenerics
|
||||||
|
methodToCall
|
||||||
|
thread
|
||||||
|
threadState
|
||||||
|
state,
|
||||||
WhatWeDid.Executed
|
WhatWeDid.Executed
|
||||||
| _ -> state, typeInit
|
| _ -> state, typeInit
|
||||||
|
|
||||||
@@ -844,7 +857,7 @@ module IlMachineState =
|
|||||||
(assy : DumpedAssembly)
|
(assy : DumpedAssembly)
|
||||||
(m : MemberReferenceHandle)
|
(m : MemberReferenceHandle)
|
||||||
(state : IlMachineState)
|
(state : IlMachineState)
|
||||||
: IlMachineState * AssemblyName * Choice<WoofWare.PawPrint.MethodInfo, WoofWare.PawPrint.FieldInfo>
|
: IlMachineState * AssemblyName * Choice<WoofWare.PawPrint.MethodInfo<TypeDefn>, WoofWare.PawPrint.FieldInfo>
|
||||||
=
|
=
|
||||||
// TODO: do we need to initialise the parent class here?
|
// TODO: do we need to initialise the parent class here?
|
||||||
let mem = assy.Members.[m]
|
let mem = assy.Members.[m]
|
||||||
@@ -887,7 +900,7 @@ module IlMachineState =
|
|||||||
| [] ->
|
| [] ->
|
||||||
failwith
|
failwith
|
||||||
$"Could not find member {memberName} with the right signature on {targetType.Namespace}.{targetType.Name}"
|
$"Could not find member {memberName} with the right signature on {targetType.Namespace}.{targetType.Name}"
|
||||||
| [ x ] -> x
|
| [ x ] -> x |> MethodInfo.mapTypeGenerics (fun i _ -> targetType.Generics.[i])
|
||||||
| _ ->
|
| _ ->
|
||||||
failwith
|
failwith
|
||||||
$"Multiple overloads matching signature for call to {targetType.Namespace}.{targetType.Name}'s {memberName}!"
|
$"Multiple overloads matching signature for call to {targetType.Namespace}.{targetType.Name}'s {memberName}!"
|
||||||
@@ -922,9 +935,8 @@ module IlMachineState =
|
|||||||
{ threadStateAtEndOfMethod with
|
{ threadStateAtEndOfMethod with
|
||||||
ActiveMethodState = returnState.JumpTo
|
ActiveMethodState = returnState.JumpTo
|
||||||
ActiveAssembly =
|
ActiveAssembly =
|
||||||
snd
|
threadStateAtEndOfMethod.MethodStates.[returnState.JumpTo].ExecutingMethod.DeclaringType
|
||||||
threadStateAtEndOfMethod.MethodStates.[returnState.JumpTo].ExecutingMethod
|
.Assembly
|
||||||
.DeclaringType
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -145,12 +145,12 @@ type MethodInstructions =
|
|||||||
/// Represents detailed information about a method in a .NET assembly.
|
/// Represents detailed information about a method in a .NET assembly.
|
||||||
/// This is a strongly-typed representation of MethodDefinition from System.Reflection.Metadata.
|
/// This is a strongly-typed representation of MethodDefinition from System.Reflection.Metadata.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
type MethodInfo =
|
type MethodInfo<'typeGenerics when 'typeGenerics :> IComparable<'typeGenerics> and 'typeGenerics : comparison> =
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The type that declares this method, along with its assembly information.
|
/// The type that declares this method, along with its assembly information.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
DeclaringType : TypeDefinitionHandle * AssemblyName
|
DeclaringType : ConcreteType<'typeGenerics>
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The metadata token handle that uniquely identifies this method in the assembly.
|
/// The metadata token handle that uniquely identifies this method in the assembly.
|
||||||
@@ -212,6 +212,26 @@ type MethodInfo =
|
|||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module MethodInfo =
|
module MethodInfo =
|
||||||
|
let mapTypeGenerics<'a, 'b
|
||||||
|
when 'a :> IComparable<'a> and 'a : comparison and 'b : comparison and 'b :> IComparable<'b>>
|
||||||
|
(f : int -> 'a -> 'b)
|
||||||
|
(m : MethodInfo<'a>)
|
||||||
|
: MethodInfo<'b>
|
||||||
|
=
|
||||||
|
{
|
||||||
|
DeclaringType = m.DeclaringType |> ConcreteType.mapGeneric f
|
||||||
|
Handle = m.Handle
|
||||||
|
Name = m.Name
|
||||||
|
Instructions = m.Instructions
|
||||||
|
Parameters = m.Parameters
|
||||||
|
Generics = m.Generics
|
||||||
|
Signature = m.Signature
|
||||||
|
CustomAttributes = m.CustomAttributes
|
||||||
|
MethodAttributes = m.MethodAttributes
|
||||||
|
ImplAttributes = m.ImplAttributes
|
||||||
|
IsStatic = m.IsStatic
|
||||||
|
}
|
||||||
|
|
||||||
type private Dummy = class end
|
type private Dummy = class end
|
||||||
|
|
||||||
type private MethodBody =
|
type private MethodBody =
|
||||||
@@ -558,7 +578,7 @@ module MethodInfo =
|
|||||||
(peReader : PEReader)
|
(peReader : PEReader)
|
||||||
(metadataReader : MetadataReader)
|
(metadataReader : MetadataReader)
|
||||||
(methodHandle : MethodDefinitionHandle)
|
(methodHandle : MethodDefinitionHandle)
|
||||||
: MethodInfo option
|
: MethodInfo<FakeUnit> option
|
||||||
=
|
=
|
||||||
let logger = loggerFactory.CreateLogger "MethodInfo"
|
let logger = loggerFactory.CreateLogger "MethodInfo"
|
||||||
let assemblyName = metadataReader.GetAssemblyDefinition().GetAssemblyName ()
|
let assemblyName = metadataReader.GetAssemblyDefinition().GetAssemblyName ()
|
||||||
@@ -592,6 +612,9 @@ module MethodInfo =
|
|||||||
|
|
||||||
let declaringType = methodDef.GetDeclaringType ()
|
let declaringType = methodDef.GetDeclaringType ()
|
||||||
|
|
||||||
|
let declaringTypeGenericParams =
|
||||||
|
metadataReader.GetTypeDefinition(declaringType).GetGenericParameters().Count
|
||||||
|
|
||||||
let attrs =
|
let attrs =
|
||||||
let result = ImmutableArray.CreateBuilder ()
|
let result = ImmutableArray.CreateBuilder ()
|
||||||
let attrs = methodDef.GetCustomAttributes ()
|
let attrs = methodDef.GetCustomAttributes ()
|
||||||
@@ -611,7 +634,7 @@ module MethodInfo =
|
|||||||
GenericParameter.readAll metadataReader (methodDef.GetGenericParameters ())
|
GenericParameter.readAll metadataReader (methodDef.GetGenericParameters ())
|
||||||
|
|
||||||
{
|
{
|
||||||
DeclaringType = (declaringType, assemblyName)
|
DeclaringType = ConcreteType.make' assemblyName declaringType declaringTypeGenericParams
|
||||||
Handle = methodHandle
|
Handle = methodHandle
|
||||||
Name = methodName
|
Name = methodName
|
||||||
Instructions = methodBody
|
Instructions = methodBody
|
||||||
@@ -624,3 +647,47 @@ module MethodInfo =
|
|||||||
ImplAttributes = implAttrs
|
ImplAttributes = implAttrs
|
||||||
}
|
}
|
||||||
|> Some
|
|> Some
|
||||||
|
|
||||||
|
let rec resolveBaseType
|
||||||
|
(methodGenerics : TypeDefn ImmutableArray option)
|
||||||
|
(executingMethod : MethodInfo<TypeDefn>)
|
||||||
|
(td : TypeDefn)
|
||||||
|
: ResolvedBaseType
|
||||||
|
=
|
||||||
|
match td with
|
||||||
|
| TypeDefn.Void -> failwith "Void isn't a type that appears at runtime and has no base type"
|
||||||
|
| TypeDefn.PrimitiveType ty ->
|
||||||
|
match ty with
|
||||||
|
| PrimitiveType.SByte
|
||||||
|
| PrimitiveType.Byte
|
||||||
|
| PrimitiveType.Int16
|
||||||
|
| PrimitiveType.UInt16
|
||||||
|
| PrimitiveType.Int32
|
||||||
|
| PrimitiveType.UInt32
|
||||||
|
| PrimitiveType.Int64
|
||||||
|
| PrimitiveType.UInt64
|
||||||
|
| PrimitiveType.Single
|
||||||
|
| PrimitiveType.Double
|
||||||
|
| PrimitiveType.Char
|
||||||
|
| PrimitiveType.Boolean -> ResolvedBaseType.ValueType
|
||||||
|
| PrimitiveType.String -> ResolvedBaseType.Object
|
||||||
|
| PrimitiveType.TypedReference -> failwith "todo"
|
||||||
|
| PrimitiveType.IntPtr -> failwith "todo"
|
||||||
|
| PrimitiveType.UIntPtr -> failwith "todo"
|
||||||
|
| PrimitiveType.Object -> failwith "todo"
|
||||||
|
| TypeDefn.Array (elt, shape) -> failwith "todo"
|
||||||
|
| TypeDefn.Pinned typeDefn -> failwith "todo"
|
||||||
|
| TypeDefn.Pointer typeDefn -> failwith "todo"
|
||||||
|
| TypeDefn.Byref typeDefn -> failwith "todo"
|
||||||
|
| TypeDefn.OneDimensionalArrayLowerBoundZero elements -> failwith "todo"
|
||||||
|
| TypeDefn.Modified (original, afterMod, modificationRequired) -> failwith "todo"
|
||||||
|
| TypeDefn.FromReference (typeRef, signatureTypeKind) -> failwith "todo"
|
||||||
|
| TypeDefn.FromDefinition (comparableTypeDefinitionHandle, signatureTypeKind) -> failwith "todo"
|
||||||
|
| TypeDefn.GenericInstantiation (generic, args) -> failwith "todo"
|
||||||
|
| TypeDefn.FunctionPointer typeMethodSignature -> failwith "todo"
|
||||||
|
| TypeDefn.GenericTypeParameter index ->
|
||||||
|
resolveBaseType methodGenerics executingMethod executingMethod.DeclaringType.Generics.[index]
|
||||||
|
| TypeDefn.GenericMethodParameter index ->
|
||||||
|
match methodGenerics with
|
||||||
|
| None -> failwith "unexpectedly asked for a generic method parameter when we had none"
|
||||||
|
| Some generics -> resolveBaseType methodGenerics executingMethod generics.[index]
|
||||||
|
@@ -1,14 +1,12 @@
|
|||||||
namespace WoofWare.PawPrint
|
namespace WoofWare.PawPrint
|
||||||
|
|
||||||
open System.Collections.Immutable
|
open System.Collections.Immutable
|
||||||
open System.Reflection
|
|
||||||
open System.Reflection.Metadata
|
|
||||||
|
|
||||||
type MethodReturnState =
|
type MethodReturnState =
|
||||||
{
|
{
|
||||||
/// Index in the MethodStates array of a ThreadState
|
/// Index in the MethodStates array of a ThreadState
|
||||||
JumpTo : int
|
JumpTo : int
|
||||||
WasInitialisingType : (TypeDefinitionHandle * AssemblyName) option
|
WasInitialisingType : RuntimeConcreteType option
|
||||||
/// The Newobj instruction means we need to push a reference immediately after Ret.
|
/// The Newobj instruction means we need to push a reference immediately after Ret.
|
||||||
WasConstructingObj : ManagedHeapAddress option
|
WasConstructingObj : ManagedHeapAddress option
|
||||||
}
|
}
|
||||||
@@ -21,11 +19,12 @@ and MethodState =
|
|||||||
IlOpIndex : int
|
IlOpIndex : int
|
||||||
EvaluationStack : EvalStack
|
EvaluationStack : EvalStack
|
||||||
Arguments : CliType ImmutableArray
|
Arguments : CliType ImmutableArray
|
||||||
ExecutingMethod : WoofWare.PawPrint.MethodInfo
|
ExecutingMethod : WoofWare.PawPrint.MethodInfo<TypeDefn>
|
||||||
/// We don't implement the local memory pool right now
|
/// We don't implement the local memory pool right now
|
||||||
LocalMemoryPool : unit
|
LocalMemoryPool : unit
|
||||||
/// On return, we restore this state. This should be Some almost always; an exception is the entry point.
|
/// On return, we restore this state. This should be Some almost always; an exception is the entry point.
|
||||||
ReturnState : MethodReturnState option
|
ReturnState : MethodReturnState option
|
||||||
|
Generics : ImmutableArray<TypeDefn> option
|
||||||
}
|
}
|
||||||
|
|
||||||
static member jumpProgramCounter (bytes : int) (state : MethodState) =
|
static member jumpProgramCounter (bytes : int) (state : MethodState) =
|
||||||
@@ -104,7 +103,8 @@ and MethodState =
|
|||||||
static member Empty
|
static member Empty
|
||||||
(loadedAssemblies : ImmutableDictionary<string, DumpedAssembly>)
|
(loadedAssemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||||
(containingAssembly : DumpedAssembly)
|
(containingAssembly : DumpedAssembly)
|
||||||
(method : WoofWare.PawPrint.MethodInfo)
|
(method : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||||
|
(methodGenerics : ImmutableArray<TypeDefn> option)
|
||||||
(args : ImmutableArray<CliType>)
|
(args : ImmutableArray<CliType>)
|
||||||
(returnState : MethodReturnState option)
|
(returnState : MethodReturnState option)
|
||||||
: Result<MethodState, WoofWare.PawPrint.AssemblyReference list>
|
: Result<MethodState, WoofWare.PawPrint.AssemblyReference list>
|
||||||
@@ -154,5 +154,6 @@ and MethodState =
|
|||||||
ExecutingMethod = method
|
ExecutingMethod = method
|
||||||
LocalMemoryPool = ()
|
LocalMemoryPool = ()
|
||||||
ReturnState = returnState
|
ReturnState = returnState
|
||||||
|
Generics = methodGenerics
|
||||||
}
|
}
|
||||||
|> Ok
|
|> Ok
|
||||||
|
@@ -65,6 +65,10 @@ module Program =
|
|||||||
if mainMethod.Signature.GenericParameterCount > 0 then
|
if mainMethod.Signature.GenericParameterCount > 0 then
|
||||||
failwith "Refusing to execute generic main method"
|
failwith "Refusing to execute generic main method"
|
||||||
|
|
||||||
|
let mainMethod =
|
||||||
|
mainMethod
|
||||||
|
|> MethodInfo.mapTypeGenerics (fun _ -> failwith "Refusing to execute generic main method")
|
||||||
|
|
||||||
let state, mainThread =
|
let state, mainThread =
|
||||||
IlMachineState.initial loggerFactory dotnetRuntimeDirs dumped
|
IlMachineState.initial loggerFactory dotnetRuntimeDirs dumped
|
||||||
// The thread's state is slightly fake: we will need to put arguments onto the stack before actually
|
// The thread's state is slightly fake: we will need to put arguments onto the stack before actually
|
||||||
@@ -78,6 +82,7 @@ module Program =
|
|||||||
s._LoadedAssemblies
|
s._LoadedAssemblies
|
||||||
dumped
|
dumped
|
||||||
mainMethod
|
mainMethod
|
||||||
|
None
|
||||||
(ImmutableArray.CreateRange [ CliType.ObjectRef None ])
|
(ImmutableArray.CreateRange [ CliType.ObjectRef None ])
|
||||||
None
|
None
|
||||||
with
|
with
|
||||||
@@ -87,11 +92,7 @@ module Program =
|
|||||||
let rec loadInitialState (state : IlMachineState) =
|
let rec loadInitialState (state : IlMachineState) =
|
||||||
match
|
match
|
||||||
state
|
state
|
||||||
|> IlMachineState.loadClass
|
|> IlMachineState.loadClass loggerFactory mainMethod.DeclaringType mainThread
|
||||||
loggerFactory
|
|
||||||
(fst mainMethod.DeclaringType)
|
|
||||||
(snd mainMethod.DeclaringType)
|
|
||||||
mainThread
|
|
||||||
with
|
with
|
||||||
| StateLoadResult.NothingToDo ilMachineState -> ilMachineState
|
| StateLoadResult.NothingToDo ilMachineState -> ilMachineState
|
||||||
| StateLoadResult.FirstLoadThis ilMachineState -> loadInitialState ilMachineState
|
| StateLoadResult.FirstLoadThis ilMachineState -> loadInitialState ilMachineState
|
||||||
@@ -126,6 +127,7 @@ module Program =
|
|||||||
state._LoadedAssemblies
|
state._LoadedAssemblies
|
||||||
dumped
|
dumped
|
||||||
mainMethod
|
mainMethod
|
||||||
|
None
|
||||||
(ImmutableArray.Create (CliType.OfManagedObject arrayAllocation))
|
(ImmutableArray.Create (CliType.OfManagedObject arrayAllocation))
|
||||||
None
|
None
|
||||||
with
|
with
|
||||||
|
@@ -3,6 +3,13 @@ namespace WoofWare.PawPrint
|
|||||||
open System.Collections.Immutable
|
open System.Collections.Immutable
|
||||||
open System.Reflection.Metadata
|
open System.Reflection.Metadata
|
||||||
open System.Reflection.Metadata.Ecma335
|
open System.Reflection.Metadata.Ecma335
|
||||||
|
open Microsoft.FSharp.Core
|
||||||
|
|
||||||
|
type ResolvedBaseType =
|
||||||
|
| Enum
|
||||||
|
| ValueType
|
||||||
|
| Object
|
||||||
|
| Delegate
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a method signature with type parameters.
|
/// Represents a method signature with type parameters.
|
||||||
@@ -13,7 +20,7 @@ type TypeMethodSignature<'Types> =
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains calling convention and other method attributes encoded in the metadata.
|
/// Contains calling convention and other method attributes encoded in the metadata.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Header : SignatureHeader
|
Header : ComparableSignatureHeader
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The types of all parameters of the method.
|
/// The types of all parameters of the method.
|
||||||
@@ -40,7 +47,7 @@ type TypeMethodSignature<'Types> =
|
|||||||
module TypeMethodSignature =
|
module TypeMethodSignature =
|
||||||
let make<'T> (p : MethodSignature<'T>) : TypeMethodSignature<'T> =
|
let make<'T> (p : MethodSignature<'T>) : TypeMethodSignature<'T> =
|
||||||
{
|
{
|
||||||
Header = p.Header
|
Header = ComparableSignatureHeader.Make p.Header
|
||||||
ReturnType = p.ReturnType
|
ReturnType = p.ReturnType
|
||||||
ParameterTypes = List.ofSeq p.ParameterTypes
|
ParameterTypes = List.ofSeq p.ParameterTypes
|
||||||
GenericParameterCount = p.GenericParameterCount
|
GenericParameterCount = p.GenericParameterCount
|
||||||
@@ -91,14 +98,15 @@ type PrimitiveType =
|
|||||||
|
|
||||||
type TypeDefn =
|
type TypeDefn =
|
||||||
| PrimitiveType of PrimitiveType
|
| PrimitiveType of PrimitiveType
|
||||||
| Array of elt : TypeDefn * shape : ArrayShape
|
// TODO: array shapes
|
||||||
|
| Array of elt : TypeDefn * shape : unit
|
||||||
| Pinned of TypeDefn
|
| Pinned of TypeDefn
|
||||||
| Pointer of TypeDefn
|
| Pointer of TypeDefn
|
||||||
| Byref of TypeDefn
|
| Byref of TypeDefn
|
||||||
| OneDimensionalArrayLowerBoundZero of elements : TypeDefn
|
| OneDimensionalArrayLowerBoundZero of elements : TypeDefn
|
||||||
| Modified of original : TypeDefn * afterMod : TypeDefn * modificationRequired : bool
|
| Modified of original : TypeDefn * afterMod : TypeDefn * modificationRequired : bool
|
||||||
| FromReference of TypeRef * SignatureTypeKind
|
| FromReference of TypeRef * SignatureTypeKind
|
||||||
| FromDefinition of TypeDefinitionHandle * SignatureTypeKind
|
| FromDefinition of ComparableTypeDefinitionHandle * SignatureTypeKind
|
||||||
| GenericInstantiation of generic : TypeDefn * args : ImmutableArray<TypeDefn>
|
| GenericInstantiation of generic : TypeDefn * args : ImmutableArray<TypeDefn>
|
||||||
| FunctionPointer of TypeMethodSignature<TypeDefn>
|
| FunctionPointer of TypeMethodSignature<TypeDefn>
|
||||||
| GenericTypeParameter of index : int
|
| GenericTypeParameter of index : int
|
||||||
@@ -169,7 +177,7 @@ module TypeDefn =
|
|||||||
let typeProvider : ISignatureTypeProvider<TypeDefn, unit> =
|
let typeProvider : ISignatureTypeProvider<TypeDefn, unit> =
|
||||||
{ new ISignatureTypeProvider<TypeDefn, unit> with
|
{ new ISignatureTypeProvider<TypeDefn, unit> with
|
||||||
member this.GetArrayType (elementType : TypeDefn, shape : ArrayShape) : TypeDefn =
|
member this.GetArrayType (elementType : TypeDefn, shape : ArrayShape) : TypeDefn =
|
||||||
TypeDefn.Array (elementType, shape)
|
TypeDefn.Array (elementType, ())
|
||||||
|
|
||||||
member this.GetByReferenceType (elementType : TypeDefn) : TypeDefn = TypeDefn.Byref elementType
|
member this.GetByReferenceType (elementType : TypeDefn) : TypeDefn = TypeDefn.Byref elementType
|
||||||
|
|
||||||
@@ -194,7 +202,7 @@ module TypeDefn =
|
|||||||
let handle' : EntityHandle = TypeDefinitionHandle.op_Implicit handle
|
let handle' : EntityHandle = TypeDefinitionHandle.op_Implicit handle
|
||||||
let typeKind = reader.ResolveSignatureTypeKind (handle', rawTypeKind)
|
let typeKind = reader.ResolveSignatureTypeKind (handle', rawTypeKind)
|
||||||
|
|
||||||
TypeDefn.FromDefinition (handle, typeKind)
|
TypeDefn.FromDefinition (ComparableTypeDefinitionHandle.Make handle, typeKind)
|
||||||
|
|
||||||
member this.GetTypeFromReference
|
member this.GetTypeFromReference
|
||||||
(reader : MetadataReader, handle : TypeReferenceHandle, rawTypeKind : byte)
|
(reader : MetadataReader, handle : TypeReferenceHandle, rawTypeKind : byte)
|
||||||
|
@@ -14,12 +14,6 @@ type BaseTypeInfo =
|
|||||||
| TypeSpec of TypeSpecificationHandle
|
| TypeSpec of TypeSpecificationHandle
|
||||||
| ForeignAssemblyType of assemblyName : AssemblyName * TypeDefinitionHandle
|
| ForeignAssemblyType of assemblyName : AssemblyName * TypeDefinitionHandle
|
||||||
|
|
||||||
type ResolvedBaseType =
|
|
||||||
| Enum
|
|
||||||
| ValueType
|
|
||||||
| Object
|
|
||||||
| Delegate
|
|
||||||
|
|
||||||
type MethodImplParsed =
|
type MethodImplParsed =
|
||||||
| MethodImplementation of MethodImplementationHandle
|
| MethodImplementation of MethodImplementationHandle
|
||||||
| MethodDefinition of MethodDefinitionHandle
|
| MethodDefinition of MethodDefinitionHandle
|
||||||
@@ -39,7 +33,7 @@ type TypeInfo<'generic> =
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// All methods defined within this type.
|
/// All methods defined within this type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Methods : WoofWare.PawPrint.MethodInfo list
|
Methods : WoofWare.PawPrint.MethodInfo<FakeUnit> list
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Method implementation mappings for this type, often used for interface implementations
|
/// Method implementation mappings for this type, often used for interface implementations
|
||||||
|
@@ -11,32 +11,22 @@ type TypeInitState =
|
|||||||
|
|
||||||
/// Tracks the initialization state of types across assemblies. The string in the key is the FullName of the AssemblyName where the type comes from.
|
/// Tracks the initialization state of types across assemblies. The string in the key is the FullName of the AssemblyName where the type comes from.
|
||||||
// TODO: need a better solution than string here! AssemblyName didn't work, we had nonequal assembly names.
|
// TODO: need a better solution than string here! AssemblyName didn't work, we had nonequal assembly names.
|
||||||
type TypeInitTable = ImmutableDictionary<TypeDefinitionHandle * string, TypeInitState>
|
type TypeInitTable = ImmutableDictionary<RuntimeConcreteType, TypeInitState>
|
||||||
|
|
||||||
[<RequireQualifiedAccess>]
|
[<RequireQualifiedAccess>]
|
||||||
module TypeInitTable =
|
module TypeInitTable =
|
||||||
let tryGet (typeDef : TypeDefinitionHandle, assy : AssemblyName) (t : TypeInitTable) =
|
let tryGet (ty : RuntimeConcreteType) (t : TypeInitTable) =
|
||||||
match t.TryGetValue ((typeDef, assy.FullName)) with
|
match t.TryGetValue ty with
|
||||||
| true, v -> Some v
|
| true, v -> Some v
|
||||||
| false, _ -> None
|
| false, _ -> None
|
||||||
|
|
||||||
let beginInitialising
|
let beginInitialising (thread : ThreadId) (ty : RuntimeConcreteType) (t : TypeInitTable) : TypeInitTable =
|
||||||
(thread : ThreadId)
|
match t.TryGetValue ty with
|
||||||
(typeDef : TypeDefinitionHandle, assy : AssemblyName)
|
| false, _ -> t.Add (ty, TypeInitState.InProgress thread)
|
||||||
(t : TypeInitTable)
|
|
||||||
: TypeInitTable
|
|
||||||
=
|
|
||||||
match t.TryGetValue ((typeDef, assy.FullName)) with
|
|
||||||
| false, _ -> t.Add ((typeDef, assy.FullName), TypeInitState.InProgress thread)
|
|
||||||
| true, v -> failwith "Logic error: tried initialising a type which has already started initialising"
|
| true, v -> failwith "Logic error: tried initialising a type which has already started initialising"
|
||||||
|
|
||||||
let markInitialised
|
let markInitialised (thread : ThreadId) (ty : RuntimeConcreteType) (t : TypeInitTable) : TypeInitTable =
|
||||||
(thread : ThreadId)
|
match t.TryGetValue ty with
|
||||||
(typeDef : TypeDefinitionHandle, assy : AssemblyName)
|
|
||||||
(t : TypeInitTable)
|
|
||||||
: TypeInitTable
|
|
||||||
=
|
|
||||||
match t.TryGetValue ((typeDef, assy.FullName)) with
|
|
||||||
| false, _ -> failwith "Logic error: completing initialisation of a type which never started initialising"
|
| false, _ -> failwith "Logic error: completing initialisation of a type which never started initialising"
|
||||||
| true, TypeInitState.Initialized ->
|
| true, TypeInitState.Initialized ->
|
||||||
failwith "Logic error: completing initialisation of a type which has already finished initialising"
|
failwith "Logic error: completing initialisation of a type which has already finished initialising"
|
||||||
@@ -45,4 +35,4 @@ module TypeInitTable =
|
|||||||
failwith
|
failwith
|
||||||
"Logic error: completed initialisation of a type on a different thread to the one which started it!"
|
"Logic error: completed initialisation of a type on a different thread to the one which started it!"
|
||||||
else
|
else
|
||||||
t.SetItem ((typeDef, assy.FullName), TypeInitState.Initialized)
|
t.SetItem (ty, TypeInitState.Initialized)
|
||||||
|
@@ -1,12 +1,60 @@
|
|||||||
namespace WoofWare.PawPrint
|
namespace WoofWare.PawPrint
|
||||||
|
|
||||||
|
open System
|
||||||
open System.Reflection.Metadata
|
open System.Reflection.Metadata
|
||||||
|
open Microsoft.FSharp.Core
|
||||||
|
|
||||||
|
[<CustomComparison>]
|
||||||
|
[<CustomEquality>]
|
||||||
type TypeRefResolutionScope =
|
type TypeRefResolutionScope =
|
||||||
| Assembly of AssemblyReferenceHandle
|
| Assembly of AssemblyReferenceHandle
|
||||||
| ModuleRef of ModuleReferenceHandle
|
| ModuleRef of ModuleReferenceHandle
|
||||||
| TypeRef of TypeReferenceHandle
|
| TypeRef of TypeReferenceHandle
|
||||||
|
|
||||||
|
override this.Equals (other : obj) : bool =
|
||||||
|
let other =
|
||||||
|
match other with
|
||||||
|
| :? TypeRefResolutionScope as other -> other
|
||||||
|
| _ -> failwith "should never compare with non-TypeRefResolutionScope"
|
||||||
|
|
||||||
|
match this, other with
|
||||||
|
| TypeRefResolutionScope.Assembly a1, TypeRefResolutionScope.Assembly a2 -> a1 = a2
|
||||||
|
| TypeRefResolutionScope.Assembly _, _ -> false
|
||||||
|
| TypeRefResolutionScope.ModuleRef m1, TypeRefResolutionScope.ModuleRef m2 -> m1 = m2
|
||||||
|
| TypeRefResolutionScope.ModuleRef _, _ -> false
|
||||||
|
| TypeRefResolutionScope.TypeRef t1, TypeRefResolutionScope.TypeRef t2 -> t1 = t2
|
||||||
|
| TypeRefResolutionScope.TypeRef _, _ -> false
|
||||||
|
|
||||||
|
override this.GetHashCode () : int =
|
||||||
|
match this with
|
||||||
|
| TypeRefResolutionScope.Assembly h -> hash (1, h)
|
||||||
|
| TypeRefResolutionScope.ModuleRef h -> hash (2, h)
|
||||||
|
| TypeRefResolutionScope.TypeRef h -> hash (3, h)
|
||||||
|
|
||||||
|
interface IComparable<TypeRefResolutionScope> with
|
||||||
|
member this.CompareTo other =
|
||||||
|
match this, other with
|
||||||
|
| TypeRefResolutionScope.Assembly h1, TypeRefResolutionScope.Assembly h2 ->
|
||||||
|
// this happens to get the underlying int
|
||||||
|
h1.GetHashCode().CompareTo (h2.GetHashCode ())
|
||||||
|
| TypeRefResolutionScope.Assembly _, TypeRefResolutionScope.ModuleRef _ -> -1
|
||||||
|
| TypeRefResolutionScope.Assembly _, TypeRefResolutionScope.TypeRef _ -> -1
|
||||||
|
| TypeRefResolutionScope.ModuleRef _, Assembly _ -> 1
|
||||||
|
| TypeRefResolutionScope.ModuleRef m1, ModuleRef m2 -> m1.GetHashCode().CompareTo (m2.GetHashCode ())
|
||||||
|
| TypeRefResolutionScope.ModuleRef _, TypeRef _ -> -1
|
||||||
|
| TypeRefResolutionScope.TypeRef _, Assembly _ -> 1
|
||||||
|
| TypeRefResolutionScope.TypeRef _, ModuleRef _ -> 1
|
||||||
|
| TypeRefResolutionScope.TypeRef t1, TypeRef t2 -> t1.GetHashCode().CompareTo (t2.GetHashCode ())
|
||||||
|
|
||||||
|
interface IComparable with
|
||||||
|
member this.CompareTo (other : obj) : int =
|
||||||
|
let other =
|
||||||
|
match other with
|
||||||
|
| :? TypeRefResolutionScope as other -> other
|
||||||
|
| _ -> failwith "unexpectedly comparing TypeRefResolutionScope with something else"
|
||||||
|
|
||||||
|
(this :> IComparable<TypeRefResolutionScope>).CompareTo other
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a type reference in a .NET assembly metadata.
|
/// Represents a type reference in a .NET assembly metadata.
|
||||||
/// This corresponds to a TypeReferenceHandle in System.Reflection.Metadata.
|
/// This corresponds to a TypeReferenceHandle in System.Reflection.Metadata.
|
||||||
|
@@ -17,14 +17,20 @@ module internal UnaryMetadataIlOp =
|
|||||||
=
|
=
|
||||||
match op with
|
match op with
|
||||||
| Call ->
|
| Call ->
|
||||||
let state, methodToCall, generics =
|
let activeAssy = state.ActiveAssembly thread
|
||||||
|
|
||||||
|
let state, methodToCall, methodGenerics =
|
||||||
match metadataToken with
|
match metadataToken with
|
||||||
| MetadataToken.MethodSpecification h ->
|
| MetadataToken.MethodSpecification h ->
|
||||||
let spec = (state.ActiveAssembly thread).MethodSpecs.[h]
|
let spec = activeAssy.MethodSpecs.[h]
|
||||||
|
|
||||||
match spec.Method with
|
match spec.Method with
|
||||||
| MetadataToken.MethodDef token ->
|
| MetadataToken.MethodDef token ->
|
||||||
state, (state.ActiveAssembly thread).Methods.[token], Some spec.Signature
|
let method =
|
||||||
|
activeAssy.Methods.[token]
|
||||||
|
|> MethodInfo.mapTypeGenerics (fun i _ -> spec.Signature.[i])
|
||||||
|
|
||||||
|
state, method, Some spec.Signature
|
||||||
| MetadataToken.MemberReference ref ->
|
| MetadataToken.MemberReference ref ->
|
||||||
let state, _, method =
|
let state, _, method =
|
||||||
IlMachineState.resolveMember loggerFactory (state.ActiveAssembly thread) ref state
|
IlMachineState.resolveMember loggerFactory (state.ActiveAssembly thread) ref state
|
||||||
@@ -42,25 +48,18 @@ module internal UnaryMetadataIlOp =
|
|||||||
| Choice1Of2 method -> state, method, None
|
| Choice1Of2 method -> state, method, None
|
||||||
|
|
||||||
| MetadataToken.MethodDef defn ->
|
| MetadataToken.MethodDef defn ->
|
||||||
let activeAssy = state.ActiveAssembly thread
|
|
||||||
|
|
||||||
match activeAssy.Methods.TryGetValue defn with
|
match activeAssy.Methods.TryGetValue defn with
|
||||||
| true, method -> state, method, None
|
| true, method ->
|
||||||
|
let method = method |> MethodInfo.mapTypeGenerics (fun _ -> failwith "not generic")
|
||||||
|
state, method, None
|
||||||
| false, _ -> failwith $"could not find method in {activeAssy.Name}"
|
| false, _ -> failwith $"could not find method in {activeAssy.Name}"
|
||||||
| k -> failwith $"Unrecognised kind: %O{k}"
|
| k -> failwith $"Unrecognised kind: %O{k}"
|
||||||
|
|
||||||
match
|
match IlMachineState.loadClass loggerFactory methodToCall.DeclaringType thread state with
|
||||||
IlMachineState.loadClass
|
|
||||||
loggerFactory
|
|
||||||
(fst methodToCall.DeclaringType)
|
|
||||||
(snd methodToCall.DeclaringType)
|
|
||||||
thread
|
|
||||||
state
|
|
||||||
with
|
|
||||||
| NothingToDo state ->
|
| NothingToDo state ->
|
||||||
state.WithThreadSwitchedToAssembly (snd methodToCall.DeclaringType) thread
|
state.WithThreadSwitchedToAssembly methodToCall.DeclaringType.Assembly thread
|
||||||
|> fst
|
|> fst
|
||||||
|> IlMachineState.callMethodInActiveAssembly loggerFactory thread generics methodToCall None
|
|> IlMachineState.callMethodInActiveAssembly loggerFactory thread methodGenerics methodToCall None
|
||||||
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
||||||
|
|
||||||
| Callvirt ->
|
| Callvirt ->
|
||||||
@@ -82,8 +81,8 @@ module internal UnaryMetadataIlOp =
|
|||||||
| Some obj -> obj
|
| Some obj -> obj
|
||||||
|
|
||||||
do
|
do
|
||||||
let assy = state.LoadedAssembly (snd method.DeclaringType) |> Option.get
|
let assy = state.LoadedAssembly method.DeclaringType.Assembly |> Option.get
|
||||||
let ty = assy.TypeDefs.[fst method.DeclaringType]
|
let ty = assy.TypeDefs.[method.DeclaringType.Definition.Get]
|
||||||
|
|
||||||
logger.LogTrace (
|
logger.LogTrace (
|
||||||
"Calling method {Assembly}.{Type}.{CallvirtMethod} on object {CallvirtObject}",
|
"Calling method {Assembly}.{Type}.{CallvirtMethod} on object {CallvirtObject}",
|
||||||
@@ -122,7 +121,11 @@ module internal UnaryMetadataIlOp =
|
|||||||
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
| EvalStackValue.ObjectRef managedHeapAddress -> failwith "todo"
|
||||||
| _ -> failwith $"TODO (Callvirt): can't identify type of {currentObj}"
|
| _ -> failwith $"TODO (Callvirt): can't identify type of {currentObj}"
|
||||||
|
|
||||||
state.WithThreadSwitchedToAssembly (snd methodToCall.DeclaringType) thread
|
let methodToCall =
|
||||||
|
methodToCall
|
||||||
|
|> MethodInfo.mapTypeGenerics (fun _ -> failwith "TODO: look up generics from runtime type information")
|
||||||
|
|
||||||
|
state.WithThreadSwitchedToAssembly methodToCall.DeclaringType.Assembly thread
|
||||||
|> fst
|
|> fst
|
||||||
|> IlMachineState.callMethodInActiveAssembly loggerFactory thread generics methodToCall None
|
|> IlMachineState.callMethodInActiveAssembly loggerFactory thread generics methodToCall None
|
||||||
| Castclass -> failwith "TODO: Castclass unimplemented"
|
| Castclass -> failwith "TODO: Castclass unimplemented"
|
||||||
@@ -134,7 +137,7 @@ module internal UnaryMetadataIlOp =
|
|||||||
| MethodDef md ->
|
| MethodDef md ->
|
||||||
let activeAssy = state.ActiveAssembly thread
|
let activeAssy = state.ActiveAssembly thread
|
||||||
let method = activeAssy.Methods.[md]
|
let method = activeAssy.Methods.[md]
|
||||||
state, activeAssy.Name, method
|
state, activeAssy.Name, MethodInfo.mapTypeGenerics (fun _ -> failwith "non-generic method") method
|
||||||
| MemberReference mr ->
|
| MemberReference mr ->
|
||||||
let state, name, method =
|
let state, name, method =
|
||||||
IlMachineState.resolveMember loggerFactory (state.ActiveAssembly thread) mr state
|
IlMachineState.resolveMember loggerFactory (state.ActiveAssembly thread) mr state
|
||||||
@@ -152,9 +155,8 @@ module internal UnaryMetadataIlOp =
|
|||||||
| WhatWeDid.SuspendedForClassInit -> state, SuspendedForClassInit
|
| WhatWeDid.SuspendedForClassInit -> state, SuspendedForClassInit
|
||||||
| WhatWeDid.Executed ->
|
| WhatWeDid.Executed ->
|
||||||
|
|
||||||
let ctorType, ctorAssembly = ctor.DeclaringType
|
let ctorAssembly = state.LoadedAssembly ctor.DeclaringType.Assembly |> Option.get
|
||||||
let ctorAssembly = state.LoadedAssembly ctorAssembly |> Option.get
|
let ctorType = ctorAssembly.TypeDefs.[ctor.DeclaringType.Definition.Get]
|
||||||
let ctorType = ctorAssembly.TypeDefs.[ctorType]
|
|
||||||
|
|
||||||
do
|
do
|
||||||
logger.LogDebug (
|
logger.LogDebug (
|
||||||
@@ -215,7 +217,7 @@ module internal UnaryMetadataIlOp =
|
|||||||
| EvalStackValue.Int32 v -> v
|
| EvalStackValue.Int32 v -> v
|
||||||
| popped -> failwith $"unexpectedly popped value %O{popped} to serve as array len"
|
| popped -> failwith $"unexpectedly popped value %O{popped} to serve as array len"
|
||||||
|
|
||||||
let elementType, baseType =
|
let baseType =
|
||||||
match metadataToken with
|
match metadataToken with
|
||||||
| MetadataToken.TypeDefinition defn ->
|
| MetadataToken.TypeDefinition defn ->
|
||||||
let assy = state.LoadedAssembly currentState.ActiveAssembly |> Option.get
|
let assy = state.LoadedAssembly currentState.ActiveAssembly |> Option.get
|
||||||
@@ -229,11 +231,12 @@ module internal UnaryMetadataIlOp =
|
|||||||
baseClassTypes
|
baseClassTypes
|
||||||
elementType.Assembly
|
elementType.Assembly
|
||||||
|
|
||||||
elementType, baseType
|
baseType
|
||||||
| MetadataToken.TypeSpecification spec ->
|
| MetadataToken.TypeSpecification spec ->
|
||||||
let assy = state.LoadedAssembly currentState.ActiveAssembly |> Option.get
|
let assy = state.LoadedAssembly currentState.ActiveAssembly |> Option.get
|
||||||
let elementType = assy.TypeSpecs.[spec]
|
let elementType = assy.TypeSpecs.[spec].Signature
|
||||||
failwith ""
|
|
||||||
|
MethodInfo.resolveBaseType newMethodState.Generics newMethodState.ExecutingMethod elementType
|
||||||
| x -> failwith $"TODO: Newarr element type resolution unimplemented for {x}"
|
| x -> failwith $"TODO: Newarr element type resolution unimplemented for {x}"
|
||||||
|
|
||||||
let zeroOfType =
|
let zeroOfType =
|
||||||
@@ -279,15 +282,20 @@ module internal UnaryMetadataIlOp =
|
|||||||
|
|
||||||
state, WhatWeDid.Executed
|
state, WhatWeDid.Executed
|
||||||
| Stfld ->
|
| Stfld ->
|
||||||
let state, assyName, field =
|
let activeAssy = state.ActiveAssembly thread
|
||||||
|
|
||||||
|
let state, declaringType, field =
|
||||||
match metadataToken with
|
match metadataToken with
|
||||||
| MetadataToken.FieldDefinition f ->
|
| MetadataToken.FieldDefinition f ->
|
||||||
state, (state.ActiveAssembly thread).Name, state.ActiveAssembly(thread).Fields.[f]
|
let field = activeAssy.Fields.[f]
|
||||||
|
// No generics on a type if we're accessing it by FieldDefinition
|
||||||
|
let declaringType = ConcreteType.make activeAssy.Name field.DeclaringType []
|
||||||
|
state, declaringType, field
|
||||||
| t -> failwith $"Unexpectedly asked to store to a non-field: {t}"
|
| t -> failwith $"Unexpectedly asked to store to a non-field: {t}"
|
||||||
|
|
||||||
do
|
do
|
||||||
let logger = loggerFactory.CreateLogger "Stfld"
|
let logger = loggerFactory.CreateLogger "Stfld"
|
||||||
let declaring = state.ActiveAssembly(thread).TypeDefs.[field.DeclaringType]
|
let declaring = activeAssy.TypeDefs.[field.DeclaringType]
|
||||||
|
|
||||||
logger.LogInformation (
|
logger.LogInformation (
|
||||||
"Storing in object field {FieldAssembly}.{FieldDeclaringType}.{FieldName} (type {FieldType})",
|
"Storing in object field {FieldAssembly}.{FieldDeclaringType}.{FieldName} (type {FieldType})",
|
||||||
@@ -300,12 +308,11 @@ module internal UnaryMetadataIlOp =
|
|||||||
let valueToStore, state = IlMachineState.popEvalStack thread state
|
let valueToStore, state = IlMachineState.popEvalStack thread state
|
||||||
|
|
||||||
let state, zero =
|
let state, zero =
|
||||||
// TODO: generics
|
|
||||||
IlMachineState.cliTypeZeroOf
|
IlMachineState.cliTypeZeroOf
|
||||||
loggerFactory
|
loggerFactory
|
||||||
(state.ActiveAssembly thread)
|
(state.ActiveAssembly thread)
|
||||||
field.Signature
|
field.Signature
|
||||||
ImmutableArray.Empty
|
(ImmutableArray.CreateRange declaringType.Generics)
|
||||||
state
|
state
|
||||||
|
|
||||||
let valueToStore = EvalStackValue.toCliTypeCoerced zero valueToStore
|
let valueToStore = EvalStackValue.toCliTypeCoerced zero valueToStore
|
||||||
@@ -313,7 +320,7 @@ module internal UnaryMetadataIlOp =
|
|||||||
let currentObj, state = IlMachineState.popEvalStack thread state
|
let currentObj, state = IlMachineState.popEvalStack thread state
|
||||||
|
|
||||||
if field.Attributes.HasFlag FieldAttributes.Static then
|
if field.Attributes.HasFlag FieldAttributes.Static then
|
||||||
let state = state.SetStatic (field.DeclaringType, assyName) field.Name valueToStore
|
let state = state.SetStatic declaringType field.Name valueToStore
|
||||||
|
|
||||||
state, WhatWeDid.Executed
|
state, WhatWeDid.Executed
|
||||||
else
|
else
|
||||||
@@ -353,16 +360,29 @@ module internal UnaryMetadataIlOp =
|
|||||||
|> Tuple.withRight WhatWeDid.Executed
|
|> Tuple.withRight WhatWeDid.Executed
|
||||||
|
|
||||||
| Stsfld ->
|
| Stsfld ->
|
||||||
let fieldHandle =
|
|
||||||
match metadataToken with
|
|
||||||
| MetadataToken.FieldDefinition f -> f
|
|
||||||
| t -> failwith $"Unexpectedly asked to store to a non-field: {t}"
|
|
||||||
|
|
||||||
let activeAssy = state.ActiveAssembly thread
|
let activeAssy = state.ActiveAssembly thread
|
||||||
|
|
||||||
|
let state, field, declaringType =
|
||||||
|
match metadataToken with
|
||||||
|
| MetadataToken.FieldDefinition fieldHandle ->
|
||||||
match activeAssy.Fields.TryGetValue fieldHandle with
|
match activeAssy.Fields.TryGetValue fieldHandle with
|
||||||
| false, _ -> failwith "TODO: Stsfld - throw MissingFieldException"
|
| false, _ -> failwith "TODO: Stsfld - throw MissingFieldException"
|
||||||
| true, field ->
|
| true, field -> state, field, ConcreteType.make activeAssy.Name field.DeclaringType []
|
||||||
|
| MetadataToken.MemberReference mr ->
|
||||||
|
let state, assy, method =
|
||||||
|
IlMachineState.resolveMember loggerFactory (state.ActiveAssembly thread) mr state
|
||||||
|
|
||||||
|
match method with
|
||||||
|
| Choice1Of2 methodInfo ->
|
||||||
|
failwith $"unexpectedly asked to store to a non-field method: {methodInfo.Name}"
|
||||||
|
| Choice2Of2 fieldInfo ->
|
||||||
|
state,
|
||||||
|
fieldInfo,
|
||||||
|
ConcreteType.make
|
||||||
|
assy
|
||||||
|
fieldInfo.DeclaringType
|
||||||
|
(failwith "TODO: refactor FieldInfo to store a Runtime type")
|
||||||
|
| t -> failwith $"Unexpectedly asked to store to a non-field: {t}"
|
||||||
|
|
||||||
do
|
do
|
||||||
let logger = loggerFactory.CreateLogger "Stsfld"
|
let logger = loggerFactory.CreateLogger "Stsfld"
|
||||||
@@ -376,41 +396,57 @@ module internal UnaryMetadataIlOp =
|
|||||||
field.Signature
|
field.Signature
|
||||||
)
|
)
|
||||||
|
|
||||||
match IlMachineState.loadClass loggerFactory field.DeclaringType activeAssy.Name thread state with
|
match IlMachineState.loadClass loggerFactory declaringType thread state with
|
||||||
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
||||||
| NothingToDo state ->
|
| NothingToDo state ->
|
||||||
|
|
||||||
let popped, state = IlMachineState.popEvalStack thread state
|
let popped, state = IlMachineState.popEvalStack thread state
|
||||||
|
|
||||||
let state, zero =
|
let state, zero =
|
||||||
// TODO: generics
|
IlMachineState.cliTypeZeroOf
|
||||||
IlMachineState.cliTypeZeroOf loggerFactory activeAssy field.Signature ImmutableArray.Empty state
|
loggerFactory
|
||||||
|
activeAssy
|
||||||
|
field.Signature
|
||||||
|
(ImmutableArray.CreateRange declaringType.Generics)
|
||||||
|
state
|
||||||
|
|
||||||
let toStore = EvalStackValue.toCliTypeCoerced zero popped
|
let toStore = EvalStackValue.toCliTypeCoerced zero popped
|
||||||
|
|
||||||
let state =
|
let state =
|
||||||
state.SetStatic (field.DeclaringType, activeAssy.Name) field.Name toStore
|
state.SetStatic declaringType field.Name toStore
|
||||||
|> IlMachineState.advanceProgramCounter thread
|
|> IlMachineState.advanceProgramCounter thread
|
||||||
|
|
||||||
state, WhatWeDid.Executed
|
state, WhatWeDid.Executed
|
||||||
|
|
||||||
| Ldfld ->
|
| Ldfld ->
|
||||||
let state, assyName, field =
|
let activeAssembly = state.ActiveAssembly thread
|
||||||
|
|
||||||
|
let state, declaringType, field =
|
||||||
match metadataToken with
|
match metadataToken with
|
||||||
| MetadataToken.FieldDefinition f ->
|
| MetadataToken.FieldDefinition f ->
|
||||||
state, (state.ActiveAssembly thread).Name, state.ActiveAssembly(thread).Fields.[f]
|
let declaringType =
|
||||||
|
ConcreteType.make activeAssembly.Name activeAssembly.Fields.[f].DeclaringType []
|
||||||
|
|
||||||
|
state, declaringType, activeAssembly.Fields.[f]
|
||||||
| MetadataToken.MemberReference mr ->
|
| MetadataToken.MemberReference mr ->
|
||||||
let state, assyName, field =
|
let state, assyName, field =
|
||||||
IlMachineState.resolveMember loggerFactory (state.ActiveAssembly thread) mr state
|
IlMachineState.resolveMember loggerFactory activeAssembly mr state
|
||||||
|
|
||||||
match field with
|
match field with
|
||||||
| Choice1Of2 _method -> failwith "member reference was unexpectedly a method"
|
| Choice1Of2 _method -> failwith "member reference was unexpectedly a method"
|
||||||
| Choice2Of2 field -> state, assyName, field
|
| Choice2Of2 field ->
|
||||||
|
let parentTy = state.LoadedAssembly(assyName).Value.TypeDefs.[field.DeclaringType]
|
||||||
|
|
||||||
|
if parentTy.Generics.Length > 0 then
|
||||||
|
failwith "oh no: generics"
|
||||||
|
|
||||||
|
let declaringType = ConcreteType.make assyName field.DeclaringType []
|
||||||
|
state, declaringType, field
|
||||||
| t -> failwith $"Unexpectedly asked to load from a non-field: {t}"
|
| t -> failwith $"Unexpectedly asked to load from a non-field: {t}"
|
||||||
|
|
||||||
do
|
do
|
||||||
let logger = loggerFactory.CreateLogger "Ldfld"
|
let logger = loggerFactory.CreateLogger "Ldfld"
|
||||||
let declaring = state.ActiveAssembly(thread).TypeDefs.[field.DeclaringType]
|
let declaring = activeAssembly.TypeDefs.[field.DeclaringType]
|
||||||
|
|
||||||
logger.LogInformation (
|
logger.LogInformation (
|
||||||
"Loading object field {FieldAssembly}.{FieldDeclaringType}.{FieldName} (type {FieldType})",
|
"Loading object field {FieldAssembly}.{FieldDeclaringType}.{FieldName} (type {FieldType})",
|
||||||
@@ -423,7 +459,7 @@ module internal UnaryMetadataIlOp =
|
|||||||
let currentObj, state = IlMachineState.popEvalStack thread state
|
let currentObj, state = IlMachineState.popEvalStack thread state
|
||||||
|
|
||||||
if field.Attributes.HasFlag FieldAttributes.Static then
|
if field.Attributes.HasFlag FieldAttributes.Static then
|
||||||
let staticField = state.Statics.[field.DeclaringType, assyName].[field.Name]
|
let staticField = state.Statics.[declaringType].[field.Name]
|
||||||
let state = state |> IlMachineState.pushToEvalStack staticField thread
|
let state = state |> IlMachineState.pushToEvalStack staticField thread
|
||||||
state, WhatWeDid.Executed
|
state, WhatWeDid.Executed
|
||||||
else
|
else
|
||||||
@@ -458,19 +494,23 @@ module internal UnaryMetadataIlOp =
|
|||||||
| Ldsfld ->
|
| Ldsfld ->
|
||||||
let logger = loggerFactory.CreateLogger "Ldsfld"
|
let logger = loggerFactory.CreateLogger "Ldsfld"
|
||||||
|
|
||||||
let fieldHandle =
|
|
||||||
match metadataToken with
|
|
||||||
| MetadataToken.FieldDefinition f -> f
|
|
||||||
| t -> failwith $"Unexpectedly asked to load from a non-field: {t}"
|
|
||||||
|
|
||||||
let activeAssy = state.ActiveAssembly thread
|
let activeAssy = state.ActiveAssembly thread
|
||||||
|
|
||||||
|
let field, declaringType =
|
||||||
|
match metadataToken with
|
||||||
|
| MetadataToken.FieldDefinition fieldHandle ->
|
||||||
match activeAssy.Fields.TryGetValue fieldHandle with
|
match activeAssy.Fields.TryGetValue fieldHandle with
|
||||||
| false, _ -> failwith "TODO: Ldsfld - throw MissingFieldException"
|
| false, _ -> failwith "TODO: Ldsfld - throw MissingFieldException"
|
||||||
| true, field ->
|
| true, field ->
|
||||||
|
// FieldDefinition won't come on a generic type
|
||||||
|
field, ConcreteType.make activeAssy.Name field.DeclaringType []
|
||||||
|
| t -> failwith $"Unexpectedly asked to load from a non-field: {t}"
|
||||||
|
|
||||||
do
|
do
|
||||||
let declaring = state.ActiveAssembly(thread).TypeDefs.[field.DeclaringType]
|
let declaring =
|
||||||
|
state.LoadedAssembly (declaringType.Assembly)
|
||||||
|
|> Option.get
|
||||||
|
|> fun a -> a.TypeDefs.[declaringType.Definition.Get]
|
||||||
|
|
||||||
logger.LogInformation (
|
logger.LogInformation (
|
||||||
"Loading from static field {FieldAssembly}.{FieldDeclaringType}.{FieldName} (type {FieldType})",
|
"Loading from static field {FieldAssembly}.{FieldDeclaringType}.{FieldName} (type {FieldType})",
|
||||||
@@ -480,28 +520,35 @@ module internal UnaryMetadataIlOp =
|
|||||||
field.Signature
|
field.Signature
|
||||||
)
|
)
|
||||||
|
|
||||||
match IlMachineState.loadClass loggerFactory field.DeclaringType activeAssy.Name thread state with
|
match IlMachineState.loadClass loggerFactory declaringType thread state with
|
||||||
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
||||||
| NothingToDo state ->
|
| NothingToDo state ->
|
||||||
|
|
||||||
// TODO: generics
|
|
||||||
let generics = ImmutableArray.Empty
|
|
||||||
|
|
||||||
let fieldValue, state =
|
let fieldValue, state =
|
||||||
match state.Statics.TryGetValue ((field.DeclaringType, activeAssy.Name)) with
|
match state.Statics.TryGetValue declaringType with
|
||||||
| false, _ ->
|
| false, _ ->
|
||||||
let state, newVal =
|
let state, newVal =
|
||||||
IlMachineState.cliTypeZeroOf loggerFactory activeAssy field.Signature generics state
|
IlMachineState.cliTypeZeroOf
|
||||||
|
loggerFactory
|
||||||
|
activeAssy
|
||||||
|
field.Signature
|
||||||
|
(declaringType.Generics |> ImmutableArray.CreateRange)
|
||||||
|
state
|
||||||
|
|
||||||
newVal, state.SetStatic (field.DeclaringType, activeAssy.Name) field.Name newVal
|
newVal, state.SetStatic declaringType field.Name newVal
|
||||||
| true, v ->
|
| true, v ->
|
||||||
match v.TryGetValue field.Name with
|
match v.TryGetValue field.Name with
|
||||||
| true, v -> v, state
|
| true, v -> v, state
|
||||||
| false, _ ->
|
| false, _ ->
|
||||||
let state, newVal =
|
let state, newVal =
|
||||||
IlMachineState.cliTypeZeroOf loggerFactory activeAssy field.Signature generics state
|
IlMachineState.cliTypeZeroOf
|
||||||
|
loggerFactory
|
||||||
|
activeAssy
|
||||||
|
field.Signature
|
||||||
|
(declaringType.Generics |> ImmutableArray.CreateRange)
|
||||||
|
state
|
||||||
|
|
||||||
newVal, state.SetStatic (field.DeclaringType, activeAssy.Name) field.Name newVal
|
newVal, state.SetStatic declaringType field.Name newVal
|
||||||
|
|
||||||
do
|
do
|
||||||
let logger = loggerFactory.CreateLogger "Ldsfld"
|
let logger = loggerFactory.CreateLogger "Ldsfld"
|
||||||
@@ -527,39 +574,39 @@ module internal UnaryMetadataIlOp =
|
|||||||
| Ldelem -> failwith "TODO: Ldelem unimplemented"
|
| Ldelem -> failwith "TODO: Ldelem unimplemented"
|
||||||
| Initobj -> failwith "TODO: Initobj unimplemented"
|
| Initobj -> failwith "TODO: Initobj unimplemented"
|
||||||
| Ldsflda ->
|
| Ldsflda ->
|
||||||
// TODO: check whether we should throw FieldAccessException
|
|
||||||
let fieldHandle =
|
|
||||||
match metadataToken with
|
|
||||||
| MetadataToken.FieldDefinition f -> f
|
|
||||||
| t -> failwith $"Unexpectedly asked to load a non-field: {t}"
|
|
||||||
|
|
||||||
let activeAssy = state.ActiveAssembly thread
|
let activeAssy = state.ActiveAssembly thread
|
||||||
|
|
||||||
|
// TODO: check whether we should throw FieldAccessException
|
||||||
|
|
||||||
|
let field, declaringType =
|
||||||
|
match metadataToken with
|
||||||
|
| MetadataToken.FieldDefinition fieldHandle ->
|
||||||
match activeAssy.Fields.TryGetValue fieldHandle with
|
match activeAssy.Fields.TryGetValue fieldHandle with
|
||||||
| false, _ -> failwith "TODO: Ldsflda - throw MissingFieldException"
|
| false, _ -> failwith "TODO: Ldsflda - throw MissingFieldException"
|
||||||
| true, field ->
|
| true, field ->
|
||||||
match IlMachineState.loadClass loggerFactory field.DeclaringType activeAssy.Name thread state with
|
// FieldDefinition is not found on generic type
|
||||||
|
field, ConcreteType.make activeAssy.Name field.DeclaringType []
|
||||||
|
| t -> failwith $"Unexpectedly asked to load a non-field: {t}"
|
||||||
|
|
||||||
|
match IlMachineState.loadClass loggerFactory declaringType thread state with
|
||||||
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
||||||
| NothingToDo state ->
|
| NothingToDo state ->
|
||||||
|
|
||||||
if TypeDefn.isManaged field.Signature then
|
if TypeDefn.isManaged field.Signature then
|
||||||
let typeId = field.DeclaringType, activeAssy.Name
|
|
||||||
|
|
||||||
let allocateStatic () =
|
let allocateStatic () =
|
||||||
// TODO: generics
|
|
||||||
let state, zero =
|
let state, zero =
|
||||||
IlMachineState.cliTypeZeroOf
|
IlMachineState.cliTypeZeroOf
|
||||||
loggerFactory
|
loggerFactory
|
||||||
activeAssy
|
activeAssy
|
||||||
field.Signature
|
field.Signature
|
||||||
ImmutableArray.Empty
|
(declaringType.Generics |> ImmutableArray.CreateRange)
|
||||||
state
|
state
|
||||||
|
|
||||||
state.SetStatic typeId field.Name zero
|
state.SetStatic declaringType field.Name zero
|
||||||
|> IlMachineState.pushToEvalStack (CliType.ObjectRef None) thread
|
|> IlMachineState.pushToEvalStack (CliType.ObjectRef None) thread
|
||||||
|> Tuple.withRight WhatWeDid.Executed
|
|> Tuple.withRight WhatWeDid.Executed
|
||||||
|
|
||||||
match state.Statics.TryGetValue typeId with
|
match state.Statics.TryGetValue declaringType with
|
||||||
| true, v ->
|
| true, v ->
|
||||||
match v.TryGetValue field.Name with
|
match v.TryGetValue field.Name with
|
||||||
| true, v ->
|
| true, v ->
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<WoofWareMyriadPluginsVersion>7.0.7</WoofWareMyriadPluginsVersion>
|
<WoofWareMyriadPluginsVersion>7.0.7</WoofWareMyriadPluginsVersion>
|
||||||
@@ -15,8 +15,11 @@
|
|||||||
<Compile Include="CustomAttribute.fs" />
|
<Compile Include="CustomAttribute.fs" />
|
||||||
<Compile Include="AssemblyReference.fs" />
|
<Compile Include="AssemblyReference.fs" />
|
||||||
<Compile Include="EventDefn.fs" />
|
<Compile Include="EventDefn.fs" />
|
||||||
|
<Compile Include="ComparableTypeDefinitionHandle.fs" />
|
||||||
|
<Compile Include="ComparableSignatureHeader.fs" />
|
||||||
<Compile Include="TypeDefn.fs" />
|
<Compile Include="TypeDefn.fs" />
|
||||||
<Compile Include="FieldInfo.fs" />
|
<Compile Include="FieldInfo.fs" />
|
||||||
|
<Compile Include="ConcreteType.fs" />
|
||||||
<Compile Include="MethodInfo.fs" />
|
<Compile Include="MethodInfo.fs" />
|
||||||
<Compile Include="TypeInfo.fs" />
|
<Compile Include="TypeInfo.fs" />
|
||||||
<Compile Include="MethodSpec.fs" />
|
<Compile Include="MethodSpec.fs" />
|
||||||
|
Reference in New Issue
Block a user