mirror of
https://github.com/Smaug123/WoofWare.PawPrint
synced 2025-10-06 14:38:40 +00:00
Ldtoken (for types) (#49)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace HelloWorldApp
|
||||
@@ -7,12 +8,8 @@ namespace HelloWorldApp
|
||||
{
|
||||
static int Main(string[] args)
|
||||
{
|
||||
var l = new List<int>();
|
||||
l.Add(3);
|
||||
l.Add(100);
|
||||
var m = l.Select(x => x.ToString()).ToList();
|
||||
// 2 + 103 + (1 + 3) = 109
|
||||
return m.Count + l.Sum() + m.Select(x => x.Length).Sum();
|
||||
Console.WriteLine("Hello");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -6,3 +6,14 @@ type ThreadId =
|
||||
override this.ToString () =
|
||||
match this with
|
||||
| ThreadId.ThreadId i -> $"%i{i}"
|
||||
|
||||
/// Currently this is just an opaque handle; it can't be treated as a pointer.
|
||||
type ManagedHeapAddress =
|
||||
| ManagedHeapAddress of int
|
||||
|
||||
override this.ToString () : string =
|
||||
match this with
|
||||
| ManagedHeapAddress.ManagedHeapAddress i -> $"<object #%i{i}>"
|
||||
|
||||
[<Measure>]
|
||||
type typeHandle
|
||||
|
@@ -5,14 +5,6 @@ open System.Collections.Immutable
|
||||
open System.Reflection
|
||||
open System.Reflection.Metadata
|
||||
|
||||
/// Currently this is just an opaque handle; it can't be treated as a pointer.
|
||||
type ManagedHeapAddress =
|
||||
| ManagedHeapAddress of int
|
||||
|
||||
override this.ToString () : string =
|
||||
match this with
|
||||
| ManagedHeapAddress.ManagedHeapAddress i -> $"<object #%i{i}>"
|
||||
|
||||
/// Source:
|
||||
/// Table I.6: Data Types Directly Supported by the CLI
|
||||
type CliSupportedObject =
|
||||
@@ -58,6 +50,8 @@ type CliNumericType =
|
||||
| Float64 of float
|
||||
/// Not a real CLI numeric type! Represents an int64 obtained by taking a NativeInt from the eval stack.
|
||||
| ProvenanceTrackedNativeInt64 of MethodInfo<FakeUnit, WoofWare.PawPrint.GenericParameter>
|
||||
/// Not a real CLI numeric type! An opaque TypeHandle pointer.
|
||||
| TypeHandlePtr of int64<typeHandle>
|
||||
|
||||
type CliValueType =
|
||||
private
|
||||
|
@@ -20,6 +20,7 @@ type NativeIntSource =
|
||||
| Verbatim of int64
|
||||
| ManagedPointer of ManagedPointerSource
|
||||
| FunctionPointer of MethodInfo<FakeUnit, GenericParameter>
|
||||
| TypeHandlePtr of int64<typeHandle>
|
||||
|
||||
override this.ToString () : string =
|
||||
match this with
|
||||
@@ -27,12 +28,14 @@ type NativeIntSource =
|
||||
| NativeIntSource.ManagedPointer ptr -> $"<managed pointer {ptr}>"
|
||||
| NativeIntSource.FunctionPointer methodDefinition ->
|
||||
$"<pointer to {methodDefinition.Name} in {methodDefinition.DeclaringType.Assembly.Name}>"
|
||||
| NativeIntSource.TypeHandlePtr ptr -> $"<type ID %i{ptr}>"
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module NativeIntSource =
|
||||
let isZero (n : NativeIntSource) : bool =
|
||||
match n with
|
||||
| NativeIntSource.Verbatim i -> i = 0L
|
||||
| NativeIntSource.TypeHandlePtr _ -> false
|
||||
| NativeIntSource.FunctionPointer _ -> failwith "TODO"
|
||||
| NativeIntSource.ManagedPointer src ->
|
||||
match src with
|
||||
@@ -43,6 +46,7 @@ module NativeIntSource =
|
||||
match n with
|
||||
| NativeIntSource.Verbatim i -> i >= 0L
|
||||
| NativeIntSource.FunctionPointer _ -> failwith "TODO"
|
||||
| NativeIntSource.TypeHandlePtr _ -> true
|
||||
| NativeIntSource.ManagedPointer _ -> true
|
||||
|
||||
/// True if a < b.
|
||||
@@ -106,6 +110,7 @@ module EvalStackValue =
|
||||
failwith "todo"
|
||||
| NativeIntSource.ManagedPointer _ -> failwith "TODO"
|
||||
| NativeIntSource.FunctionPointer _ -> failwith "TODO"
|
||||
| NativeIntSource.TypeHandlePtr _ -> failwith "TODO"
|
||||
| EvalStackValue.Float f -> failwith "todo"
|
||||
| EvalStackValue.ManagedPointer managedPointerSource ->
|
||||
UnsignedNativeIntSource.FromManagedPointer managedPointerSource |> Some
|
||||
@@ -159,6 +164,7 @@ module EvalStackValue =
|
||||
| EvalStackValue.Int32 i -> CliType.Numeric (CliNumericType.Int32 i)
|
||||
| EvalStackValue.UserDefinedValueType [ popped ] -> toCliTypeCoerced target popped
|
||||
| i -> failwith $"TODO: %O{i}"
|
||||
| CliNumericType.TypeHandlePtr _
|
||||
| CliNumericType.ProvenanceTrackedNativeInt64 _
|
||||
| CliNumericType.Int64 _ ->
|
||||
match popped with
|
||||
@@ -169,6 +175,7 @@ module EvalStackValue =
|
||||
| NativeIntSource.ManagedPointer ptr -> failwith "TODO"
|
||||
| NativeIntSource.FunctionPointer f ->
|
||||
CliType.Numeric (CliNumericType.ProvenanceTrackedNativeInt64 f)
|
||||
| NativeIntSource.TypeHandlePtr f -> CliType.Numeric (CliNumericType.TypeHandlePtr f)
|
||||
| i -> failwith $"TODO: %O{i}"
|
||||
| CliNumericType.NativeInt int64 -> failwith "todo"
|
||||
| CliNumericType.NativeFloat f -> failwith "todo"
|
||||
@@ -215,6 +222,7 @@ module EvalStackValue =
|
||||
| NativeIntSource.Verbatim 0L -> CliType.ObjectRef None
|
||||
| NativeIntSource.Verbatim i -> failwith $"refusing to interpret verbatim native int {i} as a pointer"
|
||||
| NativeIntSource.FunctionPointer _ -> failwith "TODO"
|
||||
| NativeIntSource.TypeHandlePtr _ -> failwith "refusing to interpret type handle ID as an object ref"
|
||||
| NativeIntSource.ManagedPointer ptr ->
|
||||
match ptr with
|
||||
| ManagedPointerSource.Null -> CliType.ObjectRef None
|
||||
@@ -263,6 +271,7 @@ module EvalStackValue =
|
||||
CliType.RuntimePointer (CliRuntimePointer.Managed (CliRuntimePointerSource.Argument (a, b, c)))
|
||||
| NativeIntSource.FunctionPointer methodInfo ->
|
||||
CliType.Numeric (CliNumericType.ProvenanceTrackedNativeInt64 methodInfo)
|
||||
| NativeIntSource.TypeHandlePtr int64 -> failwith "todo"
|
||||
| _ -> failwith $"TODO: %O{popped}"
|
||||
| CliType.Char _ ->
|
||||
match popped with
|
||||
@@ -301,6 +310,7 @@ module EvalStackValue =
|
||||
| CliNumericType.NativeFloat f -> EvalStackValue.Float f
|
||||
| CliNumericType.ProvenanceTrackedNativeInt64 f ->
|
||||
EvalStackValue.NativeInt (NativeIntSource.FunctionPointer f)
|
||||
| CliNumericType.TypeHandlePtr f -> EvalStackValue.NativeInt (NativeIntSource.TypeHandlePtr f)
|
||||
| CliType.ObjectRef i ->
|
||||
match i with
|
||||
| None -> EvalStackValue.ManagedPointer ManagedPointerSource.Null
|
||||
|
@@ -25,6 +25,7 @@ type IlMachineState =
|
||||
/// 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>>
|
||||
DotnetRuntimeDirs : string ImmutableArray
|
||||
TypeHandles : TypeHandleRegistry
|
||||
}
|
||||
|
||||
member this.WithTypeBeginInit (thread : ThreadId) (ty : RuntimeConcreteType) =
|
||||
@@ -547,15 +548,50 @@ module IlMachineState =
|
||||
match methodToCall.DeclaringType.Assembly.Name, methodToCall.DeclaringType.Name, methodToCall.Name with
|
||||
| "System.Private.CoreLib", "Type", "get_TypeHandle" ->
|
||||
// https://github.com/dotnet/runtime/blob/ec11903827fc28847d775ba17e0cd1ff56cfbc2e/src/libraries/System.Private.CoreLib/src/System/Type.cs#L470
|
||||
// no args, returns RuntimeTypeHandle, a struct with a single field
|
||||
let desiredType = baseClassTypes.RuntimeTypeHandle
|
||||
let resultField = desiredType.Fields |> List.exactlyOne
|
||||
// no args, returns RuntimeTypeHandle, a struct with a single field (a RuntimeType class)
|
||||
|
||||
if resultField.Name <> "m_type" then
|
||||
failwith $"unexpected field name {resultField.Name}"
|
||||
// The thing on top of the stack will be a RuntimeType.
|
||||
let arg, state = popEvalStack currentThread state
|
||||
|
||||
let resultFieldType = resultField.Signature
|
||||
failwith "TODO"
|
||||
let arg =
|
||||
let rec go (arg : EvalStackValue) =
|
||||
match arg with
|
||||
| EvalStackValue.UserDefinedValueType [ s ] -> go s
|
||||
| EvalStackValue.ManagedPointer ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||
| EvalStackValue.ManagedPointer (ManagedPointerSource.Heap addr) -> Some addr
|
||||
| s -> failwith $"TODO: called with unrecognised arg %O{s}"
|
||||
|
||||
go arg
|
||||
|
||||
let state =
|
||||
pushToEvalStack (CliType.ValueType [ CliType.ObjectRef arg ]) currentThread state
|
||||
|> advanceProgramCounter currentThread
|
||||
|
||||
Some state
|
||||
| "System.Private.CoreLib", "Unsafe", "AsPointer" ->
|
||||
// Method signature: 1 generic parameter, we take a Byref of that parameter, and return a TypeDefn.Pointer(Void)
|
||||
let arg, state = popEvalStack currentThread state
|
||||
|
||||
let toPush =
|
||||
match arg with
|
||||
| EvalStackValue.ManagedPointer ptr ->
|
||||
match ptr with
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
CliRuntimePointer.Managed (
|
||||
CliRuntimePointerSource.LocalVariable (sourceThread, methodFrame, whichVar)
|
||||
)
|
||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
||||
CliRuntimePointer.Managed (
|
||||
CliRuntimePointerSource.Argument (sourceThread, methodFrame, whichVar)
|
||||
)
|
||||
| ManagedPointerSource.Heap managedHeapAddress ->
|
||||
CliRuntimePointer.Managed (CliRuntimePointerSource.Heap managedHeapAddress)
|
||||
| ManagedPointerSource.Null -> failwith "todo"
|
||||
| x -> failwith $"TODO: Unsafe.AsPointer(%O{x})"
|
||||
|
||||
pushToEvalStack (CliType.RuntimePointer toPush) currentThread state
|
||||
|> advanceProgramCounter currentThread
|
||||
|> Some
|
||||
| "System.Private.CoreLib", "BitConverter", "SingleToInt32Bits" ->
|
||||
let arg, state = popEvalStack currentThread state
|
||||
|
||||
@@ -989,6 +1025,7 @@ module IlMachineState =
|
||||
_Statics = ImmutableDictionary.Empty
|
||||
TypeInitTable = ImmutableDictionary.Empty
|
||||
DotnetRuntimeDirs = dotnetRuntimeDirs
|
||||
TypeHandles = TypeHandleRegistry.empty ()
|
||||
}
|
||||
|
||||
state.WithLoadedAssembly assyName entryAssembly
|
||||
@@ -1197,6 +1234,7 @@ module IlMachineState =
|
||||
let availableMethods =
|
||||
targetType.Methods
|
||||
|> List.filter (fun mi -> mi.Name = memberName)
|
||||
// TODO: this needs to resolve the TypeMethodSignature to e.g. remove references to generic parameters
|
||||
|> List.filter (fun mi -> mi.Signature = memberSig)
|
||||
|
||||
let method =
|
||||
@@ -1287,6 +1325,27 @@ module IlMachineState =
|
||||
ManagedHeap = updatedHeap
|
||||
}
|
||||
|
||||
/// Returns the type handle and an allocated System.RuntimeType.
|
||||
let getOrAllocateType<'corelib>
|
||||
(baseClassTypes : BaseClassTypes<'corelib>)
|
||||
(defn : CanonicalTypeIdentity)
|
||||
(state : IlMachineState)
|
||||
: (int64<typeHandle> * ManagedHeapAddress) * IlMachineState
|
||||
=
|
||||
let result, reg, state =
|
||||
TypeHandleRegistry.getOrAllocate
|
||||
state
|
||||
(fun fields state -> allocateManagedObject baseClassTypes.RuntimeType fields state)
|
||||
defn
|
||||
state.TypeHandles
|
||||
|
||||
let state =
|
||||
{ state with
|
||||
TypeHandles = reg
|
||||
}
|
||||
|
||||
result, state
|
||||
|
||||
let setStatic
|
||||
(ty : RuntimeConcreteType)
|
||||
(field : string)
|
||||
@@ -1316,3 +1375,70 @@ module IlMachineState =
|
||||
match v.TryGetValue field with
|
||||
| false, _ -> None
|
||||
| true, v -> Some v
|
||||
|
||||
let rec canonicaliseTypeReference
|
||||
(assy : AssemblyName)
|
||||
(ty : TypeReferenceHandle)
|
||||
(state : IlMachineState)
|
||||
: Result<CanonicalTypeIdentity, AssemblyName>
|
||||
=
|
||||
match state.LoadedAssembly assy with
|
||||
| None -> Error assy
|
||||
| Some assy ->
|
||||
|
||||
match assy.TypeRefs.TryGetValue ty with
|
||||
| false, _ -> failwith $"could not find type reference in assembly %s{assy.Name.FullName}"
|
||||
| true, v ->
|
||||
|
||||
match v.ResolutionScope with
|
||||
| TypeRefResolutionScope.Assembly newAssy ->
|
||||
let newAssy = assy.AssemblyReferences.[newAssy].Name
|
||||
|
||||
match state.LoadedAssembly newAssy with
|
||||
| None -> Error newAssy
|
||||
| Some newAssy ->
|
||||
{
|
||||
AssemblyFullName = newAssy.Name.FullName
|
||||
FullyQualifiedTypeName = $"%s{v.Namespace}.%s{v.Name}"
|
||||
// TODO: I think TypeRef can't have generics?
|
||||
Generics = []
|
||||
}
|
||||
|> Ok
|
||||
| TypeRefResolutionScope.ModuleRef _ -> failwith "todo"
|
||||
| TypeRefResolutionScope.TypeRef r ->
|
||||
if (r.GetHashCode ()) <> (ty.GetHashCode ()) then
|
||||
failwith "apparently this doesn't do what I thought"
|
||||
|
||||
{
|
||||
|
||||
AssemblyFullName = assy.Name.FullName
|
||||
FullyQualifiedTypeName = $"%s{v.Namespace}.%s{v.Name}"
|
||||
Generics = []
|
||||
}
|
||||
|> Ok
|
||||
|
||||
let canonicaliseTypeDef
|
||||
(assy : AssemblyName)
|
||||
(ty : TypeDefinitionHandle)
|
||||
(typeGenerics : CanonicalTypeIdentity list)
|
||||
(methodGenerics : CanonicalTypeIdentity list)
|
||||
(state : IlMachineState)
|
||||
: Result<CanonicalTypeIdentity, AssemblyName>
|
||||
=
|
||||
match state.LoadedAssembly assy with
|
||||
| None -> Error assy
|
||||
| Some assy ->
|
||||
|
||||
match assy.TypeDefs.TryGetValue ty with
|
||||
| false, _ -> failwith $"could not find type def in assembly %s{assy.Name.FullName}"
|
||||
| true, v ->
|
||||
|
||||
if not (typeGenerics.IsEmpty && methodGenerics.IsEmpty) then
|
||||
failwith "TODO: generics"
|
||||
|
||||
{
|
||||
AssemblyFullName = assy.Name.FullName
|
||||
FullyQualifiedTypeName = $"%s{v.Namespace}.%s{v.Name}"
|
||||
Generics = []
|
||||
}
|
||||
|> Ok
|
||||
|
@@ -776,7 +776,29 @@ module NullaryIlOp =
|
||||
| Conv_ovf_u -> failwith "TODO: Conv_ovf_u unimplemented"
|
||||
| Neg -> failwith "TODO: Neg unimplemented"
|
||||
| Not -> failwith "TODO: Not unimplemented"
|
||||
| Ldind_ref -> failwith "TODO: Ldind_ref unimplemented"
|
||||
| Ldind_ref ->
|
||||
let addr, state = IlMachineState.popEvalStack currentThread state
|
||||
|
||||
let referenced =
|
||||
match addr with
|
||||
| EvalStackValue.ManagedPointer src ->
|
||||
match src with
|
||||
| ManagedPointerSource.Null -> failwith "TODO: throw NRE"
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
state.ThreadState.[sourceThread].MethodStates.[methodFrame].LocalVariables
|
||||
.[int<uint16> whichVar]
|
||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) ->
|
||||
state.ThreadState.[sourceThread].MethodStates.[methodFrame].Arguments.[int<uint16> whichVar]
|
||||
| ManagedPointerSource.Heap managedHeapAddress -> failwith "todo"
|
||||
| a -> failwith $"TODO: {a}"
|
||||
|
||||
let state =
|
||||
match referenced with
|
||||
| CliType.ObjectRef _ -> IlMachineState.pushToEvalStack referenced currentThread state
|
||||
| _ -> failwith $"Unexpected non-reference {referenced}"
|
||||
|> IlMachineState.advanceProgramCounter currentThread
|
||||
|
||||
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
|
||||
| Stind_ref -> failwith "TODO: Stind_ref unimplemented"
|
||||
| Ldelem_i -> failwith "TODO: Ldelem_i unimplemented"
|
||||
| Ldelem_i1 -> failwith "TODO: Ldelem_i1 unimplemented"
|
||||
|
64
WoofWare.PawPrint/TypeHandleRegistry.fs
Normal file
64
WoofWare.PawPrint/TypeHandleRegistry.fs
Normal file
@@ -0,0 +1,64 @@
|
||||
namespace WoofWare.PawPrint
|
||||
|
||||
type CanonicalTypeIdentity =
|
||||
{
|
||||
AssemblyFullName : string
|
||||
FullyQualifiedTypeName : string
|
||||
Generics : CanonicalTypeIdentity list
|
||||
}
|
||||
|
||||
type TypeHandleRegistry =
|
||||
private
|
||||
{
|
||||
TypeHandleToType : Map<int64<typeHandle>, CanonicalTypeIdentity>
|
||||
TypeToHandle : Map<CanonicalTypeIdentity, int64<typeHandle> * ManagedHeapAddress>
|
||||
NextHandle : int64<typeHandle>
|
||||
}
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module TypeHandleRegistry =
|
||||
let empty () =
|
||||
{
|
||||
TypeHandleToType = Map.empty
|
||||
TypeToHandle = Map.empty
|
||||
NextHandle = 1L<typeHandle>
|
||||
}
|
||||
|
||||
/// Returns an allocated System.RuntimeType as well.
|
||||
let getOrAllocate
|
||||
(allocState : 'allocState)
|
||||
(allocate : (string * CliType) list -> 'allocState -> ManagedHeapAddress * 'allocState)
|
||||
(def : CanonicalTypeIdentity)
|
||||
(reg : TypeHandleRegistry)
|
||||
: (int64<typeHandle> * ManagedHeapAddress) * TypeHandleRegistry * 'allocState
|
||||
=
|
||||
match Map.tryFind def reg.TypeToHandle with
|
||||
| Some v -> v, reg, allocState
|
||||
| None ->
|
||||
|
||||
let handle = reg.NextHandle
|
||||
|
||||
// Here follows the class System.RuntimeType, which is an internal class type with a constructor
|
||||
// whose only purpose is to throw.
|
||||
let fields =
|
||||
[
|
||||
// for the GC, I think?
|
||||
"m_keepalive", CliType.ObjectRef None
|
||||
// TODO: this is actually a System.IntPtr https://github.com/dotnet/runtime/blob/ec11903827fc28847d775ba17e0cd1ff56cfbc2e/src/coreclr/nativeaot/Runtime.Base/src/System/Primitives.cs#L339
|
||||
"m_cache", CliType.Numeric (CliNumericType.NativeInt 0L)
|
||||
"m_handle", CliType.Numeric (CliNumericType.TypeHandlePtr handle)
|
||||
// This is the const -1, apparently?!
|
||||
// https://github.com/dotnet/runtime/blob/f0168ee80ba9aca18a7e7140b2bb436defda623c/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs#L2496
|
||||
"GenericParameterCountAny", CliType.Numeric (CliNumericType.Int32 -1)
|
||||
]
|
||||
|
||||
let alloc, state = allocate fields allocState
|
||||
|
||||
let reg =
|
||||
{
|
||||
NextHandle = handle + 1L<typeHandle>
|
||||
TypeHandleToType = reg.TypeHandleToType |> Map.add handle def
|
||||
TypeToHandle = reg.TypeToHandle |> Map.add def (handle, alloc)
|
||||
}
|
||||
|
||||
(handle, alloc), reg, state
|
@@ -461,9 +461,8 @@ module internal UnaryMetadataIlOp =
|
||||
match source with
|
||||
| ManagedPointerSource.Null -> failwith "TODO: raise NullReferenceException"
|
||||
| ManagedPointerSource.LocalVariable (sourceThread, methodFrame, whichVar) ->
|
||||
let threadState = state.ThreadState.[sourceThread]
|
||||
let methodState = threadState.MethodStates.[methodFrame]
|
||||
failwith "TODO"
|
||||
state
|
||||
|> IlMachineState.setLocalVariable sourceThread methodFrame whichVar valueToStore
|
||||
| ManagedPointerSource.Argument (sourceThread, methodFrame, whichVar) -> failwith "todo"
|
||||
| ManagedPointerSource.Heap addr ->
|
||||
match state.ManagedHeap.NonArrayObjects.TryGetValue addr with
|
||||
@@ -940,7 +939,53 @@ module internal UnaryMetadataIlOp =
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Stobj -> failwith "TODO: Stobj unimplemented"
|
||||
| Constrained -> failwith "TODO: Constrained unimplemented"
|
||||
| Ldtoken -> failwith "TODO: Ldtoken unimplemented"
|
||||
| Ldtoken ->
|
||||
let state =
|
||||
match metadataToken with
|
||||
| MetadataToken.FieldDefinition h ->
|
||||
let ty = baseClassTypes.RuntimeFieldHandle
|
||||
// this is a struct; it contains one field, an IRuntimeFieldInfo
|
||||
// https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs#L1097
|
||||
let field = ty.Fields |> List.exactlyOne
|
||||
|
||||
if field.Name <> "m_ptr" then
|
||||
failwith $"unexpected field name ${field.Name} for BCL type RuntimeFieldHandle"
|
||||
|
||||
failwith ""
|
||||
| MetadataToken.MethodDef h ->
|
||||
let ty = baseClassTypes.RuntimeMethodHandle
|
||||
let field = ty.Fields |> List.exactlyOne
|
||||
failwith ""
|
||||
| MetadataToken.TypeDefinition h ->
|
||||
let ty = baseClassTypes.RuntimeTypeHandle
|
||||
let field = ty.Fields |> List.exactlyOne
|
||||
|
||||
if field.Name <> "m_type" then
|
||||
failwith $"unexpected field name ${field.Name} for BCL type RuntimeTypeHandle"
|
||||
|
||||
let currentMethod = state.ThreadState.[thread].MethodState
|
||||
|
||||
let methodGenerics =
|
||||
currentMethod.Generics |> Option.defaultValue ImmutableArray.Empty
|
||||
|
||||
let typeGenerics = currentMethod.ExecutingMethod.DeclaringType.Generics
|
||||
|
||||
if not (methodGenerics.IsEmpty && typeGenerics.IsEmpty) then
|
||||
failwith "TODO: generics"
|
||||
|
||||
let handle =
|
||||
match IlMachineState.canonicaliseTypeDef (state.ActiveAssembly(thread).Name) h [] [] state with
|
||||
| Error e -> failwith $"TODO: somehow need to load {e.FullName} first"
|
||||
| Ok h -> h
|
||||
|
||||
let (_, alloc), state = IlMachineState.getOrAllocateType baseClassTypes handle state
|
||||
|
||||
IlMachineState.pushToEvalStack (CliType.ValueType [ CliType.ObjectRef (Some alloc) ]) thread state
|
||||
| _ -> failwith $"Unexpected metadata token %O{metadataToken} in LdToken"
|
||||
|
||||
state
|
||||
|> IlMachineState.advanceProgramCounter thread
|
||||
|> Tuple.withRight WhatWeDid.Executed
|
||||
| Cpobj -> failwith "TODO: Cpobj unimplemented"
|
||||
| Ldobj -> failwith "TODO: Ldobj unimplemented"
|
||||
| Sizeof -> failwith "TODO: Sizeof unimplemented"
|
||||
|
@@ -11,6 +11,7 @@
|
||||
<Compile Include="Corelib.fs" />
|
||||
<Compile Include="AbstractMachineDomain.fs" />
|
||||
<Compile Include="BasicCliType.fs" />
|
||||
<Compile Include="TypeHandleRegistry.fs" />
|
||||
<Compile Include="ManagedHeap.fs" />
|
||||
<Compile Include="TypeInitialisation.fs" />
|
||||
<Compile Include="Exceptions.fs" />
|
||||
|
Reference in New Issue
Block a user