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