Resolve more types during startup (#47)

This commit is contained in:
Patrick Stevens
2025-06-15 16:52:30 +01:00
committed by GitHub
parent 3181e24817
commit f3565fe8b5
2 changed files with 67 additions and 25 deletions

View File

@@ -151,7 +151,21 @@ module CliType =
| SignatureTypeKind.Unknown -> failwith "todo" | SignatureTypeKind.Unknown -> failwith "todo"
| SignatureTypeKind.ValueType -> | SignatureTypeKind.ValueType ->
match Assembly.resolveTypeRef assemblies assy typeRef typeGenerics with match Assembly.resolveTypeRef assemblies assy typeRef typeGenerics with
| TypeResolutionResult.Resolved (_, ty) -> failwith $"TODO: {ty}" | TypeResolutionResult.Resolved (sourceAssy, ty) ->
let fields =
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
| CliTypeResolutionResult.Resolved ty -> Ok ty
| CliTypeResolutionResult.FirstLoad a -> Error a
)
|> Result.allOkOrError
match fields with
| Error (_, []) -> failwith "logic error"
| Error (_, f :: _) -> CliTypeResolutionResult.FirstLoad f
| Ok fields -> CliType.ValueType fields |> CliTypeResolutionResult.Resolved
| TypeResolutionResult.FirstLoadAssy assy -> CliTypeResolutionResult.FirstLoad assy | TypeResolutionResult.FirstLoadAssy assy -> CliTypeResolutionResult.FirstLoad assy
| SignatureTypeKind.Class -> CliType.ObjectRef None |> CliTypeResolutionResult.Resolved | SignatureTypeKind.Class -> CliType.ObjectRef None |> CliTypeResolutionResult.Resolved
| _ -> raise (ArgumentOutOfRangeException ()) | _ -> raise (ArgumentOutOfRangeException ())

View File

@@ -69,47 +69,75 @@ module Program =
mainMethod mainMethod
|> MethodInfo.mapTypeGenerics (fun _ -> failwith "Refusing to execute generic main method") |> MethodInfo.mapTypeGenerics (fun _ -> failwith "Refusing to execute generic main method")
let state, mainThread = let rec computeState (baseClassTypes : BaseClassTypes<DumpedAssembly> option) (state : IlMachineState) =
IlMachineState.initial loggerFactory dotnetRuntimeDirs dumped
// The thread's state is slightly fake: we will need to put arguments onto the stack before actually // The thread's state is slightly fake: we will need to put arguments onto the stack before actually
// executing the main method. // executing the main method.
// We construct the thread here before we are entirely ready, because we need a thread from which to // We construct the thread here before we are entirely ready, because we need a thread from which to
// initialise the class containing the main method. // initialise the class containing the main method.
// Once we've obtained e.g. the String and Array classes, we can populate the args array. // Once we've obtained e.g. the String and Array classes, we can populate the args array.
|> fun s -> match
match MethodState.Empty
MethodState.Empty (Option.toObj baseClassTypes)
Unchecked.defaultof<_> state._LoadedAssemblies
s._LoadedAssemblies dumped
dumped mainMethod
mainMethod None
None (ImmutableArray.CreateRange [ CliType.ObjectRef None ])
(ImmutableArray.CreateRange [ CliType.ObjectRef None ]) None
None with
with | Ok meth -> IlMachineState.addThread meth dumped.Name state, baseClassTypes
| Ok meth -> IlMachineState.addThread meth dumped.Name s | Error requiresRefs ->
| Error requiresRefs -> failwith "TODO: I'd be surprised if this could ever happen in a valid program" let state =
(state, requiresRefs)
||> List.fold (fun state ref ->
let handle, referencingAssy = ref.Handle
let referencingAssy = state.LoadedAssembly referencingAssy |> Option.get
let state, _, _ =
IlMachineState.loadAssembly loggerFactory referencingAssy handle state
state
)
let corelib =
let coreLib =
state._LoadedAssemblies.Keys
|> Seq.tryFind (fun x -> x.StartsWith ("System.Private.CoreLib, ", StringComparison.Ordinal))
coreLib
|> Option.map (fun coreLib -> state._LoadedAssemblies.[coreLib] |> Corelib.getBaseTypes)
computeState corelib state
let (state, mainThread), baseClassTypes =
IlMachineState.initial loggerFactory dotnetRuntimeDirs dumped
|> computeState None
let rec loadInitialState (state : IlMachineState) = let rec loadInitialState (state : IlMachineState) =
match match
state state
|> IlMachineState.loadClass loggerFactory Unchecked.defaultof<_> mainMethod.DeclaringType mainThread |> IlMachineState.loadClass
loggerFactory
(Option.toObj baseClassTypes)
mainMethod.DeclaringType
mainThread
with with
| StateLoadResult.NothingToDo ilMachineState -> ilMachineState | StateLoadResult.NothingToDo ilMachineState -> ilMachineState
| StateLoadResult.FirstLoadThis ilMachineState -> loadInitialState ilMachineState | StateLoadResult.FirstLoadThis ilMachineState -> loadInitialState ilMachineState
let state = loadInitialState state let state = loadInitialState state
// Now that the object has been loaded, we can identify the String type from System.Private.CoreLib. // Now that the object has been loaded, we can identify the critical types like `string` from System.Private.CoreLib.
let corelib = let baseClassTypes =
let coreLib = match baseClassTypes with
state._LoadedAssemblies.Keys | None ->
|> Seq.find (fun x -> x.StartsWith ("System.Private.CoreLib, ", StringComparison.Ordinal)) let coreLib =
state._LoadedAssemblies.Keys
|> Seq.find (fun x -> x.StartsWith ("System.Private.CoreLib, ", StringComparison.Ordinal))
state._LoadedAssemblies.[coreLib] state._LoadedAssemblies.[coreLib] |> Corelib.getBaseTypes
| Some c -> c
let baseClassTypes = Corelib.getBaseTypes corelib
let arrayAllocation, state = let arrayAllocation, state =
match mainMethod.Signature.ParameterTypes |> Seq.toList with match mainMethod.Signature.ParameterTypes |> Seq.toList with