diff --git a/WoofWare.PawPrint.Domain/MethodInfo.fs b/WoofWare.PawPrint.Domain/MethodInfo.fs index e5912bb..d17febc 100644 --- a/WoofWare.PawPrint.Domain/MethodInfo.fs +++ b/WoofWare.PawPrint.Domain/MethodInfo.fs @@ -52,6 +52,14 @@ 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. @@ -66,6 +74,10 @@ type GenericParameter = /// 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 } [] @@ -79,9 +91,31 @@ module GenericParameter = |> 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 diff --git a/WoofWare.PawPrint.Domain/TypeConcretisation.fs b/WoofWare.PawPrint.Domain/TypeConcretisation.fs index 5c83535..0f9c29c 100644 --- a/WoofWare.PawPrint.Domain/TypeConcretisation.fs +++ b/WoofWare.PawPrint.Domain/TypeConcretisation.fs @@ -119,7 +119,13 @@ module ConcreteActivePatterns = match handle with | ConcreteTypeHandle.Concrete id -> match concreteTypes.Mapping |> Map.tryFind id with - | Some ct when ct.Namespace = "System" && ct.Name = "Void" && ct.Generics.IsEmpty -> Some () + | Some ct when + ct.Assembly.Name = "System.Private.CoreLib" + && ct.Namespace = "System" + && ct.Name = "Void" + && ct.Generics.IsEmpty + -> + Some () | _ -> None | _ -> None @@ -149,6 +155,34 @@ module ConcreteActivePatterns = | None -> None | _ -> None + let (|ConcreteRuntimeFieldHandle|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) = + match handle with + | ConcreteTypeHandle.Concrete id -> + match concreteTypes.Mapping |> Map.tryFind id with + | Some ct when + ct.Assembly.Name = "System.Private.CoreLib" + && ct.Namespace = "System" + && ct.Name = "RuntimeFieldHandle" + && ct.Generics.IsEmpty + -> + Some () + | _ -> None + | _ -> None + + let (|ConcreteNonGenericArray|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) = + match handle with + | ConcreteTypeHandle.Concrete id -> + match concreteTypes.Mapping |> Map.tryFind id with + | Some ct when + ct.Assembly.Name = "System.Private.CoreLib" + && ct.Namespace = "System" + && ct.Name = "Array" + && ct.Generics.IsEmpty + -> + Some () + | _ -> None + | _ -> None + let (|ConcreteBool|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) : unit option = match handle with | ConcreteTypeHandle.Concrete id -> @@ -542,7 +576,7 @@ module TypeConcretization = let rec concretizeType (ctx : ConcretizationContext<'corelib>) (loadAssembly : - AssemblyName -> AssemblyReferenceHandle -> (ImmutableDictionary * DumpedAssembly)) + AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary * DumpedAssembly) (assembly : AssemblyName) (typeGenerics : ConcreteTypeHandle ImmutableArray) (methodGenerics : ConcreteTypeHandle ImmutableArray) @@ -890,7 +924,7 @@ module Concretization = let concretizeMethod (ctx : AllConcreteTypes) (loadAssembly : - AssemblyName -> AssemblyReferenceHandle -> (ImmutableDictionary * DumpedAssembly)) + AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary * DumpedAssembly) (assemblies : ImmutableDictionary) (baseTypes : BaseClassTypes) (method : WoofWare.PawPrint.MethodInfo) diff --git a/WoofWare.PawPrint/IlMachineState.fs b/WoofWare.PawPrint/IlMachineState.fs index 28f6128..1fc14a2 100644 --- a/WoofWare.PawPrint/IlMachineState.fs +++ b/WoofWare.PawPrint/IlMachineState.fs @@ -403,9 +403,9 @@ module IlMachineState = | PrimitiveType.Double -> baseClassTypes.Double | PrimitiveType.String -> baseClassTypes.String | PrimitiveType.TypedReference -> failwith "todo" - | PrimitiveType.IntPtr -> failwith "todo" - | PrimitiveType.UIntPtr -> failwith "todo" - | PrimitiveType.Object -> failwith "todo" + | PrimitiveType.IntPtr -> baseClassTypes.IntPtr + | PrimitiveType.UIntPtr -> baseClassTypes.UIntPtr + | PrimitiveType.Object -> baseClassTypes.Object |> TypeInfo.mapGeneric (fun _ -> failwith "none of these types are generic") state, baseClassTypes.Corelib, ty diff --git a/WoofWare.PawPrint/UnaryConstIlOp.fs b/WoofWare.PawPrint/UnaryConstIlOp.fs index 22b789d..1f4167f 100644 --- a/WoofWare.PawPrint/UnaryConstIlOp.fs +++ b/WoofWare.PawPrint/UnaryConstIlOp.fs @@ -403,7 +403,34 @@ module internal UnaryConstIlOp = else id |> Tuple.withRight WhatWeDid.Executed - | Bne_un_s b -> failwith "TODO: Bne_un_s unimplemented" + | Bne_un_s b -> + // Table III.4 + let value2, state = IlMachineState.popEvalStack currentThread state + let value1, state = IlMachineState.popEvalStack currentThread state + + let isNotEqual = + match value1, value2 with + | EvalStackValue.Int32 v1, EvalStackValue.Int32 v2 -> v1 <> v2 + | EvalStackValue.Int32 v1, EvalStackValue.NativeInt v2 -> failwith "TODO" + | EvalStackValue.Int32 v1, _ -> failwith $"invalid comparison, {v1} with {value2}" + | _, EvalStackValue.Int32 v2 -> failwith $"invalid comparison, {value1} with {v2}" + | EvalStackValue.Int64 v1, EvalStackValue.Int64 v2 -> v1 <> v2 + | EvalStackValue.Int64 v1, _ -> failwith $"invalid comparison, {v1} with {value2}" + | _, EvalStackValue.Int64 v2 -> failwith $"invalid comparison, {value1} with {v2}" + | EvalStackValue.Float v1, EvalStackValue.Float v2 -> v1 <> v2 + | _, EvalStackValue.Float v2 -> failwith $"invalid comparison, {value1} with {v2}" + | EvalStackValue.Float v1, _ -> failwith $"invalid comparison, {v1} with {value2}" + | EvalStackValue.NativeInt v1, EvalStackValue.NativeInt v2 -> v1 <> v2 + | EvalStackValue.ManagedPointer ptr1, EvalStackValue.ManagedPointer ptr2 -> ptr1 <> ptr2 + | _, _ -> failwith $"TODO {value1} {value2} (see table III.4)" + + state + |> IlMachineState.advanceProgramCounter currentThread + |> if isNotEqual then + IlMachineState.jumpProgramCounter currentThread (int b) + else + id + |> Tuple.withRight WhatWeDid.Executed | Bge_un_s b -> let value2, state = IlMachineState.popEvalStack currentThread state let value1, state = IlMachineState.popEvalStack currentThread state