mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-05 22:28:38 +00:00
Implement Ldtoken for fields (#94)
This commit is contained in:
44
CLAUDE.md
44
CLAUDE.md
@@ -182,3 +182,47 @@ When encountering errors:
|
||||
4. Add logging to see generic contexts: `failwithf "Failed to concretize: %A" typeDefn`
|
||||
5. Check if you're in a generic method calling another generic method
|
||||
6. Verify TypeRefs are being resolved in the correct assembly
|
||||
|
||||
## Common Type System Patterns
|
||||
|
||||
### Creating TypeDefn from Type Metadata
|
||||
|
||||
When you need to create a `TypeDefn` from type metadata (e.g., from a `TypeInfo`), there's a common pattern that involves:
|
||||
1. Resolving the base type to determine `SignatureTypeKind`
|
||||
2. Creating the base `TypeDefn.FromDefinition`
|
||||
3. For generic types, creating a `GenericInstantiation` with type parameters
|
||||
|
||||
This pattern is implemented in `UnaryMetadataIlOp.lookupTypeDefn`. Example usage:
|
||||
```fsharp
|
||||
let state, typeDefn =
|
||||
UnaryMetadataIlOp.lookupTypeDefn
|
||||
baseClassTypes
|
||||
state
|
||||
activeAssembly
|
||||
typeDefHandle
|
||||
```
|
||||
|
||||
### Field Signature Comparison in Generic Contexts
|
||||
|
||||
When comparing field signatures in generic contexts (e.g., when resolving member references), signatures must be concretized before comparison. This ensures generic type parameters are properly substituted:
|
||||
|
||||
```fsharp
|
||||
// Concretize both signatures before comparing
|
||||
let state, concreteFieldSig = concretizeType ... fieldSig
|
||||
let state, fieldSigConcrete = concretizeType ... fi.Signature
|
||||
if fieldSigConcrete = concreteFieldSig then ...
|
||||
```
|
||||
|
||||
### Static vs Instance Fields
|
||||
|
||||
When constructing objects with `Newobj`:
|
||||
- Only instance fields should be included in the object
|
||||
- Static fields belong to the type, not instances
|
||||
- Filter using: `field.Attributes.HasFlag FieldAttributes.Static`
|
||||
|
||||
Example:
|
||||
```fsharp
|
||||
let instanceFields =
|
||||
ctorType.Fields
|
||||
|> List.filter (fun field -> not (field.Attributes.HasFlag FieldAttributes.Static))
|
||||
```
|
||||
|
37
WoofWare.PawPrint.Domain/ComparableFieldDefinitionHandle.fs
Normal file
37
WoofWare.PawPrint.Domain/ComparableFieldDefinitionHandle.fs
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
open System
|
||||
open System.Reflection.Metadata
|
||||
|
||||
[<CustomEquality>]
|
||||
[<CustomComparison>]
|
||||
type ComparableFieldDefinitionHandle =
|
||||
private
|
||||
{
|
||||
_Inner : FieldDefinitionHandle
|
||||
}
|
||||
|
||||
override this.Equals other =
|
||||
match other with
|
||||
| :? ComparableFieldDefinitionHandle as other -> this._Inner.GetHashCode () = other._Inner.GetHashCode ()
|
||||
| _ -> false
|
||||
|
||||
override this.GetHashCode () : int = this._Inner.GetHashCode ()
|
||||
|
||||
interface IComparable<ComparableFieldDefinitionHandle> with
|
||||
member this.CompareTo (other : ComparableFieldDefinitionHandle) : int =
|
||||
this._Inner.GetHashCode().CompareTo (other._Inner.GetHashCode ())
|
||||
|
||||
interface IComparable with
|
||||
member this.CompareTo (other : obj) : int =
|
||||
match other with
|
||||
| :? ComparableFieldDefinitionHandle as other ->
|
||||
(this :> IComparable<ComparableFieldDefinitionHandle>).CompareTo other
|
||||
| _ -> failwith "invalid comparison"
|
||||
|
||||
static member Make (h : FieldDefinitionHandle) =
|
||||
{
|
||||
_Inner = h
|
||||
}
|
||||
|
||||
member this.Get = this._Inner
|
@@ -11,7 +11,7 @@ type ComparableTypeDefinitionHandle =
|
||||
_Inner : TypeDefinitionHandle
|
||||
}
|
||||
|
||||
override this.Equals (other) =
|
||||
override this.Equals other =
|
||||
match other with
|
||||
| :? ComparableTypeDefinitionHandle as other -> this._Inner.GetHashCode () = other._Inner.GetHashCode ()
|
||||
| _ -> false
|
||||
|
@@ -36,6 +36,8 @@ type FieldInfo<'typeGeneric, 'fieldGeneric when 'typeGeneric : comparison and 't
|
||||
Attributes : FieldAttributes
|
||||
}
|
||||
|
||||
member this.HasFieldRVA = this.Attributes.HasFlag FieldAttributes.HasFieldRVA
|
||||
|
||||
override this.ToString () : string =
|
||||
$"%s{this.DeclaringType.Assembly.Name}.{this.DeclaringType.Name}.%s{this.Name}"
|
||||
|
||||
@@ -52,7 +54,7 @@ module FieldInfo =
|
||||
let fieldSig = def.DecodeSignature (TypeDefn.typeProvider assembly, ())
|
||||
let declaringType = def.GetDeclaringType ()
|
||||
let typeGenerics = mr.GetTypeDefinition(declaringType).GetGenericParameters().Count
|
||||
let decType = mr.GetTypeDefinition (declaringType)
|
||||
let decType = mr.GetTypeDefinition declaringType
|
||||
let declaringTypeNamespace = mr.GetString decType.Namespace
|
||||
let declaringTypeName = mr.GetString decType.Name
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
open System
|
||||
open System.Collections.Immutable
|
||||
open System.Reflection
|
||||
open System.Reflection.Metadata
|
||||
@@ -81,10 +82,72 @@ module AllConcreteTypes =
|
||||
|
||||
toRet, newState
|
||||
|
||||
// Active patterns for matching concrete types
|
||||
|
||||
[<AutoOpen>]
|
||||
module ConcreteActivePatterns =
|
||||
/// Active pattern to match primitive types from concrete type handles
|
||||
let (|ConcretePrimitive|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) =
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Concrete id ->
|
||||
match concreteTypes.Mapping |> Map.tryFind id with
|
||||
| Some ct when ct.Namespace = "System" && ct.Generics.IsEmpty ->
|
||||
match ct.Name with
|
||||
| "Int32" -> Some PrimitiveType.Int32
|
||||
| "Int64" -> Some PrimitiveType.Int64
|
||||
| "Int16" -> Some PrimitiveType.Int16
|
||||
| "UInt32" -> Some PrimitiveType.UInt32
|
||||
| "UInt64" -> Some PrimitiveType.UInt64
|
||||
| "UInt16" -> Some PrimitiveType.UInt16
|
||||
| "Byte" -> Some PrimitiveType.Byte
|
||||
| "SByte" -> Some PrimitiveType.SByte
|
||||
| "Single" -> Some PrimitiveType.Single
|
||||
| "Double" -> Some PrimitiveType.Double
|
||||
| "String" -> Some PrimitiveType.String
|
||||
| "Boolean" -> Some PrimitiveType.Boolean
|
||||
| "Char" -> Some PrimitiveType.Char
|
||||
| "Object" -> Some PrimitiveType.Object
|
||||
| "IntPtr" -> Some PrimitiveType.IntPtr
|
||||
| "UIntPtr" -> Some PrimitiveType.UIntPtr
|
||||
| "TypedReference" -> Some PrimitiveType.TypedReference
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
/// Active pattern to match void type
|
||||
let (|ConcreteVoid|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) =
|
||||
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 ()
|
||||
| _ -> None
|
||||
| _ -> None
|
||||
|
||||
/// Active pattern to match any concrete type by assembly/namespace/name and generics
|
||||
let (|ConcreteType|_|) (concreteTypes : AllConcreteTypes) (handle : ConcreteTypeHandle) =
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Concrete id ->
|
||||
match concreteTypes.Mapping |> Map.tryFind id with
|
||||
| Some ct -> Some (ct.Assembly.Name, ct.Namespace, ct.Name, ct.Generics)
|
||||
| None -> None
|
||||
| _ -> None
|
||||
|
||||
/// Active pattern to match byref types
|
||||
let (|ConcreteByref|_|) (handle : ConcreteTypeHandle) =
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Byref inner -> Some inner
|
||||
| _ -> None
|
||||
|
||||
/// Active pattern to match pointer types
|
||||
let (|ConcretePointer|_|) (handle : ConcreteTypeHandle) =
|
||||
match handle with
|
||||
| ConcreteTypeHandle.Pointer inner -> Some inner
|
||||
| _ -> None
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module TypeConcretization =
|
||||
|
||||
type ConcretizationContext =
|
||||
type ConcretizationContext<'corelib> =
|
||||
{
|
||||
/// Types currently being processed (to detect cycles)
|
||||
InProgress : ImmutableDictionary<AssemblyName * TypeDefn, ConcreteTypeHandle>
|
||||
@@ -92,7 +155,7 @@ module TypeConcretization =
|
||||
ConcreteTypes : AllConcreteTypes
|
||||
/// For resolving type references
|
||||
LoadedAssemblies : ImmutableDictionary<string, DumpedAssembly>
|
||||
BaseTypes : BaseClassTypes<DumpedAssembly>
|
||||
BaseTypes : BaseClassTypes<'corelib>
|
||||
}
|
||||
|
||||
// Helper function to find existing types by assembly, namespace, name, and generics
|
||||
@@ -128,13 +191,13 @@ module TypeConcretization =
|
||||
|
||||
// Helper function to create and add a ConcreteType to the context
|
||||
let private createAndAddConcreteType
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(assembly : AssemblyName)
|
||||
(definition : ComparableTypeDefinitionHandle)
|
||||
(ns : string)
|
||||
(name : string)
|
||||
(generics : ConcreteTypeHandle ImmutableArray)
|
||||
: ConcreteTypeHandle * ConcretizationContext
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
=
|
||||
let concreteType =
|
||||
{
|
||||
@@ -158,10 +221,10 @@ module TypeConcretization =
|
||||
let private loadAssemblyAndResolveTypeRef
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(currentAssembly : AssemblyName)
|
||||
(typeRef : TypeRef)
|
||||
: (DumpedAssembly * WoofWare.PawPrint.TypeInfo<_, _>) * ConcretizationContext
|
||||
: (DumpedAssembly * WoofWare.PawPrint.TypeInfo<_, _>) * ConcretizationContext<'corelib>
|
||||
=
|
||||
let currentAssy =
|
||||
match ctx.LoadedAssemblies.TryGetValue currentAssembly.FullName with
|
||||
@@ -196,9 +259,9 @@ module TypeConcretization =
|
||||
| _ -> failwith "Unexpected resolution scope"
|
||||
|
||||
let private concretizePrimitive
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(prim : PrimitiveType)
|
||||
: ConcreteTypeHandle * ConcretizationContext
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
=
|
||||
|
||||
// Get the TypeInfo for this primitive from BaseClassTypes
|
||||
@@ -238,10 +301,10 @@ module TypeConcretization =
|
||||
ImmutableArray.Empty // Primitives have no generic parameters
|
||||
|
||||
let private concretizeArray
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(elementHandle : ConcreteTypeHandle)
|
||||
(shape : 'a)
|
||||
: ConcreteTypeHandle * ConcretizationContext
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
=
|
||||
|
||||
// Arrays are System.Array<T> where T is the element type
|
||||
@@ -268,9 +331,9 @@ module TypeConcretization =
|
||||
(ImmutableArray.Create elementHandle) // Array<T> has one generic parameter
|
||||
|
||||
let private concretizeOneDimArray
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(elementHandle : ConcreteTypeHandle)
|
||||
: ConcreteTypeHandle * ConcretizationContext
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
=
|
||||
|
||||
// One-dimensional arrays with lower bound 0 are also System.Array<T>
|
||||
@@ -298,10 +361,10 @@ module TypeConcretization =
|
||||
(ImmutableArray.Create elementHandle) // Array<T> has one generic parameter
|
||||
|
||||
let concretizeTypeDefinition
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(assemblyName : AssemblyName)
|
||||
(typeDefHandle : ComparableTypeDefinitionHandle)
|
||||
: ConcreteTypeHandle * ConcretizationContext
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
=
|
||||
|
||||
// Look up the type definition in the assembly
|
||||
@@ -336,10 +399,10 @@ module TypeConcretization =
|
||||
let private concretizeTypeReference
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(currentAssembly : AssemblyName)
|
||||
(typeRef : TypeRef)
|
||||
: ConcreteTypeHandle * ConcretizationContext
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
=
|
||||
// Use the helper to load assembly and resolve the type reference
|
||||
let (targetAssy, typeInfo), ctx =
|
||||
@@ -358,14 +421,14 @@ module TypeConcretization =
|
||||
|
||||
/// Concretize a type in a specific generic context
|
||||
let rec concretizeType
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> (ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly))
|
||||
(assembly : AssemblyName)
|
||||
(typeGenerics : ConcreteTypeHandle ImmutableArray)
|
||||
(methodGenerics : ConcreteTypeHandle ImmutableArray)
|
||||
(typeDefn : TypeDefn)
|
||||
: ConcreteTypeHandle * ConcretizationContext
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
=
|
||||
|
||||
let key = (assembly, typeDefn)
|
||||
@@ -394,13 +457,13 @@ module TypeConcretization =
|
||||
if index < typeGenerics.Length then
|
||||
typeGenerics.[index], ctx
|
||||
else
|
||||
failwithf "Generic type parameter %d out of range" index
|
||||
raise (IndexOutOfRangeException $"Generic type parameter %i{index}")
|
||||
|
||||
| TypeDefn.GenericMethodParameter index ->
|
||||
if index < methodGenerics.Length then
|
||||
methodGenerics.[index], ctx
|
||||
else
|
||||
failwithf "Generic method parameter %d out of range" index
|
||||
raise (IndexOutOfRangeException $"Generic method parameter %i{index}")
|
||||
|
||||
| TypeDefn.GenericInstantiation (genericDef, args) ->
|
||||
concretizeGenericInstantiation ctx loadAssembly assembly typeGenerics methodGenerics genericDef args
|
||||
@@ -455,15 +518,15 @@ module TypeConcretization =
|
||||
| _ -> failwithf "TODO: Concretization of %A not implemented" typeDefn
|
||||
|
||||
and private concretizeGenericInstantiation
|
||||
(ctx : ConcretizationContext)
|
||||
(ctx : ConcretizationContext<'corelib>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> (ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly))
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(assembly : AssemblyName)
|
||||
(typeGenerics : ConcreteTypeHandle ImmutableArray)
|
||||
(methodGenerics : ConcreteTypeHandle ImmutableArray)
|
||||
(genericDef : TypeDefn)
|
||||
(args : ImmutableArray<TypeDefn>)
|
||||
: ConcreteTypeHandle * ConcretizationContext
|
||||
: ConcreteTypeHandle * ConcretizationContext<'corelib>
|
||||
=
|
||||
// First, concretize all type arguments
|
||||
let argHandles, ctxAfterArgs =
|
||||
@@ -614,17 +677,17 @@ module Concretization =
|
||||
|
||||
/// Helper to concretize an array of types
|
||||
let private concretizeTypeArray
|
||||
(ctx : TypeConcretization.ConcretizationContext)
|
||||
(ctx : TypeConcretization.ConcretizationContext<'corelib>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> (ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly))
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(assembly : AssemblyName)
|
||||
(typeArgs : ConcreteTypeHandle ImmutableArray)
|
||||
(methodArgs : ConcreteTypeHandle ImmutableArray)
|
||||
(types : ImmutableArray<TypeDefn>)
|
||||
: ImmutableArray<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext
|
||||
: ImmutableArray<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<'corelib>
|
||||
=
|
||||
|
||||
let handles = ImmutableArray.CreateBuilder (types.Length)
|
||||
let handles = ImmutableArray.CreateBuilder types.Length
|
||||
let mutable ctx = ctx
|
||||
|
||||
for i = 0 to types.Length - 1 do
|
||||
@@ -638,14 +701,14 @@ module Concretization =
|
||||
|
||||
/// Helper to concretize a method signature
|
||||
let private concretizeMethodSignature
|
||||
(ctx : TypeConcretization.ConcretizationContext)
|
||||
(ctx : TypeConcretization.ConcretizationContext<'corelib>)
|
||||
(loadAssembly :
|
||||
AssemblyName -> AssemblyReferenceHandle -> (ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly))
|
||||
AssemblyName -> AssemblyReferenceHandle -> ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
(assembly : AssemblyName)
|
||||
(typeArgs : ConcreteTypeHandle ImmutableArray)
|
||||
(methodArgs : ConcreteTypeHandle ImmutableArray)
|
||||
(signature : TypeMethodSignature<TypeDefn>)
|
||||
: TypeMethodSignature<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext
|
||||
: TypeMethodSignature<ConcreteTypeHandle> * TypeConcretization.ConcretizationContext<'corelib>
|
||||
=
|
||||
|
||||
// Concretize return type
|
||||
|
@@ -150,6 +150,8 @@ type BaseClassTypes<'corelib> =
|
||||
RuntimeMethodHandle : TypeInfo<WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
RuntimeFieldHandle : TypeInfo<WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
RuntimeTypeHandle : TypeInfo<WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
RuntimeFieldInfoStub : TypeInfo<WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
RuntimeFieldHandleInternal : TypeInfo<WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
RuntimeType : TypeInfo<WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
Void : TypeInfo<WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
TypedReference : TypeInfo<WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
@@ -323,7 +325,7 @@ module TypeInfo =
|
||||
(Some (BaseTypeInfo.TypeDef typeDefinitionHandle))
|
||||
|
||||
let toTypeDefn
|
||||
(corelib : BaseClassTypes<'corelib>)
|
||||
(baseClassTypes : BaseClassTypes<'corelib>)
|
||||
(getName : 'corelib -> AssemblyName)
|
||||
(getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'field>)
|
||||
(getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic, 'field>)
|
||||
@@ -331,7 +333,7 @@ module TypeInfo =
|
||||
: TypeDefn
|
||||
=
|
||||
let stk =
|
||||
match resolveBaseType corelib getName getTypeDef getTypeRef ty.Assembly ty.BaseType with
|
||||
match resolveBaseType baseClassTypes getName getTypeDef getTypeRef ty.Assembly ty.BaseType with
|
||||
| ResolvedBaseType.Enum
|
||||
| ResolvedBaseType.ValueType -> SignatureTypeKind.ValueType
|
||||
| ResolvedBaseType.Object
|
||||
|
@@ -14,6 +14,7 @@
|
||||
<Compile Include="AssemblyReference.fs" />
|
||||
<Compile Include="EventDefn.fs" />
|
||||
<Compile Include="ComparableTypeDefinitionHandle.fs" />
|
||||
<Compile Include="ComparableFieldDefinitionHandle.fs" />
|
||||
<Compile Include="ComparableSignatureHeader.fs" />
|
||||
<Compile Include="TypeDefn.fs" />
|
||||
<Compile Include="ConcreteType.fs" />
|
||||
|
@@ -19,6 +19,12 @@ module TestPureCases =
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
{
|
||||
FileName = "InitializeArray.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
{
|
||||
FileName = "GenericEdgeCases.cs"
|
||||
ExpectedReturnCode = 0
|
||||
@@ -73,6 +79,12 @@ module TestPureCases =
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
{
|
||||
FileName = "LdtokenField.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
]
|
||||
|
||||
let cases : TestCase list =
|
||||
|
@@ -21,6 +21,8 @@
|
||||
<EmbeddedResource Include="sourcesPure\BasicLock.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\Floats.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\NoOp.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\InitializeArray.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\LdtokenField.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\StaticVariables.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\Ldelema.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpCatch.cs" />
|
||||
|
19
WoofWare.PawPrint.Test/sourcesPure/InitializeArray.cs
Normal file
19
WoofWare.PawPrint.Test/sourcesPure/InitializeArray.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace HelloWorldApp
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
int[] array = new[] { 1, 2, 3 };
|
||||
|
||||
if (array.Sum() != 60)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
@@ -39,7 +39,7 @@ unsafe class LdindTest
|
||||
failures += TestTruncation();
|
||||
|
||||
// Test with managed pointers (ref)
|
||||
// failures += TestManagedPointers();
|
||||
failures += TestManagedPointers();
|
||||
|
||||
// Test Ldind.i (native int)
|
||||
failures += TestLdindI();
|
||||
@@ -325,7 +325,10 @@ unsafe class LdindTest
|
||||
}
|
||||
|
||||
// Test with array element
|
||||
int[] array = { 10, 20, 30 };
|
||||
int[] array = new int[3];
|
||||
array[0] = 10;
|
||||
array[1] = 20;
|
||||
array[2] = 30;
|
||||
ref int element = ref array[1];
|
||||
if (element != 20)
|
||||
{
|
||||
|
128
WoofWare.PawPrint.Test/sourcesPure/LdtokenField.cs
Normal file
128
WoofWare.PawPrint.Test/sourcesPure/LdtokenField.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace LdtokenFieldTest
|
||||
{
|
||||
class Program
|
||||
{
|
||||
// Various field types to test ldtoken with
|
||||
public static int StaticIntField = 42;
|
||||
public string InstanceStringField = "test";
|
||||
private readonly double PrivateReadonlyField = 3.14;
|
||||
internal decimal InternalField;
|
||||
protected bool ProtectedField;
|
||||
public static readonly DateTime StaticReadonlyField = DateTime.MinValue;
|
||||
|
||||
// Generic type fields
|
||||
public GenericClass<int>.NestedClass<string> GenericField;
|
||||
|
||||
static int Main(string[] args)
|
||||
{
|
||||
int testsFailed = 0;
|
||||
|
||||
// Test 1: Static field via FieldInfo
|
||||
FieldInfo staticField = typeof(Program).GetField(nameof(StaticIntField));
|
||||
if (staticField == null || staticField.FieldType != typeof(int))
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
// Test 2: Instance field via FieldInfo
|
||||
FieldInfo instanceField = typeof(Program).GetField(nameof(InstanceStringField));
|
||||
if (instanceField == null || instanceField.FieldType != typeof(string))
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
// Test 3: Private field via FieldInfo with binding flags
|
||||
FieldInfo privateField = typeof(Program).GetField("PrivateReadonlyField",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (privateField == null || privateField.FieldType != typeof(double))
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
// Test 4: Using RuntimeFieldHandle directly
|
||||
RuntimeFieldHandle handle = staticField.FieldHandle;
|
||||
FieldInfo fieldFromHandle = FieldInfo.GetFieldFromHandle(handle);
|
||||
if (!ReferenceEquals(fieldFromHandle, staticField))
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
// Test 5: Field from generic type
|
||||
Type genericType = typeof(GenericClass<>);
|
||||
FieldInfo genericFieldInfo = genericType.GetField("GenericField");
|
||||
if (genericFieldInfo == null)
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
// Test 6: Field from nested type
|
||||
Type nestedType = typeof(OuterClass.InnerClass);
|
||||
FieldInfo nestedField = nestedType.GetField("NestedField");
|
||||
if (nestedField == null || nestedField.FieldType != typeof(int))
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
// Test 7: Field handle with generic context
|
||||
Type constructedGeneric = typeof(GenericClass<int>);
|
||||
FieldInfo constructedField = constructedGeneric.GetField("GenericField");
|
||||
RuntimeFieldHandle genericHandle = constructedField.FieldHandle;
|
||||
FieldInfo reconstructed = FieldInfo.GetFieldFromHandle(genericHandle, constructedGeneric.TypeHandle);
|
||||
if (reconstructed.DeclaringType != constructedGeneric)
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
// Test 8: Struct field
|
||||
Type structType = typeof(TestStruct);
|
||||
FieldInfo structField = structType.GetField("StructField");
|
||||
if (structField == null || structField.FieldType != typeof(long))
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
// Test 9: Volatile field
|
||||
FieldInfo volatileField = typeof(VolatileFieldClass).GetField("VolatileField");
|
||||
if (volatileField == null || !volatileField.GetRequiredCustomModifiers().Any(t => t == typeof(IsVolatile)))
|
||||
{
|
||||
testsFailed++;
|
||||
}
|
||||
|
||||
return testsFailed;
|
||||
}
|
||||
}
|
||||
|
||||
// Supporting types for testing
|
||||
public class GenericClass<T>
|
||||
{
|
||||
public T GenericField;
|
||||
|
||||
public class NestedClass<U>
|
||||
{
|
||||
public U NestedGenericField;
|
||||
}
|
||||
}
|
||||
|
||||
public class OuterClass
|
||||
{
|
||||
public class InnerClass
|
||||
{
|
||||
public int NestedField = 100;
|
||||
}
|
||||
}
|
||||
|
||||
public struct TestStruct
|
||||
{
|
||||
public long StructField;
|
||||
}
|
||||
|
||||
public class VolatileFieldClass
|
||||
{
|
||||
public volatile int VolatileField;
|
||||
}
|
||||
}
|
@@ -125,42 +125,55 @@ module AbstractMachine =
|
||||
targetType.Namespace,
|
||||
targetType.Name,
|
||||
instruction.ExecutingMethod.Name,
|
||||
instruction.ExecutingMethod.RawSignature.ParameterTypes,
|
||||
instruction.ExecutingMethod.RawSignature.ReturnType
|
||||
instruction.ExecutingMethod.Signature.ParameterTypes,
|
||||
instruction.ExecutingMethod.Signature.ReturnType
|
||||
with
|
||||
| "System.Private.CoreLib",
|
||||
"System",
|
||||
"Environment",
|
||||
"GetProcessorCount",
|
||||
[],
|
||||
TypeDefn.PrimitiveType PrimitiveType.Int32 ->
|
||||
ConcretePrimitive state.ConcreteTypes PrimitiveType.Int32 ->
|
||||
let env = ISystem_Environment_Env.get impls
|
||||
env.GetProcessorCount thread state
|
||||
| "System.Private.CoreLib",
|
||||
"System",
|
||||
"Environment",
|
||||
"_Exit",
|
||||
[ TypeDefn.PrimitiveType PrimitiveType.Int32 ],
|
||||
TypeDefn.Void ->
|
||||
[ ConcretePrimitive state.ConcreteTypes PrimitiveType.Int32 ],
|
||||
ConcreteVoid state.ConcreteTypes ->
|
||||
let env = ISystem_Environment_Env.get impls
|
||||
env._Exit thread state
|
||||
| "System.Private.CoreLib",
|
||||
"System.Threading",
|
||||
"Monitor",
|
||||
"ReliableEnter",
|
||||
[ TypeDefn.PrimitiveType PrimitiveType.Object
|
||||
TypeDefn.Byref (TypeDefn.PrimitiveType PrimitiveType.Boolean) ],
|
||||
TypeDefn.Void ->
|
||||
[ ConcretePrimitive state.ConcreteTypes PrimitiveType.Object
|
||||
ConcreteByref (ConcretePrimitive state.ConcreteTypes PrimitiveType.Boolean) ],
|
||||
ConcreteVoid state.ConcreteTypes ->
|
||||
let env = ISystem_Threading_Monitor_Env.get impls
|
||||
env.ReliableEnter thread state
|
||||
| "System.Private.CoreLib",
|
||||
"System.Threading",
|
||||
"Monitor",
|
||||
"Exit",
|
||||
[ TypeDefn.PrimitiveType PrimitiveType.Object ],
|
||||
TypeDefn.Void ->
|
||||
[ ConcretePrimitive state.ConcreteTypes PrimitiveType.Object ],
|
||||
ConcreteVoid state.ConcreteTypes ->
|
||||
let env = ISystem_Threading_Monitor_Env.get impls
|
||||
env.Exit thread state
|
||||
| "System.Private.CoreLib",
|
||||
"System",
|
||||
"Type",
|
||||
"GetField",
|
||||
[ ConcretePrimitive state.ConcreteTypes PrimitiveType.String ; ty ],
|
||||
ret ->
|
||||
let ty = AllConcreteTypes.lookup ty state.ConcreteTypes |> Option.get
|
||||
let ret = AllConcreteTypes.lookup ret state.ConcreteTypes |> Option.get
|
||||
|
||||
match ty.Namespace, ty.Name, ty.Generics.IsEmpty, ret.Namespace, ret.Name, ret.Generics.IsEmpty with
|
||||
| "System.Reflection", "BindingFlags", true, "System.Reflection", "FieldInfo", true ->
|
||||
failwith "TODO: GetField"
|
||||
| _ -> failwith "unexpected signature for Type.GetField"
|
||||
| assy, ns, typeName, methName, param, retType ->
|
||||
failwith
|
||||
$"TODO: tried to IL-interpret a method in {assy} {ns}.{typeName} named {methName} with no implementation; {param} -> {retType}"
|
||||
|
@@ -396,7 +396,7 @@ module CliType =
|
||||
let loadAssembly
|
||||
(assyName : AssemblyName)
|
||||
(ref : AssemblyReferenceHandle)
|
||||
: (ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
: ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly
|
||||
=
|
||||
match assemblies.TryGetValue assyName.FullName with
|
||||
| true, currentAssy ->
|
||||
|
@@ -134,6 +134,21 @@ module Corelib =
|
||||
|> Seq.choose (fun (KeyValue (_, v)) -> if v.Name = "UIntPtr" then Some v else None)
|
||||
|> Seq.exactlyOne
|
||||
|
||||
let runtimeFieldInfoStubType =
|
||||
corelib.TypeDefs
|
||||
|> Seq.choose (fun (KeyValue (_, v)) -> if v.Name = "RuntimeFieldInfoStub" then Some v else None)
|
||||
|> Seq.exactlyOne
|
||||
|
||||
let runtimeFieldHandleInternalType =
|
||||
corelib.TypeDefs
|
||||
|> Seq.choose (fun (KeyValue (_, v)) ->
|
||||
if v.Name = "RuntimeFieldHandleInternal" then
|
||||
Some v
|
||||
else
|
||||
None
|
||||
)
|
||||
|> Seq.exactlyOne
|
||||
|
||||
{
|
||||
Corelib = corelib
|
||||
String = stringType
|
||||
@@ -157,6 +172,8 @@ module Corelib =
|
||||
RuntimeTypeHandle = runtimeTypeHandleType
|
||||
RuntimeMethodHandle = runtimeMethodHandleType
|
||||
RuntimeFieldHandle = runtimeFieldHandleType
|
||||
RuntimeFieldInfoStub = runtimeFieldInfoStubType
|
||||
RuntimeFieldHandleInternal = runtimeFieldHandleInternalType
|
||||
RuntimeType = runtimeTypeType
|
||||
Void = voidType
|
||||
TypedReference = typedReferenceType
|
||||
|
111
WoofWare.PawPrint/FieldHandleRegistry.fs
Normal file
111
WoofWare.PawPrint/FieldHandleRegistry.fs
Normal file
@@ -0,0 +1,111 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
open System.Reflection
|
||||
open System.Reflection.Metadata
|
||||
|
||||
type FieldHandle =
|
||||
private
|
||||
{
|
||||
AssemblyFullName : string
|
||||
DeclaringType : ConcreteTypeHandle
|
||||
FieldHandle : ComparableFieldDefinitionHandle
|
||||
}
|
||||
|
||||
type FieldHandleRegistry =
|
||||
private
|
||||
{
|
||||
FieldHandleToId : Map<FieldHandle, int64>
|
||||
FieldHandleToField : Map<ManagedHeapAddress, FieldHandle>
|
||||
FieldToHandle : Map<FieldHandle, ManagedHeapAddress>
|
||||
NextHandle : int64
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module FieldHandleRegistry =
|
||||
let empty () =
|
||||
{
|
||||
FieldHandleToField = Map.empty
|
||||
FieldToHandle = Map.empty
|
||||
FieldHandleToId = Map.empty
|
||||
NextHandle = 1L
|
||||
}
|
||||
|
||||
/// Returns a (struct) System.RuntimeFieldHandle, with its contents (reference type) freshly allocated if necessary.
|
||||
let getOrAllocate
|
||||
(baseClassTypes : BaseClassTypes<'corelib>)
|
||||
(allocState : 'allocState)
|
||||
(allocate : (string * CliType) list -> 'allocState -> ManagedHeapAddress * 'allocState)
|
||||
(declaringAssy : AssemblyName)
|
||||
(declaringType : ConcreteTypeHandle)
|
||||
(handle : FieldDefinitionHandle)
|
||||
(reg : FieldHandleRegistry)
|
||||
: CliType * FieldHandleRegistry * 'allocState
|
||||
=
|
||||
|
||||
let runtimeFieldHandle (runtimeFieldInfoStub : ManagedHeapAddress) =
|
||||
// RuntimeFieldHandle is a struct; it contains one field, an IRuntimeFieldInfo
|
||||
// https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs#L1048
|
||||
// In practice we expect to use RuntimeFieldInfoStub for that IRuntimeFieldInfo:
|
||||
// https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs#L1157
|
||||
let runtimeFieldHandleType = baseClassTypes.RuntimeFieldHandle
|
||||
let field = runtimeFieldHandleType.Fields |> List.exactlyOne
|
||||
|
||||
if field.Name <> "m_ptr" then
|
||||
failwith $"unexpected field name %s{field.Name} for BCL type RuntimeFieldHandle"
|
||||
|
||||
{
|
||||
Fields = [ "m_ptr", CliType.ofManagedObject runtimeFieldInfoStub ]
|
||||
}
|
||||
|> CliType.ValueType
|
||||
|
||||
let handle =
|
||||
{
|
||||
AssemblyFullName = declaringAssy.FullName
|
||||
FieldHandle = ComparableFieldDefinitionHandle.Make handle
|
||||
DeclaringType = declaringType
|
||||
}
|
||||
|
||||
match Map.tryFind handle reg.FieldToHandle with
|
||||
| Some v -> runtimeFieldHandle v, reg, allocState
|
||||
| None ->
|
||||
|
||||
let newHandle = reg.NextHandle
|
||||
|
||||
let runtimeFieldHandleInternal =
|
||||
let field = baseClassTypes.RuntimeFieldHandleInternal.Fields |> List.exactlyOne
|
||||
|
||||
if field.Name <> "m_handle" then
|
||||
failwith $"unexpected field name %s{field.Name} for BCL type RuntimeFieldHandleInternal"
|
||||
|
||||
match field.Signature with
|
||||
| TypeDefn.PrimitiveType PrimitiveType.IntPtr -> ()
|
||||
| s -> failwith $"bad sig: {s}"
|
||||
|
||||
{
|
||||
Fields = [ "m_handle", CliType.RuntimePointer (CliRuntimePointer.Unmanaged newHandle) ]
|
||||
}
|
||||
|> CliType.ValueType
|
||||
|
||||
let runtimeFieldInfoStub =
|
||||
[
|
||||
// If we ever implement a GC, something should change here
|
||||
"m_keepalive", CliType.ObjectRef None
|
||||
"m_c", CliType.ObjectRef None
|
||||
"m_d", CliType.ObjectRef None
|
||||
"m_b", CliType.Numeric (CliNumericType.Int32 0)
|
||||
"m_e", CliType.ObjectRef None
|
||||
// RuntimeFieldHandleInternal: https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs#L1048
|
||||
"m_fieldHandle", runtimeFieldHandleInternal
|
||||
]
|
||||
|
||||
let alloc, state = allocate runtimeFieldInfoStub allocState
|
||||
|
||||
let reg =
|
||||
{
|
||||
FieldHandleToField = reg.FieldHandleToField |> Map.add alloc handle
|
||||
FieldToHandle = reg.FieldToHandle |> Map.add handle alloc
|
||||
FieldHandleToId = reg.FieldHandleToId |> Map.add handle newHandle
|
||||
NextHandle = reg.NextHandle + 1L
|
||||
}
|
||||
|
||||
runtimeFieldHandle alloc, reg, state
|
@@ -1,5 +1,6 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
open System
|
||||
open System.Collections.Immutable
|
||||
open System.IO
|
||||
open System.Reflection
|
||||
@@ -26,6 +27,7 @@ type IlMachineState =
|
||||
_Statics : ImmutableDictionary<ConcreteTypeHandle, ImmutableDictionary<string, CliType>>
|
||||
DotnetRuntimeDirs : string ImmutableArray
|
||||
TypeHandles : TypeHandleRegistry
|
||||
FieldHandles : FieldHandleRegistry
|
||||
}
|
||||
|
||||
member this.WithTypeBeginInit (thread : ThreadId) (ty : ConcreteTypeHandle) =
|
||||
@@ -147,6 +149,47 @@ type StateLoadResult =
|
||||
module IlMachineState =
|
||||
type private Dummy = class end
|
||||
|
||||
let concretizeType
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(state : IlMachineState)
|
||||
(declaringAssembly : AssemblyName)
|
||||
(typeGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(ty : TypeDefn)
|
||||
: IlMachineState * ConcreteTypeHandle
|
||||
=
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = baseClassTypes
|
||||
}
|
||||
|
||||
let handle, ctx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun assyName ref ->
|
||||
let currentAssy = state.LoadedAssembly assyName |> Option.get
|
||||
|
||||
let targetAssy =
|
||||
currentAssy.AssemblyReferences.[ref].Name |> state.LoadedAssembly |> Option.get
|
||||
|
||||
state._LoadedAssemblies, targetAssy
|
||||
)
|
||||
declaringAssembly
|
||||
typeGenerics
|
||||
methodGenerics
|
||||
ty
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
_LoadedAssemblies = ctx.LoadedAssemblies
|
||||
ConcreteTypes = ctx.ConcreteTypes
|
||||
}
|
||||
|
||||
state, handle
|
||||
|
||||
/// <summary>
|
||||
/// Create a new IlMachineState which has loaded the given assembly.
|
||||
/// This involves reading assemblies from the disk and doing a complete parse of them, so it might be quite slow!
|
||||
@@ -267,7 +310,7 @@ module IlMachineState =
|
||||
|
||||
let rec resolveTypeFromDefn
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : TypeDefn)
|
||||
(typeGenericArgs : ImmutableArray<TypeDefn>)
|
||||
(methodGenericArgs : ImmutableArray<TypeDefn>)
|
||||
@@ -283,14 +326,21 @@ module IlMachineState =
|
||||
(state, args)
|
||||
||> Seq.fold (fun state arg ->
|
||||
let state, assy, resolvedArg =
|
||||
resolveTypeFromDefn loggerFactory corelib arg typeGenericArgs methodGenericArgs assy state
|
||||
resolveTypeFromDefn
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
arg
|
||||
typeGenericArgs
|
||||
methodGenericArgs
|
||||
assy
|
||||
state
|
||||
|
||||
// If the resolved argument has generics, create a GenericInstantiation
|
||||
// Otherwise, create a FromDefinition
|
||||
let preservedArg =
|
||||
let baseType =
|
||||
resolvedArg.BaseType
|
||||
|> DumpedAssembly.resolveBaseType corelib state._LoadedAssemblies assy.Name
|
||||
|> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies assy.Name
|
||||
|
||||
let signatureTypeKind =
|
||||
match baseType with
|
||||
@@ -322,7 +372,7 @@ module IlMachineState =
|
||||
)
|
||||
|
||||
let args' = args'.ToImmutable ()
|
||||
resolveTypeFromDefn loggerFactory corelib generic args' methodGenericArgs assy state
|
||||
resolveTypeFromDefn loggerFactory baseClassTypes generic args' methodGenericArgs assy state
|
||||
| TypeDefn.FromDefinition (defn, assy, _typeKind) ->
|
||||
let assy = state._LoadedAssemblies.[assy]
|
||||
|
||||
@@ -339,39 +389,39 @@ module IlMachineState =
|
||||
| TypeDefn.PrimitiveType prim ->
|
||||
let ty =
|
||||
match prim with
|
||||
| PrimitiveType.Boolean -> corelib.Boolean
|
||||
| PrimitiveType.Char -> corelib.Char
|
||||
| PrimitiveType.SByte -> corelib.SByte
|
||||
| PrimitiveType.Byte -> corelib.Byte
|
||||
| PrimitiveType.Int16 -> corelib.Int16
|
||||
| PrimitiveType.UInt16 -> corelib.UInt16
|
||||
| PrimitiveType.Int32 -> corelib.Int32
|
||||
| PrimitiveType.UInt32 -> corelib.UInt32
|
||||
| PrimitiveType.Int64 -> corelib.Int64
|
||||
| PrimitiveType.UInt64 -> corelib.UInt64
|
||||
| PrimitiveType.Single -> corelib.Single
|
||||
| PrimitiveType.Double -> corelib.Double
|
||||
| PrimitiveType.String -> corelib.String
|
||||
| PrimitiveType.Boolean -> baseClassTypes.Boolean
|
||||
| PrimitiveType.Char -> baseClassTypes.Char
|
||||
| PrimitiveType.SByte -> baseClassTypes.SByte
|
||||
| PrimitiveType.Byte -> baseClassTypes.Byte
|
||||
| PrimitiveType.Int16 -> baseClassTypes.Int16
|
||||
| PrimitiveType.UInt16 -> baseClassTypes.UInt16
|
||||
| PrimitiveType.Int32 -> baseClassTypes.Int32
|
||||
| PrimitiveType.UInt32 -> baseClassTypes.UInt32
|
||||
| PrimitiveType.Int64 -> baseClassTypes.Int64
|
||||
| PrimitiveType.UInt64 -> baseClassTypes.UInt64
|
||||
| PrimitiveType.Single -> baseClassTypes.Single
|
||||
| PrimitiveType.Double -> baseClassTypes.Double
|
||||
| PrimitiveType.String -> baseClassTypes.String
|
||||
| PrimitiveType.TypedReference -> failwith "todo"
|
||||
| PrimitiveType.IntPtr -> failwith "todo"
|
||||
| PrimitiveType.UIntPtr -> failwith "todo"
|
||||
| PrimitiveType.Object -> failwith "todo"
|
||||
|> TypeInfo.mapGeneric (fun _ -> failwith "none of these types are generic")
|
||||
|
||||
state, corelib.Corelib, ty
|
||||
state, baseClassTypes.Corelib, ty
|
||||
| TypeDefn.GenericTypeParameter param ->
|
||||
let arg = typeGenericArgs.[param]
|
||||
// TODO: this assembly is probably wrong?
|
||||
resolveTypeFromDefn loggerFactory corelib arg typeGenericArgs methodGenericArgs assy state
|
||||
resolveTypeFromDefn loggerFactory baseClassTypes arg typeGenericArgs methodGenericArgs assy state
|
||||
| TypeDefn.GenericMethodParameter param ->
|
||||
let arg = methodGenericArgs.[param]
|
||||
// TODO: this assembly is probably wrong?
|
||||
resolveTypeFromDefn loggerFactory corelib arg typeGenericArgs methodGenericArgs assy state
|
||||
resolveTypeFromDefn loggerFactory baseClassTypes arg typeGenericArgs methodGenericArgs assy state
|
||||
| s -> failwith $"TODO: resolveTypeFromDefn unimplemented for {s}"
|
||||
|
||||
let resolveTypeFromSpec
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : TypeSpecificationHandle)
|
||||
(assy : DumpedAssembly)
|
||||
(typeGenericArgs : TypeDefn ImmutableArray)
|
||||
@@ -380,12 +430,12 @@ module IlMachineState =
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
let sign = assy.TypeSpecs.[ty].Signature
|
||||
resolveTypeFromDefn loggerFactory corelib sign typeGenericArgs methodGenericArgs assy state
|
||||
resolveTypeFromDefn loggerFactory baseClassTypes sign typeGenericArgs methodGenericArgs assy state
|
||||
|
||||
/// Resolve a TypeSpecification using concrete type handles from execution context
|
||||
let resolveTypeFromSpecConcrete
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : TypeSpecificationHandle)
|
||||
(assy : DumpedAssembly)
|
||||
(typeGenericArgs : ConcreteTypeHandle ImmutableArray)
|
||||
@@ -399,28 +449,36 @@ module IlMachineState =
|
||||
let typeGenericArgsAsDefn =
|
||||
typeGenericArgs
|
||||
|> Seq.map (fun handle ->
|
||||
Concretization.concreteHandleToTypeDefn corelib handle state.ConcreteTypes state._LoadedAssemblies
|
||||
Concretization.concreteHandleToTypeDefn
|
||||
baseClassTypes
|
||||
handle
|
||||
state.ConcreteTypes
|
||||
state._LoadedAssemblies
|
||||
)
|
||||
|> ImmutableArray.CreateRange
|
||||
|
||||
let methodGenericArgsAsDefn =
|
||||
methodGenericArgs
|
||||
|> Seq.map (fun handle ->
|
||||
Concretization.concreteHandleToTypeDefn corelib handle state.ConcreteTypes state._LoadedAssemblies
|
||||
Concretization.concreteHandleToTypeDefn
|
||||
baseClassTypes
|
||||
handle
|
||||
state.ConcreteTypes
|
||||
state._LoadedAssemblies
|
||||
)
|
||||
|> ImmutableArray.CreateRange
|
||||
|
||||
resolveTypeFromDefn loggerFactory corelib sign typeGenericArgsAsDefn methodGenericArgsAsDefn assy state
|
||||
resolveTypeFromDefn loggerFactory baseClassTypes sign typeGenericArgsAsDefn methodGenericArgsAsDefn assy state
|
||||
|
||||
/// Get zero value for a type that's already been concretized
|
||||
let cliTypeZeroOfHandle
|
||||
(state : IlMachineState)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(handle : ConcreteTypeHandle)
|
||||
: CliType * IlMachineState
|
||||
=
|
||||
let zero, updatedConcreteTypes =
|
||||
CliType.zeroOf state.ConcreteTypes state._LoadedAssemblies corelib handle
|
||||
CliType.zeroOf state.ConcreteTypes state._LoadedAssemblies baseClassTypes handle
|
||||
|
||||
let newState =
|
||||
{ state with
|
||||
@@ -440,25 +498,25 @@ module IlMachineState =
|
||||
/// Concretize a ConcreteType<TypeDefn> to get a ConcreteTypeHandle for static field access
|
||||
let concretizeFieldDeclaringType
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<'corelib>)
|
||||
(declaringType : ConcreteType<TypeDefn>)
|
||||
(state : IlMachineState)
|
||||
: ConcreteTypeHandle * IlMachineState
|
||||
=
|
||||
// Create a concretization context from the current state
|
||||
let ctx : TypeConcretization.ConcretizationContext =
|
||||
let ctx : TypeConcretization.ConcretizationContext<'corelib> =
|
||||
{
|
||||
InProgress = ImmutableDictionary.Empty
|
||||
ConcreteTypes = state.ConcreteTypes
|
||||
LoadedAssemblies = state._LoadedAssemblies
|
||||
BaseTypes = corelib
|
||||
BaseTypes = baseClassTypes
|
||||
}
|
||||
|
||||
// Helper function to get assembly from reference
|
||||
let loadAssembly
|
||||
(currentAssembly : AssemblyName)
|
||||
(assyRef : AssemblyReferenceHandle)
|
||||
: (ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly)
|
||||
: ImmutableDictionary<string, DumpedAssembly> * DumpedAssembly
|
||||
=
|
||||
let assyToLoad =
|
||||
match state.LoadedAssembly currentAssembly with
|
||||
@@ -537,7 +595,7 @@ module IlMachineState =
|
||||
/// Get zero value for a TypeDefn, concretizing it first
|
||||
let cliTypeZeroOf
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(assy : DumpedAssembly)
|
||||
(ty : TypeDefn)
|
||||
(typeGenerics : ConcreteTypeHandle ImmutableArray)
|
||||
@@ -554,39 +612,11 @@ module IlMachineState =
|
||||
else
|
||||
state.WithLoadedAssembly assy.Name assy
|
||||
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = corelib
|
||||
}
|
||||
|
||||
let handle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun assyName ref ->
|
||||
// Helper to get assembly from reference
|
||||
let currentAssy = state.LoadedAssembly (assyName) |> Option.get
|
||||
|
||||
let targetAssy =
|
||||
currentAssy.AssemblyReferences.[ref].Name |> state.LoadedAssembly |> Option.get
|
||||
|
||||
state._LoadedAssemblies, targetAssy
|
||||
)
|
||||
assy.Name
|
||||
typeGenerics
|
||||
methodGenerics
|
||||
ty
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
ConcreteTypes = newCtx.ConcreteTypes
|
||||
_LoadedAssemblies = newCtx.LoadedAssemblies
|
||||
}
|
||||
let state, handle =
|
||||
concretizeType baseClassTypes state assy.Name typeGenerics methodGenerics ty
|
||||
|
||||
// Now get the zero value
|
||||
let zero, state = cliTypeZeroOfHandle state corelib handle
|
||||
let zero, state = cliTypeZeroOfHandle state baseClassTypes handle
|
||||
state, zero
|
||||
|
||||
let pushToEvalStack' (o : EvalStackValue) (thread : ThreadId) (state : IlMachineState) =
|
||||
@@ -656,7 +686,7 @@ module IlMachineState =
|
||||
/// There might be no stack frame to return to, so you might get None.
|
||||
let returnStackFrame
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(currentThread : ThreadId)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState option
|
||||
@@ -696,7 +726,7 @@ module IlMachineState =
|
||||
|
||||
let resolvedBaseType =
|
||||
DumpedAssembly.resolveBaseType
|
||||
corelib
|
||||
baseClassTypes
|
||||
state._LoadedAssemblies
|
||||
constructed.Type.Assembly
|
||||
constructed.Type.BaseType
|
||||
@@ -728,7 +758,7 @@ module IlMachineState =
|
||||
// | TypeDefn.Void -> state
|
||||
| retType ->
|
||||
// TODO: generics
|
||||
let zero, state = cliTypeZeroOfHandle state corelib retType
|
||||
let zero, state = cliTypeZeroOfHandle state baseClassTypes retType
|
||||
|
||||
let toPush = EvalStackValue.toCliTypeCoerced zero retVal
|
||||
|
||||
@@ -741,7 +771,7 @@ module IlMachineState =
|
||||
|
||||
let concretizeMethodWithTypeGenerics
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(typeGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter, TypeDefn>)
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
@@ -762,45 +792,17 @@ module IlMachineState =
|
||||
let mutable state = state
|
||||
|
||||
for i = 0 to generics.Length - 1 do
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = corelib
|
||||
}
|
||||
|
||||
// When concretizing method generic arguments, we need to handle the case where
|
||||
// the generic argument itself doesn't reference method parameters
|
||||
try
|
||||
let handle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun assyName ref ->
|
||||
let currentAssy = state.LoadedAssembly assyName |> Option.get
|
||||
|
||||
let targetAssy =
|
||||
currentAssy.AssemblyReferences.[ref].Name |> state.LoadedAssembly |> Option.get
|
||||
|
||||
state._LoadedAssemblies, targetAssy
|
||||
)
|
||||
callingAssembly
|
||||
typeGenerics
|
||||
currentExecutingMethodGenerics
|
||||
generics.[i]
|
||||
|
||||
state <-
|
||||
{ state with
|
||||
ConcreteTypes = newCtx.ConcreteTypes
|
||||
}
|
||||
|
||||
handles.Add handle
|
||||
with ex ->
|
||||
failwithf
|
||||
"Failed to concretize method generic argument %d: %A. Exception: %s"
|
||||
i
|
||||
let state2, handle =
|
||||
concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
callingAssembly
|
||||
typeGenerics
|
||||
currentExecutingMethodGenerics
|
||||
generics.[i]
|
||||
ex.Message
|
||||
|
||||
state <- state2
|
||||
handles.Add handle
|
||||
|
||||
state, handles.ToImmutable ()
|
||||
|
||||
@@ -825,7 +827,7 @@ module IlMachineState =
|
||||
failwithf "Current assembly %s not loaded when trying to resolve reference" assyName.FullName
|
||||
)
|
||||
state._LoadedAssemblies
|
||||
corelib
|
||||
baseClassTypes
|
||||
methodToCall
|
||||
typeGenerics
|
||||
concretizedMethodGenerics
|
||||
@@ -846,7 +848,7 @@ module IlMachineState =
|
||||
|
||||
let concretizeMethodForExecution
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(thread : ThreadId)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter, TypeDefn>)
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
@@ -871,7 +873,7 @@ module IlMachineState =
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = corelib
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = baseClassTypes
|
||||
}
|
||||
|
||||
let handle, newCtx =
|
||||
@@ -910,7 +912,7 @@ module IlMachineState =
|
||||
|
||||
concretizeMethodWithTypeGenerics
|
||||
loggerFactory
|
||||
corelib
|
||||
baseClassTypes
|
||||
typeGenerics
|
||||
methodToCall
|
||||
methodGenerics
|
||||
@@ -921,7 +923,7 @@ module IlMachineState =
|
||||
// Add to IlMachineState module
|
||||
let concretizeFieldForExecution
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(thread : ThreadId)
|
||||
(field : WoofWare.PawPrint.FieldInfo<TypeDefn, TypeDefn>)
|
||||
(state : IlMachineState)
|
||||
@@ -940,7 +942,7 @@ module IlMachineState =
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = corelib
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = baseClassTypes
|
||||
}
|
||||
|
||||
// Create a TypeDefn for the field's declaring type
|
||||
@@ -952,7 +954,7 @@ module IlMachineState =
|
||||
|
||||
let baseType =
|
||||
typeDef.BaseType
|
||||
|> DumpedAssembly.resolveBaseType corelib state._LoadedAssemblies assy.Name
|
||||
|> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies assy.Name
|
||||
|
||||
let signatureTypeKind =
|
||||
match baseType with
|
||||
@@ -973,7 +975,7 @@ module IlMachineState =
|
||||
|
||||
let baseTypeResolved =
|
||||
typeDef.BaseType
|
||||
|> DumpedAssembly.resolveBaseType corelib state._LoadedAssemblies assy.Name
|
||||
|> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies assy.Name
|
||||
|
||||
let signatureTypeKind =
|
||||
match baseTypeResolved with
|
||||
@@ -1049,6 +1051,7 @@ module IlMachineState =
|
||||
TypeInitTable = ImmutableDictionary.Empty
|
||||
DotnetRuntimeDirs = dotnetRuntimeDirs
|
||||
TypeHandles = TypeHandleRegistry.empty ()
|
||||
FieldHandles = FieldHandleRegistry.empty ()
|
||||
}
|
||||
|
||||
state.WithLoadedAssembly assyName entryAssembly
|
||||
@@ -1188,7 +1191,7 @@ module IlMachineState =
|
||||
|
||||
let resolveMember
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(currentThread : ThreadId)
|
||||
(assy : DumpedAssembly)
|
||||
(m : MemberReferenceHandle)
|
||||
@@ -1211,7 +1214,11 @@ module IlMachineState =
|
||||
let typeGenerics =
|
||||
executing.DeclaringType.Generics
|
||||
|> Seq.map (fun handle ->
|
||||
Concretization.concreteHandleToTypeDefn corelib handle state.ConcreteTypes state._LoadedAssemblies
|
||||
Concretization.concreteHandleToTypeDefn
|
||||
baseClassTypes
|
||||
handle
|
||||
state.ConcreteTypes
|
||||
state._LoadedAssemblies
|
||||
)
|
||||
|> ImmutableArray.CreateRange
|
||||
|
||||
@@ -1222,13 +1229,13 @@ module IlMachineState =
|
||||
let state, assy, targetType =
|
||||
resolveType loggerFactory parent ImmutableArray.Empty assy state
|
||||
|
||||
state, assy, targetType, ImmutableArray<TypeDefn>.Empty // No type args from TypeReference
|
||||
state, assy, targetType, ImmutableArray.Empty // No type args from TypeReference
|
||||
| MetadataToken.TypeSpecification parent ->
|
||||
let methodGenerics =
|
||||
executing.Generics
|
||||
|> Seq.map (fun handle ->
|
||||
Concretization.concreteHandleToTypeDefn
|
||||
corelib
|
||||
baseClassTypes
|
||||
handle
|
||||
state.ConcreteTypes
|
||||
state._LoadedAssemblies
|
||||
@@ -1236,7 +1243,7 @@ module IlMachineState =
|
||||
|> ImmutableArray.CreateRange
|
||||
|
||||
let state, assy, targetType =
|
||||
resolveTypeFromSpec loggerFactory corelib parent assy typeGenerics methodGenerics state
|
||||
resolveTypeFromSpec loggerFactory baseClassTypes parent assy typeGenerics methodGenerics state
|
||||
|
||||
// Extract type arguments from the resolved type
|
||||
let extractedTypeArgs = targetType.Generics
|
||||
@@ -1244,12 +1251,58 @@ module IlMachineState =
|
||||
state, assy, targetType, extractedTypeArgs
|
||||
| parent -> failwith $"Unexpected: {parent}"
|
||||
|
||||
let state, concreteExtractedTypeArgs =
|
||||
((state, ImmutableArray.CreateBuilder ()), extractedTypeArgs)
|
||||
||> Seq.fold (fun (state, acc) ty ->
|
||||
// TODO: generics?
|
||||
let state, t =
|
||||
concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
targetType.Assembly
|
||||
ImmutableArray.Empty
|
||||
ImmutableArray.Empty
|
||||
ty
|
||||
|
||||
acc.Add t
|
||||
state, acc
|
||||
)
|
||||
|> Tuple.rmap (fun x -> x.ToImmutable ())
|
||||
|
||||
match mem.Signature with
|
||||
| MemberSignature.Field fieldSig ->
|
||||
let availableFields =
|
||||
targetType.Fields
|
||||
|> List.filter (fun fi -> fi.Name = memberName)
|
||||
|> List.filter (fun fi -> fi.Signature = fieldSig)
|
||||
// Concretize the field signature from the member reference
|
||||
let state, concreteFieldSig =
|
||||
concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
(state.ActiveAssembly(currentThread).Name)
|
||||
concreteExtractedTypeArgs
|
||||
ImmutableArray.Empty
|
||||
fieldSig
|
||||
|
||||
// Find matching fields by comparing concretized signatures
|
||||
let state, availableFields =
|
||||
((state, []), targetType.Fields)
|
||||
||> List.fold (fun (state, acc) fi ->
|
||||
if fi.Name <> memberName then
|
||||
state, acc
|
||||
else
|
||||
// Concretize the field's signature for comparison
|
||||
let state, fieldSigConcrete =
|
||||
concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
assy.Name
|
||||
concreteExtractedTypeArgs
|
||||
ImmutableArray.Empty
|
||||
fi.Signature
|
||||
|
||||
if fieldSigConcrete = concreteFieldSig then
|
||||
state, fi :: acc
|
||||
else
|
||||
state, acc
|
||||
)
|
||||
|
||||
let field =
|
||||
match availableFields with
|
||||
@@ -1265,16 +1318,50 @@ module IlMachineState =
|
||||
|
||||
| MemberSignature.Method memberSig ->
|
||||
let availableMethods =
|
||||
targetType.Methods
|
||||
|> List.filter (fun mi -> mi.Name = memberName)
|
||||
// TODO: this needs to resolve the TypeMethodSignature to e.g. remove references to generic parameters
|
||||
|> List.filter (fun mi -> mi.Signature = memberSig)
|
||||
targetType.Methods |> List.filter (fun mi -> mi.Name = memberName)
|
||||
|
||||
let state, memberSig =
|
||||
memberSig
|
||||
|> TypeMethodSignature.map
|
||||
state
|
||||
(fun state ty ->
|
||||
concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
(state.ActiveAssembly(currentThread).Name)
|
||||
concreteExtractedTypeArgs
|
||||
ImmutableArray.Empty
|
||||
ty
|
||||
)
|
||||
|
||||
let state, availableMethods =
|
||||
((state, []), availableMethods)
|
||||
||> List.fold (fun (state, acc) meth ->
|
||||
let state, methSig =
|
||||
meth.Signature
|
||||
|> TypeMethodSignature.map
|
||||
state
|
||||
(fun state ty ->
|
||||
concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
assy.Name
|
||||
concreteExtractedTypeArgs
|
||||
ImmutableArray.Empty
|
||||
ty
|
||||
)
|
||||
|
||||
if methSig = memberSig then
|
||||
state, meth :: acc
|
||||
else
|
||||
state, acc
|
||||
)
|
||||
|
||||
let method =
|
||||
match availableMethods with
|
||||
| [] ->
|
||||
failwith
|
||||
$"Could not find member {memberName} with the right signature on {targetType.Namespace}.{targetType.Name}"
|
||||
$"Could not find member {memberName} with the right signature {memberSig} on {targetType.Namespace}.{targetType.Name}"
|
||||
| [ x ] -> x |> MethodInfo.mapTypeGenerics (fun i _ -> targetType.Generics.[i])
|
||||
| _ ->
|
||||
failwith
|
||||
@@ -1379,6 +1466,47 @@ module IlMachineState =
|
||||
|
||||
result, state
|
||||
|
||||
/// Returns a System.RuntimeFieldHandle.
|
||||
let getOrAllocateField<'corelib>
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(baseClassTypes : BaseClassTypes<'corelib>)
|
||||
(declaringAssy : AssemblyName)
|
||||
(fieldHandle : FieldDefinitionHandle)
|
||||
(state : IlMachineState)
|
||||
: CliType * 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<TypeDefn> =
|
||||
ConcreteType.make
|
||||
field.DeclaringType.Assembly
|
||||
field.DeclaringType.Namespace
|
||||
field.DeclaringType.Name
|
||||
field.DeclaringType.Definition.Get
|
||||
ImmutableArray.Empty // No generic arguments in this context
|
||||
|
||||
let declaringType, state =
|
||||
concretizeFieldDeclaringType loggerFactory baseClassTypes declaringTypeWithGenerics state
|
||||
|
||||
let result, reg, state =
|
||||
FieldHandleRegistry.getOrAllocate
|
||||
baseClassTypes
|
||||
state
|
||||
(fun fields state -> allocateManagedObject baseClassTypes.RuntimeType fields state)
|
||||
declaringAssy
|
||||
declaringType
|
||||
fieldHandle
|
||||
state.FieldHandles
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
FieldHandles = reg
|
||||
}
|
||||
|
||||
result, state
|
||||
|
||||
let setStatic
|
||||
(ty : ConcreteTypeHandle)
|
||||
(field : string)
|
||||
|
@@ -7,7 +7,7 @@ open Microsoft.Extensions.Logging
|
||||
module IlMachineStateExecution =
|
||||
let callMethod
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(wasInitialising : ConcreteTypeHandle option)
|
||||
(wasConstructing : ManagedHeapAddress option)
|
||||
(wasClassConstructor : bool)
|
||||
@@ -34,7 +34,7 @@ module IlMachineStateExecution =
|
||||
|
||||
match
|
||||
if isIntrinsic then
|
||||
Intrinsics.call corelib methodToCall thread state
|
||||
Intrinsics.call baseClassTypes methodToCall thread state
|
||||
else
|
||||
None
|
||||
with
|
||||
@@ -45,7 +45,7 @@ module IlMachineStateExecution =
|
||||
let state, argZeroObjects =
|
||||
((state, []), methodToCall.Signature.ParameterTypes)
|
||||
||> List.fold (fun (state, zeros) tyHandle ->
|
||||
let zero, state = IlMachineState.cliTypeZeroOfHandle state corelib tyHandle
|
||||
let zero, state = IlMachineState.cliTypeZeroOfHandle state baseClassTypes tyHandle
|
||||
state, zero :: zeros
|
||||
)
|
||||
|
||||
@@ -129,7 +129,7 @@ module IlMachineStateExecution =
|
||||
match
|
||||
MethodState.Empty
|
||||
state.ConcreteTypes
|
||||
corelib
|
||||
baseClassTypes
|
||||
state._LoadedAssemblies
|
||||
(state.ActiveAssembly thread)
|
||||
methodToCall
|
||||
@@ -174,7 +174,7 @@ module IlMachineStateExecution =
|
||||
|
||||
let rec loadClass
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : ConcreteTypeHandle)
|
||||
(currentThread : ThreadId)
|
||||
(state : IlMachineState)
|
||||
@@ -251,7 +251,10 @@ module IlMachineStateExecution =
|
||||
|
||||
let baseType =
|
||||
baseTypeDef.BaseType
|
||||
|> DumpedAssembly.resolveBaseType corelib state._LoadedAssemblies sourceAssembly.Name
|
||||
|> DumpedAssembly.resolveBaseType
|
||||
baseClassTypes
|
||||
state._LoadedAssemblies
|
||||
sourceAssembly.Name
|
||||
|
||||
let signatureTypeKind =
|
||||
match baseType with
|
||||
@@ -267,30 +270,18 @@ module IlMachineStateExecution =
|
||||
)
|
||||
|
||||
// Concretize the base type
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = corelib
|
||||
}
|
||||
|
||||
let baseTypeHandle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun _ _ -> failwith "getAssembly not needed for base type concretization")
|
||||
let state, baseTypeHandle =
|
||||
IlMachineState.concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
sourceAssembly.Name
|
||||
concreteType.Generics // Use the current type's generics
|
||||
ImmutableArray.Empty // No method generics
|
||||
concreteType.Generics
|
||||
// TODO: surely we have generics in scope here?
|
||||
ImmutableArray.Empty
|
||||
baseTypeDefn
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
ConcreteTypes = newCtx.ConcreteTypes
|
||||
}
|
||||
|
||||
// Recursively load the base class
|
||||
match loadClass loggerFactory corelib baseTypeHandle currentThread state with
|
||||
match loadClass loggerFactory baseClassTypes baseTypeHandle currentThread state with
|
||||
| FirstLoadThis state -> Error state
|
||||
| NothingToDo state -> Ok state
|
||||
| BaseTypeInfo.TypeRef typeReferenceHandle ->
|
||||
@@ -316,7 +307,7 @@ module IlMachineStateExecution =
|
||||
let baseTypeDefn =
|
||||
let baseType =
|
||||
targetType.BaseType
|
||||
|> DumpedAssembly.resolveBaseType corelib state._LoadedAssemblies assy.Name
|
||||
|> DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies assy.Name
|
||||
|
||||
let signatureTypeKind =
|
||||
match baseType with
|
||||
@@ -332,30 +323,18 @@ module IlMachineStateExecution =
|
||||
)
|
||||
|
||||
// Concretize the base type
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = corelib
|
||||
}
|
||||
|
||||
let baseTypeHandle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun _ _ -> failwith "getAssembly not needed for base type concretization")
|
||||
assy.Name
|
||||
concreteType.Generics // Use the current type's generics
|
||||
ImmutableArray.Empty // No method generics
|
||||
let state, baseTypeHandle =
|
||||
IlMachineState.concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
sourceAssembly.Name
|
||||
concreteType.Generics
|
||||
// TODO: surely we have generics in scope here?
|
||||
ImmutableArray.Empty
|
||||
baseTypeDefn
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
ConcreteTypes = newCtx.ConcreteTypes
|
||||
}
|
||||
|
||||
// Recursively load the base class
|
||||
match loadClass loggerFactory corelib baseTypeHandle currentThread state with
|
||||
match loadClass loggerFactory baseClassTypes baseTypeHandle currentThread state with
|
||||
| FirstLoadThis state -> Error state
|
||||
| NothingToDo state -> Ok state
|
||||
| BaseTypeInfo.TypeSpec typeSpecificationHandle ->
|
||||
@@ -395,40 +374,14 @@ module IlMachineStateExecution =
|
||||
|> TypeMethodSignature.map
|
||||
state
|
||||
(fun state typeDefn ->
|
||||
// Concretize each TypeDefn in the signature
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = corelib
|
||||
}
|
||||
|
||||
let handle, ctx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun assyName ref ->
|
||||
let currentAssy = state.LoadedAssembly assyName |> Option.get
|
||||
|
||||
let targetAssy =
|
||||
currentAssy.AssemblyReferences.[ref].Name
|
||||
|> state.LoadedAssembly
|
||||
|> Option.get
|
||||
|
||||
state._LoadedAssemblies, targetAssy
|
||||
)
|
||||
concreteType.Assembly
|
||||
concreteType.Generics
|
||||
ImmutableArray.Empty // no method generics for cctor
|
||||
typeDefn
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
_LoadedAssemblies = ctx.LoadedAssemblies
|
||||
ConcreteTypes = ctx.ConcreteTypes
|
||||
}
|
||||
|
||||
state, handle
|
||||
IlMachineState.concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
concreteType.Assembly
|
||||
concreteType.Generics
|
||||
// no method generics for cctor
|
||||
ImmutableArray.Empty
|
||||
typeDefn
|
||||
)
|
||||
|
||||
// Convert method instructions (local variables)
|
||||
@@ -444,41 +397,15 @@ module IlMachineStateExecution =
|
||||
let state, convertedVars =
|
||||
((state, []), localVars)
|
||||
||> Seq.fold (fun (state, acc) typeDefn ->
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress =
|
||||
ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes =
|
||||
state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies =
|
||||
state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = corelib
|
||||
}
|
||||
|
||||
let handle, ctx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun assyName ref ->
|
||||
let currentAssy = state.LoadedAssembly assyName |> Option.get
|
||||
|
||||
let targetAssy =
|
||||
currentAssy.AssemblyReferences.[ref].Name
|
||||
|> state.LoadedAssembly
|
||||
|> Option.get
|
||||
|
||||
state._LoadedAssemblies, targetAssy
|
||||
)
|
||||
let state, handle =
|
||||
IlMachineState.concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
concreteType.Assembly
|
||||
concreteType.Generics
|
||||
ImmutableArray.Empty // no method generics for cctor
|
||||
typeDefn
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
_LoadedAssemblies = ctx.LoadedAssemblies
|
||||
ConcreteTypes = ctx.ConcreteTypes
|
||||
}
|
||||
|
||||
state, handle :: acc
|
||||
)
|
||||
|> Tuple.rmap ImmutableArray.CreateRange
|
||||
@@ -492,7 +419,7 @@ module IlMachineStateExecution =
|
||||
|
||||
callMethod
|
||||
loggerFactory
|
||||
corelib
|
||||
baseClassTypes
|
||||
(Some ty)
|
||||
None
|
||||
true
|
||||
@@ -516,7 +443,7 @@ module IlMachineStateExecution =
|
||||
|
||||
let ensureTypeInitialised
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(thread : ThreadId)
|
||||
(ty : ConcreteTypeHandle)
|
||||
(state : IlMachineState)
|
||||
@@ -524,7 +451,7 @@ module IlMachineStateExecution =
|
||||
=
|
||||
match TypeInitTable.tryGet ty state.TypeInitTable with
|
||||
| None ->
|
||||
match loadClass loggerFactory corelib ty thread state with
|
||||
match loadClass loggerFactory baseClassTypes ty thread state with
|
||||
| NothingToDo state -> state, WhatWeDid.Executed
|
||||
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
||||
| Some TypeInitState.Initialized -> state, WhatWeDid.Executed
|
||||
@@ -541,7 +468,7 @@ module IlMachineStateExecution =
|
||||
/// another call to its function pointer.)
|
||||
let callMethodInActiveAssembly
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(thread : ThreadId)
|
||||
(advanceProgramCounterOfCaller : bool)
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
@@ -556,7 +483,7 @@ module IlMachineStateExecution =
|
||||
let state, concretizedMethod, declaringTypeHandle =
|
||||
IlMachineState.concretizeMethodForExecution
|
||||
loggerFactory
|
||||
corelib
|
||||
baseClassTypes
|
||||
thread
|
||||
methodToCall
|
||||
methodGenerics
|
||||
@@ -564,13 +491,13 @@ module IlMachineStateExecution =
|
||||
state
|
||||
|
||||
let state, typeInit =
|
||||
ensureTypeInitialised loggerFactory corelib thread declaringTypeHandle state
|
||||
ensureTypeInitialised loggerFactory baseClassTypes thread declaringTypeHandle state
|
||||
|
||||
match typeInit with
|
||||
| WhatWeDid.Executed ->
|
||||
callMethod
|
||||
loggerFactory
|
||||
corelib
|
||||
baseClassTypes
|
||||
None
|
||||
weAreConstructingObj
|
||||
false
|
||||
|
@@ -234,5 +234,8 @@ module Intrinsics =
|
||||
else
|
||||
failwith "TODO: unexpected params to String.op_Implicit"
|
||||
| _ -> failwith "TODO: unexpected params to String.op_Implicit"
|
||||
| "System.Private.CoreLib", "RuntimeHelpers", "InitializeArray" ->
|
||||
// https://github.com/dotnet/runtime/blob/9e5e6aa7bc36aeb2a154709a9d1192030c30a2ef/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs#L18
|
||||
failwith "TODO: array initialization"
|
||||
| a, b, c -> failwith $"TODO: implement JIT intrinsic {a}.{b}.{c}"
|
||||
|> Option.map (fun s -> s.WithThreadSwitchedToAssembly callerAssy currentThread |> fst)
|
||||
|
@@ -137,7 +137,7 @@ and MethodState =
|
||||
/// If `method` is static, `args` must be of length numParams.
|
||||
static member Empty
|
||||
(concreteTypes : AllConcreteTypes)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(baseClassTypes : BaseClassTypes<DumpedAssembly>)
|
||||
(loadedAssemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(containingAssembly : DumpedAssembly)
|
||||
(method : WoofWare.PawPrint.MethodInfo<ConcreteTypeHandle, ConcreteTypeHandle, ConcreteTypeHandle>)
|
||||
@@ -172,7 +172,7 @@ and MethodState =
|
||||
// Note: This assumes all types have already been concretized
|
||||
// If this fails with "ConcreteTypeHandle not found", it means
|
||||
// we need to ensure types are concretized before creating the MethodState
|
||||
let zero, _ = CliType.zeroOf concreteTypes loadedAssemblies corelib var
|
||||
let zero, _ = CliType.zeroOf concreteTypes loadedAssemblies baseClassTypes var
|
||||
result.Add zero
|
||||
|
||||
result.ToImmutable ()
|
||||
|
@@ -46,7 +46,9 @@ module NullaryIlOp =
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
state.ThreadState.[sourceThread].MethodStates.[methodFrame].LocalVariables.[int<uint16> whichVar]
|
||||
| ManagedPointerSource.Heap managedHeapAddress -> failwith "TODO: Heap pointer dereferencing not implemented"
|
||||
| ManagedPointerSource.ArrayIndex _ -> failwith "TODO: array index pointer dereferencing not implemented"
|
||||
| ManagedPointerSource.ArrayIndex (arr, index) ->
|
||||
let arr = state.ManagedHeap.Arrays.[arr]
|
||||
arr.Elements.[index]
|
||||
|
||||
// Unified Ldind implementation
|
||||
let private executeLdind
|
||||
|
@@ -337,7 +337,12 @@ module internal UnaryMetadataIlOp =
|
||||
let typeGenerics = concretizedCtor.DeclaringType.Generics
|
||||
|
||||
let state, fieldZeros =
|
||||
((state, []), ctorType.Fields)
|
||||
// Only include instance fields when constructing objects
|
||||
let instanceFields =
|
||||
ctorType.Fields
|
||||
|> List.filter (fun field -> not (field.Attributes.HasFlag FieldAttributes.Static))
|
||||
|
||||
((state, []), instanceFields)
|
||||
||> List.fold (fun (state, zeros) field ->
|
||||
// TODO: generics
|
||||
let state, zero =
|
||||
@@ -1071,15 +1076,11 @@ module internal UnaryMetadataIlOp =
|
||||
let state =
|
||||
match metadataToken with
|
||||
| MetadataToken.FieldDefinition h ->
|
||||
let ty = baseClassTypes.RuntimeFieldHandle
|
||||
// this is a struct; it contains one field, an IRuntimeFieldInfo
|
||||
// https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs#L1097
|
||||
let field = ty.Fields |> List.exactlyOne
|
||||
// TODO: how do we know what concrete type this is a field on?
|
||||
let runtimeFieldHandle, state =
|
||||
IlMachineState.getOrAllocateField loggerFactory baseClassTypes activeAssy.Name h state
|
||||
|
||||
if field.Name <> "m_ptr" then
|
||||
failwith $"unexpected field name ${field.Name} for BCL type RuntimeFieldHandle"
|
||||
|
||||
failwith ""
|
||||
IlMachineState.pushToEvalStack runtimeFieldHandle thread state
|
||||
| MetadataToken.MethodDef h ->
|
||||
let ty = baseClassTypes.RuntimeMethodHandle
|
||||
let field = ty.Fields |> List.exactlyOne
|
||||
@@ -1095,34 +1096,17 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
let typeGenerics = currentMethod.DeclaringType.Generics
|
||||
|
||||
if not (methodGenerics.IsEmpty && typeGenerics.IsEmpty) then
|
||||
failwith "TODO: generics"
|
||||
|
||||
let state, typeDefn = lookupTypeDefn baseClassTypes state activeAssy h
|
||||
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = baseClassTypes
|
||||
}
|
||||
|
||||
let handle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun _ _ -> failwith "getAssembly not needed for type def concretization")
|
||||
let state, handle =
|
||||
IlMachineState.concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
activeAssy.Name
|
||||
typeGenerics
|
||||
methodGenerics
|
||||
typeDefn
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
_LoadedAssemblies = newCtx.LoadedAssemblies
|
||||
ConcreteTypes = newCtx.ConcreteTypes
|
||||
}
|
||||
|
||||
let alloc, state = IlMachineState.getOrAllocateType baseClassTypes handle state
|
||||
|
||||
let vt =
|
||||
@@ -1148,29 +1132,15 @@ module internal UnaryMetadataIlOp =
|
||||
lookupTypeRef loggerFactory baseClassTypes state activeAssy currentMethod.DeclaringType.Generics ref
|
||||
| _ -> failwith $"unexpected token {metadataToken} in Sizeof"
|
||||
|
||||
let ctx =
|
||||
{
|
||||
TypeConcretization.ConcretizationContext.InProgress = ImmutableDictionary.Empty
|
||||
TypeConcretization.ConcretizationContext.ConcreteTypes = state.ConcreteTypes
|
||||
TypeConcretization.ConcretizationContext.LoadedAssemblies = state._LoadedAssemblies
|
||||
TypeConcretization.ConcretizationContext.BaseTypes = baseClassTypes
|
||||
}
|
||||
|
||||
let typeHandle, newCtx =
|
||||
TypeConcretization.concretizeType
|
||||
ctx
|
||||
(fun _ _ -> failwith "getAssembly not needed for base type concretization")
|
||||
let state, typeHandle =
|
||||
IlMachineState.concretizeType
|
||||
baseClassTypes
|
||||
state
|
||||
assy.Name
|
||||
currentMethod.DeclaringType.Generics
|
||||
currentMethod.Generics
|
||||
ty
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
_LoadedAssemblies = newCtx.LoadedAssemblies
|
||||
ConcreteTypes = newCtx.ConcreteTypes
|
||||
}
|
||||
|
||||
let zero, state = IlMachineState.cliTypeZeroOfHandle state baseClassTypes typeHandle
|
||||
|
||||
let size = CliType.sizeOf zero
|
||||
|
@@ -12,6 +12,7 @@
|
||||
<Compile Include="AbstractMachineDomain.fs" />
|
||||
<Compile Include="BasicCliType.fs" />
|
||||
<Compile Include="TypeHandleRegistry.fs" />
|
||||
<Compile Include="FieldHandleRegistry.fs" />
|
||||
<Compile Include="ManagedHeap.fs" />
|
||||
<Compile Include="TypeInitialisation.fs" />
|
||||
<Compile Include="Exceptions.fs" />
|
||||
|
Reference in New Issue
Block a user