diff --git a/WoofWare.PawPrint.Domain/Assembly.fs b/WoofWare.PawPrint.Domain/Assembly.fs index 127899d..4104be6 100644 --- a/WoofWare.PawPrint.Domain/Assembly.fs +++ b/WoofWare.PawPrint.Domain/Assembly.fs @@ -45,10 +45,7 @@ type DumpedAssembly = /// Dictionary of all type definitions in this assembly, keyed by their handle. /// TypeDefs : - IReadOnlyDictionary< - TypeDefinitionHandle, - WoofWare.PawPrint.TypeInfo - > + IReadOnlyDictionary> /// /// Dictionary of all type references in this assembly, keyed by their handle. @@ -67,7 +64,7 @@ type DumpedAssembly = Methods : IReadOnlyDictionary< MethodDefinitionHandle, - WoofWare.PawPrint.MethodInfo + WoofWare.PawPrint.MethodInfo > /// @@ -78,7 +75,8 @@ type DumpedAssembly = /// /// Dictionary of all field definitions in this assembly, keyed by their handle. /// - Fields : IReadOnlyDictionary> + Fields : + IReadOnlyDictionary> /// /// The entry point method of the assembly, if one exists. @@ -146,10 +144,7 @@ type DumpedAssembly = /// Internal lookup for type definitions by namespace and name. /// _TypeDefsLookup : - ImmutableDictionary< - string * string, - WoofWare.PawPrint.TypeInfo - > + ImmutableDictionary> } static member internal BuildExportedTypesLookup @@ -205,7 +200,7 @@ type DumpedAssembly = static member internal BuildTypeDefsLookup (logger : ILogger) (name : AssemblyName) - (typeDefs : WoofWare.PawPrint.TypeInfo seq) + (typeDefs : WoofWare.PawPrint.TypeInfo seq) = let result = ImmutableDictionary.CreateBuilder () let keys = HashSet () @@ -236,7 +231,7 @@ type DumpedAssembly = member this.TypeDef (``namespace`` : string) (name : string) - : WoofWare.PawPrint.TypeInfo option + : WoofWare.PawPrint.TypeInfo option = match this._TypeDefsLookup.TryGetValue ((``namespace``, name)) with | false, _ -> None @@ -467,7 +462,9 @@ module Assembly = match targetType with | [ t ] -> - let t = t |> TypeInfo.mapGeneric (fun _ param -> genericArgs.[param.SequenceNumber]) + let t = + t + |> TypeInfo.mapGeneric (fun _ (param, md) -> genericArgs.[param.SequenceNumber]) TypeResolutionResult.Resolved (assy, t) | _ :: _ :: _ -> failwith $"Multiple matching type definitions! {nsPath} {target.Name}" @@ -493,7 +490,7 @@ module Assembly = | Some typeDef -> let typeDef = typeDef - |> TypeInfo.mapGeneric (fun _ param -> genericArgs.[param.SequenceNumber]) + |> TypeInfo.mapGeneric (fun _ (param, md) -> genericArgs.[param.SequenceNumber]) TypeResolutionResult.Resolved (assy, typeDef) | None -> diff --git a/WoofWare.PawPrint.Domain/ConcreteType.fs b/WoofWare.PawPrint.Domain/ConcreteType.fs index 87601e7..b104d62 100644 --- a/WoofWare.PawPrint.Domain/ConcreteType.fs +++ b/WoofWare.PawPrint.Domain/ConcreteType.fs @@ -1,6 +1,5 @@ namespace WoofWare.PawPrint -open System open System.Collections.Immutable open System.Reflection open System.Reflection.Metadata @@ -17,8 +16,8 @@ module FakeUnit = /// A type which has been concretised, runtime-representable, etc. [] -[] -type ConcreteType<'typeGeneric when 'typeGeneric : comparison and 'typeGeneric :> IComparable<'typeGeneric>> = +[] +type ConcreteType<'typeGeneric> = private { /// Do not use this, because it's intended to be private; use the accessor `.Assembly : AssemblyName` @@ -31,12 +30,12 @@ type ConcreteType<'typeGeneric when 'typeGeneric : comparison and 'typeGeneric : /// Do not use this, because it's intended to be private; use the accessor `.Namespace` instead. _Namespace : string /// Do not use this, because it's intended to be private; use the accessor `.Generics` instead. - _Generics : 'typeGeneric ImmutableArray + _Generics : ImmutableArray<'typeGeneric> } member this.Assembly : AssemblyName = this._AssemblyName member this.Definition : ComparableTypeDefinitionHandle = this._Definition - member this.Generics : 'typeGeneric ImmutableArray = this._Generics + member this.Generics : ImmutableArray<'typeGeneric> = this._Generics member this.Name = this._Name member this.Namespace = this._Namespace @@ -51,71 +50,26 @@ type ConcreteType<'typeGeneric when 'typeGeneric : comparison and 'typeGeneric : override this.GetHashCode () : int = hash (this._AssemblyName.FullName, this._Definition, this._Generics) - interface IComparable> with - member this.CompareTo (other : ConcreteType<'typeGeneric>) : int = - let comp = this._AssemblyName.FullName.CompareTo other._AssemblyName.FullName - - if comp <> 0 then - comp - else - - let comp = - (this._Definition :> IComparable).CompareTo other._Definition - - if comp <> 0 then - comp - else - - let thisGen = this._Generics |> Seq.toList :> IComparable<'typeGeneric list> - thisGen.CompareTo (other._Generics |> Seq.toList) - - interface IComparable with - member this.CompareTo other = - match other with - | :? ConcreteType<'typeGeneric> as other -> - (this :> IComparable>).CompareTo other - | _ -> failwith "bad comparison" [] module ConcreteType = let make (assemblyName : AssemblyName) + (defn : TypeDefinitionHandle) (ns : string) (name : string) - (defn : TypeDefinitionHandle) - (generics : TypeDefn ImmutableArray) - : ConcreteType + (genericParam : ImmutableArray) + : ConcreteType = { _AssemblyName = assemblyName _Definition = ComparableTypeDefinitionHandle.Make defn _Name = name _Namespace = ns - _Generics = generics + _Generics = genericParam } - let make' - (assemblyName : AssemblyName) - (defn : TypeDefinitionHandle) - (ns : string) - (name : string) - (genericParamCount : int) - : ConcreteType - = - { - _AssemblyName = assemblyName - _Definition = ComparableTypeDefinitionHandle.Make defn - _Name = name - _Namespace = ns - _Generics = Seq.replicate genericParamCount FakeUnit.FakeUnit |> ImmutableArray.CreateRange - } - - 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 mapGeneric<'a, 'b> (f : int -> 'a -> 'b) (x : ConcreteType<'a>) : ConcreteType<'b> = let generics = x._Generics |> Seq.mapi f |> ImmutableArray.CreateRange { diff --git a/WoofWare.PawPrint.Domain/FieldInfo.fs b/WoofWare.PawPrint.Domain/FieldInfo.fs index 3ff4918..0b75670 100644 --- a/WoofWare.PawPrint.Domain/FieldInfo.fs +++ b/WoofWare.PawPrint.Domain/FieldInfo.fs @@ -1,6 +1,5 @@ namespace WoofWare.PawPrint -open System open System.Reflection open System.Reflection.Metadata @@ -8,8 +7,7 @@ open System.Reflection.Metadata /// Represents detailed information about a field in a .NET assembly. /// This is a strongly-typed representation of FieldDefinition from System.Reflection.Metadata. /// -type FieldInfo<'typeGeneric, 'fieldGeneric when 'typeGeneric : comparison and 'typeGeneric :> IComparable<'typeGeneric>> - = +type FieldInfo<'typeGeneric, 'fieldGeneric> = { /// /// The metadata token handle that uniquely identifies this field in the assembly. @@ -48,18 +46,22 @@ module FieldInfo = (assembly : AssemblyName) (handle : FieldDefinitionHandle) (def : FieldDefinition) - : FieldInfo + : FieldInfo = let name = mr.GetString def.Name let fieldSig = def.DecodeSignature (TypeDefn.typeProvider assembly, ()) let declaringType = def.GetDeclaringType () - let typeGenerics = mr.GetTypeDefinition(declaringType).GetGenericParameters().Count + + let typeGenerics = + mr.GetTypeDefinition(declaringType).GetGenericParameters () + |> GenericParameter.readAll mr + let decType = mr.GetTypeDefinition declaringType let declaringTypeNamespace = mr.GetString decType.Namespace let declaringTypeName = mr.GetString decType.Name let declaringType = - ConcreteType.make' assembly declaringType declaringTypeNamespace declaringTypeName typeGenerics + ConcreteType.make assembly declaringType declaringTypeNamespace declaringTypeName typeGenerics { Name = name @@ -69,12 +71,7 @@ module FieldInfo = Attributes = def.Attributes } - let mapTypeGenerics<'a, 'b, 'field - when 'a :> IComparable<'a> and 'a : comparison and 'b :> IComparable<'b> and 'b : comparison> - (f : int -> 'a -> 'b) - (input : FieldInfo<'a, 'field>) - : FieldInfo<'b, 'field> - = + let mapTypeGenerics<'a, 'b, 'field> (f : int -> 'a -> 'b) (input : FieldInfo<'a, 'field>) : FieldInfo<'b, 'field> = let declaringType = input.DeclaringType |> ConcreteType.mapGeneric f { diff --git a/WoofWare.PawPrint.Domain/GenericParameter.fs b/WoofWare.PawPrint.Domain/GenericParameter.fs new file mode 100644 index 0000000..57e7730 --- /dev/null +++ b/WoofWare.PawPrint.Domain/GenericParameter.fs @@ -0,0 +1,85 @@ +namespace WoofWare.PawPrint + +open System.Collections.Immutable +open System.Reflection +open System.Reflection.Metadata + +type GenericVariance = + | Covariant + | Contravariant + +type GenericConstraint = + | Reference + | NonNullableValue + +type GenericParamMetadata = + { + Variance : GenericVariance option + Constraint : GenericConstraint option + RequiresParameterlessConstructor : bool + } + +/// +/// Represents a generic type or method parameter definition. +/// Corresponds to GenericParameter in System.Reflection.Metadata. +/// +type GenericParameter = + { + /// The name of the generic parameter (e.g., 'T', 'TKey', etc.). + Name : string + + /// + /// The zero-based index of the generic parameter in the generic parameter list. + /// For example, in Dictionary<TKey, TValue&rt;, TKey has index 0 and TValue has index 1. + /// + SequenceNumber : int + } + +type GenericParamFromMetadata = GenericParameter * GenericParamMetadata + +[] +module GenericParameter = + let readAll + (metadata : MetadataReader) + (param : GenericParameterHandleCollection) + : GenericParamFromMetadata ImmutableArray + = + param + |> Seq.map (fun param -> + let param = metadata.GetGenericParameter param + + let requiresParamlessCons = + param.Attributes.HasFlag GenericParameterAttributes.DefaultConstructorConstraint + + let constr = + if param.Attributes.HasFlag GenericParameterAttributes.NotNullableValueTypeConstraint then + Some GenericConstraint.NonNullableValue + elif param.Attributes.HasFlag GenericParameterAttributes.ReferenceTypeConstraint then + Some GenericConstraint.Reference + else + None + + let variance = + if param.Attributes.HasFlag GenericParameterAttributes.Contravariant then + Some GenericVariance.Contravariant + elif param.Attributes.HasFlag GenericParameterAttributes.Covariant then + Some GenericVariance.Covariant + else + None + + let md = + { + Variance = variance + Constraint = constr + RequiresParameterlessConstructor = requiresParamlessCons + } + + let p = + { + Name = metadata.GetString param.Name + SequenceNumber = param.Index + } + + p, md + ) + |> ImmutableArray.CreateRange diff --git a/WoofWare.PawPrint.Domain/ImmutableArray.fs b/WoofWare.PawPrint.Domain/ImmutableArray.fs new file mode 100644 index 0000000..ac4d48b --- /dev/null +++ b/WoofWare.PawPrint.Domain/ImmutableArray.fs @@ -0,0 +1,22 @@ +namespace WoofWare.PawPrint + +open System.Collections.Immutable + +[] +module internal ImmutableArray = + + let inline map ([] f : 'a -> 'b) (arr : ImmutableArray<'a>) : ImmutableArray<'b> = + let b = ImmutableArray.CreateBuilder () + + for i in arr do + b.Add (f i) + + b.ToImmutable () + + let inline mapi ([] f : int -> 'a -> 'b) (arr : ImmutableArray<'a>) : ImmutableArray<'b> = + let b = ImmutableArray.CreateBuilder () + + for i = 0 to arr.Length - 1 do + b.Add (f i arr.[i]) + + b.ToImmutable () diff --git a/WoofWare.PawPrint.Domain/MethodInfo.fs b/WoofWare.PawPrint.Domain/MethodInfo.fs index d17febc..36f18c0 100644 --- a/WoofWare.PawPrint.Domain/MethodInfo.fs +++ b/WoofWare.PawPrint.Domain/MethodInfo.fs @@ -52,74 +52,6 @@ module Parameter = result.ToImmutable () -type GenericVariance = - | Covariant - | Contravariant - -type GenericConstraint = - | Reference - | NonNullableValue - -/// -/// Represents a generic type or method parameter definition. -/// Corresponds to GenericParameter in System.Reflection.Metadata. -/// -type GenericParameter = - { - /// The name of the generic parameter (e.g., 'T', 'TKey', etc.). - Name : string - - /// - /// The zero-based index of the generic parameter in the generic parameter list. - /// For example, in Dictionary<TKey, TValue&rt;, TKey has index 0 and TValue has index 1. - /// - SequenceNumber : int - - Variance : GenericVariance option - Constraint : GenericConstraint option - RequiresParameterlessConstructor : bool - } - -[] -module GenericParameter = - let readAll - (metadata : MetadataReader) - (param : GenericParameterHandleCollection) - : GenericParameter ImmutableArray - = - param - |> Seq.map (fun param -> - let param = metadata.GetGenericParameter param - - let requiresParamlessCons = - param.Attributes.HasFlag GenericParameterAttributes.DefaultConstructorConstraint - - let constr = - if param.Attributes.HasFlag GenericParameterAttributes.NotNullableValueTypeConstraint then - Some GenericConstraint.NonNullableValue - elif param.Attributes.HasFlag GenericParameterAttributes.ReferenceTypeConstraint then - Some GenericConstraint.Reference - else - None - - let variance = - if param.Attributes.HasFlag GenericParameterAttributes.Contravariant then - Some GenericVariance.Contravariant - elif param.Attributes.HasFlag GenericParameterAttributes.Covariant then - Some GenericVariance.Covariant - else - None - - { - Name = metadata.GetString param.Name - SequenceNumber = param.Index - Variance = variance - Constraint = constr - RequiresParameterlessConstructor = requiresParamlessCons - } - ) - |> ImmutableArray.CreateRange - type ExceptionOffset = { TryLength : int @@ -202,8 +134,7 @@ module MethodInstructions = /// Represents detailed information about a method in a .NET assembly. /// This is a strongly-typed representation of MethodDefinition from System.Reflection.Metadata. /// -type MethodInfo<'typeGenerics, 'methodGenerics, 'methodVars - when 'typeGenerics :> IComparable<'typeGenerics> and 'typeGenerics : comparison> = +type MethodInfo<'typeGenerics, 'methodGenerics, 'methodVars> = { /// /// The type that declares this method, along with its assembly information. @@ -301,14 +232,13 @@ module MethodInfo = | con -> failwith $"TODO: {con}" ) - let mapTypeGenerics<'a, 'b, 'methodGen, 'vars - when 'a :> IComparable<'a> and 'a : comparison and 'b : comparison and 'b :> IComparable<'b>> - (f : int -> 'a -> 'b) + let mapTypeGenerics<'a, 'b, 'methodGen, 'vars> + (f : 'a -> 'b) (m : MethodInfo<'a, 'methodGen, 'vars>) : MethodInfo<'b, 'methodGen, 'vars> = { - DeclaringType = m.DeclaringType |> ConcreteType.mapGeneric f + DeclaringType = m.DeclaringType |> ConcreteType.mapGeneric (fun _ -> f) Handle = m.Handle Name = m.Name Instructions = m.Instructions @@ -322,18 +252,20 @@ module MethodInfo = IsStatic = m.IsStatic } - let mapMethodGenerics<'a, 'b, 'vars, 'typeGen when 'typeGen :> IComparable<'typeGen> and 'typeGen : comparison> + let mapMethodGenerics<'a, 'b, 'vars, 'typeGen> (f : int -> 'a -> 'b) (m : MethodInfo<'typeGen, 'a, 'vars>) : MethodInfo<'typeGen, 'b, 'vars> = + let generics = m.Generics |> Seq.mapi f |> ImmutableArray.CreateRange + { DeclaringType = m.DeclaringType Handle = m.Handle Name = m.Name Instructions = m.Instructions Parameters = m.Parameters - Generics = m.Generics |> Seq.mapi f |> ImmutableArray.CreateRange + Generics = generics Signature = m.Signature RawSignature = m.RawSignature CustomAttributes = m.CustomAttributes @@ -710,7 +642,7 @@ module MethodInfo = (peReader : PEReader) (metadataReader : MetadataReader) (methodHandle : MethodDefinitionHandle) - : MethodInfo option + : MethodInfo option = let logger = loggerFactory.CreateLogger "MethodInfo" let assemblyName = metadataReader.GetAssemblyDefinition().GetAssemblyName () @@ -751,7 +683,8 @@ module MethodInfo = let declaringTypeName = metadataReader.GetString declaringDefn.Name let declaringTypeGenericParams = - metadataReader.GetTypeDefinition(declaringType).GetGenericParameters().Count + metadataReader.GetTypeDefinition(declaringType).GetGenericParameters () + |> GenericParameter.readAll metadataReader let attrs = let result = ImmutableArray.CreateBuilder () @@ -772,7 +705,7 @@ module MethodInfo = GenericParameter.readAll metadataReader (methodDef.GetGenericParameters ()) let declaringType = - ConcreteType.make' + ConcreteType.make assemblyName declaringType declaringTypeNamespace diff --git a/WoofWare.PawPrint.Domain/TypeConcretisation.fs b/WoofWare.PawPrint.Domain/TypeConcretisation.fs index dcaac33..5e8247e 100644 --- a/WoofWare.PawPrint.Domain/TypeConcretisation.fs +++ b/WoofWare.PawPrint.Domain/TypeConcretisation.fs @@ -910,7 +910,7 @@ module Concretization = AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary * DumpedAssembly) (assemblies : ImmutableDictionary) (baseTypes : BaseClassTypes) - (method : WoofWare.PawPrint.MethodInfo) + (method : WoofWare.PawPrint.MethodInfo) (typeArgs : ConcreteTypeHandle ImmutableArray) (methodArgs : ConcreteTypeHandle ImmutableArray) : WoofWare.PawPrint.MethodInfo * diff --git a/WoofWare.PawPrint.Domain/TypeInfo.fs b/WoofWare.PawPrint.Domain/TypeInfo.fs index 475ff19..bd288d4 100644 --- a/WoofWare.PawPrint.Domain/TypeInfo.fs +++ b/WoofWare.PawPrint.Domain/TypeInfo.fs @@ -43,7 +43,7 @@ type TypeInfo<'generic, 'fieldGeneric> = /// /// All methods defined within this type. /// - Methods : WoofWare.PawPrint.MethodInfo list + Methods : WoofWare.PawPrint.MethodInfo list /// /// Method implementation mappings for this type, often used for interface implementations @@ -54,7 +54,7 @@ type TypeInfo<'generic, 'fieldGeneric> = /// /// Fields defined in this type. /// - Fields : WoofWare.PawPrint.FieldInfo list + Fields : WoofWare.PawPrint.FieldInfo list /// /// The base type that this type inherits from, or None for types that don't have a base type @@ -140,34 +140,34 @@ module TypeInfoCrate = type BaseClassTypes<'corelib> = { Corelib : 'corelib - String : TypeInfo - Boolean : TypeInfo - Char : TypeInfo - SByte : TypeInfo - Byte : TypeInfo - Int16 : TypeInfo - UInt16 : TypeInfo - Int32 : TypeInfo - UInt32 : TypeInfo - Int64 : TypeInfo - UInt64 : TypeInfo - Single : TypeInfo - Double : TypeInfo - Array : TypeInfo - Enum : TypeInfo - ValueType : TypeInfo - DelegateType : TypeInfo - Object : TypeInfo - RuntimeMethodHandle : TypeInfo - RuntimeFieldHandle : TypeInfo - RuntimeTypeHandle : TypeInfo - RuntimeFieldInfoStub : TypeInfo - RuntimeFieldHandleInternal : TypeInfo - RuntimeType : TypeInfo - Void : TypeInfo - TypedReference : TypeInfo - IntPtr : TypeInfo - UIntPtr : TypeInfo + String : TypeInfo + Boolean : TypeInfo + Char : TypeInfo + SByte : TypeInfo + Byte : TypeInfo + Int16 : TypeInfo + UInt16 : TypeInfo + Int32 : TypeInfo + UInt32 : TypeInfo + Int64 : TypeInfo + UInt64 : TypeInfo + Single : TypeInfo + Double : TypeInfo + Array : TypeInfo + Enum : TypeInfo + ValueType : TypeInfo + DelegateType : TypeInfo + Object : TypeInfo + RuntimeMethodHandle : TypeInfo + RuntimeFieldHandle : TypeInfo + RuntimeTypeHandle : TypeInfo + RuntimeFieldInfoStub : TypeInfo + RuntimeFieldHandleInternal : TypeInfo + RuntimeType : TypeInfo + Void : TypeInfo + TypedReference : TypeInfo + IntPtr : TypeInfo + UIntPtr : TypeInfo } [] @@ -198,7 +198,7 @@ module TypeInfo = (thisAssembly : AssemblyName) (metadataReader : MetadataReader) (typeHandle : TypeDefinitionHandle) - : TypeInfo + : TypeInfo = let typeDef = metadataReader.GetTypeDefinition typeHandle let methods = typeDef.GetMethods () diff --git a/WoofWare.PawPrint.Domain/WoofWare.PawPrint.Domain.fsproj b/WoofWare.PawPrint.Domain/WoofWare.PawPrint.Domain.fsproj index b4e15c3..812ee2d 100644 --- a/WoofWare.PawPrint.Domain/WoofWare.PawPrint.Domain.fsproj +++ b/WoofWare.PawPrint.Domain/WoofWare.PawPrint.Domain.fsproj @@ -11,6 +11,7 @@ + diff --git a/WoofWare.PawPrint/BasicCliType.fs b/WoofWare.PawPrint/BasicCliType.fs index 7ae763c..c14805f 100644 --- a/WoofWare.PawPrint/BasicCliType.fs +++ b/WoofWare.PawPrint/BasicCliType.fs @@ -326,7 +326,7 @@ module CliType = (corelib : BaseClassTypes) (handle : ConcreteTypeHandle) (concreteType : ConcreteType) - (typeDef : WoofWare.PawPrint.TypeInfo) + (typeDef : WoofWare.PawPrint.TypeInfo) (visited : Set) : CliType * AllConcreteTypes = diff --git a/WoofWare.PawPrint/IlMachineState.fs b/WoofWare.PawPrint/IlMachineState.fs index 097b493..7089365 100644 --- a/WoofWare.PawPrint/IlMachineState.fs +++ b/WoofWare.PawPrint/IlMachineState.fs @@ -378,7 +378,7 @@ module IlMachineState = let defn = assy.TypeDefs.[defn.Get] - |> TypeInfo.mapGeneric (fun _ param -> typeGenericArgs.[param.SequenceNumber]) + |> TypeInfo.mapGeneric (fun _ (param, _) -> typeGenericArgs.[param.SequenceNumber]) state, assy, defn | TypeDefn.FromReference (ref, _typeKind) -> @@ -773,7 +773,7 @@ module IlMachineState = (loggerFactory : ILoggerFactory) (baseClassTypes : BaseClassTypes) (typeGenerics : ImmutableArray) - (methodToCall : WoofWare.PawPrint.MethodInfo) + (methodToCall : WoofWare.PawPrint.MethodInfo) (methodGenerics : TypeDefn ImmutableArray option) (callingAssembly : AssemblyName) (currentExecutingMethodGenerics : ImmutableArray) @@ -850,7 +850,7 @@ module IlMachineState = (loggerFactory : ILoggerFactory) (baseClassTypes : BaseClassTypes) (thread : ThreadId) - (methodToCall : WoofWare.PawPrint.MethodInfo) + (methodToCall : WoofWare.PawPrint.MethodInfo) (methodGenerics : TypeDefn ImmutableArray option) (typeArgsFromMetadata : TypeDefn ImmutableArray option) (state : IlMachineState) @@ -1199,7 +1199,7 @@ module IlMachineState = : IlMachineState * AssemblyName * Choice< - WoofWare.PawPrint.MethodInfo, + WoofWare.PawPrint.MethodInfo, WoofWare.PawPrint.FieldInfo > * TypeDefn ImmutableArray @@ -1362,7 +1362,9 @@ module IlMachineState = | [] -> failwith $"Could not find member {memberName} with the right signature {memberSig} on {targetType.Namespace}.{targetType.Name}" - | [ x ] -> x |> MethodInfo.mapTypeGenerics (fun i _ -> targetType.Generics.[i]) + | [ x ] -> + x + |> MethodInfo.mapTypeGenerics (fun (par, _) -> targetType.Generics.[par.SequenceNumber]) | _ -> failwith $"Multiple overloads matching signature for call to {targetType.Namespace}.{targetType.Name}'s {memberName}!" @@ -1480,15 +1482,13 @@ module IlMachineState = = let field = state.LoadedAssembly(declaringAssy).Value.Fields.[fieldHandle] - // For LdToken, we don't have generic context, so we create a non-generic type - // TODO: This might need to be revisited if we need to support generic field handles - let declaringTypeWithGenerics : ConcreteType = - ConcreteType.make - field.DeclaringType.Assembly - field.DeclaringType.Namespace - field.DeclaringType.Name - field.DeclaringType.Definition.Get - ImmutableArray.Empty // No generic arguments in this context + // For LdToken, we need to convert GenericParamFromMetadata to TypeDefn + // When we don't have generic context, we use the generic type parameters directly + let declaringTypeWithGenerics = + field.DeclaringType + |> ConcreteType.mapGeneric (fun _index (param, _metadata) -> + TypeDefn.GenericTypeParameter param.SequenceNumber + ) let declaringType, state = concretizeFieldDeclaringType loggerFactory baseClassTypes declaringTypeWithGenerics state diff --git a/WoofWare.PawPrint/IlMachineStateExecution.fs b/WoofWare.PawPrint/IlMachineStateExecution.fs index 8ca7d0e..ba02346 100644 --- a/WoofWare.PawPrint/IlMachineStateExecution.fs +++ b/WoofWare.PawPrint/IlMachineStateExecution.fs @@ -361,7 +361,8 @@ module IlMachineStateExecution = // Convert the method's type generics from TypeDefn to ConcreteTypeHandle let cctorMethodWithTypeGenerics = - cctorMethod |> MethodInfo.mapTypeGenerics (fun i _ -> concreteType.Generics.[i]) + cctorMethod + |> MethodInfo.mapTypeGenerics (fun (par, _) -> concreteType.Generics.[par.SequenceNumber]) // Convert method generics (should be empty for cctor) let cctorMethodWithMethodGenerics = @@ -472,7 +473,7 @@ module IlMachineStateExecution = (thread : ThreadId) (advanceProgramCounterOfCaller : bool) (methodGenerics : TypeDefn ImmutableArray option) - (methodToCall : WoofWare.PawPrint.MethodInfo) + (methodToCall : WoofWare.PawPrint.MethodInfo) (weAreConstructingObj : ManagedHeapAddress option) (typeArgsFromMetadata : TypeDefn ImmutableArray option) (state : IlMachineState) diff --git a/WoofWare.PawPrint/ImmutableArray.fs b/WoofWare.PawPrint/ImmutableArray.fs new file mode 100644 index 0000000..ea389fd --- /dev/null +++ b/WoofWare.PawPrint/ImmutableArray.fs @@ -0,0 +1,14 @@ +namespace WoofWare.PawPrint + +open System.Collections.Immutable + +[] +module internal ImmutableArray = + + let map (f : 'a -> 'b) (arr : ImmutableArray<'a>) : ImmutableArray<'b> = + let b = ImmutableArray.CreateBuilder () + + for i in arr do + b.Add (f i) + + b.ToImmutable () diff --git a/WoofWare.PawPrint/Program.fs b/WoofWare.PawPrint/Program.fs index eee741b..806f8bb 100644 --- a/WoofWare.PawPrint/Program.fs +++ b/WoofWare.PawPrint/Program.fs @@ -94,7 +94,7 @@ module Program = (currentAssembly : DumpedAssembly) (continueWithGeneric : IlMachineState - -> TypeInfo + -> TypeInfo -> DumpedAssembly -> IlMachineState * BaseClassTypes option) (continueWithResolved : @@ -145,7 +145,7 @@ module Program = let rec findCoreLibraryAssemblyFromGeneric (state : IlMachineState) - (currentType : TypeInfo) + (currentType : TypeInfo) (currentAssembly : DumpedAssembly) = match currentType.BaseType with @@ -186,7 +186,7 @@ module Program = // Use the original method from metadata, but convert FakeUnit to TypeDefn let rawMainMethod = mainMethodFromMetadata - |> MethodInfo.mapTypeGenerics (fun i _ -> TypeDefn.GenericTypeParameter i) + |> MethodInfo.mapTypeGenerics (fun (i, _) -> TypeDefn.GenericTypeParameter i.SequenceNumber) let state, concretizedMainMethod, _ = IlMachineState.concretizeMethodWithTypeGenerics @@ -233,7 +233,7 @@ module Program = | Some baseTypes -> let rawMainMethod = mainMethodFromMetadata - |> MethodInfo.mapTypeGenerics (fun i _ -> TypeDefn.GenericTypeParameter i) + |> MethodInfo.mapTypeGenerics (fun (i, _) -> TypeDefn.GenericTypeParameter i.SequenceNumber) IlMachineState.concretizeMethodWithTypeGenerics loggerFactory diff --git a/WoofWare.PawPrint/UnaryMetadataIlOp.fs b/WoofWare.PawPrint/UnaryMetadataIlOp.fs index f0164e7..5115280 100644 --- a/WoofWare.PawPrint/UnaryMetadataIlOp.fs +++ b/WoofWare.PawPrint/UnaryMetadataIlOp.fs @@ -126,7 +126,9 @@ module internal UnaryMetadataIlOp = | MetadataToken.MethodDef token -> let method = activeAssy.Methods.[token] - |> MethodInfo.mapTypeGenerics (fun i _ -> TypeDefn.GenericTypeParameter i) + |> MethodInfo.mapTypeGenerics (fun (par, _) -> + TypeDefn.GenericTypeParameter par.SequenceNumber + ) state, method, Some spec.Signature, None | MetadataToken.MemberReference ref -> @@ -209,7 +211,7 @@ module internal UnaryMetadataIlOp = | MetadataToken.MethodDef token -> let method = activeAssy.Methods.[token] - |> MethodInfo.mapTypeGenerics (fun i _ -> spec.Signature.[i]) + |> MethodInfo.mapTypeGenerics (fun (p, _) -> spec.Signature.[p.SequenceNumber]) state, method, Some spec.Signature, None | MetadataToken.MemberReference ref -> @@ -872,7 +874,7 @@ module internal UnaryMetadataIlOp = state, activeAssy, activeAssy.TypeDefs.[defn] - |> TypeInfo.mapGeneric (fun _ p -> TypeDefn.GenericTypeParameter p.SequenceNumber) + |> TypeInfo.mapGeneric (fun _ (p, _) -> TypeDefn.GenericTypeParameter p.SequenceNumber) | MetadataToken.TypeSpecification spec -> let state, assy, ty = IlMachineState.resolveTypeFromSpecConcrete @@ -936,7 +938,7 @@ module internal UnaryMetadataIlOp = state, activeAssy, activeAssy.TypeDefs.[defn] - |> TypeInfo.mapGeneric (fun _ p -> TypeDefn.GenericTypeParameter p.SequenceNumber) + |> TypeInfo.mapGeneric (fun _ (p, _) -> TypeDefn.GenericTypeParameter p.SequenceNumber) | MetadataToken.TypeSpecification spec -> let state, assy, ty = IlMachineState.resolveTypeFromSpecConcrete @@ -1026,12 +1028,12 @@ module internal UnaryMetadataIlOp = failwith "TODO: Ldsflda - push unmanaged pointer" | Ldftn -> - let (method : MethodInfo), methodGenerics = + let method, methodGenerics = match metadataToken with | MetadataToken.MethodDef handle -> let method = activeAssy.Methods.[handle] - |> MethodInfo.mapTypeGenerics (fun i _ -> TypeDefn.GenericTypeParameter i) + |> MethodInfo.mapTypeGenerics (fun (par, _) -> TypeDefn.GenericTypeParameter par.SequenceNumber) method, None | MetadataToken.MethodSpecification h -> @@ -1041,7 +1043,9 @@ module internal UnaryMetadataIlOp = | MetadataToken.MethodDef token -> let method = activeAssy.Methods.[token] - |> MethodInfo.mapTypeGenerics (fun i _ -> TypeDefn.GenericTypeParameter i) + |> MethodInfo.mapTypeGenerics (fun (par, _) -> + TypeDefn.GenericTypeParameter par.SequenceNumber + ) method, Some spec.Signature | k -> failwith $"Unrecognised MethodSpecification kind: %O{k}"