mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-08 15:38:41 +00:00
Add method generics to type resolution (#48)
This commit is contained in:
@@ -61,7 +61,11 @@ type DumpedAssembly =
|
||||
/// <summary>
|
||||
/// Dictionary of all method definitions in this assembly, keyed by their handle.
|
||||
/// </summary>
|
||||
Methods : IReadOnlyDictionary<MethodDefinitionHandle, WoofWare.PawPrint.MethodInfo<FakeUnit>>
|
||||
Methods :
|
||||
IReadOnlyDictionary<
|
||||
MethodDefinitionHandle,
|
||||
WoofWare.PawPrint.MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter>
|
||||
>
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary of all member references in this assembly, keyed by their handle.
|
||||
|
@@ -145,7 +145,8 @@ type MethodInstructions =
|
||||
/// Represents detailed information about a method in a .NET assembly.
|
||||
/// This is a strongly-typed representation of MethodDefinition from System.Reflection.Metadata.
|
||||
/// </summary>
|
||||
type MethodInfo<'typeGenerics when 'typeGenerics :> IComparable<'typeGenerics> and 'typeGenerics : comparison> =
|
||||
type MethodInfo<'typeGenerics, 'methodGenerics
|
||||
when 'typeGenerics :> IComparable<'typeGenerics> and 'typeGenerics : comparison> =
|
||||
{
|
||||
/// <summary>
|
||||
/// The type that declares this method, along with its assembly information.
|
||||
@@ -175,7 +176,7 @@ type MethodInfo<'typeGenerics when 'typeGenerics :> IComparable<'typeGenerics> a
|
||||
/// <summary>
|
||||
/// The generic type parameters defined by this method, if any.
|
||||
/// </summary>
|
||||
Generics : GenericParameter ImmutableArray
|
||||
Generics : 'methodGenerics ImmutableArray
|
||||
|
||||
/// <summary>
|
||||
/// The signature of the method, including return type and parameter types.
|
||||
@@ -215,11 +216,11 @@ type MethodInfo<'typeGenerics when 'typeGenerics :> IComparable<'typeGenerics> a
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module MethodInfo =
|
||||
let mapTypeGenerics<'a, 'b
|
||||
let mapTypeGenerics<'a, 'b, 'methodGen
|
||||
when 'a :> IComparable<'a> and 'a : comparison and 'b : comparison and 'b :> IComparable<'b>>
|
||||
(f : int -> 'a -> 'b)
|
||||
(m : MethodInfo<'a>)
|
||||
: MethodInfo<'b>
|
||||
(m : MethodInfo<'a, 'methodGen>)
|
||||
: MethodInfo<'b, 'methodGen>
|
||||
=
|
||||
{
|
||||
DeclaringType = m.DeclaringType |> ConcreteType.mapGeneric f
|
||||
@@ -235,6 +236,26 @@ module MethodInfo =
|
||||
IsStatic = m.IsStatic
|
||||
}
|
||||
|
||||
let mapMethodGenerics<'a, 'b, 'typeGen when 'typeGen :> IComparable<'typeGen> and 'typeGen : comparison>
|
||||
(f : int -> 'a -> 'b)
|
||||
(m : MethodInfo<'typeGen, 'a>)
|
||||
: MethodInfo<'typeGen, 'b>
|
||||
=
|
||||
{
|
||||
DeclaringType = m.DeclaringType
|
||||
Handle = m.Handle
|
||||
Name = m.Name
|
||||
Instructions = m.Instructions
|
||||
Parameters = m.Parameters
|
||||
Generics = m.Generics |> Seq.mapi f |> ImmutableArray.CreateRange
|
||||
Signature = m.Signature
|
||||
CustomAttributes = m.CustomAttributes
|
||||
MethodAttributes = m.MethodAttributes
|
||||
ImplAttributes = m.ImplAttributes
|
||||
IsStatic = m.IsStatic
|
||||
}
|
||||
|
||||
|
||||
type private Dummy = class end
|
||||
|
||||
type private MethodBody =
|
||||
@@ -582,7 +603,7 @@ module MethodInfo =
|
||||
(peReader : PEReader)
|
||||
(metadataReader : MetadataReader)
|
||||
(methodHandle : MethodDefinitionHandle)
|
||||
: MethodInfo<FakeUnit> option
|
||||
: MethodInfo<FakeUnit, GenericParameter> option
|
||||
=
|
||||
let logger = loggerFactory.CreateLogger "MethodInfo"
|
||||
let assemblyName = metadataReader.GetAssemblyDefinition().GetAssemblyName ()
|
||||
@@ -660,7 +681,7 @@ module MethodInfo =
|
||||
|
||||
let rec resolveBaseType
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
(executingMethod : MethodInfo<TypeDefn>)
|
||||
(executingMethod : MethodInfo<TypeDefn, 'methodGen>)
|
||||
(td : TypeDefn)
|
||||
: ResolvedBaseType
|
||||
=
|
||||
|
@@ -34,7 +34,7 @@ type TypeInfo<'generic> =
|
||||
/// <summary>
|
||||
/// All methods defined within this type.
|
||||
/// </summary>
|
||||
Methods : WoofWare.PawPrint.MethodInfo<FakeUnit> list
|
||||
Methods : WoofWare.PawPrint.MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter> list
|
||||
|
||||
/// <summary>
|
||||
/// Method implementation mappings for this type, often used for interface implementations
|
||||
@@ -128,6 +128,7 @@ type BaseClassTypes<'corelib> =
|
||||
RuntimeMethodHandle : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
RuntimeFieldHandle : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
RuntimeTypeHandle : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
RuntimeType : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
|
@@ -57,7 +57,7 @@ type CliNumericType =
|
||||
| Float32 of float32
|
||||
| Float64 of float
|
||||
/// Not a real CLI numeric type! Represents an int64 obtained by taking a NativeInt from the eval stack.
|
||||
| ProvenanceTrackedNativeInt64 of MethodInfo<FakeUnit>
|
||||
| ProvenanceTrackedNativeInt64 of MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter>
|
||||
|
||||
type CliValueType =
|
||||
private
|
||||
|
@@ -104,6 +104,11 @@ module Corelib =
|
||||
|> Seq.choose (fun (KeyValue (_, v)) -> if v.Name = "RuntimeTypeHandle" then Some v else None)
|
||||
|> Seq.exactlyOne
|
||||
|
||||
let runtimeTypeType =
|
||||
corelib.TypeDefs
|
||||
|> Seq.choose (fun (KeyValue (_, v)) -> if v.Name = "RuntimeType" then Some v else None)
|
||||
|> Seq.exactlyOne
|
||||
|
||||
let runtimeFieldHandleType =
|
||||
corelib.TypeDefs
|
||||
|> Seq.choose (fun (KeyValue (_, v)) -> if v.Name = "RuntimeFieldHandle" then Some v else None)
|
||||
@@ -132,4 +137,5 @@ module Corelib =
|
||||
RuntimeTypeHandle = runtimeTypeHandleType
|
||||
RuntimeMethodHandle = runtimeMethodHandleType
|
||||
RuntimeFieldHandle = runtimeFieldHandleType
|
||||
RuntimeType = runtimeTypeType
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ type ManagedPointerSource =
|
||||
[<RequireQualifiedAccess>]
|
||||
type NativeIntSource =
|
||||
| Verbatim of int64
|
||||
| FunctionPointer of MethodInfo<FakeUnit>
|
||||
| FunctionPointer of MethodInfo<FakeUnit, GenericParameter>
|
||||
|
||||
override this.ToString () : string =
|
||||
match this with
|
||||
|
@@ -5,7 +5,7 @@ open System.Collections.Immutable
|
||||
/// Represents a location in the code where an exception occurred
|
||||
type ExceptionStackFrame =
|
||||
{
|
||||
Method : WoofWare.PawPrint.MethodInfo<TypeDefn>
|
||||
Method : WoofWare.PawPrint.MethodInfo<TypeDefn, TypeDefn>
|
||||
/// The number of bytes into the IL of the method we were in
|
||||
IlOffset : int
|
||||
}
|
||||
@@ -44,7 +44,7 @@ module ExceptionHandling =
|
||||
let findExceptionHandler
|
||||
(currentPC : int)
|
||||
(exceptionTypeCrate : TypeInfoCrate)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
: (WoofWare.PawPrint.ExceptionRegion * bool) option // handler, isFinally
|
||||
=
|
||||
@@ -92,7 +92,7 @@ module ExceptionHandling =
|
||||
let findFinallyBlocksToRun
|
||||
(currentPC : int)
|
||||
(targetPC : int)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||
: ExceptionOffset list
|
||||
=
|
||||
match method.Instructions with
|
||||
@@ -122,7 +122,7 @@ module ExceptionHandling =
|
||||
/// Get the active exception regions at a given offset
|
||||
let getActiveRegionsAtOffset
|
||||
(offset : int)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||
: WoofWare.PawPrint.ExceptionRegion list
|
||||
=
|
||||
match method.Instructions with
|
||||
|
@@ -1,6 +1,5 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
open System
|
||||
open System.Collections.Immutable
|
||||
open System.IO
|
||||
open System.Reflection
|
||||
@@ -246,11 +245,11 @@ module IlMachineState =
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(referencedInAssembly : DumpedAssembly)
|
||||
(target : TypeRef)
|
||||
(genericArgs : ImmutableArray<TypeDefn> option)
|
||||
(typeGenericArgs : ImmutableArray<TypeDefn> option)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
=
|
||||
match Assembly.resolveTypeRef state._LoadedAssemblies referencedInAssembly target genericArgs with
|
||||
match Assembly.resolveTypeRef state._LoadedAssemblies referencedInAssembly target typeGenericArgs with
|
||||
| TypeResolutionResult.Resolved (assy, typeDef) -> state, assy, typeDef
|
||||
| TypeResolutionResult.FirstLoadAssy loadFirst ->
|
||||
let state, _, _ =
|
||||
@@ -260,7 +259,7 @@ module IlMachineState =
|
||||
(fst loadFirst.Handle)
|
||||
state
|
||||
|
||||
resolveTypeFromRef loggerFactory referencedInAssembly target genericArgs state
|
||||
resolveTypeFromRef loggerFactory referencedInAssembly target typeGenericArgs state
|
||||
|
||||
and resolveType
|
||||
(loggerFactory : ILoggerFactory)
|
||||
@@ -278,7 +277,8 @@ module IlMachineState =
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : TypeDefn)
|
||||
(genericArgs : ImmutableArray<TypeDefn> option)
|
||||
(typeGenericArgs : ImmutableArray<TypeDefn> option)
|
||||
(methodGenericArgs : ImmutableArray<TypeDefn>)
|
||||
(assy : DumpedAssembly)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
@@ -291,7 +291,7 @@ module IlMachineState =
|
||||
(state, args)
|
||||
||> Seq.fold (fun state arg ->
|
||||
let state, assy, arg =
|
||||
resolveTypeFromDefn loggerFactory corelib arg genericArgs assy state
|
||||
resolveTypeFromDefn loggerFactory corelib arg typeGenericArgs methodGenericArgs assy state
|
||||
|
||||
let baseType =
|
||||
arg.BaseType
|
||||
@@ -316,21 +316,23 @@ module IlMachineState =
|
||||
)
|
||||
|
||||
let args' = args'.ToImmutable ()
|
||||
resolveTypeFromDefn loggerFactory corelib generic (Some args') assy state
|
||||
resolveTypeFromDefn loggerFactory corelib generic (Some args') methodGenericArgs assy state
|
||||
| TypeDefn.FromDefinition (defn, assy, _typeKind) ->
|
||||
let assy = state._LoadedAssemblies.[assy]
|
||||
|
||||
let defn =
|
||||
assy.TypeDefs.[defn.Get]
|
||||
|> TypeInfo.mapGeneric (fun _ param ->
|
||||
match genericArgs with
|
||||
| None -> failwith "somehow got a generic TypeDefn.FromDefinition without any generic args"
|
||||
match typeGenericArgs with
|
||||
| None -> failwith "somehow got a generic TypeDefn.FromDefinition without any type generic args"
|
||||
| Some genericArgs -> genericArgs.[param.SequenceNumber]
|
||||
)
|
||||
|
||||
state, assy, defn
|
||||
| TypeDefn.FromReference (ref, _typeKind) ->
|
||||
let state, assy, ty = resolveTypeFromRef loggerFactory assy ref genericArgs state
|
||||
let state, assy, ty =
|
||||
resolveTypeFromRef loggerFactory assy ref typeGenericArgs state
|
||||
|
||||
state, assy, ty
|
||||
| TypeDefn.PrimitiveType prim ->
|
||||
let ty =
|
||||
@@ -356,12 +358,16 @@ module IlMachineState =
|
||||
|
||||
state, corelib.Corelib, ty
|
||||
| TypeDefn.GenericTypeParameter param ->
|
||||
match genericArgs with
|
||||
match typeGenericArgs with
|
||||
| None -> failwith "tried to resolve generic parameter without generic args"
|
||||
| Some genericArgs ->
|
||||
let arg = genericArgs.[param]
|
||||
// TODO: this assembly is probably wrong?
|
||||
resolveTypeFromDefn loggerFactory corelib arg (Some genericArgs) assy state
|
||||
resolveTypeFromDefn loggerFactory corelib arg (Some genericArgs) methodGenericArgs assy state
|
||||
| TypeDefn.GenericMethodParameter param ->
|
||||
let arg = methodGenericArgs.[param]
|
||||
// TODO: this assembly is probably wrong?
|
||||
resolveTypeFromDefn loggerFactory corelib arg typeGenericArgs methodGenericArgs assy state
|
||||
| s -> failwith $"TODO: resolveTypeFromDefn unimplemented for {s}"
|
||||
|
||||
let resolveTypeFromSpec
|
||||
@@ -370,10 +376,12 @@ module IlMachineState =
|
||||
(ty : TypeSpecificationHandle)
|
||||
(assy : DumpedAssembly)
|
||||
(typeGenericArgs : TypeDefn ImmutableArray option)
|
||||
(methodGenericArgs : TypeDefn ImmutableArray)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
=
|
||||
resolveTypeFromDefn loggerFactory corelib assy.TypeSpecs.[ty].Signature typeGenericArgs assy state
|
||||
let sign = assy.TypeSpecs.[ty].Signature
|
||||
resolveTypeFromDefn loggerFactory corelib sign typeGenericArgs methodGenericArgs assy state
|
||||
|
||||
let rec cliTypeZeroOf
|
||||
(loggerFactory : ILoggerFactory)
|
||||
@@ -400,7 +408,7 @@ module IlMachineState =
|
||||
(wasConstructing : ManagedHeapAddress option)
|
||||
(wasClassConstructor : bool)
|
||||
(methodGenerics : ImmutableArray<TypeDefn> option)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter>)
|
||||
(thread : ThreadId)
|
||||
(threadState : ThreadState)
|
||||
(state : IlMachineState)
|
||||
@@ -431,6 +439,10 @@ module IlMachineState =
|
||||
|
||||
let activeMethodState = threadState.MethodStates.[threadState.ActiveMethodState]
|
||||
|
||||
let methodToCall =
|
||||
methodToCall
|
||||
|> MethodInfo.mapMethodGenerics (fun _ param -> methodGenerics.Value.[param.SequenceNumber])
|
||||
|
||||
let state, newFrame, oldFrame =
|
||||
if methodToCall.IsStatic then
|
||||
let args = ImmutableArray.CreateBuilder methodToCall.Parameters.Length
|
||||
@@ -672,7 +684,9 @@ module IlMachineState =
|
||||
let currentThreadState = state.ThreadState.[currentThread]
|
||||
|
||||
let cctorMethod =
|
||||
cctorMethod |> MethodInfo.mapTypeGenerics (fun i _ -> ty.Generics.[i])
|
||||
cctorMethod
|
||||
|> MethodInfo.mapTypeGenerics (fun i _ -> ty.Generics.[i])
|
||||
|> MethodInfo.mapMethodGenerics (fun _ -> failwith "cctor cannot be generic")
|
||||
|
||||
callMethod
|
||||
loggerFactory
|
||||
@@ -723,7 +737,7 @@ module IlMachineState =
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(thread : ThreadId)
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter>)
|
||||
(weAreConstructingObj : ManagedHeapAddress option)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * WhatWeDid
|
||||
@@ -977,7 +991,10 @@ module IlMachineState =
|
||||
(state : IlMachineState)
|
||||
: IlMachineState *
|
||||
AssemblyName *
|
||||
Choice<WoofWare.PawPrint.MethodInfo<TypeDefn>, WoofWare.PawPrint.FieldInfo<TypeDefn>>
|
||||
Choice<
|
||||
WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter>,
|
||||
WoofWare.PawPrint.FieldInfo<TypeDefn>
|
||||
>
|
||||
=
|
||||
// TODO: do we need to initialise the parent class here?
|
||||
let mem = assy.Members.[m]
|
||||
@@ -988,12 +1005,16 @@ module IlMachineState =
|
||||
match mem.Parent with
|
||||
| MetadataToken.TypeReference parent -> resolveType loggerFactory parent None assy state
|
||||
| MetadataToken.TypeSpecification parent ->
|
||||
let executing = state.ThreadState.[currentThread].MethodState.ExecutingMethod
|
||||
|
||||
let typeGenerics =
|
||||
match state.ThreadState.[currentThread].MethodState.ExecutingMethod.DeclaringType.Generics with
|
||||
match executing.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| l -> Some (ImmutableArray.CreateRange l)
|
||||
|
||||
resolveTypeFromSpec loggerFactory corelib parent assy typeGenerics state
|
||||
let methodGenerics = executing.Generics
|
||||
|
||||
resolveTypeFromSpec loggerFactory corelib parent assy typeGenerics methodGenerics state
|
||||
| parent -> failwith $"Unexpected: {parent}"
|
||||
|
||||
match mem.Signature with
|
||||
|
@@ -19,7 +19,7 @@ and MethodState =
|
||||
_IlOpIndex : int
|
||||
EvaluationStack : EvalStack
|
||||
Arguments : CliType ImmutableArray
|
||||
ExecutingMethod : WoofWare.PawPrint.MethodInfo<TypeDefn>
|
||||
ExecutingMethod : WoofWare.PawPrint.MethodInfo<TypeDefn, TypeDefn>
|
||||
/// We don't implement the local memory pool right now
|
||||
LocalMemoryPool : unit
|
||||
/// On return, we restore this state. This should be Some almost always; an exception is the entry point.
|
||||
@@ -138,7 +138,7 @@ and MethodState =
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(loadedAssemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(containingAssembly : DumpedAssembly)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn>)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, TypeDefn>)
|
||||
(methodGenerics : ImmutableArray<TypeDefn> option)
|
||||
(args : ImmutableArray<CliType>)
|
||||
(returnState : MethodReturnState option)
|
||||
|
@@ -68,6 +68,7 @@ module Program =
|
||||
let mainMethod =
|
||||
mainMethod
|
||||
|> MethodInfo.mapTypeGenerics (fun _ -> failwith "Refusing to execute generic main method")
|
||||
|> MethodInfo.mapMethodGenerics (fun _ -> failwith "Refusing to execute generic main method")
|
||||
|
||||
let rec computeState (baseClassTypes : BaseClassTypes<DumpedAssembly> option) (state : IlMachineState) =
|
||||
// The thread's state is slightly fake: we will need to put arguments onto the stack before actually
|
||||
|
@@ -681,6 +681,7 @@ module internal UnaryMetadataIlOp =
|
||||
spec
|
||||
assy
|
||||
declaringTypeGenerics
|
||||
currentMethod.Generics
|
||||
state
|
||||
| x -> failwith $"TODO: Stelem element type resolution unimplemented for {x}"
|
||||
|
||||
@@ -754,6 +755,7 @@ module internal UnaryMetadataIlOp =
|
||||
spec
|
||||
assy
|
||||
declaringTypeGenerics
|
||||
currentMethod.Generics
|
||||
state
|
||||
| x -> failwith $"TODO: Ldelem element type resolution unimplemented for {x}"
|
||||
|
||||
|
Reference in New Issue
Block a user