From 0e31d74586c01053e2c2b24b2b6bc7ab7ccb802b Mon Sep 17 00:00:00 2001 From: Patrick Stevens <3138005+Smaug123@users.noreply.github.com> Date: Sat, 30 Aug 2025 16:36:26 +0100 Subject: [PATCH] Implement Ldobj and Box for reference types (#124) --- WoofWare.PawPrint/UnaryMetadataIlOp.fs | 115 ++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/WoofWare.PawPrint/UnaryMetadataIlOp.fs b/WoofWare.PawPrint/UnaryMetadataIlOp.fs index 5d6d4cb..679dcfc 100644 --- a/WoofWare.PawPrint/UnaryMetadataIlOp.fs +++ b/WoofWare.PawPrint/UnaryMetadataIlOp.fs @@ -416,7 +416,55 @@ module internal UnaryMetadataIlOp = |> IlMachineState.advanceProgramCounter thread state, WhatWeDid.Executed - | Box -> failwith "TODO: Box unimplemented" + | Box -> + let state, ty, assy = + match metadataToken with + | MetadataToken.TypeDefinition h -> + let state, ty = IlMachineState.lookupTypeDefn baseClassTypes state activeAssy h + state, ty, activeAssy + | MetadataToken.TypeReference ref -> + IlMachineState.lookupTypeRef + loggerFactory + baseClassTypes + state + activeAssy + currentMethod.DeclaringType.Generics + ref + | MetadataToken.TypeSpecification spec -> state, activeAssy.TypeSpecs.[spec].Signature, activeAssy + | _ -> failwith $"unexpected token {metadataToken} in Box" + + let state, typeHandle = + IlMachineState.concretizeType + loggerFactory + baseClassTypes + state + assy.Name + currentMethod.DeclaringType.Generics + currentMethod.Generics + ty + + let toBox, state = state |> IlMachineState.popEvalStack thread + + let targetType = + AllConcreteTypes.lookup typeHandle state.ConcreteTypes |> Option.get + + let defn = + state._LoadedAssemblies.[targetType.Assembly.FullName].TypeDefs.[targetType.Definition.Get] + + let baseType = + DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies targetType.Assembly defn.BaseType + + let toPush = + match baseType with + | ResolvedBaseType.Enum + | ResolvedBaseType.ValueType -> failwith "TODO: implement Box" + | ResolvedBaseType.Object + | ResolvedBaseType.Delegate -> toBox + + state + |> IlMachineState.pushToEvalStack' toPush thread + |> IlMachineState.advanceProgramCounter thread + |> Tuple.withRight WhatWeDid.Executed | Ldelema -> let index, state = IlMachineState.popEvalStack thread state let arr, state = IlMachineState.popEvalStack thread state @@ -1376,7 +1424,70 @@ module internal UnaryMetadataIlOp = |> IlMachineState.advanceProgramCounter thread |> Tuple.withRight WhatWeDid.Executed | Cpobj -> failwith "TODO: Cpobj unimplemented" - | Ldobj -> failwith "TODO: Ldobj unimplemented" + | Ldobj -> + let state, ty, assy = + match metadataToken with + | MetadataToken.TypeDefinition h -> + let state, ty = IlMachineState.lookupTypeDefn baseClassTypes state activeAssy h + state, ty, activeAssy + | MetadataToken.TypeReference ref -> + IlMachineState.lookupTypeRef + loggerFactory + baseClassTypes + state + activeAssy + currentMethod.DeclaringType.Generics + ref + | MetadataToken.TypeSpecification spec -> state, activeAssy.TypeSpecs.[spec].Signature, activeAssy + | _ -> failwith $"unexpected token {metadataToken} in Ldobj" + + let state, typeHandle = + IlMachineState.concretizeType + loggerFactory + baseClassTypes + state + assy.Name + currentMethod.DeclaringType.Generics + currentMethod.Generics + ty + + let addr, state = state |> IlMachineState.popEvalStack thread + + let obj = + match addr with + | EvalStackValue.ObjectRef addr -> + IlMachineState.dereferencePointer state (ManagedPointerSource.Heap addr) + | EvalStackValue.ManagedPointer ptr -> IlMachineState.dereferencePointer state ptr + | EvalStackValue.Float _ + | EvalStackValue.Int64 _ + | EvalStackValue.Int32 _ -> failwith "refusing to interpret constant as address" + | _ -> failwith "TODO" + + let targetType = + AllConcreteTypes.lookup typeHandle state.ConcreteTypes |> Option.get + + let defn = + state._LoadedAssemblies.[targetType.Assembly.FullName].TypeDefs.[targetType.Definition.Get] + + let baseType = + DumpedAssembly.resolveBaseType baseClassTypes state._LoadedAssemblies targetType.Assembly defn.BaseType + + let toPush = + match baseType with + | ResolvedBaseType.Enum + | ResolvedBaseType.ValueType -> + failwith + $"TODO: push %O{obj} as type %s{targetType.Assembly.Name}.%s{targetType.Namespace}.%s{targetType.Name}" + | ResolvedBaseType.Object + | ResolvedBaseType.Delegate -> + // III.4.13: reference types are just copied as pointers. + // We should have received a pointer, so let's just pass it back. + obj + + state + |> IlMachineState.pushToEvalStack toPush thread + |> IlMachineState.advanceProgramCounter thread + |> Tuple.withRight WhatWeDid.Executed | Sizeof -> let state, ty, assy = match metadataToken with