diff --git a/source2/IL2CPU/Cosmos.IL2CPU.X86/IL/Newobj.cs b/source2/IL2CPU/Cosmos.IL2CPU.X86/IL/Newobj.cs index 82add88a4..d6b9b07f6 100644 --- a/source2/IL2CPU/Cosmos.IL2CPU.X86/IL/Newobj.cs +++ b/source2/IL2CPU/Cosmos.IL2CPU.X86/IL/Newobj.cs @@ -6,242 +6,219 @@ using Cosmos.IL2CPU.ILOpCodes; using Cosmos.IL2CPU.IL.CustomImplementations.System; using System.Reflection; -namespace Cosmos.IL2CPU.X86.IL -{ - [Cosmos.IL2CPU.OpCode( ILOpCode.Code.Newobj )] - public class Newobj : ILOp - { - public Newobj( Cosmos.Compiler.Assembler.Assembler aAsmblr ) - : base( aAsmblr ) - { - } - - public override void Execute( MethodInfo aMethod, ILOpCode aOpCode ) - { - OpMethod xMethod = ( OpMethod )aOpCode; - string xCurrentLabel = GetLabel( aMethod, aOpCode ); - var xType = xMethod.Value.DeclaringType; - - Assemble(Assembler, aMethod, xMethod, xCurrentLabel, xType, xMethod.Value); - } - - public static void Assemble(Assembler aAssembler, MethodInfo aMethod, OpMethod xMethod, string currentLabel, Type objectType, MethodBase constructor) - { - // call cctor: - if (aMethod != null) - { - var xCctor = (objectType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); - if (xCctor != null) - { - new CPUx86.Call { DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(xCctor) }; - ILOp.EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck"); - new Label(".AfterCCTorExceptionCheck"); - } - } - - // If not ValueType, then we need gc - if (!objectType.IsValueType) - { - var xParams = constructor.GetParameters(); - for (int i = 0; i < xParams.Length; i++) - { - aAssembler.Stack.Pop(); - } - - // array length +8 - - bool xHasCalcSize = false; - // try calculating size: - if (constructor.DeclaringType == typeof(string)) - { - if (xParams.Length == 1 && xParams[0].ParameterType == typeof(char[])) - { - xHasCalcSize = true; - new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true, SourceDisplacement = 8 }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.EDX, SourceValue = 2 }; - new CPUx86.Multiply { DestinationReg = CPUx86.Registers.EDX }; - new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; - } - else if (xParams.Length == 3 - && xParams[0].ParameterType == typeof(char[]) - && xParams[1].ParameterType == typeof(int) - && xParams[2].ParameterType == typeof(int)) - { - xHasCalcSize = true; - new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; - } - } - uint xMemSize = GetStorageSize(objectType); - int xExtraSize = 20; - new CPUx86.Push { DestinationValue = (uint)(xMemSize + xExtraSize) }; - if (xHasCalcSize) - { - new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; - new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX }; - } - - // todo: probably we want to check for exceptions after calling Alloc - new CPUx86.Call { DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(GCImplementationRefs.AllocNewObjectRef) }; - new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; - new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; - - //? ?? uint xObjSize;// = 0; - //int xGCFieldCount = ( from item in aCtorDeclTypeInfo.Fields.Values - //where item.NeedsGC - //select item ).Count(); - - //int xGCFieldCount = ( from item in aCtorDeclTypeInfo.Fields.Values - //where item.NeedsGC - //select item ).Count(); - int xGCFieldCount = objectType.GetFields().Count(x => x.FieldType.IsValueType); - - // todo: use a cleaner approach here. this class shouldnt assemble the string - string strTypeId = GetTypeIDLabel(constructor.DeclaringType); - - new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.EBX, SourceRef = ElementReference.New(strTypeId), SourceIsIndirect = true }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EBX }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = (uint)InstanceTypeEnum.NormalObject, Size = 32 }; - new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 8, SourceValue = (uint)xGCFieldCount, Size = 32 }; - uint xSize = (uint)(((from item in xParams - let xQSize = Align(SizeOfType(item.ParameterType), 4) - select (int)xQSize).Take(xParams.Length).Sum())); - - foreach (var xParam in xParams) - { - uint xParamSize = Align(SizeOfType(xParam.ParameterType), 4); - new Comment(aAssembler, String.Format("Arg {0}: {1}", xParam.Name, xParamSize)); - for (int i = 0; i < xParamSize; i += 4) { - new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xSize + 4) }; - } - } - - new CPUx86.Call { DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(constructor) }; - if (aMethod != null) - { - new CPUx86.Test { DestinationReg = CPUx86.Registers.ECX, SourceValue = 2 }; - string xNoErrorLabel = currentLabel + "_NO_ERROR_" + MethodInfoLabelGenerator.LabelCount.ToString(); - new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Equal, DestinationLabel = xNoErrorLabel }; - - //for( int i = 1; i < aCtorMethodInfo.Arguments.Length; i++ ) - //{ - // new CPUx86.Add - // { - // DestinationReg = CPUx86.Registers.ESP, - // SourceValue = ( aCtorMethodInfo.Arguments[ i ].Size % 4 == 0 - // ? aCtorMethodInfo.Arguments[ i ].Size - // : ( ( aCtorMethodInfo.Arguments[ i ].Size / 4 ) * 4 ) + 1 ) - // }; - //} - PushAlignedParameterSize(constructor); - // an exception occurred, we need to cleanup the stack, and jump to the exit - new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; - new Comment(aAssembler, "[ Newobj.Execute cleanup start count = " + aAssembler.Stack.Count.ToString() + " ]"); - //foreach( var xStackInt in Assembler.Stack ) - //{ - // new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = ( uint )xStackInt.Size }; - //} - - uint xESPOffset = 0; - foreach (var xParam in xParams) { - xESPOffset += Align(SizeOfType(xParam.ParameterType), 4); - } - new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = xESPOffset }; - - new Comment(aAssembler, "[ Newobj.Execute cleanup end ]"); - Jump_Exception(aMethod); - new Label(xNoErrorLabel); - } - new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; - - //for( int i = 1; i < aCtorMethodInfo.Arguments.Length; i++ ) - //{ - // new CPUx86.Add - // { - // DestinationReg = CPUx86.Registers.ESP, - // SourceValue = ( aCtorMethodInfo.Arguments[ i ].Size % 4 == 0 - // ? aCtorMethodInfo.Arguments[ i ].Size - // : ( ( aCtorMethodInfo.Arguments[ i ].Size / 4 ) * 4 ) + 1 ) - // }; - //} - PushAlignedParameterSize(constructor); - - new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; - aAssembler.Stack.Push(4, constructor.DeclaringType); - } - else - { - //throw new Exception("Not implemented yet: .ctor on value type"); - /* - * Current sitation on stack: - * $ESP Arg - * $ESP+.. other items - * - * What should happen: - * + The stack should be increased to allow space to contain: - * + .ctor arguments - * + struct _pointer_ (ref to start of emptied space) - * + empty space for struct - * + arguments should be copied to the new place - * + old place where arguments were should be cleared - * + pointer should be set - * + call .ctor - */ - var xStorageSize = Align(SizeOfType(objectType), 4); - //var xStorageSize = aCtorDeclTypeInfo.StorageSize; - //uint xArgSize = 0; - var xParams = constructor.GetParameters(); - uint xArgSize = (uint)(((from item in xParams.Skip(1) - let xQSize = Align(SizeOfType(item.ParameterType), 4) - select (int)xQSize).Take(xParams.Length - 1).Sum())); - - //foreach( var xArg in aCtorMethodInfo.Arguments.Skip( 1 ) ) - //{ - // xArgSize += xArg.Size + ( xArg.Size % 4 == 0 - // ? 0 - // : ( 4 - ( xArg.Size % 4 ) ) ); - //} - int xExtraArgSize = (int)(xStorageSize - xArgSize); - if (xExtraArgSize < 0) - { - xExtraArgSize = 0; - } - if (xExtraArgSize > 0) { - new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xExtraArgSize }; - } - new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP }; - aAssembler.Stack.Push(new StackContents.Item(4, null)); - //at this point, we need to move copy all arguments over. - for (int i = 0; i < (xArgSize / 4); i++) - { - new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xStorageSize + 4) }; // + 4 because the ptr is pushed too - new CPUx86.Move { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xStorageSize + 4 + 4), SourceValue = 0, Size = 32 }; - } - new Call(aAssembler).Execute(aMethod, xMethod); - //var xCall = new Call( aCtorDef, - // ( uint )aCurrentILOffset, - // true, - // aNextLabel ); - //xCall.SetServiceProvider( aServiceProvider ); - //xCall.Assembler = aAssembler; - //xCall.Assemble(); - aAssembler.Stack.Push(new StackContents.Item(xStorageSize, objectType)); - } - } - - private static void PushAlignedParameterSize( System.Reflection.MethodBase aMethod ) - { - System.Reflection.ParameterInfo[] xParams = aMethod.GetParameters(); - - uint xSize; - new Comment("[ Newobj.PushAlignedParameterSize start count = " + xParams.Length.ToString() + " ]" ); - for( int i = 0; i < xParams.Length; i++ ) - { - xSize = SizeOfType( xParams[ i ].ParameterType ); - new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = Align( xSize, 4 ) }; - } - new Comment("[ Newobj.PushAlignedParameterSize end ]" ); - } +namespace Cosmos.IL2CPU.X86.IL { + [Cosmos.IL2CPU.OpCode(ILOpCode.Code.Newobj)] + public class Newobj : ILOp { + public Newobj(Cosmos.Compiler.Assembler.Assembler aAsmblr) + : base(aAsmblr) { } + + public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { + OpMethod xMethod = (OpMethod)aOpCode; + string xCurrentLabel = GetLabel(aMethod, aOpCode); + var xType = xMethod.Value.DeclaringType; + + Assemble(Assembler, aMethod, xMethod, xCurrentLabel, xType, xMethod.Value); + } + + public static void Assemble(Assembler aAssembler, MethodInfo aMethod, OpMethod xMethod, string currentLabel, Type objectType, MethodBase constructor) { + // call cctor: + if (aMethod != null) { + var xCctor = (objectType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); + if (xCctor != null) { + new CPUx86.Call { DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(xCctor) }; + ILOp.EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck"); + new Label(".AfterCCTorExceptionCheck"); + } + } + + if (objectType.IsValueType) { + /* + * Current sitation on stack: + * $ESP Arg + * $ESP+.. other items + * + * What should happen: + * + The stack should be increased to allow space to contain: + * + .ctor arguments + * + struct _pointer_ (ref to start of emptied space) + * + empty space for struct + * + arguments should be copied to the new place + * + old place where arguments were should be cleared + * + pointer should be set + * + call .ctor + */ + var xStorageSize = Align(SizeOfType(objectType), 4); + //var xStorageSize = aCtorDeclTypeInfo.StorageSize; + //uint xArgSize = 0; + var xParams = constructor.GetParameters(); + uint xArgSize = (uint)(((from item in xParams.Skip(1) + let xQSize = Align(SizeOfType(item.ParameterType), 4) + select (int)xQSize).Take(xParams.Length - 1).Sum())); + + //foreach( var xArg in aCtorMethodInfo.Arguments.Skip( 1 ) ) + //{ + // xArgSize += xArg.Size + ( xArg.Size % 4 == 0 + // ? 0 + // : ( 4 - ( xArg.Size % 4 ) ) ); + //} + int xExtraArgSize = (int)(xStorageSize - xArgSize); + if (xExtraArgSize < 0) { + xExtraArgSize = 0; + } + if (xExtraArgSize > 0) { + new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xExtraArgSize }; + } + new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP }; + aAssembler.Stack.Push(new StackContents.Item(4, null)); + //at this point, we need to move copy all arguments over. + for (int i = 0; i < (xArgSize / 4); i++) { + new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xStorageSize + 4) }; // + 4 because the ptr is pushed too + new CPUx86.Move { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xStorageSize + 4 + 4), SourceValue = 0, Size = 32 }; + } + new Call(aAssembler).Execute(aMethod, xMethod); + //var xCall = new Call( aCtorDef, + // ( uint )aCurrentILOffset, + // true, + // aNextLabel ); + //xCall.SetServiceProvider( aServiceProvider ); + //xCall.Assembler = aAssembler; + //xCall.Assemble(); + aAssembler.Stack.Push(new StackContents.Item(xStorageSize, objectType)); + } else { + // If not ValueType, then we need gc + var xParams = constructor.GetParameters(); + for (int i = 0; i < xParams.Length; i++) { + aAssembler.Stack.Pop(); + } + + // array length +8 + + bool xHasCalcSize = false; + // try calculating size: + if (constructor.DeclaringType == typeof(string)) { + if (xParams.Length == 1 && xParams[0].ParameterType == typeof(char[])) { + xHasCalcSize = true; + new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true, SourceDisplacement = 8 }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.EDX, SourceValue = 2 }; + new CPUx86.Multiply { DestinationReg = CPUx86.Registers.EDX }; + new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; + } else if (xParams.Length == 3 + && xParams[0].ParameterType == typeof(char[]) + && xParams[1].ParameterType == typeof(int) + && xParams[2].ParameterType == typeof(int)) { + xHasCalcSize = true; + new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; + } + } + uint xMemSize = GetStorageSize(objectType); + int xExtraSize = 20; + new CPUx86.Push { DestinationValue = (uint)(xMemSize + xExtraSize) }; + if (xHasCalcSize) { + new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; + new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX }; + } + + // todo: probably we want to check for exceptions after calling Alloc + new CPUx86.Call { DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(GCImplementationRefs.AllocNewObjectRef) }; + new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; + new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; + + //? ?? uint xObjSize;// = 0; + //int xGCFieldCount = ( from item in aCtorDeclTypeInfo.Fields.Values + //where item.NeedsGC + //select item ).Count(); + + //int xGCFieldCount = ( from item in aCtorDeclTypeInfo.Fields.Values + //where item.NeedsGC + //select item ).Count(); + int xGCFieldCount = objectType.GetFields().Count(x => x.FieldType.IsValueType); + + // todo: use a cleaner approach here. this class shouldnt assemble the string + string strTypeId = GetTypeIDLabel(constructor.DeclaringType); + + new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.EBX, SourceRef = ElementReference.New(strTypeId), SourceIsIndirect = true }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EBX }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = (uint)InstanceTypeEnum.NormalObject, Size = 32 }; + new CPUx86.Move { DestinationReg = CPUx86.Registers.EAX, DestinationIsIndirect = true, DestinationDisplacement = 8, SourceValue = (uint)xGCFieldCount, Size = 32 }; + uint xSize = (uint)(((from item in xParams + let xQSize = Align(SizeOfType(item.ParameterType), 4) + select (int)xQSize).Take(xParams.Length).Sum())); + + foreach (var xParam in xParams) { + uint xParamSize = Align(SizeOfType(xParam.ParameterType), 4); + new Comment(aAssembler, String.Format("Arg {0}: {1}", xParam.Name, xParamSize)); + for (int i = 0; i < xParamSize; i += 4) { + new CPUx86.Push { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xSize + 4) }; + } + } + + new CPUx86.Call { DestinationLabel = MethodInfoLabelGenerator.GenerateLabelName(constructor) }; + if (aMethod != null) { + new CPUx86.Test { DestinationReg = CPUx86.Registers.ECX, SourceValue = 2 }; + string xNoErrorLabel = currentLabel + "_NO_ERROR_" + MethodInfoLabelGenerator.LabelCount.ToString(); + new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Equal, DestinationLabel = xNoErrorLabel }; + + //for( int i = 1; i < aCtorMethodInfo.Arguments.Length; i++ ) + //{ + // new CPUx86.Add + // { + // DestinationReg = CPUx86.Registers.ESP, + // SourceValue = ( aCtorMethodInfo.Arguments[ i ].Size % 4 == 0 + // ? aCtorMethodInfo.Arguments[ i ].Size + // : ( ( aCtorMethodInfo.Arguments[ i ].Size / 4 ) * 4 ) + 1 ) + // }; + //} + PushAlignedParameterSize(constructor); + // an exception occurred, we need to cleanup the stack, and jump to the exit + new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; + new Comment(aAssembler, "[ Newobj.Execute cleanup start count = " + aAssembler.Stack.Count.ToString() + " ]"); + //foreach( var xStackInt in Assembler.Stack ) + //{ + // new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = ( uint )xStackInt.Size }; + //} + + uint xESPOffset = 0; + foreach (var xParam in xParams) { + xESPOffset += Align(SizeOfType(xParam.ParameterType), 4); + } + new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = xESPOffset }; + + new Comment(aAssembler, "[ Newobj.Execute cleanup end ]"); + Jump_Exception(aMethod); + new Label(xNoErrorLabel); + } + new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; + + //for( int i = 1; i < aCtorMethodInfo.Arguments.Length; i++ ) + //{ + // new CPUx86.Add + // { + // DestinationReg = CPUx86.Registers.ESP, + // SourceValue = ( aCtorMethodInfo.Arguments[ i ].Size % 4 == 0 + // ? aCtorMethodInfo.Arguments[ i ].Size + // : ( ( aCtorMethodInfo.Arguments[ i ].Size / 4 ) * 4 ) + 1 ) + // }; + //} + PushAlignedParameterSize(constructor); + + new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; + aAssembler.Stack.Push(4, constructor.DeclaringType); + } + } + + private static void PushAlignedParameterSize(System.Reflection.MethodBase aMethod) { + System.Reflection.ParameterInfo[] xParams = aMethod.GetParameters(); + + uint xSize; + new Comment("[ Newobj.PushAlignedParameterSize start count = " + xParams.Length.ToString() + " ]"); + for (int i = 0; i < xParams.Length; i++) { + xSize = SizeOfType(xParams[i].ParameterType); + new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = Align(xSize, 4) }; + } + new Comment("[ Newobj.PushAlignedParameterSize end ]"); + } + } } \ No newline at end of file diff --git a/source2/Users/Kudzu/Breakpoints/NullableTest.cs b/source2/Users/Kudzu/Breakpoints/NullableTest.cs index b77387142..1d31a4b90 100644 --- a/source2/Users/Kudzu/Breakpoints/NullableTest.cs +++ b/source2/Users/Kudzu/Breakpoints/NullableTest.cs @@ -18,13 +18,14 @@ namespace BreakpointsKernel { } public override void Run() { - UInt32 x = 32; + UInt32 x = 1; UInt32? xSize; - xSize = 8; + xSize = 2; + aSize = 3; - mSize = 7; + mSize = 4; bool xHasValue = mSize.HasValue; // .HasValue is false Chk(xHasValue); x = mSize.Value;