mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-06 06:28:39 +00:00
Compare commits
4 Commits
55677a507b
...
runtime-ty
Author | SHA1 | Date | |
---|---|---|---|
|
a7150e3294 | ||
|
ab4c251c97 | ||
|
cbbde0c4ba | ||
|
8aa33b5606 |
@@ -45,7 +45,10 @@ type DumpedAssembly =
|
||||
/// Dictionary of all type definitions in this assembly, keyed by their handle.
|
||||
/// </summary>
|
||||
TypeDefs :
|
||||
IReadOnlyDictionary<TypeDefinitionHandle, WoofWare.PawPrint.TypeInfo<WoofWare.PawPrint.GenericParameter>>
|
||||
IReadOnlyDictionary<
|
||||
TypeDefinitionHandle,
|
||||
WoofWare.PawPrint.TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
>
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary of all type references in this assembly, keyed by their handle.
|
||||
@@ -64,7 +67,7 @@ type DumpedAssembly =
|
||||
Methods :
|
||||
IReadOnlyDictionary<
|
||||
MethodDefinitionHandle,
|
||||
WoofWare.PawPrint.MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter>
|
||||
WoofWare.PawPrint.MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
>
|
||||
|
||||
/// <summary>
|
||||
@@ -75,7 +78,8 @@ type DumpedAssembly =
|
||||
/// <summary>
|
||||
/// Dictionary of all field definitions in this assembly, keyed by their handle.
|
||||
/// </summary>
|
||||
Fields : IReadOnlyDictionary<FieldDefinitionHandle, WoofWare.PawPrint.FieldInfo<FakeUnit>>
|
||||
Fields :
|
||||
IReadOnlyDictionary<FieldDefinitionHandle, WoofWare.PawPrint.FieldInfo<FakeUnit, WoofWare.PawPrint.TypeDefn>>
|
||||
|
||||
/// <summary>
|
||||
/// The entry point method of the assembly, if one exists.
|
||||
@@ -143,7 +147,10 @@ type DumpedAssembly =
|
||||
/// Internal lookup for type definitions by namespace and name.
|
||||
/// </summary>
|
||||
_TypeDefsLookup :
|
||||
ImmutableDictionary<string * string, WoofWare.PawPrint.TypeInfo<WoofWare.PawPrint.GenericParameter>>
|
||||
ImmutableDictionary<
|
||||
string * string,
|
||||
WoofWare.PawPrint.TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
>
|
||||
}
|
||||
|
||||
static member internal BuildExportedTypesLookup
|
||||
@@ -199,7 +206,7 @@ type DumpedAssembly =
|
||||
static member internal BuildTypeDefsLookup
|
||||
(logger : ILogger)
|
||||
(name : AssemblyName)
|
||||
(typeDefs : WoofWare.PawPrint.TypeInfo<WoofWare.PawPrint.GenericParameter> seq)
|
||||
(typeDefs : WoofWare.PawPrint.TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn> seq)
|
||||
=
|
||||
let result = ImmutableDictionary.CreateBuilder ()
|
||||
let keys = HashSet ()
|
||||
@@ -230,7 +237,7 @@ type DumpedAssembly =
|
||||
member this.TypeDef
|
||||
(``namespace`` : string)
|
||||
(name : string)
|
||||
: WoofWare.PawPrint.TypeInfo<WoofWare.PawPrint.GenericParameter> option
|
||||
: WoofWare.PawPrint.TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn> option
|
||||
=
|
||||
match this._TypeDefsLookup.TryGetValue ((``namespace``, name)) with
|
||||
| false, _ -> None
|
||||
@@ -245,15 +252,14 @@ type DumpedAssembly =
|
||||
member this.Dispose () = this.PeReader.Dispose ()
|
||||
|
||||
|
||||
type TypeResolutionResult =
|
||||
type TypeResolutionResult<'generic> =
|
||||
| FirstLoadAssy of WoofWare.PawPrint.AssemblyReference
|
||||
| Resolved of DumpedAssembly * TypeInfo<TypeDefn>
|
||||
| Resolved of DumpedAssembly * TypeInfo<'generic, WoofWare.PawPrint.TypeDefn>
|
||||
|
||||
override this.ToString () : string =
|
||||
match this with
|
||||
| TypeResolutionResult.FirstLoadAssy a -> $"FirstLoadAssy(%s{a.Name.FullName})"
|
||||
| TypeResolutionResult.Resolved (assy, ty) ->
|
||||
$"Resolved(%s{assy.Name.FullName}: {string<TypeInfo<TypeDefn>> ty})"
|
||||
| TypeResolutionResult.Resolved (assy, ty) -> $"Resolved(%s{assy.Name.FullName}: {ty})"
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Assembly =
|
||||
@@ -423,8 +429,8 @@ module Assembly =
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(referencedInAssembly : DumpedAssembly)
|
||||
(target : TypeRef)
|
||||
(genericArgs : ImmutableArray<TypeDefn> option)
|
||||
: TypeResolutionResult
|
||||
(genericArgs : ImmutableArray<'generic>)
|
||||
: TypeResolutionResult<'generic>
|
||||
=
|
||||
match target.ResolutionScope with
|
||||
| TypeRefResolutionScope.Assembly r ->
|
||||
@@ -453,13 +459,7 @@ module Assembly =
|
||||
|
||||
match targetType with
|
||||
| [ t ] ->
|
||||
let t =
|
||||
t
|
||||
|> TypeInfo.mapGeneric (fun _ param ->
|
||||
match genericArgs with
|
||||
| None -> failwith "got a generic TypeRef but no generic args in context"
|
||||
| Some genericArgs -> genericArgs.[param.SequenceNumber]
|
||||
)
|
||||
let t = t |> TypeInfo.mapGeneric (fun _ param -> genericArgs.[param.SequenceNumber])
|
||||
|
||||
TypeResolutionResult.Resolved (assy, t)
|
||||
| _ :: _ :: _ -> failwith $"Multiple matching type definitions! {nsPath} {target.Name}"
|
||||
@@ -474,8 +474,8 @@ module Assembly =
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(ns : string option)
|
||||
(name : string)
|
||||
(genericArgs : ImmutableArray<TypeDefn> option)
|
||||
: TypeResolutionResult
|
||||
(genericArgs : ImmutableArray<'generic>)
|
||||
: TypeResolutionResult<'generic>
|
||||
=
|
||||
match ns with
|
||||
| None -> failwith "what are the semantics here"
|
||||
@@ -485,11 +485,7 @@ module Assembly =
|
||||
| Some typeDef ->
|
||||
let typeDef =
|
||||
typeDef
|
||||
|> TypeInfo.mapGeneric (fun _ param ->
|
||||
match genericArgs with
|
||||
| None -> failwith<TypeDefn> $"tried to resolve generic type {ns}.{name} but no generics in scope"
|
||||
| Some genericArgs -> genericArgs.[param.SequenceNumber]
|
||||
)
|
||||
|> TypeInfo.mapGeneric (fun _ param -> genericArgs.[param.SequenceNumber])
|
||||
|
||||
TypeResolutionResult.Resolved (assy, typeDef)
|
||||
| None ->
|
||||
@@ -506,8 +502,8 @@ module Assembly =
|
||||
(fromAssembly : DumpedAssembly)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(ty : WoofWare.PawPrint.ExportedType)
|
||||
(genericArgs : ImmutableArray<TypeDefn> option)
|
||||
: TypeResolutionResult
|
||||
(genericArgs : ImmutableArray<'generic>)
|
||||
: TypeResolutionResult<'generic>
|
||||
=
|
||||
match ty.Data with
|
||||
| NonForwarded _ -> failwith "Somehow didn't find type definition but it is exported"
|
||||
@@ -532,7 +528,7 @@ module DumpedAssembly =
|
||||
| Some (BaseTypeInfo.TypeRef r) ->
|
||||
let assy = loadedAssemblies.[source.FullName]
|
||||
// TODO: generics
|
||||
match Assembly.resolveTypeRef loadedAssemblies assy assy.TypeRefs.[r] None with
|
||||
match Assembly.resolveTypeRef loadedAssemblies assy assy.TypeRefs.[r] ImmutableArray<unit>.Empty with
|
||||
| TypeResolutionResult.FirstLoadAssy _ ->
|
||||
failwith
|
||||
"seems pretty unlikely that we could have constructed this object without loading its base type"
|
||||
@@ -560,3 +556,249 @@ module DumpedAssembly =
|
||||
| None -> ResolvedBaseType.Object
|
||||
|
||||
go source baseTypeInfo
|
||||
|
||||
// TODO: this is in totally the wrong place, it was just convenient to put it here
|
||||
/// Returns a mapping whose keys are assembly full name * type definition.
|
||||
let concretiseType
|
||||
(mapping : AllConcreteTypes)
|
||||
(baseTypes : BaseClassTypes<'corelib>)
|
||||
(getCorelibAssembly : 'corelib -> AssemblyName)
|
||||
(getTypeInfo :
|
||||
ComparableTypeDefinitionHandle
|
||||
-> AssemblyName
|
||||
-> TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>)
|
||||
(resolveTypeRef : TypeRef -> TypeResolutionResult<'a>)
|
||||
(typeGenerics : (AssemblyName * TypeDefn) ImmutableArray)
|
||||
(methodGenerics : (AssemblyName * TypeDefn) ImmutableArray)
|
||||
(defn : AssemblyName * TypeDefn)
|
||||
: Map<string * TypeDefn, ConcreteTypeHandle> * AllConcreteTypes
|
||||
=
|
||||
// Track types currently being processed to detect cycles
|
||||
let rec concretiseTypeRec
|
||||
(inProgress : Map<string * TypeDefn, ConcreteTypeHandle>)
|
||||
(newlyCreated : Map<string * TypeDefn, ConcreteTypeHandle>)
|
||||
(mapping : AllConcreteTypes)
|
||||
(assy : AssemblyName)
|
||||
(typeDefn : TypeDefn)
|
||||
: ConcreteTypeHandle * Map<string * TypeDefn, ConcreteTypeHandle> * AllConcreteTypes
|
||||
=
|
||||
|
||||
// First check if we're already processing this type (cycle)
|
||||
match inProgress |> Map.tryFind (assy.FullName, typeDefn) with
|
||||
| Some handle -> handle, newlyCreated, mapping
|
||||
| None ->
|
||||
|
||||
// Check if already concretised in this session
|
||||
match newlyCreated |> Map.tryFind (assy.FullName, typeDefn) with
|
||||
| Some handle -> handle, newlyCreated, mapping
|
||||
| None ->
|
||||
|
||||
match typeDefn with
|
||||
| PrimitiveType primitiveType ->
|
||||
let typeInfo =
|
||||
match primitiveType with
|
||||
| PrimitiveType.Boolean -> baseTypes.Boolean
|
||||
| PrimitiveType.Char -> baseTypes.Char
|
||||
| PrimitiveType.SByte -> baseTypes.SByte
|
||||
| PrimitiveType.Byte -> baseTypes.Byte
|
||||
| PrimitiveType.Int16 -> baseTypes.Int16
|
||||
| PrimitiveType.UInt16 -> baseTypes.UInt16
|
||||
| PrimitiveType.Int32 -> baseTypes.Int32
|
||||
| PrimitiveType.UInt32 -> baseTypes.UInt32
|
||||
| PrimitiveType.Int64 -> baseTypes.Int64
|
||||
| PrimitiveType.UInt64 -> baseTypes.UInt64
|
||||
| PrimitiveType.Single -> baseTypes.Single
|
||||
| PrimitiveType.Double -> baseTypes.Double
|
||||
| PrimitiveType.String -> baseTypes.String
|
||||
| PrimitiveType.TypedReference -> failwith "TypedReference not supported in BaseClassTypes"
|
||||
| PrimitiveType.IntPtr -> failwith "IntPtr not supported in BaseClassTypes"
|
||||
| PrimitiveType.UIntPtr -> failwith "UIntPtr not supported in BaseClassTypes"
|
||||
| PrimitiveType.Object -> baseTypes.Object
|
||||
|
||||
let cth, concreteType, mapping =
|
||||
ConcreteType.make
|
||||
mapping
|
||||
typeInfo.Assembly
|
||||
typeInfo.Namespace
|
||||
typeInfo.Name
|
||||
typeInfo.TypeDefHandle
|
||||
[]
|
||||
|
||||
let handle, mapping = mapping |> AllConcreteTypes.add concreteType
|
||||
|
||||
handle,
|
||||
newlyCreated
|
||||
|> Map.add ((getCorelibAssembly baseTypes.Corelib).FullName, typeDefn) handle,
|
||||
mapping
|
||||
|
||||
| Void -> failwith "Void is not a real type and cannot be concretised"
|
||||
|
||||
| Array (elt, shape) ->
|
||||
let eltHandle, newlyCreated, mapping =
|
||||
concretiseTypeRec inProgress newlyCreated mapping elt
|
||||
|
||||
let arrayTypeInfo = baseTypes.Array
|
||||
|
||||
let cth, concreteType, mapping =
|
||||
ConcreteType.make
|
||||
mapping
|
||||
arrayTypeInfo.Assembly
|
||||
arrayTypeInfo.Namespace
|
||||
arrayTypeInfo.Name
|
||||
arrayTypeInfo.TypeDefHandle
|
||||
[ eltHandle ]
|
||||
|
||||
let handle, mapping = mapping |> AllConcreteTypes.add concreteType
|
||||
handle, newlyCreated |> Map.add typeDefn handle, mapping
|
||||
|
||||
| OneDimensionalArrayLowerBoundZero elements ->
|
||||
let eltHandle, newlyCreated, mapping =
|
||||
concretiseTypeRec inProgress newlyCreated mapping elements
|
||||
|
||||
let arrayTypeInfo = baseTypes.Array
|
||||
|
||||
let cth, concreteType, mapping =
|
||||
ConcreteType.make
|
||||
mapping
|
||||
arrayTypeInfo.Assembly
|
||||
arrayTypeInfo.Namespace
|
||||
arrayTypeInfo.Name
|
||||
arrayTypeInfo.TypeDefHandle
|
||||
[ eltHandle ]
|
||||
|
||||
let handle, mapping = mapping |> AllConcreteTypes.add concreteType
|
||||
|
||||
handle,
|
||||
newlyCreated
|
||||
|> Map.add ((getCorelibAssembly baseTypes.Corelib).FullName, typeDefn) handle,
|
||||
mapping
|
||||
|
||||
| Pointer inner -> failwith "Pointer types require special handling - no TypeDefinition available"
|
||||
|
||||
| Byref inner -> failwith "Byref types require special handling - no TypeDefinition available"
|
||||
|
||||
| Pinned inner -> failwith "Pinned types require special handling - no TypeDefinition available"
|
||||
|
||||
| GenericTypeParameter index ->
|
||||
if index < typeGenerics.Length then
|
||||
concretiseTypeRec inProgress newlyCreated mapping typeGenerics.[index]
|
||||
else
|
||||
failwithf "Generic type parameter index %d out of range" index
|
||||
|
||||
| GenericMethodParameter index ->
|
||||
if index < methodGenerics.Length then
|
||||
concretiseTypeRec inProgress newlyCreated mapping methodGenerics.[index]
|
||||
else
|
||||
failwithf "Generic method parameter index %d out of range" index
|
||||
|
||||
| FromDefinition (typeDefHandle, assemblyFullName, _) ->
|
||||
let assemblyName = AssemblyName assemblyFullName
|
||||
let typeInfo = getTypeInfo typeDefHandle assemblyName
|
||||
|
||||
let cth, concreteType, mapping =
|
||||
ConcreteType.make mapping assemblyName typeInfo.Namespace typeInfo.Name typeDefHandle.Get []
|
||||
|
||||
let handle, mapping = mapping |> AllConcreteTypes.add concreteType
|
||||
handle, newlyCreated |> Map.add (assemblyFullName, typeDefn) handle, mapping
|
||||
|
||||
| FromReference (typeRef, sigKind) ->
|
||||
match resolveTypeRef typeRef with
|
||||
| TypeResolutionResult.FirstLoadAssy assy -> failwith "TODO"
|
||||
| TypeResolutionResult.Resolved (resolvedAssy, typeInfo) ->
|
||||
let cth, concreteType, mapping =
|
||||
ConcreteType.make
|
||||
mapping
|
||||
resolvedAssy.Name
|
||||
typeInfo.Namespace
|
||||
typeInfo.Name
|
||||
typeInfo.TypeDefHandle
|
||||
[]
|
||||
|
||||
let handle, mapping = mapping |> AllConcreteTypes.add concreteType
|
||||
handle, newlyCreated |> Map.add typeDefn handle, mapping
|
||||
|
||||
| GenericInstantiation (genericDef, args) ->
|
||||
// This is the tricky case - we might have self-reference
|
||||
// First, allocate a handle for this type
|
||||
let tempHandle = ConcreteTypeHandle mapping.NextHandle
|
||||
|
||||
let mapping =
|
||||
{ mapping with
|
||||
NextHandle = mapping.NextHandle + 1
|
||||
}
|
||||
|
||||
let inProgress = inProgress |> Map.add typeDefn tempHandle
|
||||
|
||||
// Concretise all type arguments first
|
||||
let rec concretiseArgs
|
||||
(acc : ConcreteTypeHandle list)
|
||||
(newlyCreated : Map<TypeDefn, ConcreteTypeHandle>)
|
||||
(mapping : AllConcreteTypes)
|
||||
(args : TypeDefn list)
|
||||
: ConcreteTypeHandle list * Map<TypeDefn, ConcreteTypeHandle> * AllConcreteTypes
|
||||
=
|
||||
match args with
|
||||
| [] -> List.rev acc, newlyCreated, mapping
|
||||
| arg :: rest ->
|
||||
let argHandle, newlyCreated, mapping =
|
||||
concretiseTypeRec inProgress newlyCreated mapping arg
|
||||
|
||||
concretiseArgs (argHandle :: acc) newlyCreated mapping rest
|
||||
|
||||
let argHandles, newlyCreated, mapping =
|
||||
concretiseArgs [] newlyCreated mapping (args |> Seq.toList)
|
||||
|
||||
// Now extract the definition from the generic def
|
||||
match genericDef with
|
||||
| FromDefinition (typeDefHandle, assemblyFullName, _) ->
|
||||
let assemblyName = AssemblyName (assemblyFullName)
|
||||
let typeInfo = getTypeInfo typeDefHandle assemblyName
|
||||
|
||||
let cth, concreteType, mapping =
|
||||
ConcreteType.make
|
||||
mapping
|
||||
assemblyName
|
||||
typeInfo.Namespace
|
||||
typeInfo.Name
|
||||
typeDefHandle.Get
|
||||
argHandles
|
||||
// Update the pre-allocated entry
|
||||
let mapping =
|
||||
{ mapping with
|
||||
Mapping = mapping.Mapping |> Map.add tempHandle concreteType
|
||||
}
|
||||
|
||||
tempHandle, newlyCreated |> Map.add typeDefn tempHandle, mapping
|
||||
|
||||
| FromReference (typeRef, _) ->
|
||||
match resolveTypeRef typeRef with
|
||||
| TypeResolutionResult.FirstLoadAssy _ -> failwith "TODO"
|
||||
| TypeResolutionResult.Resolved (resolvedAssy, typeInfo) ->
|
||||
|
||||
let cth, concreteType, mapping =
|
||||
ConcreteType.make
|
||||
mapping
|
||||
resolvedAssy.Name
|
||||
typeInfo.Namespace
|
||||
typeInfo.Name
|
||||
typeInfo.TypeDefHandle
|
||||
argHandles
|
||||
|
||||
let mapping =
|
||||
{ mapping with
|
||||
Mapping = mapping.Mapping |> Map.add tempHandle concreteType
|
||||
}
|
||||
|
||||
tempHandle, newlyCreated |> Map.add typeDefn tempHandle, mapping
|
||||
|
||||
| _ -> failwithf "Generic instantiation of non-definition type: %A" genericDef
|
||||
|
||||
| Modified (original, afterMod, required) ->
|
||||
failwith "Modified types require special handling - not yet implemented"
|
||||
|
||||
| FunctionPointer _ -> failwith "Function pointer concretisation not implemented"
|
||||
|
||||
let _, newlyCreated, finalMapping =
|
||||
concretiseTypeRec Map.empty Map.empty mapping (fst defn) (snd defn)
|
||||
|
||||
newlyCreated, finalMapping
|
||||
|
@@ -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
|
||||
|
@@ -22,8 +22,8 @@ type ConcreteType<'typeGeneric when 'typeGeneric : comparison and 'typeGeneric :
|
||||
{
|
||||
_AssemblyName : AssemblyName
|
||||
_Definition : ComparableTypeDefinitionHandle
|
||||
_Name : string
|
||||
_Namespace : string
|
||||
_Name : string
|
||||
_Generics : 'typeGeneric list
|
||||
}
|
||||
|
||||
@@ -67,25 +67,64 @@ type ConcreteType<'typeGeneric when 'typeGeneric : comparison and 'typeGeneric :
|
||||
(this :> IComparable<ConcreteType<'typeGeneric>>).CompareTo other
|
||||
| _ -> failwith "bad comparison"
|
||||
|
||||
type RuntimeConcreteType = ConcreteType<TypeDefn>
|
||||
/// Because a runtime type may depend on itself by some chain of generics, we need to break the indirection;
|
||||
/// we do so by storing all concrete types in some global mapping and then referring to them only by handle.
|
||||
type ConcreteTypeHandle = | ConcreteTypeHandle of int
|
||||
|
||||
type AllConcreteTypes =
|
||||
{
|
||||
Mapping : Map<ConcreteTypeHandle, ConcreteType<ConcreteTypeHandle>>
|
||||
NextHandle : int
|
||||
}
|
||||
|
||||
static member Empty =
|
||||
{
|
||||
Mapping = Map.empty
|
||||
NextHandle = 0
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module AllConcreteTypes =
|
||||
let lookup (cth : ConcreteTypeHandle) (this : AllConcreteTypes) : ConcreteType<ConcreteTypeHandle> option =
|
||||
this.Mapping |> Map.tryFind cth
|
||||
|
||||
let lookup' (ct : ConcreteType<ConcreteTypeHandle>) (this : AllConcreteTypes) : ConcreteTypeHandle option =
|
||||
failwith "TODO"
|
||||
|
||||
/// `source` is AssemblyName * Namespace * Name
|
||||
let add (ct : ConcreteType<ConcreteTypeHandle>) (this : AllConcreteTypes) : ConcreteTypeHandle * AllConcreteTypes =
|
||||
let toRet = ConcreteTypeHandle this.NextHandle
|
||||
|
||||
let newState =
|
||||
{
|
||||
NextHandle = this.NextHandle + 1
|
||||
Mapping = this.Mapping |> Map.add toRet ct
|
||||
}
|
||||
|
||||
toRet, newState
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module ConcreteType =
|
||||
let make
|
||||
(mapping : AllConcreteTypes)
|
||||
(assemblyName : AssemblyName)
|
||||
(ns : string)
|
||||
(name : string)
|
||||
(defn : TypeDefinitionHandle)
|
||||
(generics : TypeDefn list)
|
||||
: RuntimeConcreteType
|
||||
(generics : ConcreteTypeHandle list)
|
||||
: ConcreteTypeHandle * ConcreteType<_> * AllConcreteTypes
|
||||
=
|
||||
{
|
||||
_AssemblyName = assemblyName
|
||||
_Definition = ComparableTypeDefinitionHandle.Make defn
|
||||
_Name = name
|
||||
_Namespace = ns
|
||||
_Generics = generics
|
||||
}
|
||||
let toAdd =
|
||||
{
|
||||
_AssemblyName = assemblyName
|
||||
_Definition = ComparableTypeDefinitionHandle.Make defn
|
||||
_Name = name
|
||||
_Namespace = ns
|
||||
_Generics = generics
|
||||
}
|
||||
|
||||
let added, mapping = AllConcreteTypes.add toAdd mapping
|
||||
added, toAdd, mapping
|
||||
|
||||
let make'
|
||||
(assemblyName : AssemblyName)
|
||||
@@ -98,8 +137,8 @@ module ConcreteType =
|
||||
{
|
||||
_AssemblyName = assemblyName
|
||||
_Definition = ComparableTypeDefinitionHandle.Make defn
|
||||
_Name = name
|
||||
_Namespace = ns
|
||||
_Name = name
|
||||
_Generics = List.replicate genericParamCount FakeUnit.FakeUnit
|
||||
}
|
||||
|
||||
@@ -115,6 +154,6 @@ module ConcreteType =
|
||||
_AssemblyName = x._AssemblyName
|
||||
_Definition = x._Definition
|
||||
_Generics = generics
|
||||
_Name = x._Name
|
||||
_Namespace = x._Namespace
|
||||
_Name = x._Name
|
||||
}
|
||||
|
@@ -8,7 +8,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.
|
||||
/// </summary>
|
||||
type FieldInfo<'typeGeneric when 'typeGeneric : comparison and 'typeGeneric :> IComparable<'typeGeneric>> =
|
||||
type FieldInfo<'typeGeneric, 'sigGeneric when 'typeGeneric : comparison and 'typeGeneric :> IComparable<'typeGeneric>> =
|
||||
{
|
||||
/// <summary>
|
||||
/// The metadata token handle that uniquely identifies this field in the assembly.
|
||||
@@ -26,7 +26,7 @@ type FieldInfo<'typeGeneric when 'typeGeneric : comparison and 'typeGeneric :> I
|
||||
/// <summary>
|
||||
/// The type of the field.
|
||||
/// </summary>
|
||||
Signature : TypeDefn
|
||||
Signature : 'sigGeneric
|
||||
|
||||
/// <summary>
|
||||
/// The attributes applied to this field, including visibility, static/instance,
|
||||
@@ -45,7 +45,7 @@ module FieldInfo =
|
||||
(assembly : AssemblyName)
|
||||
(handle : FieldDefinitionHandle)
|
||||
(def : FieldDefinition)
|
||||
: FieldInfo<FakeUnit>
|
||||
: FieldInfo<FakeUnit, TypeDefn>
|
||||
=
|
||||
let name = mr.GetString def.Name
|
||||
let fieldSig = def.DecodeSignature (TypeDefn.typeProvider assembly, ())
|
||||
@@ -66,11 +66,11 @@ module FieldInfo =
|
||||
Attributes = def.Attributes
|
||||
}
|
||||
|
||||
let mapTypeGenerics<'a, 'b
|
||||
let mapTypeGenerics<'a, 'b, 'sigGen
|
||||
when 'a :> IComparable<'a> and 'a : comparison and 'b :> IComparable<'b> and 'b : comparison>
|
||||
(f : int -> 'a -> 'b)
|
||||
(input : FieldInfo<'a>)
|
||||
: FieldInfo<'b>
|
||||
(input : FieldInfo<'a, 'sigGen>)
|
||||
: FieldInfo<'b, 'sigGen>
|
||||
=
|
||||
let declaringType = input.DeclaringType |> ConcreteType.mapGeneric f
|
||||
|
||||
@@ -80,5 +80,23 @@ module FieldInfo =
|
||||
DeclaringType = declaringType
|
||||
Signature = input.Signature
|
||||
Attributes = input.Attributes
|
||||
|
||||
}
|
||||
|
||||
let mapSigGenerics<'a, 'b, 'state, 'typeGen when 'typeGen :> IComparable<'typeGen> and 'typeGen : comparison>
|
||||
(state : 'state)
|
||||
(f : 'state -> 'a -> 'state * 'b)
|
||||
(input : FieldInfo<'typeGen, 'a>)
|
||||
: FieldInfo<'typeGen, 'b> * 'state
|
||||
=
|
||||
let state, signature = f state input.Signature
|
||||
|
||||
let ret =
|
||||
{
|
||||
Handle = input.Handle
|
||||
Name = input.Name
|
||||
DeclaringType = input.DeclaringType
|
||||
Signature = signature
|
||||
Attributes = input.Attributes
|
||||
}
|
||||
|
||||
ret, state
|
||||
|
@@ -117,7 +117,7 @@ type ExceptionRegion =
|
||||
| ExceptionRegionKind.Fault -> ExceptionRegion.Fault offset
|
||||
| _ -> raise (ArgumentOutOfRangeException ())
|
||||
|
||||
type MethodInstructions =
|
||||
type MethodInstructions<'methodVar> =
|
||||
{
|
||||
/// <summary>
|
||||
/// The IL instructions that compose the method body, along with their offset positions.
|
||||
@@ -137,12 +137,14 @@ type MethodInstructions =
|
||||
/// </summary>
|
||||
LocalsInit : bool
|
||||
|
||||
LocalVars : ImmutableArray<TypeDefn> option
|
||||
LocalVars : ImmutableArray<'methodVar> option
|
||||
|
||||
ExceptionRegions : ImmutableArray<ExceptionRegion>
|
||||
}
|
||||
|
||||
static member OnlyRet : MethodInstructions =
|
||||
[<RequireQualifiedAccess>]
|
||||
module MethodInstructions =
|
||||
let onlyRet<'a> () : MethodInstructions<'a> =
|
||||
let op = IlOp.Nullary NullaryIlOp.Ret
|
||||
|
||||
{
|
||||
@@ -153,11 +155,42 @@ type MethodInstructions =
|
||||
ExceptionRegions = ImmutableArray.Empty
|
||||
}
|
||||
|
||||
let map<'a, 'b, 'state>
|
||||
(state : 'state)
|
||||
(f : 'state -> 'a -> 'b * 'state)
|
||||
(i : MethodInstructions<'a>)
|
||||
: MethodInstructions<'b> * 'state
|
||||
=
|
||||
let vars, state =
|
||||
match i.LocalVars with
|
||||
| None -> None, state
|
||||
| Some v ->
|
||||
let result = ImmutableArray.CreateBuilder v.Length
|
||||
let mutable state = state
|
||||
|
||||
for i = 0 to v.Length - 1 do
|
||||
let res, state' = f state v.[i]
|
||||
state <- state'
|
||||
result.Add res
|
||||
|
||||
Some (result.ToImmutable ()), state
|
||||
|
||||
let result =
|
||||
{
|
||||
Instructions = i.Instructions
|
||||
Locations = i.Locations
|
||||
LocalsInit = i.LocalsInit
|
||||
LocalVars = vars
|
||||
ExceptionRegions = i.ExceptionRegions
|
||||
}
|
||||
|
||||
result, state
|
||||
|
||||
/// <summary>
|
||||
/// Represents detailed information about a method in a .NET assembly.
|
||||
/// This is a strongly-typed representation of MethodDefinition from System.Reflection.Metadata.
|
||||
/// </summary>
|
||||
type MethodInfo<'typeGenerics, 'methodGenerics
|
||||
type MethodInfo<'typeGenerics, 'methodGenerics, 'methodVars
|
||||
when 'typeGenerics :> IComparable<'typeGenerics> and 'typeGenerics : comparison> =
|
||||
{
|
||||
/// <summary>
|
||||
@@ -178,7 +211,7 @@ type MethodInfo<'typeGenerics, 'methodGenerics
|
||||
///
|
||||
/// There may be no instructions for this method, e.g. if it's an `InternalCall`.
|
||||
/// </summary>
|
||||
Instructions : MethodInstructions option
|
||||
Instructions : MethodInstructions<'methodVars> option
|
||||
|
||||
/// <summary>
|
||||
/// The parameters of this method.
|
||||
@@ -193,7 +226,13 @@ type MethodInfo<'typeGenerics, 'methodGenerics
|
||||
/// <summary>
|
||||
/// The signature of the method, including return type and parameter types.
|
||||
/// </summary>
|
||||
Signature : TypeMethodSignature<TypeDefn>
|
||||
Signature : TypeMethodSignature<'methodVars>
|
||||
|
||||
/// <summary>
|
||||
/// The signature of the method, including return type and parameter types, as read directly from metadata
|
||||
/// (not made concrete in a running instance of the program).
|
||||
/// </summary>
|
||||
RawSignature : TypeMethodSignature<TypeDefn>
|
||||
|
||||
/// <summary>
|
||||
/// Custom attributes defined on the method. I've never yet seen one of these in practice.
|
||||
@@ -226,9 +265,9 @@ type MethodInfo<'typeGenerics, 'methodGenerics
|
||||
member this.IsPinvokeImpl : bool =
|
||||
this.MethodAttributes.HasFlag MethodAttributes.PinvokeImpl
|
||||
|
||||
member this.IsJITIntrinsic
|
||||
member this.IsJITIntrinsic<'a, 'b, 'c when 'a :> IComparable<'a> and 'a : comparison>
|
||||
(getMemberRefParentType : MemberReferenceHandle -> TypeRef)
|
||||
(methodDefs : IReadOnlyDictionary<MethodDefinitionHandle, MethodInfo<FakeUnit, GenericParameter>>)
|
||||
(methodDefs : IReadOnlyDictionary<MethodDefinitionHandle, MethodInfo<'a, 'b, 'c>>)
|
||||
: bool
|
||||
=
|
||||
this.CustomAttributes
|
||||
@@ -250,11 +289,11 @@ type MethodInfo<'typeGenerics, 'methodGenerics
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module MethodInfo =
|
||||
let mapTypeGenerics<'a, 'b, 'methodGen
|
||||
let mapTypeGenerics<'a, 'b, 'methodGen, 'methodVars
|
||||
when 'a :> IComparable<'a> and 'a : comparison and 'b : comparison and 'b :> IComparable<'b>>
|
||||
(f : int -> 'a -> 'b)
|
||||
(m : MethodInfo<'a, 'methodGen>)
|
||||
: MethodInfo<'b, 'methodGen>
|
||||
(m : MethodInfo<'a, 'methodGen, 'methodVars>)
|
||||
: MethodInfo<'b, 'methodGen, 'methodVars>
|
||||
=
|
||||
{
|
||||
DeclaringType = m.DeclaringType |> ConcreteType.mapGeneric f
|
||||
@@ -268,12 +307,13 @@ module MethodInfo =
|
||||
MethodAttributes = m.MethodAttributes
|
||||
ImplAttributes = m.ImplAttributes
|
||||
IsStatic = m.IsStatic
|
||||
RawSignature = m.RawSignature
|
||||
}
|
||||
|
||||
let mapMethodGenerics<'a, 'b, 'typeGen when 'typeGen :> IComparable<'typeGen> and 'typeGen : comparison>
|
||||
let mapMethodGenerics<'a, 'b, 'typeGen, 'methodVars when 'typeGen :> IComparable<'typeGen> and 'typeGen : comparison>
|
||||
(f : int -> 'a -> 'b)
|
||||
(m : MethodInfo<'typeGen, 'a>)
|
||||
: MethodInfo<'typeGen, 'b>
|
||||
(m : MethodInfo<'typeGen, 'a, 'methodVars>)
|
||||
: MethodInfo<'typeGen, 'b, 'methodVars>
|
||||
=
|
||||
{
|
||||
DeclaringType = m.DeclaringType
|
||||
@@ -287,8 +327,42 @@ module MethodInfo =
|
||||
MethodAttributes = m.MethodAttributes
|
||||
ImplAttributes = m.ImplAttributes
|
||||
IsStatic = m.IsStatic
|
||||
RawSignature = m.RawSignature
|
||||
}
|
||||
|
||||
let mapVarGenerics<'a, 'b, 'state, 'typeGen, 'methodGen
|
||||
when 'typeGen :> IComparable<'typeGen> and 'typeGen : comparison>
|
||||
(state : 'state)
|
||||
(f : 'state -> 'a -> 'b * 'state)
|
||||
(m : MethodInfo<'typeGen, 'methodGen, 'a>)
|
||||
: MethodInfo<'typeGen, 'methodGen, 'b> * 'state
|
||||
=
|
||||
let instructions, state =
|
||||
match m.Instructions with
|
||||
| None -> None, state
|
||||
| Some i ->
|
||||
let result, state = MethodInstructions.map state f i
|
||||
Some result, state
|
||||
|
||||
let signature, state = m.Signature |> TypeMethodSignature.map f state
|
||||
|
||||
let result =
|
||||
{
|
||||
DeclaringType = m.DeclaringType
|
||||
Handle = m.Handle
|
||||
Name = m.Name
|
||||
Instructions = instructions
|
||||
Parameters = m.Parameters
|
||||
Generics = m.Generics
|
||||
Signature = signature
|
||||
CustomAttributes = m.CustomAttributes
|
||||
MethodAttributes = m.MethodAttributes
|
||||
ImplAttributes = m.ImplAttributes
|
||||
IsStatic = m.IsStatic
|
||||
RawSignature = m.RawSignature
|
||||
}
|
||||
|
||||
result, state
|
||||
|
||||
type private Dummy = class end
|
||||
|
||||
@@ -637,7 +711,7 @@ module MethodInfo =
|
||||
(peReader : PEReader)
|
||||
(metadataReader : MetadataReader)
|
||||
(methodHandle : MethodDefinitionHandle)
|
||||
: MethodInfo<FakeUnit, GenericParameter> option
|
||||
: MethodInfo<FakeUnit, GenericParameter, TypeDefn> option
|
||||
=
|
||||
let logger = loggerFactory.CreateLogger "MethodInfo"
|
||||
let assemblyName = metadataReader.GetAssemblyDefinition().GetAssemblyName ()
|
||||
@@ -718,12 +792,13 @@ module MethodInfo =
|
||||
CustomAttributes = attrs
|
||||
IsStatic = not methodSig.Header.IsInstance
|
||||
ImplAttributes = implAttrs
|
||||
RawSignature = typeSig
|
||||
}
|
||||
|> Some
|
||||
|
||||
let rec resolveBaseType
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
(executingMethod : MethodInfo<TypeDefn, 'methodGen>)
|
||||
(executingMethod : MethodInfo<TypeDefn, 'methodGen, 'methodVars>)
|
||||
(td : TypeDefn)
|
||||
: ResolvedBaseType
|
||||
=
|
||||
|
@@ -55,6 +55,34 @@ module TypeMethodSignature =
|
||||
RequiredParameterCount = p.RequiredParameterCount
|
||||
}
|
||||
|
||||
let map<'a, 'b, 'state>
|
||||
(f : 'state -> 'a -> 'b * 'state)
|
||||
(state : 'state)
|
||||
(s : TypeMethodSignature<'a>)
|
||||
: TypeMethodSignature<'b> * 'state
|
||||
=
|
||||
let ret, state = s.ReturnType |> f state
|
||||
|
||||
let state, paramTypes =
|
||||
((state, []), s.ParameterTypes)
|
||||
||> List.fold (fun (state, acc) ty ->
|
||||
let result, state = f state ty
|
||||
state, result :: acc
|
||||
)
|
||||
|
||||
let paramTypes = paramTypes |> List.rev
|
||||
|
||||
let result =
|
||||
{
|
||||
Header = s.Header
|
||||
ParameterTypes = paramTypes
|
||||
GenericParameterCount = s.GenericParameterCount
|
||||
RequiredParameterCount = s.RequiredParameterCount
|
||||
ReturnType = ret
|
||||
}
|
||||
|
||||
result, state
|
||||
|
||||
/// See I.8.2.2
|
||||
type PrimitiveType =
|
||||
| Boolean
|
||||
|
@@ -23,7 +23,7 @@ type MethodImplParsed =
|
||||
/// Represents detailed information about a type definition in a .NET assembly.
|
||||
/// This is a strongly-typed representation of TypeDefinition from System.Reflection.Metadata.
|
||||
/// </summary>
|
||||
type TypeInfo<'generic> =
|
||||
type TypeInfo<'generic, 'fieldGeneric> =
|
||||
{
|
||||
/// <summary>The namespace containing the type.</summary>
|
||||
Namespace : string
|
||||
@@ -34,7 +34,7 @@ type TypeInfo<'generic> =
|
||||
/// <summary>
|
||||
/// All methods defined within this type.
|
||||
/// </summary>
|
||||
Methods : WoofWare.PawPrint.MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter> list
|
||||
Methods : WoofWare.PawPrint.MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter, TypeDefn> list
|
||||
|
||||
/// <summary>
|
||||
/// Method implementation mappings for this type, often used for interface implementations
|
||||
@@ -45,7 +45,7 @@ type TypeInfo<'generic> =
|
||||
/// <summary>
|
||||
/// Fields defined in this type.
|
||||
/// </summary>
|
||||
Fields : WoofWare.PawPrint.FieldInfo<FakeUnit> list
|
||||
Fields : WoofWare.PawPrint.FieldInfo<FakeUnit, 'fieldGeneric> list
|
||||
|
||||
/// <summary>
|
||||
/// The base type that this type inherits from, or None for types that don't have a base type
|
||||
@@ -85,7 +85,7 @@ type TypeInfo<'generic> =
|
||||
$"%s{this.Assembly.Name}.%s{this.Namespace}.%s{this.Name}"
|
||||
|
||||
type TypeInfoEval<'ret> =
|
||||
abstract Eval<'a> : TypeInfo<'a> -> 'ret
|
||||
abstract Eval<'a, 'fieldGeneric> : TypeInfo<'a, 'fieldGeneric> -> 'ret
|
||||
|
||||
type TypeInfoCrate =
|
||||
abstract Apply<'ret> : TypeInfoEval<'ret> -> 'ret
|
||||
@@ -97,13 +97,13 @@ type TypeInfoCrate =
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module TypeInfoCrate =
|
||||
let make<'a> (t : TypeInfo<'a>) =
|
||||
let make<'a, 'b> (t : TypeInfo<'a, 'b>) : TypeInfoCrate =
|
||||
{ new TypeInfoCrate with
|
||||
member _.Apply e = e.Eval t
|
||||
|
||||
member this.ToString () =
|
||||
{ new TypeInfoEval<_> with
|
||||
member _.Eval this = string<TypeInfo<_>> this
|
||||
member _.Eval this = string<TypeInfo<_, _>> this
|
||||
}
|
||||
|> this.Apply
|
||||
|
||||
@@ -119,33 +119,37 @@ module TypeInfoCrate =
|
||||
type BaseClassTypes<'corelib> =
|
||||
{
|
||||
Corelib : 'corelib
|
||||
String : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Boolean : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Char : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
SByte : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Byte : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Int16 : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
UInt16 : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Int32 : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
UInt32 : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Int64 : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
UInt64 : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Single : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Double : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Array : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Enum : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
ValueType : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
DelegateType : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
Object : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
RuntimeMethodHandle : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
RuntimeFieldHandle : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
RuntimeTypeHandle : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
RuntimeType : TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
String : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Boolean : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Char : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
SByte : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Byte : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Int16 : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
UInt16 : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Int32 : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
UInt32 : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Int64 : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
UInt64 : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Single : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Double : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Array : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Enum : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
ValueType : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
DelegateType : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
Object : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
RuntimeMethodHandle : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
RuntimeFieldHandle : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
RuntimeTypeHandle : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
RuntimeType : TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module TypeInfo =
|
||||
let withGenerics<'a, 'b> (gen : 'b ImmutableArray) (t : TypeInfo<'a>) : TypeInfo<'b> =
|
||||
let withGenerics<'a, 'b, 'fieldSig>
|
||||
(gen : 'b ImmutableArray)
|
||||
(t : TypeInfo<'a, 'fieldSig>)
|
||||
: TypeInfo<'b, 'fieldSig>
|
||||
=
|
||||
{
|
||||
Namespace = t.Namespace
|
||||
Name = t.Name
|
||||
@@ -161,7 +165,7 @@ module TypeInfo =
|
||||
Events = t.Events
|
||||
}
|
||||
|
||||
let mapGeneric<'a, 'b> (f : int -> 'a -> 'b) (t : TypeInfo<'a>) : TypeInfo<'b> =
|
||||
let mapGeneric<'a, 'b, 'fieldSig> (f : int -> 'a -> 'b) (t : TypeInfo<'a, 'fieldSig>) : TypeInfo<'b, 'fieldSig> =
|
||||
withGenerics (t.Generics |> Seq.mapi f |> ImmutableArray.CreateRange) t
|
||||
|
||||
let internal read
|
||||
@@ -170,7 +174,7 @@ module TypeInfo =
|
||||
(thisAssembly : AssemblyName)
|
||||
(metadataReader : MetadataReader)
|
||||
(typeHandle : TypeDefinitionHandle)
|
||||
: TypeInfo<WoofWare.PawPrint.GenericParameter>
|
||||
: TypeInfo<WoofWare.PawPrint.GenericParameter, WoofWare.PawPrint.TypeDefn>
|
||||
=
|
||||
let typeDef = metadataReader.GetTypeDefinition typeHandle
|
||||
let methods = typeDef.GetMethods ()
|
||||
@@ -275,11 +279,11 @@ module TypeInfo =
|
||||
else
|
||||
None
|
||||
|
||||
let rec resolveBaseType<'corelib, 'generic>
|
||||
let rec resolveBaseType<'corelib, 'generic, 'fieldGeneric>
|
||||
(baseClassTypes : BaseClassTypes<'corelib>)
|
||||
(getName : 'corelib -> AssemblyName)
|
||||
(getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic>)
|
||||
(getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic>)
|
||||
(getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'fieldGeneric>)
|
||||
(getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic, 'fieldGeneric>)
|
||||
(sourceAssembly : AssemblyName)
|
||||
(value : BaseTypeInfo option)
|
||||
: ResolvedBaseType
|
||||
@@ -311,9 +315,9 @@ module TypeInfo =
|
||||
let toTypeDefn
|
||||
(corelib : BaseClassTypes<'corelib>)
|
||||
(getName : 'corelib -> AssemblyName)
|
||||
(getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic>)
|
||||
(getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic>)
|
||||
(ty : TypeInfo<'generic>)
|
||||
(getTypeDef : 'corelib -> TypeDefinitionHandle -> TypeInfo<'generic, 'fieldGeneric>)
|
||||
(getTypeRef : 'corelib -> TypeReferenceHandle -> TypeInfo<'generic, 'fieldGeneric>)
|
||||
(ty : TypeInfo<'generic, 'fieldGeneric>)
|
||||
: TypeDefn
|
||||
=
|
||||
let stk =
|
||||
|
@@ -68,6 +68,12 @@ module TestPureCases =
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 1) ] |> Some
|
||||
}
|
||||
{
|
||||
FileName = "StaticVariables.cs"
|
||||
ExpectedReturnCode = 0
|
||||
NativeImpls = MockEnv.make ()
|
||||
LocalVariablesOfMain = None
|
||||
}
|
||||
{
|
||||
FileName = "Ldind.cs"
|
||||
ExpectedReturnCode = 0
|
||||
|
@@ -22,6 +22,7 @@
|
||||
<EmbeddedResource Include="sourcesPure\BasicLock.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\Floats.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\NoOp.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\StaticVariables.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\Ldelema.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpCatch.cs" />
|
||||
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpFinally.cs" />
|
||||
|
54
WoofWare.PawPrint.Test/sourcesPure/StaticVariables.cs
Normal file
54
WoofWare.PawPrint.Test/sourcesPure/StaticVariables.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
public class GenericCounter<T>
|
||||
{
|
||||
private static int count = 0;
|
||||
|
||||
public static void Increment()
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
public static int GetCount()
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Program
|
||||
{
|
||||
static int Main()
|
||||
{
|
||||
// Test that different generic instantiations have separate static variables
|
||||
|
||||
// Initial state should be 0 for all
|
||||
if (GenericCounter<int>.GetCount() != 0) return 1;
|
||||
if (GenericCounter<string>.GetCount() != 0) return 2;
|
||||
|
||||
// Increment int version 3 times
|
||||
GenericCounter<int>.Increment();
|
||||
GenericCounter<int>.Increment();
|
||||
GenericCounter<int>.Increment();
|
||||
|
||||
// Increment string version 2 times
|
||||
GenericCounter<string>.Increment();
|
||||
GenericCounter<string>.Increment();
|
||||
|
||||
// Verify counts are independent
|
||||
if (GenericCounter<int>.GetCount() != 3) return 3;
|
||||
if (GenericCounter<string>.GetCount() != 2) return 4;
|
||||
|
||||
// Reset int version only
|
||||
GenericCounter<int>.Reset();
|
||||
|
||||
// Verify reset only affected int version
|
||||
if (GenericCounter<int>.GetCount() != 0) return 5;
|
||||
if (GenericCounter<string>.GetCount() != 2) return 6;
|
||||
|
||||
// Test passes - static variables are isolated per generic instantiation
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -98,7 +98,7 @@ module AbstractMachine =
|
||||
baseClassTypes
|
||||
thread
|
||||
false
|
||||
(Some methodGenerics)
|
||||
methodGenerics
|
||||
methodPtr
|
||||
None
|
||||
|
||||
@@ -111,8 +111,8 @@ module AbstractMachine =
|
||||
targetType.Namespace,
|
||||
targetType.Name,
|
||||
instruction.ExecutingMethod.Name,
|
||||
instruction.ExecutingMethod.Signature.ParameterTypes,
|
||||
instruction.ExecutingMethod.Signature.ReturnType
|
||||
instruction.ExecutingMethod.RawSignature.ParameterTypes,
|
||||
instruction.ExecutingMethod.RawSignature.ReturnType
|
||||
with
|
||||
| "System.Private.CoreLib",
|
||||
"System",
|
||||
|
@@ -63,7 +63,7 @@ type UnsignedNativeIntSource =
|
||||
type NativeIntSource =
|
||||
| Verbatim of int64
|
||||
| ManagedPointer of ManagedPointerSource
|
||||
| FunctionPointer of MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter>
|
||||
| FunctionPointer of MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter, TypeDefn>
|
||||
| TypeHandlePtr of int64<typeHandle>
|
||||
|
||||
override this.ToString () : string =
|
||||
@@ -193,24 +193,25 @@ module CliType =
|
||||
| PrimitiveType.UIntPtr -> CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null)
|
||||
| PrimitiveType.Object -> CliType.ObjectRef None
|
||||
|
||||
let rec zeroOf
|
||||
let rec zeroOfTypeDefn
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(assy : DumpedAssembly)
|
||||
(typeGenerics : TypeDefn ImmutableArray option)
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
(typeGenerics : TypeDefn ImmutableArray)
|
||||
(methodGenerics : TypeDefn ImmutableArray)
|
||||
(ty : TypeDefn)
|
||||
: CliTypeResolutionResult
|
||||
=
|
||||
match ty with
|
||||
| TypeDefn.PrimitiveType primitiveType -> CliTypeResolutionResult.Resolved (zeroOfPrimitive primitiveType)
|
||||
| TypeDefn.Array _ -> CliType.ObjectRef None |> CliTypeResolutionResult.Resolved
|
||||
| TypeDefn.Array _ -> CliTypeResolutionResult.Resolved (CliType.ObjectRef None)
|
||||
| TypeDefn.Pinned typeDefn -> failwith "todo"
|
||||
| TypeDefn.Pointer _ ->
|
||||
CliType.RuntimePointer (CliRuntimePointer.Managed CliRuntimePointerSource.Null)
|
||||
CliRuntimePointer.Managed CliRuntimePointerSource.Null
|
||||
|> CliType.RuntimePointer
|
||||
|> CliTypeResolutionResult.Resolved
|
||||
| TypeDefn.Byref _ -> CliType.ObjectRef None |> CliTypeResolutionResult.Resolved
|
||||
| TypeDefn.OneDimensionalArrayLowerBoundZero _ -> CliType.ObjectRef None |> CliTypeResolutionResult.Resolved
|
||||
| TypeDefn.Byref _ -> CliTypeResolutionResult.Resolved (CliType.ObjectRef None)
|
||||
| TypeDefn.OneDimensionalArrayLowerBoundZero _ -> CliTypeResolutionResult.Resolved (CliType.ObjectRef None)
|
||||
| TypeDefn.Modified (original, afterMod, modificationRequired) -> failwith "todo"
|
||||
| TypeDefn.FromReference (typeRef, signatureTypeKind) ->
|
||||
match signatureTypeKind with
|
||||
@@ -222,7 +223,9 @@ module CliType =
|
||||
ty.Fields
|
||||
|> List.filter (fun field -> not (field.Attributes.HasFlag FieldAttributes.Static))
|
||||
|> List.map (fun fi ->
|
||||
match zeroOf assemblies corelib sourceAssy typeGenerics methodGenerics fi.Signature with
|
||||
match
|
||||
zeroOfTypeDefn assemblies corelib sourceAssy typeGenerics methodGenerics fi.Signature
|
||||
with
|
||||
| CliTypeResolutionResult.Resolved ty -> Ok ty
|
||||
| CliTypeResolutionResult.FirstLoad a -> Error a
|
||||
)
|
||||
@@ -256,7 +259,7 @@ module CliType =
|
||||
// oh lord, this is awfully ominous - I really don't want to store the statics here
|
||||
|> List.filter (fun field -> not (field.Attributes.HasFlag FieldAttributes.Static))
|
||||
|> List.map (fun fi ->
|
||||
match zeroOf assemblies corelib assy typeGenerics methodGenerics fi.Signature with
|
||||
match zeroOfTypeDefn assemblies corelib assy typeGenerics methodGenerics fi.Signature with
|
||||
| CliTypeResolutionResult.Resolved ty -> Ok ty
|
||||
| CliTypeResolutionResult.FirstLoad a -> Error a
|
||||
)
|
||||
@@ -271,15 +274,15 @@ module CliType =
|
||||
| SignatureTypeKind.Class -> CliType.ObjectRef None |> CliTypeResolutionResult.Resolved
|
||||
| _ -> raise (ArgumentOutOfRangeException ())
|
||||
| TypeDefn.GenericInstantiation (generic, args) ->
|
||||
zeroOf assemblies corelib assy (Some args) methodGenerics generic
|
||||
zeroOfTypeDefn assemblies corelib assy args methodGenerics generic
|
||||
| TypeDefn.FunctionPointer typeMethodSignature -> failwith "todo"
|
||||
| TypeDefn.GenericTypeParameter index ->
|
||||
// TODO: can generics depend on other generics? presumably, so we pass the array down again
|
||||
match typeGenerics with
|
||||
| None -> failwith "asked for a type parameter of generic type, but no generics in scope"
|
||||
| Some generics -> zeroOf assemblies corelib assy (Some generics) methodGenerics generics.[index]
|
||||
zeroOfTypeDefn assemblies corelib assy typeGenerics methodGenerics typeGenerics.[index]
|
||||
| TypeDefn.GenericMethodParameter index ->
|
||||
match methodGenerics with
|
||||
| None -> failwith "asked for a method parameter of generic type, but no generics in scope"
|
||||
| Some generics -> zeroOf assemblies corelib assy typeGenerics (Some generics) generics.[index]
|
||||
zeroOfTypeDefn assemblies corelib assy typeGenerics methodGenerics methodGenerics.[index]
|
||||
| TypeDefn.Void -> failwith "should never construct an element of type Void"
|
||||
|
||||
let rec zeroOf (concreteTypes : AllConcreteTypes) (cth : ConcreteTypeHandle) : CliType =
|
||||
let ty = AllConcreteTypes.lookup cth concreteTypes |> Option.get
|
||||
failwith "TODO"
|
||||
|
@@ -5,7 +5,7 @@ open System.Collections.Immutable
|
||||
/// Represents a location in the code where an exception occurred
|
||||
type ExceptionStackFrame =
|
||||
{
|
||||
Method : WoofWare.PawPrint.MethodInfo<TypeDefn, TypeDefn>
|
||||
Method : WoofWare.PawPrint.MethodInfo<ConcreteTypeHandle, ConcreteTypeHandle, ConcreteTypeHandle>
|
||||
/// The number of bytes into the IL of the method we were in
|
||||
IlOffset : int
|
||||
}
|
||||
@@ -44,7 +44,7 @@ module ExceptionHandling =
|
||||
let findExceptionHandler
|
||||
(currentPC : int)
|
||||
(exceptionTypeCrate : TypeInfoCrate)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||
(method : WoofWare.PawPrint.MethodInfo<'typeGeneric, 'methodGeneric, 'methodVar>)
|
||||
(assemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
: (WoofWare.PawPrint.ExceptionRegion * bool) option // handler, isFinally
|
||||
=
|
||||
@@ -92,7 +92,7 @@ module ExceptionHandling =
|
||||
let findFinallyBlocksToRun
|
||||
(currentPC : int)
|
||||
(targetPC : int)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||
(method : WoofWare.PawPrint.MethodInfo<'typeGeneric, 'methodGeneric, 'methodVar>)
|
||||
: ExceptionOffset list
|
||||
=
|
||||
match method.Instructions with
|
||||
@@ -122,7 +122,7 @@ module ExceptionHandling =
|
||||
/// Get the active exception regions at a given offset
|
||||
let getActiveRegionsAtOffset
|
||||
(offset : int)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, 'methodGeneric>)
|
||||
(method : WoofWare.PawPrint.MethodInfo<'typeGeneric, 'methodGeneric, 'methodVar>)
|
||||
: WoofWare.PawPrint.ExceptionRegion list
|
||||
=
|
||||
match method.Instructions with
|
||||
|
@@ -16,6 +16,7 @@ type IlMachineState =
|
||||
/// Multiple managed heaps are allowed, but we hopefully only need one.
|
||||
ManagedHeap : ManagedHeap
|
||||
ThreadState : Map<ThreadId, ThreadState>
|
||||
ConcreteTypes : AllConcreteTypes
|
||||
InternedStrings : ImmutableDictionary<StringToken, ManagedHeapAddress>
|
||||
/// Keyed by FullName. (Sometimes an assembly has a PublicKey when we read it from the disk, but we
|
||||
/// only have a reference to it by an AssemblyName without a PublicKey.)
|
||||
@@ -23,18 +24,21 @@ type IlMachineState =
|
||||
/// Tracks initialization state of types across assemblies
|
||||
TypeInitTable : TypeInitTable
|
||||
/// For each type, specialised to each set of generic args, a map of string field name to static value contained therein.
|
||||
_Statics : ImmutableDictionary<ConcreteType<FakeUnit>, ImmutableDictionary<string, CliType>>
|
||||
_Statics : ImmutableDictionary<ConcreteTypeHandle, ImmutableDictionary<string, CliType>>
|
||||
DotnetRuntimeDirs : string ImmutableArray
|
||||
TypeHandles : TypeHandleRegistry
|
||||
}
|
||||
|
||||
member this.WithTypeBeginInit (thread : ThreadId) (ty : RuntimeConcreteType) =
|
||||
this.Logger.LogDebug (
|
||||
"Beginning initialisation of type {s_Assembly}.{TypeName}, handle {TypeDefinitionHandle}",
|
||||
ty.Assembly.FullName,
|
||||
this.LoadedAssembly(ty.Assembly).Value.TypeDefs.[ty.Definition.Get].Name,
|
||||
ty.Definition.Get.GetHashCode ()
|
||||
)
|
||||
member this.WithTypeBeginInit (thread : ThreadId) (ty : ConcreteTypeHandle) =
|
||||
do
|
||||
let ty = AllConcreteTypes.lookup ty this.ConcreteTypes |> Option.get
|
||||
|
||||
this.Logger.LogDebug (
|
||||
"Beginning initialisation of type {s_Assembly}.{TypeName}, handle {TypeDefinitionHandle}",
|
||||
ty.Assembly.FullName,
|
||||
this.LoadedAssembly(ty.Assembly).Value.TypeDefs.[ty.Definition.Get].Name,
|
||||
ty.Definition.Get.GetHashCode ()
|
||||
)
|
||||
|
||||
let typeInitTable = this.TypeInitTable |> TypeInitTable.beginInitialising thread ty
|
||||
|
||||
@@ -42,13 +46,16 @@ type IlMachineState =
|
||||
TypeInitTable = typeInitTable
|
||||
}
|
||||
|
||||
member this.WithTypeEndInit (thread : ThreadId) (ty : RuntimeConcreteType) =
|
||||
this.Logger.LogDebug (
|
||||
"Marking complete initialisation of type {s_Assembly}.{TypeName}, handle {TypeDefinitionHandle}",
|
||||
ty.Assembly.FullName,
|
||||
this.LoadedAssembly(ty.Assembly).Value.TypeDefs.[ty.Definition.Get].Name,
|
||||
ty.Definition.Get.GetHashCode ()
|
||||
)
|
||||
member this.WithTypeEndInit (thread : ThreadId) (ty : ConcreteTypeHandle) =
|
||||
do
|
||||
let ty = AllConcreteTypes.lookup ty this.ConcreteTypes |> Option.get
|
||||
|
||||
this.Logger.LogDebug (
|
||||
"Marking complete initialisation of type {s_Assembly}.{TypeName}, handle {TypeDefinitionHandle}",
|
||||
ty.Assembly.FullName,
|
||||
this.LoadedAssembly(ty.Assembly).Value.TypeDefs.[ty.Definition.Get].Name,
|
||||
ty.Definition.Get.GetHashCode ()
|
||||
)
|
||||
|
||||
let typeInitTable = this.TypeInitTable |> TypeInitTable.markInitialised thread ty
|
||||
|
||||
@@ -182,10 +189,10 @@ module IlMachineState =
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(ns : string option)
|
||||
(name : string)
|
||||
(genericArgs : ImmutableArray<TypeDefn> option)
|
||||
(genericArgs : ImmutableArray<TypeDefn>)
|
||||
(assy : DumpedAssembly)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
match Assembly.resolveTypeFromName assy state._LoadedAssemblies ns name genericArgs with
|
||||
| TypeResolutionResult.Resolved (assy, typeDef) -> state, assy, typeDef
|
||||
@@ -203,9 +210,9 @@ module IlMachineState =
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(fromAssembly : DumpedAssembly)
|
||||
(ty : WoofWare.PawPrint.ExportedType)
|
||||
(genericArgs : ImmutableArray<TypeDefn> option)
|
||||
(genericArgs : ImmutableArray<TypeDefn>)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
match Assembly.resolveTypeFromExport fromAssembly state._LoadedAssemblies ty genericArgs with
|
||||
| TypeResolutionResult.Resolved (assy, typeDef) -> state, assy, typeDef
|
||||
@@ -223,9 +230,9 @@ module IlMachineState =
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(referencedInAssembly : DumpedAssembly)
|
||||
(target : TypeRef)
|
||||
(typeGenericArgs : ImmutableArray<TypeDefn> option)
|
||||
(typeGenericArgs : ImmutableArray<TypeDefn>)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
match Assembly.resolveTypeRef state._LoadedAssemblies referencedInAssembly target typeGenericArgs with
|
||||
| TypeResolutionResult.Resolved (assy, typeDef) -> state, assy, typeDef
|
||||
@@ -242,10 +249,10 @@ module IlMachineState =
|
||||
and resolveType
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(ty : TypeReferenceHandle)
|
||||
(genericArgs : ImmutableArray<TypeDefn> option)
|
||||
(genericArgs : ImmutableArray<TypeDefn>)
|
||||
(assy : DumpedAssembly)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
let target = assy.TypeRefs.[ty]
|
||||
|
||||
@@ -255,11 +262,11 @@ module IlMachineState =
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : TypeDefn)
|
||||
(typeGenericArgs : ImmutableArray<TypeDefn> option)
|
||||
(typeGenericArgs : ImmutableArray<TypeDefn>)
|
||||
(methodGenericArgs : ImmutableArray<TypeDefn>)
|
||||
(assy : DumpedAssembly)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
match ty with
|
||||
| TypeDefn.GenericInstantiation (generic, args) ->
|
||||
@@ -294,17 +301,13 @@ module IlMachineState =
|
||||
)
|
||||
|
||||
let args' = args'.ToImmutable ()
|
||||
resolveTypeFromDefn loggerFactory corelib generic (Some args') methodGenericArgs assy state
|
||||
resolveTypeFromDefn loggerFactory corelib generic args' methodGenericArgs assy state
|
||||
| TypeDefn.FromDefinition (defn, assy, _typeKind) ->
|
||||
let assy = state._LoadedAssemblies.[assy]
|
||||
|
||||
let defn =
|
||||
assy.TypeDefs.[defn.Get]
|
||||
|> TypeInfo.mapGeneric (fun _ param ->
|
||||
match typeGenericArgs with
|
||||
| None -> failwith "somehow got a generic TypeDefn.FromDefinition without any type generic args"
|
||||
| Some genericArgs -> genericArgs.[param.SequenceNumber]
|
||||
)
|
||||
|> TypeInfo.mapGeneric (fun _ param -> typeGenericArgs.[param.SequenceNumber])
|
||||
|
||||
state, assy, defn
|
||||
| TypeDefn.FromReference (ref, _typeKind) ->
|
||||
@@ -336,12 +339,9 @@ module IlMachineState =
|
||||
|
||||
state, corelib.Corelib, ty
|
||||
| TypeDefn.GenericTypeParameter param ->
|
||||
match typeGenericArgs with
|
||||
| None -> failwith "tried to resolve generic parameter without generic args"
|
||||
| Some genericArgs ->
|
||||
let arg = genericArgs.[param]
|
||||
// TODO: this assembly is probably wrong?
|
||||
resolveTypeFromDefn loggerFactory corelib arg (Some genericArgs) methodGenericArgs assy state
|
||||
let arg = typeGenericArgs.[param]
|
||||
// TODO: this assembly is probably wrong?
|
||||
resolveTypeFromDefn loggerFactory corelib arg typeGenericArgs methodGenericArgs assy state
|
||||
| TypeDefn.GenericMethodParameter param ->
|
||||
let arg = methodGenericArgs.[param]
|
||||
// TODO: this assembly is probably wrong?
|
||||
@@ -353,10 +353,10 @@ module IlMachineState =
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : TypeSpecificationHandle)
|
||||
(assy : DumpedAssembly)
|
||||
(typeGenericArgs : TypeDefn ImmutableArray option)
|
||||
(typeGenericArgs : TypeDefn ImmutableArray)
|
||||
(methodGenericArgs : TypeDefn ImmutableArray)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn>
|
||||
: IlMachineState * DumpedAssembly * WoofWare.PawPrint.TypeInfo<TypeDefn, TypeDefn>
|
||||
=
|
||||
let sign = assy.TypeSpecs.[ty].Signature
|
||||
resolveTypeFromDefn loggerFactory corelib sign typeGenericArgs methodGenericArgs assy state
|
||||
@@ -366,19 +366,34 @@ module IlMachineState =
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(assy : DumpedAssembly)
|
||||
(ty : TypeDefn)
|
||||
(typeGenerics : TypeDefn ImmutableArray option)
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
(typeGenerics : ConcreteTypeHandle ImmutableArray)
|
||||
(methodGenerics : ConcreteTypeHandle ImmutableArray)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * CliType
|
||||
=
|
||||
match CliType.zeroOf state._LoadedAssemblies corelib assy typeGenerics methodGenerics ty with
|
||||
| CliTypeResolutionResult.Resolved result -> state, result
|
||||
| CliTypeResolutionResult.FirstLoad ref ->
|
||||
match
|
||||
CliType.zeroOf state.ConcreteTypes state._LoadedAssemblies corelib assy typeGenerics methodGenerics ty
|
||||
with
|
||||
| CliTypeResolutionResult.Resolved result, concreteTypes ->
|
||||
let state =
|
||||
{ state with
|
||||
ConcreteTypes = concreteTypes
|
||||
}
|
||||
|
||||
state, result
|
||||
| CliTypeResolutionResult.FirstLoad ref, concreteTypes ->
|
||||
let state =
|
||||
{ state with
|
||||
ConcreteTypes = concreteTypes
|
||||
}
|
||||
|
||||
let state, _, _ =
|
||||
loadAssembly loggerFactory state._LoadedAssemblies.[snd(ref.Handle).FullName] (fst ref.Handle) state
|
||||
|
||||
cliTypeZeroOf loggerFactory corelib assy ty typeGenerics methodGenerics state
|
||||
|
||||
let zeroOfConcreteType (ct : ConcreteTypeHandle) : CliType = failwith ""
|
||||
|
||||
let pushToEvalStack' (o : EvalStackValue) (thread : ThreadId) (state : IlMachineState) =
|
||||
let activeThreadState = state.ThreadState.[thread]
|
||||
|
||||
@@ -510,9 +525,7 @@ module IlMachineState =
|
||||
match retType with
|
||||
| TypeDefn.Void -> state
|
||||
| retType ->
|
||||
// TODO: generics
|
||||
let state, zero =
|
||||
cliTypeZeroOf loggerFactory corelib (state.ActiveAssembly currentThread) retType None None state
|
||||
let zero = zeroOfConcreteType retType
|
||||
|
||||
let toPush = EvalStackValue.toCliTypeCoerced zero retVal
|
||||
|
||||
@@ -538,7 +551,7 @@ module IlMachineState =
|
||||
|
||||
let callIntrinsic
|
||||
(baseClassTypes : BaseClassTypes<_>)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter>)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<'typeGenerics, 'methodGenerics, 'methodVars>)
|
||||
(currentThread : ThreadId)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState option
|
||||
@@ -725,12 +738,17 @@ module IlMachineState =
|
||||
let callMethod
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(wasInitialising : RuntimeConcreteType option)
|
||||
(wasInitialising : ConcreteTypeHandle option)
|
||||
(wasConstructing : ManagedHeapAddress option)
|
||||
(wasClassConstructor : bool)
|
||||
(advanceProgramCounterOfCaller : bool)
|
||||
(methodGenerics : ImmutableArray<TypeDefn> option)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter>)
|
||||
(methodGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(methodToCall :
|
||||
WoofWare.PawPrint.MethodInfo<
|
||||
ConcreteTypeHandle,
|
||||
WoofWare.PawPrint.GenericParameter,
|
||||
WoofWare.PawPrint.TypeDefn
|
||||
>)
|
||||
(thread : ThreadId)
|
||||
(threadState : ThreadState)
|
||||
(state : IlMachineState)
|
||||
@@ -757,10 +775,7 @@ module IlMachineState =
|
||||
| Some result -> result
|
||||
| None ->
|
||||
|
||||
let typeGenerics =
|
||||
match methodToCall.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| x -> Some (ImmutableArray.CreateRange x)
|
||||
let typeGenerics = methodToCall.DeclaringType.Generics |> ImmutableArray.CreateRange
|
||||
|
||||
// Get zero values for all parameters
|
||||
let state, argZeroObjects =
|
||||
@@ -783,9 +798,10 @@ module IlMachineState =
|
||||
|
||||
let activeMethodState = threadState.MethodStates.[threadState.ActiveMethodState]
|
||||
|
||||
let methodToCall =
|
||||
let methodToCall, state =
|
||||
methodToCall
|
||||
|> MethodInfo.mapMethodGenerics (fun _ param -> methodGenerics.Value.[param.SequenceNumber])
|
||||
|> MethodInfo.mapMethodGenerics (fun _ param -> methodGenerics.[param.SequenceNumber])
|
||||
|> MethodInfo.mapVarGenerics state (fun state mi -> failwith "TODO")
|
||||
|
||||
// Helper to pop and coerce a single argument
|
||||
let popAndCoerceArg zeroType methodState =
|
||||
@@ -835,7 +851,7 @@ module IlMachineState =
|
||||
// Regular instance method: args then `this`
|
||||
for i = argCount - 1 downto 0 do
|
||||
let arg, newState = popAndCoerceArg argZeroObjects.[i] currentState
|
||||
args.Add (arg)
|
||||
args.Add arg
|
||||
currentState <- newState
|
||||
|
||||
let thisArg, newState =
|
||||
@@ -861,6 +877,7 @@ module IlMachineState =
|
||||
|
||||
match
|
||||
MethodState.Empty
|
||||
state.ConcreteTypes
|
||||
corelib
|
||||
state._LoadedAssemblies
|
||||
(state.ActiveAssembly thread)
|
||||
@@ -904,10 +921,33 @@ module IlMachineState =
|
||||
ThreadState = state.ThreadState |> Map.add thread newThreadState
|
||||
}
|
||||
|
||||
let concretiseType
|
||||
(state : IlMachineState)
|
||||
(corelib : BaseClassTypes<'corelib>)
|
||||
(typeGenerics : _)
|
||||
(methodGenerics : ImmutableArray<TypeDefn>)
|
||||
(ty : AssemblyName * TypeDefn)
|
||||
: ConcreteTypeHandle * IlMachineState
|
||||
=
|
||||
let ct, mapping =
|
||||
DumpedAssembly.concretiseType
|
||||
state.ConcreteTypes
|
||||
corelib
|
||||
getTypeInfo
|
||||
resolveTypeRef
|
||||
typeGenerics
|
||||
methodGenerics
|
||||
ty
|
||||
|
||||
ct.[snd ty],
|
||||
{ state with
|
||||
ConcreteTypes = mapping
|
||||
}
|
||||
|
||||
let rec loadClass
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(ty : RuntimeConcreteType)
|
||||
(ty : ConcreteTypeHandle)
|
||||
(currentThread : ThreadId)
|
||||
(state : IlMachineState)
|
||||
: StateLoadResult
|
||||
@@ -928,15 +968,16 @@ module IlMachineState =
|
||||
"TODO: cross-thread class init synchronization unimplemented - this thread has to wait for the other thread to finish initialisation"
|
||||
| None ->
|
||||
// We have work to do!
|
||||
let ty' = AllConcreteTypes.lookup ty state.ConcreteTypes |> Option.get
|
||||
|
||||
let state, origAssyName =
|
||||
state.WithThreadSwitchedToAssembly ty.Assembly currentThread
|
||||
state.WithThreadSwitchedToAssembly ty'.Assembly currentThread
|
||||
|
||||
let sourceAssembly = state.LoadedAssembly ty.Assembly |> Option.get
|
||||
let sourceAssembly = state.LoadedAssembly ty'.Assembly |> Option.get
|
||||
|
||||
let typeDef =
|
||||
match sourceAssembly.TypeDefs.TryGetValue ty.Definition.Get with
|
||||
| false, _ -> failwith $"Failed to find type definition {ty.Definition.Get} in {ty.Assembly.FullName}"
|
||||
match sourceAssembly.TypeDefs.TryGetValue ty'.Definition.Get with
|
||||
| false, _ -> failwith $"Failed to find type definition {ty'.Definition.Get} in {ty'.Assembly.FullName}"
|
||||
| true, v -> v
|
||||
|
||||
logger.LogDebug ("Resolving type {TypeDefNamespace}.{TypeDefName}", typeDef.Namespace, typeDef.Name)
|
||||
@@ -950,13 +991,15 @@ module IlMachineState =
|
||||
| Some baseTypeInfo ->
|
||||
// Determine if base type is in the same or different assembly
|
||||
match baseTypeInfo with
|
||||
| BaseTypeInfo.ForeignAssemblyType _ -> failwith "TODO"
|
||||
//logger.LogDebug (
|
||||
// "Resolved base type of {TypeDefNamespace}.{TypeDefName} to foreign assembly {ForeignAssemblyName}",
|
||||
// typeDef.Namespace,
|
||||
// typeDef.Name,
|
||||
// baseAssemblyName.Name
|
||||
//)
|
||||
| BaseTypeInfo.ForeignAssemblyType (baseAssemblyName, _) ->
|
||||
logger.LogDebug (
|
||||
"Resolved base type of {TypeDefNamespace}.{TypeDefName} to foreign assembly {ForeignAssemblyName}",
|
||||
typeDef.Namespace,
|
||||
typeDef.Name,
|
||||
baseAssemblyName.Name
|
||||
)
|
||||
|
||||
failwith "TODO"
|
||||
|
||||
//match loadClass loggerFactory baseTypeHandle baseAssemblyName currentThread state with
|
||||
//| FirstLoadThis state -> Error state
|
||||
@@ -969,9 +1012,21 @@ module IlMachineState =
|
||||
)
|
||||
|
||||
// TypeDef won't have any generics; it would be a TypeSpec if it did
|
||||
let ty = ConcreteType.make ty.Assembly ty.Namespace ty.Name typeDefinitionHandle []
|
||||
let cth, ty, concreteTypes =
|
||||
ConcreteType.make
|
||||
state.ConcreteTypes
|
||||
ty'.Assembly
|
||||
ty'.Namespace
|
||||
ty'.Name
|
||||
typeDefinitionHandle
|
||||
[]
|
||||
|
||||
match loadClass loggerFactory corelib ty currentThread state with
|
||||
let state =
|
||||
{ state with
|
||||
ConcreteTypes = concreteTypes
|
||||
}
|
||||
|
||||
match loadClass loggerFactory corelib cth currentThread state with
|
||||
| FirstLoadThis state -> Error state
|
||||
| NothingToDo state -> Ok state
|
||||
| BaseTypeInfo.TypeRef typeReferenceHandle ->
|
||||
@@ -980,7 +1035,7 @@ module IlMachineState =
|
||||
resolveType
|
||||
loggerFactory
|
||||
typeReferenceHandle
|
||||
None
|
||||
ImmutableArray.Empty
|
||||
(state.ActiveAssembly currentThread)
|
||||
state
|
||||
|
||||
@@ -993,10 +1048,21 @@ module IlMachineState =
|
||||
targetType.Name
|
||||
)
|
||||
|
||||
let ty =
|
||||
ConcreteType.make assy.Name targetType.Namespace targetType.Name targetType.TypeDefHandle []
|
||||
let cth, ty, concreteTypes =
|
||||
ConcreteType.make
|
||||
state.ConcreteTypes
|
||||
assy.Name
|
||||
targetType.Namespace
|
||||
targetType.Name
|
||||
targetType.TypeDefHandle
|
||||
[]
|
||||
|
||||
match loadClass loggerFactory corelib ty currentThread state with
|
||||
let state =
|
||||
{ state with
|
||||
ConcreteTypes = concreteTypes
|
||||
}
|
||||
|
||||
match loadClass loggerFactory corelib cth currentThread state with
|
||||
| FirstLoadThis state -> Error state
|
||||
| NothingToDo state -> Ok state
|
||||
| BaseTypeInfo.TypeSpec typeSpecificationHandle ->
|
||||
@@ -1021,10 +1087,25 @@ module IlMachineState =
|
||||
// TODO: factor out the common bit.
|
||||
let currentThreadState = state.ThreadState.[currentThread]
|
||||
|
||||
let cctorMethod =
|
||||
let cctorMethod, state =
|
||||
cctorMethod
|
||||
|> MethodInfo.mapTypeGenerics (fun i _ -> ty.Generics.[i])
|
||||
|> MethodInfo.mapTypeGenerics (fun i _ -> ty'.Generics.[i])
|
||||
|> MethodInfo.mapMethodGenerics (fun _ -> failwith "cctor cannot be generic")
|
||||
|> MethodInfo.mapVarGenerics
|
||||
state
|
||||
(fun state v ->
|
||||
let ty, state =
|
||||
DumpedAssembly.concretiseType
|
||||
state.ConcreteTypes
|
||||
corelib
|
||||
(failwith "")
|
||||
(failwith "")
|
||||
(failwith "")
|
||||
ImmutableArray.Empty
|
||||
(failwith "")
|
||||
|
||||
ty.[v], state
|
||||
)
|
||||
|
||||
callMethod
|
||||
loggerFactory
|
||||
@@ -1034,7 +1115,7 @@ module IlMachineState =
|
||||
true
|
||||
true
|
||||
// constructor is surely not generic
|
||||
None
|
||||
ImmutableArray.Empty
|
||||
cctorMethod
|
||||
currentThread
|
||||
currentThreadState
|
||||
@@ -1054,7 +1135,7 @@ module IlMachineState =
|
||||
(loggerFactory : ILoggerFactory)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(thread : ThreadId)
|
||||
(ty : RuntimeConcreteType)
|
||||
(ty : ConcreteTypeHandle)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * WhatWeDid
|
||||
=
|
||||
@@ -1080,8 +1161,8 @@ module IlMachineState =
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(thread : ThreadId)
|
||||
(advanceProgramCounterOfCaller : bool)
|
||||
(methodGenerics : TypeDefn ImmutableArray option)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter>)
|
||||
(methodGenerics : ConcreteTypeHandle ImmutableArray)
|
||||
(methodToCall : WoofWare.PawPrint.MethodInfo<ConcreteTypeHandle, WoofWare.PawPrint.GenericParameter, _>)
|
||||
(weAreConstructingObj : ManagedHeapAddress option)
|
||||
(state : IlMachineState)
|
||||
: IlMachineState * WhatWeDid
|
||||
@@ -1089,7 +1170,12 @@ module IlMachineState =
|
||||
let threadState = state.ThreadState.[thread]
|
||||
|
||||
let state, typeInit =
|
||||
ensureTypeInitialised loggerFactory corelib thread methodToCall.DeclaringType state
|
||||
let declaringTypeHandle =
|
||||
state.ConcreteTypes
|
||||
|> AllConcreteTypes.lookup' methodToCall.DeclaringType
|
||||
|> Option.get
|
||||
|
||||
ensureTypeInitialised loggerFactory corelib thread declaringTypeHandle state
|
||||
|
||||
match typeInit with
|
||||
| WhatWeDid.Executed ->
|
||||
@@ -1130,6 +1216,7 @@ module IlMachineState =
|
||||
TypeInitTable = ImmutableDictionary.Empty
|
||||
DotnetRuntimeDirs = dotnetRuntimeDirs
|
||||
TypeHandles = TypeHandleRegistry.empty ()
|
||||
ConcreteTypes = AllConcreteTypes.Empty
|
||||
}
|
||||
|
||||
state.WithLoadedAssembly assyName entryAssembly
|
||||
@@ -1277,8 +1364,8 @@ module IlMachineState =
|
||||
: IlMachineState *
|
||||
AssemblyName *
|
||||
Choice<
|
||||
WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter>,
|
||||
WoofWare.PawPrint.FieldInfo<TypeDefn>
|
||||
WoofWare.PawPrint.MethodInfo<TypeDefn, WoofWare.PawPrint.GenericParameter, TypeDefn>,
|
||||
WoofWare.PawPrint.FieldInfo<TypeDefn, TypeDefn>
|
||||
>
|
||||
=
|
||||
// TODO: do we need to initialise the parent class here?
|
||||
@@ -1288,17 +1375,15 @@ module IlMachineState =
|
||||
|
||||
let state, assy, targetType =
|
||||
match mem.Parent with
|
||||
| MetadataToken.TypeReference parent -> resolveType loggerFactory parent None assy state
|
||||
| MetadataToken.TypeReference parent -> resolveType loggerFactory parent ImmutableArray.Empty assy state
|
||||
| MetadataToken.TypeSpecification parent ->
|
||||
let executing = state.ThreadState.[currentThread].MethodState.ExecutingMethod
|
||||
|
||||
let typeGenerics =
|
||||
match executing.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| l -> Some (ImmutableArray.CreateRange l)
|
||||
let typeGenerics = executing.DeclaringType.Generics |> ImmutableArray.CreateRange
|
||||
|
||||
let methodGenerics = executing.Generics
|
||||
|
||||
// TODO: I think this really does want to be the TypeDefn version
|
||||
resolveTypeFromSpec loggerFactory corelib parent assy typeGenerics methodGenerics state
|
||||
| parent -> failwith $"Unexpected: {parent}"
|
||||
|
||||
@@ -1438,15 +1523,12 @@ module IlMachineState =
|
||||
result, state
|
||||
|
||||
let setStatic
|
||||
(ty : RuntimeConcreteType)
|
||||
(ty : ConcreteTypeHandle)
|
||||
(field : string)
|
||||
(value : CliType)
|
||||
(this : IlMachineState)
|
||||
: IlMachineState
|
||||
=
|
||||
// Static variables are shared among all instantiations of a generic type.
|
||||
let ty = ty |> ConcreteType.mapGeneric (fun _ _ -> FakeUnit.ofUnit ())
|
||||
|
||||
let statics =
|
||||
match this._Statics.TryGetValue ty with
|
||||
| false, _ -> this._Statics.Add (ty, ImmutableDictionary.Create().Add (field, value))
|
||||
@@ -1456,10 +1538,7 @@ module IlMachineState =
|
||||
_Statics = statics
|
||||
}
|
||||
|
||||
let getStatic (ty : RuntimeConcreteType) (field : string) (this : IlMachineState) : CliType option =
|
||||
// Static variables are shared among all instantiations of a generic type.
|
||||
let ty = ty |> ConcreteType.mapGeneric (fun _ _ -> FakeUnit.ofUnit ())
|
||||
|
||||
let getStatic (ty : ConcreteTypeHandle) (field : string) (this : IlMachineState) : CliType option =
|
||||
match this._Statics.TryGetValue ty with
|
||||
| false, _ -> None
|
||||
| true, v ->
|
||||
|
@@ -6,7 +6,7 @@ type MethodReturnState =
|
||||
{
|
||||
/// Index in the MethodStates array of a ThreadState
|
||||
JumpTo : int
|
||||
WasInitialisingType : RuntimeConcreteType option
|
||||
WasInitialisingType : ConcreteTypeHandle option
|
||||
/// The Newobj instruction means we need to push a reference immediately after Ret.
|
||||
WasConstructingObj : ManagedHeapAddress option
|
||||
}
|
||||
@@ -19,12 +19,12 @@ and MethodState =
|
||||
_IlOpIndex : int
|
||||
EvaluationStack : EvalStack
|
||||
Arguments : CliType ImmutableArray
|
||||
ExecutingMethod : WoofWare.PawPrint.MethodInfo<TypeDefn, TypeDefn>
|
||||
ExecutingMethod : WoofWare.PawPrint.MethodInfo<ConcreteTypeHandle, ConcreteTypeHandle, ConcreteTypeHandle>
|
||||
/// We don't implement the local memory pool right now
|
||||
LocalMemoryPool : unit
|
||||
/// On return, we restore this state. This should be Some almost always; an exception is the entry point.
|
||||
ReturnState : MethodReturnState option
|
||||
Generics : ImmutableArray<TypeDefn> option
|
||||
Generics : ImmutableArray<ConcreteTypeHandle>
|
||||
/// Track which exception regions are currently active (innermost first)
|
||||
ActiveExceptionRegions : ExceptionRegion list
|
||||
/// When executing a finally/fault/filter, we need to know where to return
|
||||
@@ -136,11 +136,12 @@ and MethodState =
|
||||
/// If `method` is an instance method, `args` must be of length 1+numParams.
|
||||
/// If `method` is static, `args` must be of length numParams.
|
||||
static member Empty
|
||||
(types : AllConcreteTypes)
|
||||
(corelib : BaseClassTypes<DumpedAssembly>)
|
||||
(loadedAssemblies : ImmutableDictionary<string, DumpedAssembly>)
|
||||
(containingAssembly : DumpedAssembly)
|
||||
(method : WoofWare.PawPrint.MethodInfo<TypeDefn, TypeDefn>)
|
||||
(methodGenerics : ImmutableArray<TypeDefn> option)
|
||||
(method : WoofWare.PawPrint.MethodInfo<ConcreteTypeHandle, ConcreteTypeHandle, ConcreteTypeHandle>)
|
||||
(methodGenerics : ImmutableArray<ConcreteTypeHandle>)
|
||||
(args : ImmutableArray<CliType>)
|
||||
(returnState : MethodReturnState option)
|
||||
: Result<MethodState, WoofWare.PawPrint.AssemblyReference list>
|
||||
@@ -166,19 +167,11 @@ and MethodState =
|
||||
|
||||
let requiredAssemblies = ResizeArray<WoofWare.PawPrint.AssemblyReference> ()
|
||||
|
||||
let typeGenerics =
|
||||
match method.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| x -> ImmutableArray.CreateRange x |> Some
|
||||
|
||||
let localVars =
|
||||
let result = ImmutableArray.CreateBuilder ()
|
||||
|
||||
for var in localVariableSig do
|
||||
match CliType.zeroOf loadedAssemblies corelib containingAssembly typeGenerics methodGenerics var with
|
||||
| CliTypeResolutionResult.Resolved t -> result.Add t
|
||||
| CliTypeResolutionResult.FirstLoad (assy : WoofWare.PawPrint.AssemblyReference) ->
|
||||
requiredAssemblies.Add assy
|
||||
CliType.zeroOf types var |> result.Add
|
||||
|
||||
result.ToImmutable ()
|
||||
|
||||
|
@@ -19,7 +19,7 @@ module Program =
|
||||
||> Seq.mapFold (fun state arg ->
|
||||
IlMachineState.allocateManagedObject
|
||||
(corelib.String
|
||||
|> TypeInfo.mapGeneric (fun _ _ -> failwith<unit> "there are no generics here"))
|
||||
|> TypeInfo.mapGeneric (fun _ _ -> failwith "there are no generics here"))
|
||||
(failwith "TODO: assert fields and populate")
|
||||
state
|
||||
// TODO: set the char values in memory
|
||||
@@ -88,11 +88,17 @@ module Program =
|
||||
if mainMethod.Signature.GenericParameterCount > 0 then
|
||||
failwith "Refusing to execute generic main method"
|
||||
|
||||
let mainMethod =
|
||||
let state = IlMachineState.initial loggerFactory dotnetRuntimeDirs dumped
|
||||
|
||||
let mainMethod' =
|
||||
mainMethod
|
||||
|> MethodInfo.mapTypeGenerics (fun _ -> failwith "Refusing to execute generic main method")
|
||||
|> MethodInfo.mapMethodGenerics (fun _ -> failwith "Refusing to execute generic main method")
|
||||
|
||||
let mainMethod, state =
|
||||
mainMethod'
|
||||
|> MethodInfo.mapVarGenerics state (fun state generic -> failwith "")
|
||||
|
||||
let rec computeState (baseClassTypes : BaseClassTypes<DumpedAssembly> option) (state : IlMachineState) =
|
||||
// The thread's state is slightly fake: we will need to put arguments onto the stack before actually
|
||||
// executing the main method.
|
||||
@@ -101,14 +107,15 @@ module Program =
|
||||
// Once we've obtained e.g. the String and Array classes, we can populate the args array.
|
||||
match
|
||||
MethodState.Empty
|
||||
state.ConcreteTypes
|
||||
(Option.toObj baseClassTypes)
|
||||
state._LoadedAssemblies
|
||||
dumped
|
||||
// pretend there are no instructions, so we avoid preparing anything
|
||||
{ mainMethod with
|
||||
Instructions = Some MethodInstructions.OnlyRet
|
||||
Instructions = Some (MethodInstructions.onlyRet ())
|
||||
}
|
||||
None
|
||||
ImmutableArray.Empty
|
||||
(ImmutableArray.CreateRange [ CliType.ObjectRef None ])
|
||||
None
|
||||
with
|
||||
@@ -136,9 +143,7 @@ module Program =
|
||||
|
||||
computeState corelib state
|
||||
|
||||
let (state, mainThread), baseClassTypes =
|
||||
IlMachineState.initial loggerFactory dotnetRuntimeDirs dumped
|
||||
|> computeState None
|
||||
let (state, mainThread), baseClassTypes = state |> computeState None
|
||||
|
||||
let rec loadInitialState (state : IlMachineState) =
|
||||
match
|
||||
@@ -146,7 +151,8 @@ module Program =
|
||||
|> IlMachineState.loadClass
|
||||
loggerFactory
|
||||
(Option.toObj baseClassTypes)
|
||||
mainMethod.DeclaringType
|
||||
(AllConcreteTypes.lookup' mainMethod.DeclaringType state.ConcreteTypes
|
||||
|> Option.get)
|
||||
mainThread
|
||||
with
|
||||
| StateLoadResult.NothingToDo ilMachineState -> ilMachineState
|
||||
@@ -167,12 +173,12 @@ module Program =
|
||||
| Some c -> c
|
||||
|
||||
let arrayAllocation, state =
|
||||
match mainMethod.Signature.ParameterTypes |> Seq.toList with
|
||||
match mainMethod'.Signature.ParameterTypes |> Seq.toList with
|
||||
| [ TypeDefn.OneDimensionalArrayLowerBoundZero (TypeDefn.PrimitiveType PrimitiveType.String) ] ->
|
||||
allocateArgs argv baseClassTypes state
|
||||
| _ -> failwith "Main method must take an array of strings; other signatures not yet implemented"
|
||||
|
||||
match mainMethod.Signature.ReturnType with
|
||||
match mainMethod'.Signature.ReturnType with
|
||||
| TypeDefn.PrimitiveType PrimitiveType.Int32 -> ()
|
||||
| _ -> failwith "Main method must return int32; other types not currently supported"
|
||||
|
||||
@@ -189,11 +195,12 @@ module Program =
|
||||
let methodState =
|
||||
match
|
||||
MethodState.Empty
|
||||
state.ConcreteTypes
|
||||
baseClassTypes
|
||||
state._LoadedAssemblies
|
||||
dumped
|
||||
mainMethod
|
||||
None
|
||||
ImmutableArray.Empty
|
||||
(ImmutableArray.Create (CliType.OfManagedObject arrayAllocation))
|
||||
None
|
||||
with
|
||||
@@ -214,7 +221,8 @@ module Program =
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
mainThread
|
||||
methodState.ExecutingMethod.DeclaringType
|
||||
(AllConcreteTypes.lookup' methodState.ExecutingMethod.DeclaringType state.ConcreteTypes
|
||||
|> Option.get)
|
||||
|
||||
match init with
|
||||
| WhatWeDid.SuspendedForClassInit -> failwith "TODO: suspended for class init"
|
||||
|
@@ -9,21 +9,21 @@ type TypeInitState =
|
||||
|
||||
/// Tracks the initialization state of types across assemblies. The string in the key is the FullName of the AssemblyName where the type comes from.
|
||||
// TODO: need a better solution than string here! AssemblyName didn't work, we had nonequal assembly names.
|
||||
type TypeInitTable = ImmutableDictionary<RuntimeConcreteType, TypeInitState>
|
||||
type TypeInitTable = ImmutableDictionary<ConcreteTypeHandle, TypeInitState>
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module TypeInitTable =
|
||||
let tryGet (ty : RuntimeConcreteType) (t : TypeInitTable) =
|
||||
let tryGet (ty : ConcreteTypeHandle) (t : TypeInitTable) =
|
||||
match t.TryGetValue ty with
|
||||
| true, v -> Some v
|
||||
| false, _ -> None
|
||||
|
||||
let beginInitialising (thread : ThreadId) (ty : RuntimeConcreteType) (t : TypeInitTable) : TypeInitTable =
|
||||
let beginInitialising (thread : ThreadId) (ty : ConcreteTypeHandle) (t : TypeInitTable) : TypeInitTable =
|
||||
match t.TryGetValue ty with
|
||||
| false, _ -> t.Add (ty, TypeInitState.InProgress thread)
|
||||
| true, v -> failwith "Logic error: tried initialising a type which has already started initialising"
|
||||
|
||||
let markInitialised (thread : ThreadId) (ty : RuntimeConcreteType) (t : TypeInitTable) : TypeInitTable =
|
||||
let markInitialised (thread : ThreadId) (ty : ConcreteTypeHandle) (t : TypeInitTable) : TypeInitTable =
|
||||
match t.TryGetValue ty with
|
||||
| false, _ -> failwith "Logic error: completing initialisation of a type which never started initialising"
|
||||
| true, TypeInitState.Initialized ->
|
||||
|
@@ -31,7 +31,7 @@ module internal UnaryMetadataIlOp =
|
||||
activeAssy.Methods.[token]
|
||||
|> MethodInfo.mapTypeGenerics (fun i _ -> spec.Signature.[i])
|
||||
|
||||
state, method, Some spec.Signature
|
||||
state, method, spec.Signature
|
||||
| MetadataToken.MemberReference ref ->
|
||||
let state, _, method =
|
||||
IlMachineState.resolveMember
|
||||
@@ -44,7 +44,7 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
match method with
|
||||
| Choice2Of2 _field -> failwith "tried to Call a field"
|
||||
| Choice1Of2 method -> state, method, Some spec.Signature
|
||||
| Choice1Of2 method -> state, method, spec.Signature
|
||||
| k -> failwith $"Unrecognised kind: %O{k}"
|
||||
| MetadataToken.MemberReference h ->
|
||||
let state, _, method =
|
||||
@@ -58,13 +58,13 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
match method with
|
||||
| Choice2Of2 _field -> failwith "tried to Call a field"
|
||||
| Choice1Of2 method -> state, method, None
|
||||
| Choice1Of2 method -> state, method, ImmutableArray.Empty
|
||||
|
||||
| MetadataToken.MethodDef defn ->
|
||||
match activeAssy.Methods.TryGetValue defn with
|
||||
| true, method ->
|
||||
let method = method |> MethodInfo.mapTypeGenerics (fun _ -> failwith "not generic")
|
||||
state, method, None
|
||||
state, method, ImmutableArray.Empty
|
||||
| false, _ -> failwith $"could not find method in {activeAssy.Name}"
|
||||
| k -> failwith $"Unrecognised kind: %O{k}"
|
||||
|
||||
@@ -96,7 +96,7 @@ module internal UnaryMetadataIlOp =
|
||||
activeAssy.Methods.[token]
|
||||
|> MethodInfo.mapTypeGenerics (fun i _ -> spec.Signature.[i])
|
||||
|
||||
state, method, Some spec.Signature
|
||||
state, method, spec.Signature
|
||||
| MetadataToken.MemberReference ref ->
|
||||
let state, _, method =
|
||||
IlMachineState.resolveMember
|
||||
@@ -109,7 +109,7 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
match method with
|
||||
| Choice2Of2 _field -> failwith "tried to Callvirt a field"
|
||||
| Choice1Of2 method -> state, method, Some spec.Signature
|
||||
| Choice1Of2 method -> state, method, spec.Signature
|
||||
| k -> failwith $"Unrecognised kind: %O{k}"
|
||||
| MetadataToken.MemberReference h ->
|
||||
let state, _, method =
|
||||
@@ -123,13 +123,13 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
match method with
|
||||
| Choice2Of2 _field -> failwith "tried to Callvirt a field"
|
||||
| Choice1Of2 method -> state, method, None
|
||||
| Choice1Of2 method -> state, method, ImmutableArray.Empty
|
||||
|
||||
| MetadataToken.MethodDef defn ->
|
||||
match activeAssy.Methods.TryGetValue defn with
|
||||
| true, method ->
|
||||
let method = method |> MethodInfo.mapTypeGenerics (fun _ -> failwith "not generic")
|
||||
state, method, None
|
||||
state, method, ImmutableArray.Empty
|
||||
| false, _ -> failwith $"could not find method in {activeAssy.Name}"
|
||||
| k -> failwith $"Unrecognised kind: %O{k}"
|
||||
|
||||
@@ -183,10 +183,7 @@ module internal UnaryMetadataIlOp =
|
||||
ctorType.Name
|
||||
)
|
||||
|
||||
let typeGenerics =
|
||||
match ctor.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| l -> Some (ImmutableArray.CreateRange l)
|
||||
let typeGenerics = ctor.DeclaringType.Generics |> ImmutableArray.CreateRange
|
||||
|
||||
let state, fieldZeros =
|
||||
((state, []), ctorType.Fields)
|
||||
@@ -199,7 +196,7 @@ module internal UnaryMetadataIlOp =
|
||||
ctorAssembly
|
||||
field.Signature
|
||||
typeGenerics
|
||||
None
|
||||
ImmutableArray.Empty
|
||||
state
|
||||
|
||||
state, (field.Name, zero) :: zeros
|
||||
@@ -229,7 +226,7 @@ module internal UnaryMetadataIlOp =
|
||||
baseClassTypes
|
||||
thread
|
||||
true
|
||||
None
|
||||
ImmutableArray.Empty
|
||||
ctor
|
||||
(Some allocatedAddr)
|
||||
|
||||
@@ -255,9 +252,8 @@ module internal UnaryMetadataIlOp =
|
||||
| popped -> failwith $"unexpectedly popped value %O{popped} to serve as array len"
|
||||
|
||||
let typeGenerics =
|
||||
match newMethodState.ExecutingMethod.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| l -> Some (ImmutableArray.CreateRange l)
|
||||
newMethodState.ExecutingMethod.DeclaringType.Generics
|
||||
|> ImmutableArray.CreateRange
|
||||
|
||||
let state, elementType, assy =
|
||||
match metadataToken with
|
||||
@@ -456,10 +452,7 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
let valueToStore, state = IlMachineState.popEvalStack thread state
|
||||
|
||||
let typeGenerics =
|
||||
match field.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| l -> Some (ImmutableArray.CreateRange l)
|
||||
let typeGenerics = field.DeclaringType.Generics |> ImmutableArray.CreateRange
|
||||
|
||||
let state, zero =
|
||||
IlMachineState.cliTypeZeroOf
|
||||
@@ -468,7 +461,7 @@ module internal UnaryMetadataIlOp =
|
||||
(state.ActiveAssembly thread)
|
||||
field.Signature
|
||||
typeGenerics
|
||||
None // field can't have its own generics
|
||||
ImmutableArray.Empty // field can't have its own generics
|
||||
state
|
||||
|
||||
let valueToStore = EvalStackValue.toCliTypeCoerced zero valueToStore
|
||||
@@ -581,7 +574,7 @@ module internal UnaryMetadataIlOp =
|
||||
activeAssy
|
||||
field.Signature
|
||||
typeGenerics
|
||||
None // field can't have its own generics
|
||||
ImmutableArray.Empty // field can't have its own generics
|
||||
state
|
||||
|
||||
let toStore = EvalStackValue.toCliTypeCoerced zero popped
|
||||
@@ -641,7 +634,7 @@ module internal UnaryMetadataIlOp =
|
||||
(state.LoadedAssembly(field.DeclaringType.Assembly).Value)
|
||||
field.Signature
|
||||
typeGenerics
|
||||
None // field can't have its own generics
|
||||
ImmutableArray.Empty // field can't have its own generics
|
||||
state
|
||||
|
||||
let state = IlMachineState.setStatic field.DeclaringType field.Name zero state
|
||||
@@ -742,7 +735,7 @@ module internal UnaryMetadataIlOp =
|
||||
activeAssy
|
||||
field.Signature
|
||||
typeGenerics
|
||||
None // field can't have its own generics
|
||||
ImmutableArray.Empty // field can't have its own generics
|
||||
state
|
||||
|
||||
newVal, IlMachineState.setStatic field.DeclaringType field.Name newVal state
|
||||
@@ -779,26 +772,28 @@ module internal UnaryMetadataIlOp =
|
||||
let currentMethod = state.ThreadState.[thread].MethodState.ExecutingMethod
|
||||
|
||||
let declaringTypeGenerics =
|
||||
match currentMethod.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| x -> Some (ImmutableArray.CreateRange x)
|
||||
currentMethod.DeclaringType.Generics |> ImmutableArray.CreateRange
|
||||
|
||||
let state, assy, elementType =
|
||||
match metadataToken with
|
||||
| MetadataToken.TypeDefinition defn ->
|
||||
state,
|
||||
assy,
|
||||
assy.TypeDefs.[defn]
|
||||
|> TypeInfo.mapGeneric (fun _ i -> declaringTypeGenerics.Value.[i.SequenceNumber])
|
||||
let ty =
|
||||
assy.TypeDefs.[defn]
|
||||
|> TypeInfo.mapGeneric (fun _ i -> declaringTypeGenerics.[i.SequenceNumber])
|
||||
|
||||
state, assy, ty
|
||||
| MetadataToken.TypeSpecification spec ->
|
||||
IlMachineState.resolveTypeFromSpec
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
spec
|
||||
assy
|
||||
declaringTypeGenerics
|
||||
currentMethod.Generics
|
||||
state
|
||||
let state, assy, ty =
|
||||
IlMachineState.resolveTypeFromSpec
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
spec
|
||||
assy
|
||||
declaringTypeGenerics
|
||||
currentMethod.Generics
|
||||
state
|
||||
|
||||
state, assy, ty
|
||||
| x -> failwith $"TODO: Stelem element type resolution unimplemented for {x}"
|
||||
|
||||
let contents, state = IlMachineState.popEvalStack thread state
|
||||
@@ -838,7 +833,7 @@ module internal UnaryMetadataIlOp =
|
||||
assy
|
||||
elementType
|
||||
declaringTypeGenerics
|
||||
None
|
||||
ImmutableArray.Empty
|
||||
state
|
||||
|
||||
let contents = EvalStackValue.toCliTypeCoerced zeroOfType contents
|
||||
@@ -854,26 +849,28 @@ module internal UnaryMetadataIlOp =
|
||||
let currentMethod = state.ThreadState.[thread].MethodState.ExecutingMethod
|
||||
|
||||
let declaringTypeGenerics =
|
||||
match currentMethod.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| x -> Some (ImmutableArray.CreateRange x)
|
||||
currentMethod.DeclaringType.Generics |> ImmutableArray.CreateRange
|
||||
|
||||
let state, assy, elementType =
|
||||
match metadataToken with
|
||||
| MetadataToken.TypeDefinition defn ->
|
||||
state,
|
||||
assy,
|
||||
assy.TypeDefs.[defn]
|
||||
|> TypeInfo.mapGeneric (fun _ i -> declaringTypeGenerics.Value.[i.SequenceNumber])
|
||||
let ty =
|
||||
assy.TypeDefs.[defn]
|
||||
|> TypeInfo.mapGeneric (fun _ i -> declaringTypeGenerics.[i.SequenceNumber])
|
||||
|
||||
state, assy, ty
|
||||
| MetadataToken.TypeSpecification spec ->
|
||||
IlMachineState.resolveTypeFromSpec
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
spec
|
||||
assy
|
||||
declaringTypeGenerics
|
||||
currentMethod.Generics
|
||||
state
|
||||
let state, assy, ty =
|
||||
IlMachineState.resolveTypeFromSpec
|
||||
loggerFactory
|
||||
baseClassTypes
|
||||
spec
|
||||
assy
|
||||
declaringTypeGenerics
|
||||
currentMethod.Generics
|
||||
state
|
||||
|
||||
state, assy, ty
|
||||
| x -> failwith $"TODO: Ldelem element type resolution unimplemented for {x}"
|
||||
|
||||
let index, state = IlMachineState.popEvalStack thread state
|
||||
@@ -918,21 +915,23 @@ module internal UnaryMetadataIlOp =
|
||||
|> FieldInfo.mapTypeGenerics (fun _ _ -> failwith "generics not allowed on FieldDefinition")
|
||||
| t -> failwith $"Unexpectedly asked to load a non-field: {t}"
|
||||
|
||||
match IlMachineState.loadClass loggerFactory baseClassTypes field.DeclaringType thread state with
|
||||
let declaringTypeHandle =
|
||||
match AllConcreteTypes.lookup' field.DeclaringType state.ConcreteTypes with
|
||||
| None -> failwith "unexpectedly haven't concretised type when loading its field"
|
||||
| Some t -> t
|
||||
|
||||
match IlMachineState.loadClass loggerFactory baseClassTypes declaringTypeHandle thread state with
|
||||
| FirstLoadThis state -> state, WhatWeDid.SuspendedForClassInit
|
||||
| NothingToDo state ->
|
||||
|
||||
if TypeDefn.isManaged field.Signature then
|
||||
match IlMachineState.getStatic field.DeclaringType field.Name state with
|
||||
match IlMachineState.getStatic declaringTypeHandle field.Name state with
|
||||
| Some v ->
|
||||
IlMachineState.pushToEvalStack v thread state
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| None ->
|
||||
let typeGenerics =
|
||||
match field.DeclaringType.Generics with
|
||||
| [] -> None
|
||||
| l -> Some (ImmutableArray.CreateRange l)
|
||||
let typeGenerics = field.DeclaringType.Generics |> ImmutableArray.CreateRange
|
||||
|
||||
// Field is not yet initialised
|
||||
let state, zero =
|
||||
@@ -942,10 +941,10 @@ module internal UnaryMetadataIlOp =
|
||||
activeAssy
|
||||
field.Signature
|
||||
typeGenerics
|
||||
None // field can't have its own generics
|
||||
ImmutableArray.Empty // field can't have its own generics
|
||||
state
|
||||
|
||||
IlMachineState.setStatic field.DeclaringType field.Name zero state
|
||||
IlMachineState.setStatic declaringTypeHandle field.Name zero state
|
||||
|> IlMachineState.pushToEvalStack (CliType.ObjectRef None) thread
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
@@ -1001,9 +1000,7 @@ module internal UnaryMetadataIlOp =
|
||||
|
||||
let currentMethod = state.ThreadState.[thread].MethodState
|
||||
|
||||
let methodGenerics =
|
||||
currentMethod.Generics |> Option.defaultValue ImmutableArray.Empty
|
||||
|
||||
let methodGenerics = currentMethod.Generics
|
||||
let typeGenerics = currentMethod.ExecutingMethod.DeclaringType.Generics
|
||||
|
||||
if not (methodGenerics.IsEmpty && typeGenerics.IsEmpty) then
|
||||
|
@@ -54,7 +54,7 @@ module internal UnaryStringTokenIlOp =
|
||||
let addr, state =
|
||||
IlMachineState.allocateManagedObject
|
||||
(baseClassTypes.String
|
||||
|> TypeInfo.mapGeneric (fun _ _ -> failwith<unit> "string is not generic"))
|
||||
|> TypeInfo.mapGeneric (fun _ _ -> failwith "string is not generic"))
|
||||
fields
|
||||
state
|
||||
|
||||
|
Reference in New Issue
Block a user