// this code is mostly copied from Newarr.cs in Il2CPU, just the code to find the size and length is different public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { string xTypeID = ILOp.GetTypeIDLabel(typeof(Array)); MethodBase xCtor = typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)[0]; string xCtorName = LabelName.Get(xCtor); XS.Set(ECX, EBP, sourceDisplacement: 8); // size XS.Set(EDX, EBP, sourceDisplacement: 12); // length XS.Push(ECX); // size of element XS.Set(EAX, ECX); XS.Multiply(EDX); // total element size XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // total array size XS.Push(EAX); XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Label(".AfterAlloc"); XS.Pop(EAX); XS.Pop(ESI); XS.Push(EAX); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack 3 times now, once from the return value, twice from the pushes; XS.Pop(EAX); XS.Set(EBX, xTypeID, sourceIsIndirect: true); // array type id XS.Set(EAX, EBX, destinationIsIndirect: true); // array type id XS.Set(EAX, (uint)ObjectUtils.InstanceTypeEnum.Array, destinationDisplacement: 4, destinationIsIndirect: true); XS.Set(EAX, ESI, destinationDisplacement: 8, destinationIsIndirect: true); XS.Set(EAX, ECX); XS.Push(0); XS.Call(xCtorName); XS.Push(0); }
protected static void DoNullReferenceCheck(Assembler.Assembler assembler, bool debugEnabled, int stackOffsetToCheck) { if (stackOffsetToCheck != SignedAlign(stackOffsetToCheck, 4)) { throw new Exception("Stack offset not aligned!"); } if (debugEnabled) { if (!CompilerEngine.UseGen3Kernel) { XS.Compare(XSRegisters.ESP, 0, destinationDisplacement: (int)stackOffsetToCheck); XS.Jump(CPU.ConditionalTestEnum.NotEqual, ".AfterNullCheck"); XS.ClearInterruptFlag(); // don't remove the call. It seems pointless, but we need it to retrieve the EIP value XS.Call(".NullCheck_GetCurrAddress"); XS.Label(".NullCheck_GetCurrAddress"); XS.Pop(XSRegisters.EAX); new CPU.Mov { DestinationRef = ElementReference.New("DebugStub_CallerEIP"), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.EAX }; XS.Call("DebugStub_SendNullReferenceOccurred"); } XS.Halt(); XS.Label(".AfterNullCheck"); } }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { OpType xType = (OpType)aOpCode; if (IsReferenceType(xType.Value)) { return; } uint xSize = Align(SizeOfType(xType.Value), 4); string xTypeID = GetTypeIDLabel(xType.Value); XS.Push(ObjectUtils.FieldDataOffset + xSize); XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Pop(ESI); XS.Set(EBX, xTypeID, sourceIsIndirect: true); XS.Set(ESI, EBX, destinationIsIndirect: true); XS.Set(ESI, (uint)ObjectUtils.InstanceTypeEnum.BoxedValueType, destinationDisplacement: 4, size: RegisterSize.Int32); new Comment(Assembler, "xSize is " + xSize); for (int i = 0; i < (xSize / 4); i++) { XS.Pop(EDX); XS.Set(ESI, EDX, destinationDisplacement: (ObjectUtils.FieldDataOffset + (i * 4)), size: RegisterSize.Int32); } XS.Push(ESI); XS.Push(0); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xType = (OpType)aOpCode; var xTypeID = GetTypeIDLabel(xType.Value); var xCurrentMethodLabel = GetLabel(aMethod, aOpCode); var xAfterIsInstanceCallLabel = xCurrentMethodLabel + "_After_IsInstance_Call"; var xInvalidCastLabel = xCurrentMethodLabel + "_InvalidCast"; var xNextPositionLabel = GetLabel(aMethod, aOpCode.NextPosition); XS.Set(EAX, ESP, sourceDisplacement: 4); XS.Compare(EAX, 0); XS.Jump(ConditionalTestEnum.Zero, xNextPositionLabel); XS.Push(EAX, isIndirect: true); XS.Push(xTypeID, isIndirect: true); XS.Push(Convert.ToUInt32(xType.Value.IsInterface)); MethodBase xMethodIsInstance = VTablesImplRefs.IsInstanceRef; Call.DoExecute(Assembler, aMethod, xMethodIsInstance, aOpCode, xCurrentMethodLabel, xAfterIsInstanceCallLabel, DebugEnabled); XS.Label(xAfterIsInstanceCallLabel); XS.Pop(EAX); XS.Compare(EAX, 0); XS.Jump(ConditionalTestEnum.Equal, xInvalidCastLabel); XS.Jump(xNextPositionLabel); XS.Label(xInvalidCastLabel); XS.Call(LabelName.Get(ExceptionHelperRefs.ThrowInvalidCastExceptionRef)); }
public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: 12, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: 8, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: 16, sourceIsIndirect: true); XS.Call(XSRegisters.EAX); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { // TODO: Implement exception DoNullReferenceCheck(Assembler, DebugEnabled, 4); XS.Add(ESP, 4); XS.Pop(EAX); XS.Set(LabelName.GetStaticFieldName(ExceptionHelperRefs.CurrentExceptionRef), EAX, destinationIsIndirect: true); XS.Call("SystemExceptionOccurred"); XS.Set(ECX, 3); EmitExceptionLogic(Assembler, aMethod, aOpCode, false, null); }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { #warning TODO: Implement exception DoNullReferenceCheck(Assembler, DebugEnabled, 0); XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = Cosmos.Assembler.ElementReference.New(DataMember.GetStaticFieldName(ExceptionHelperRefs.CurrentExceptionRef)), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.EAX }; XS.Call("SystemExceptionOccurred"); XS.Set(XSRegisters.ECX, 3); Call.EmitExceptionLogic(Assembler, aMethod, aOpCode, false, null); }
public static void DoExecute(Cosmos.Assembler.Assembler assembler, _MethodInfo aMethod, string field, Type declaringType, ILOpCode aCurrentOpCode) { // call cctor: var xCctor = (declaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); if (aCurrentOpCode != null) { ILOp.EmitExceptionLogic(assembler, aMethod, aCurrentOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } } string xDataName = field; XS.Push(xDataName); }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { Cosmos.IL2CPU.ILOpCodes.OpType xType = (Cosmos.IL2CPU.ILOpCodes.OpType)aOpCode; uint xSize = SizeOfType(xType.Value); //TODO cache it to reduce calculation string xTypeID = GetTypeIDLabel(typeof(Array)); MethodBase xCtor = typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)[0]; string xCtorName = LabelName.Get(xCtor); new Comment(Assembler, "Element Size = " + xSize); // element count is on the stack XS.Pop(XSRegisters.ESI); XS.Push(XSRegisters.ESI); //Assembler.StackSizes.Push(xElementCountSize); XS.Push(xSize); new Mul(Assembler).Execute(aMethod, aOpCode); // the total items size is now on the stack XS.Push((ObjectImpl.FieldDataOffset + 4)); new Add(Assembler).Execute(aMethod, aOpCode); // the total array size is now on the stack. XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack 3 times now, once from the return value, twice from the pushes; XS.Pop(XSRegisters.EAX); XS.Set(EAX, EAX, sourceIsIndirect: true); XS.Set(EBX, xTypeID, sourceIsIndirect: true); XS.Set(EAX, EBX, destinationIsIndirect: true); XS.Add(XSRegisters.EAX, 4); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.EAX, DestinationIsIndirect = true, SourceValue = (uint)InstanceTypeEnum.Array, Size = 32 }; XS.Add(XSRegisters.EAX, 4); XS.Set(EAX, ESI, destinationIsIndirect: true, size: RegisterSize.Int32); XS.Add(XSRegisters.EAX, 4); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.EAX, DestinationIsIndirect = true, SourceValue = (uint)xSize, Size = 32 }; XS.Call(xCtorName); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xType = (ILOpCodes.OpType)aOpCode; uint xSize = SizeOfType(xType.Value.GetElementType() ?? xType.Value); string xTypeID = GetTypeIDLabel(xType.Value.GetElementType() ?? xType.Value); MethodBase xCtor = typeof(Array).GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance)[0]; string xCtorName = LabelName.Get(xCtor); XS.Comment("Element Size = " + xSize); XS.Pop(EAX); // element count XS.Push(EAX); XS.Set(EDX, xSize); XS.Multiply(EDX); // total element size XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // total array size XS.Push(EAX); //XS.Push(0x4E3A44A9); //XS.LiteralCode("Call DebugStub_SendSimpleNumber"); //XS.Pop(EAX); //XS.Push(".AfterAlloc"); //XS.LiteralCode("Call DebugStub_SendSimpleNumber"); //XS.Pop(EAX); XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Label(".AfterAlloc"); XS.Pop(EAX); // location //XS.LiteralCode("Call DebugStub_SendSimpleNumber"); XS.Pop(ESI); // element count XS.Push(EAX); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack 3 times now, once from the return value, twice from the pushes; XS.Pop(EAX); XS.Set(EBX, xTypeID, sourceIsIndirect: true); // array type id XS.Set(EAX, EBX, destinationIsIndirect: true); // array type id XS.Set(EAX, (uint)ObjectUtils.InstanceTypeEnum.Array, destinationDisplacement: 4, destinationIsIndirect: true); XS.Set(EAX, ESI, destinationDisplacement: 8, destinationIsIndirect: true); // element count XS.Set(EAX, xSize, destinationDisplacement: 12, destinationIsIndirect: true); // element size XS.Push(0); XS.Call(xCtorName); XS.Push(0); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackType = aOpCode.StackPopTypes[0]; var xNoThrowLabel = GetLabel(aMethod, aOpCode) + ".NoThrow"; switch (SizeOfType(xStackType)) { case 4: XS.Pop(EAX); XS.And(EAX, 0x7FFFFFFF); XS.Compare(EAX, 0x7F800000); XS.Jump(ConditionalTestEnum.Below, xNoThrowLabel); XS.SSE2.ConvertSS2SD(XMM0, EAX); XS.Sub(ESP, 8); XS.SSE2.MoveSD(ESP, XMM0, true); break; case 8: XS.Set(EAX, ESP, sourceDisplacement: 4); XS.And(EAX, 0x7FFFFFFF); XS.Compare(EAX, 0x7F800000); XS.Jump(ConditionalTestEnum.Below, xNoThrowLabel); break; default: throw new NotImplementedException(); } XS.Call(LabelName.Get(ExceptionHelperRefs.ThrowNotFiniteNumberExceptionRef)); XS.Label(xNoThrowLabel); }
protected static void DoNullReferenceCheck(Assembler assembler, bool debugEnabled, int stackOffsetToCheck) { if (stackOffsetToCheck != SignedAlign(stackOffsetToCheck, 4)) { throw new Exception("Stack offset not aligned!"); } if (debugEnabled) { //if (!CompilerEngine.UseGen3Kernel) { XS.Compare(XSRegisters.ESP, 0, destinationDisplacement: (int)stackOffsetToCheck); XS.Jump(CPU.ConditionalTestEnum.NotEqual, ".AfterNullCheck"); XS.ClearInterruptFlag(); // don't remove the call. It seems pointless, but we need it to retrieve the EIP value XS.Call(".NullCheck_GetCurrAddress"); XS.Label(".NullCheck_GetCurrAddress"); XS.Pop(XSRegisters.EAX); XS.Set(AsmMarker.Labels[AsmMarker.Type.DebugStub_CallerEIP], XSRegisters.EAX, destinationIsIndirect: true); XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_SendNullRefEvent]); //} XS.Halt(); XS.Label(".AfterNullCheck"); } }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { int start = 0; for (int i = start; i < 256; i++) { if (i == 1 || i == 3) { //continue; // was used for debugging } XS.Set(XSRegisters.EAX, "_isr" + i.ToString("X2")); XS.Set("_NATIVE_IDT_Contents", XSRegisters.AL, destinationDisplacement: (i * 8) + 0); XS.Set("_NATIVE_IDT_Contents", XSRegisters.AH, destinationDisplacement: (i * 8) + 1); XS.Set("_NATIVE_IDT_Contents", 0x08, destinationDisplacement: (i * 8) + 2, size: XSRegisters.RegisterSize.Byte8); XS.Set("_NATIVE_IDT_Contents", 0x00, destinationDisplacement: (i * 8) + 4, size: XSRegisters.RegisterSize.Byte8); XS.Set("_NATIVE_IDT_Contents", 0x8E, destinationDisplacement: (i * 8) + 5, size: XSRegisters.RegisterSize.Byte8); XS.ShiftRight(XSRegisters.EAX, 16); XS.Set("_NATIVE_IDT_Contents", XSRegisters.AL, destinationDisplacement: (i * 8) + 6); XS.Set("_NATIVE_IDT_Contents", XSRegisters.AH, destinationDisplacement: (i * 8) + 7); } XS.Jump("skip_isrhandlers"); var xInterruptsWithParam = new[] { 8, 10, 11, 12, 13, 14 }; for (int j = start; j < 256; j++) { XS.Label("_isr" + j.ToString("X2")); XS.ClearInterruptFlag(); XS.Call("__INTERRUPT_OCCURRED__"); if (global::System.Array.IndexOf(xInterruptsWithParam, j) == -1) { XS.Push(0); } XS.Push((uint)j); XS.Jump("CommonISRBase"); } XS.Label("CommonISRBase"); XS.PushAllRegisters(); XS.Set(XSRegisters.EAX, XSRegisters.ESP); XS.Set("static_field__Kernel_System_Core_ISR_old_esp", XSRegisters.EAX, destinationIsIndirect: true); XS.Sub(XSRegisters.ESP, 4); XS.Set(XSRegisters.EAX, XSRegisters.ESP); XS.And(XSRegisters.ESP, 0xfffffff0); XS.Sub(XSRegisters.ESP, 512); XS.SSE.FXSave(XSRegisters.ESP, isIndirect: true); XS.Set(XSRegisters.EAX, XSRegisters.ESP, destinationIsIndirect: true); XS.Push(XSRegisters.EAX); XS.Push(XSRegisters.EAX); XS.Set("static_field__Kernel_System_Core_ISR_Registers", XSRegisters.EAX, destinationIsIndirect: true); MethodBase xHandler = GetMethodDef(typeof(ISR).Assembly, typeof(ISR).FullName, "CommonISRHandler", true); XS.Call(LabelName.Get(xHandler)); XS.Pop(XSRegisters.EAX); XS.SSE.FXRestore(XSRegisters.ESP, isIndirect: true); XS.Set(XSRegisters.ESP, XSRegisters.EAX); XS.Add(XSRegisters.ESP, 4); XS.Set(XSRegisters.EAX, "static_field__Kernel_System_Core_ISR_old_esp", sourceIsIndirect: true); XS.Set(XSRegisters.ESP, XSRegisters.EAX); XS.PopAllRegisters(); XS.Add(XSRegisters.ESP, 8); XS.InterruptReturn(); XS.Label("skip_isrhandlers"); }
public override void AssembleNew(object aAssembler, object aMethodInfo) { XS.Mov(XSRegisters.BL, 0xa8); XS.Call("send_mouse_cmd"); XS.Call("mouse_read"); XS.Noop(); XS.Mov(XSRegisters.BL, 0x20); XS.Call("send_mouse_cmd"); XS.Call("mouse_read"); XS.Or(XSRegisters.AL, 3); XS.Mov(XSRegisters.BL, 0x60); XS.Push(XSRegisters.EAX); XS.Call("send_mouse_cmd"); XS.Pop(XSRegisters.EAX); XS.Call("mouse_write"); XS.Noop(); XS.Mov(XSRegisters.BL, 0xd4); XS.Call("send_mouse_cmd"); XS.Mov(XSRegisters.AL, 0xf4); XS.Call("mouse_write"); XS.Call("mouse_read"); #region mouse_read XS.Label("mouse_read"); { XS.Push(XSRegisters.ECX); XS.Push(XSRegisters.EDX); XS.Mov(XSRegisters.ECX, 0xffff); XS.Label("mouse_read_loop"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 1); XS.Jump(ConditionalTestEnum.NotZero, "mouse_read_ready"); new Loop { DestinationLabel = "mouse_read_loop" }; XS.Mov(XSRegisters.AH, 1); XS.Jump("mouse_read_exit"); } XS.Label("mouse_read_ready"); { XS.Push(XSRegisters.ECX); XS.Mov(XSRegisters.ECX, 32); } XS.Label("mouse_read_delay"); { new Loop { DestinationLabel = "mouse_read_delay" }; XS.Pop(XSRegisters.ECX); new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x60, Size = 8 }; XS.Xor(XSRegisters.AH, XSRegisters.RegistersEnum.AH); } XS.Label("mouse_read_exit"); { XS.Pop(XSRegisters.EDX); XS.Pop(XSRegisters.ECX); XS.Return(); } } #endregion #region mouse_write XS.Label("mouse_write"); { XS.Push(XSRegisters.ECX); XS.Push(XSRegisters.EDX); XS.Mov(XSRegisters.BH, XSRegisters.RegistersEnum.AL); XS.Mov(XSRegisters.ECX, 0xffff); XS.Label("mouse_write_loop1"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 32); XS.Jump(ConditionalTestEnum.Zero, "mouse_write_ok1"); new Loop { DestinationLabel = "mouse_write_loop1" }; XS.Mov(XSRegisters.AH, 1); XS.Jump("mouse_write_exit"); } XS.Label("mouse_write_ok1"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x60, Size = 8 }; XS.Mov(XSRegisters.ECX, 0xffff); } XS.Label("mouse_write_loop"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 2); XS.Jump(ConditionalTestEnum.Zero, "mouse_write_ok"); new Loop { DestinationLabel = "mouse_write_loop" }; XS.Mov(XSRegisters.AH, 1); XS.Jump("mouse_write_exit"); } XS.Label("mouse_write_ok"); { XS.Mov(XSRegisters.AL, XSRegisters.RegistersEnum.BH); new Out2Port { DestinationValue = 0x60, SourceReg = RegistersEnum.AL, Size = 8 }; XS.Mov(XSRegisters.ECX, 0xffff); } XS.Label("mouse_write_loop3"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 2); XS.Jump(ConditionalTestEnum.Zero, "mouse_write_ok3"); new Loop { DestinationLabel = "mouse_write_loop3" }; XS.Mov(XSRegisters.AH, 1); XS.Jump("mouse_write_exit"); } XS.Label("mouse_write_ok3"); { XS.Mov(XSRegisters.AH, 0x08); } XS.Label("mouse_write_loop4"); { XS.Mov(XSRegisters.ECX, 0xffff); } XS.Label("mouse_write_loop5"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 1); XS.Jump(ConditionalTestEnum.NotZero, "mouse_write_ok4"); new Loop { DestinationLabel = "mouse_write_loop5" }; XS.Dec(XSRegisters.AH); XS.Jump(ConditionalTestEnum.NotZero, "mouse_write_loop4"); } XS.Label("mouse_write_ok4"); { XS.Xor(XSRegisters.AH, XSRegisters.RegistersEnum.AH); } XS.Label("mouse_write_exit"); { XS.Pop(XSRegisters.EDX); XS.Pop(XSRegisters.ECX); XS.Return(); } } #endregion #region send_mouse_cmd XS.Label("send_mouse_cmd"); { XS.Mov(XSRegisters.ECX, 0xffff); XS.Label("mouse_cmd_wait"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 2); XS.Jump(ConditionalTestEnum.Zero, "mouse_cmd_send"); new Loop { DestinationLabel = "mouse_cmd_wait" }; XS.Jump("mouse_cmd_error"); } XS.Label("mouse_cmd_send"); { XS.Mov(XSRegisters.AL, XSRegisters.RegistersEnum.BL); new Out2Port { #if DebugMouse SourceValue = 0x64, DestinationReg = RegistersEnum.AL, #else DestinationValue = 0x64, SourceReg = RegistersEnum.AL, #endif Size = 8 }; XS.Mov(XSRegisters.ECX, 0xffff); } XS.Label("mouse_cmd_accept"); { new In2Port { DestinationReg = RegistersEnum.AL, SourceValue = 0x64, Size = 8 }; XS.Test(XSRegisters.AL, 0x02); XS.Jump(ConditionalTestEnum.Zero, "mouse_cmd_ok"); new Loop { DestinationLabel = "mouse_cmd_accept" }; } XS.Label("mouse_cmd_error"); { XS.Mov(XSRegisters.AH, 0x01); XS.Jump("mouse_cmd_exit"); } XS.Label("mouse_cmd_ok"); { XS.Xor(XSRegisters.AH, XSRegisters.RegistersEnum.AH); } XS.Label("mouse_cmd_exit"); { XS.Return(); } } #endregion }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { var xAssembler = aAssembler; var xMethodInfo = (_MethodInfo)aMethodInfo; var xMethodBaseAsInfo = xMethodInfo.MethodBase as global::System.Reflection.MethodInfo; if (xMethodBaseAsInfo.ReturnType != typeof(void)) { throw new Exception("Events with return type not yet supported!"); } /* * EAX contains the GetInvocationList() array at the index at which it was last used * EDX contains the index at which the EAX is * EBX contains the number of items in the array * ECX contains the argument size */ XS.ClearInterruptFlag(); XS.Comment("Get Invoke list count"); var xGetInvocationListMethod = typeof(MulticastDelegate).GetMethod("GetInvocationList"); Ldarg.DoExecute(aAssembler, xMethodInfo, 0); XS.Call(LabelName.Get(xGetInvocationListMethod)); XS.Add(XSRegisters.ESP, 4); XS.Pop(XSRegisters.EAX); XS.Add(XSRegisters.EAX, 8); XS.Set(XSRegisters.EBX, XSRegisters.EAX, sourceIsIndirect: true); XS.Comment("Get invoke method"); XS.Add(XSRegisters.EAX, 8); XS.Set(XSRegisters.EDI, XSRegisters.EAX, sourceIsIndirect: true, sourceDisplacement: 4); XS.Comment("Get ArgSize"); int xArgSizeOffset = Ldfld.GetFieldOffset(typeof(global::System.Delegate), "$$ArgSize$$"); Ldarg.DoExecute(aAssembler, xMethodInfo, 0); XS.Add(XSRegisters.ESP, 4); XS.Pop(XSRegisters.ECX); XS.Add(XSRegisters.ECX, (uint)xArgSizeOffset); XS.Set(XSRegisters.ECX, XSRegisters.ECX, sourceIsIndirect: true); XS.Comment("Set current invoke list index"); XS.Set(XSRegisters.EDX, 0); XS.Label(".BEGIN_OF_LOOP"); { XS.Compare(XSRegisters.EDX, XSRegisters.EBX); XS.Jump(x86.ConditionalTestEnum.GreaterThanOrEqualTo, ".END_OF_INVOKE"); XS.PushAllRegisters(); XS.Comment("Check if delegate has $this"); XS.Set(XSRegisters.EDI, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Add(XSRegisters.EDI, 4); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.Object System.Delegate._target")); XS.Compare(XSRegisters.EDI, 0); XS.Jump(x86.ConditionalTestEnum.Zero, ".NO_THIS"); XS.Label(".HAS_THIS"); XS.Push(XSRegisters.EDI); XS.Push(0); XS.Label(".NO_THIS"); XS.Set(XSRegisters.EDI, XSRegisters.EAX, sourceIsIndirect: true, sourceDisplacement: 4); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.IntPtr System.Delegate._methodPtr")); XS.Comment("Check if delegate has args"); XS.Compare(XSRegisters.ECX, 0); XS.Jump(x86.ConditionalTestEnum.Zero, ".NO_ARGS"); XS.Label(".HAS_ARGS"); XS.Sub(XSRegisters.ESP, XSRegisters.ECX); XS.Push(XSRegisters.EDI); XS.Set(XSRegisters.EDI, XSRegisters.ESP); XS.Add(XSRegisters.EDI, 4); XS.Set(XSRegisters.ESI, XSRegisters.EBP); XS.Add(XSRegisters.ESI, 8); new x86.Movs { Size = 8, Prefixes = x86.InstructionPrefixes.Repeat }; XS.Pop(XSRegisters.EDI); XS.Label(".NO_ARGS"); XS.Call(XSRegisters.EDI); XS.PopAllRegisters(); XS.Increment(XSRegisters.EDX); XS.Jump(".BEGIN_OF_LOOP"); } XS.Label(".END_OF_INVOKE"); XS.Set(XSRegisters.EDX, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Set(XSRegisters.EDX, XSRegisters.EDX, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "$$ReturnsValue$$")); XS.Compare(XSRegisters.EDX, 0); XS.Jump(x86.ConditionalTestEnum.Equal, ".NO_RETURN"); XS.Label(".HAS_RETURN"); XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationDisplacement: 8); XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationDisplacement: 4); XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationIsIndirect: true); XS.Push(XSRegisters.EDX); XS.Set(XSRegisters.ESP, XSRegisters.EDI, destinationDisplacement: 12); XS.Label(".NO_RETURN"); XS.EnableInterrupts(); }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { var xMethodInfo = (Il2cpuMethodInfo)aMethodInfo; /* * EAX contains the GetInvocationList() array at the index at which it was last used * EBX contains the number of items in the array * ECX contains the argument size * EDX contains the current index in the array * ESI contains the size of the return value * EDI contains the function pointer */ XS.ClearInterruptFlag(); XS.Comment("Get Invoke list count"); var xGetInvocationListMethod = typeof(MulticastDelegate).GetMethod("GetInvocationList"); Ldarg.DoExecute(aAssembler, xMethodInfo, 0); XS.Call(LabelName.Get(xGetInvocationListMethod)); XS.Add(ESP, 4); XS.Pop(EAX); XS.Add(EAX, 8); XS.Set(EBX, EAX, sourceIsIndirect: true); XS.Comment("Get invoke method"); XS.Add(EAX, 8); XS.Set(EDI, EAX, sourceIsIndirect: true, sourceDisplacement: 4); // this line can propably can be removed XS.Comment("Get ArgSize"); int xArgSizeOffset = Ldfld.GetFieldOffset(typeof(Delegate), "$$ArgSize$$"); Ldarg.DoExecute(aAssembler, xMethodInfo, 0); XS.Add(ESP, 4); XS.Pop(ECX); XS.Add(ECX, (uint)xArgSizeOffset); XS.Set(ECX, ECX, sourceIsIndirect: true); XS.Comment("Set current invoke list index"); XS.Set(EDX, 0); XS.Comment("Make space for return value"); int returnSizeOffset = Ldfld.GetFieldOffset(typeof(Delegate), "$$ReturnSize$$"); Ldarg.DoExecute(aAssembler, xMethodInfo, 0); XS.Add(ESP, 4); XS.Pop(ESI); XS.Add(ESI, (uint)returnSizeOffset); XS.Set(ESI, ESI, sourceIsIndirect: true); XS.Sub(ESP, ESI); XS.Label(".BEGIN_OF_LOOP"); { XS.Compare(EDX, EBX); XS.Jump(x86.ConditionalTestEnum.GreaterThanOrEqualTo, ".END_OF_INVOKE"); XS.PushAllRegisters(); XS.Comment("Check if delegate has $this"); XS.Set(EDI, EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Add(EDI, 4); XS.Set(EDI, EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.Object System.Delegate._target")); XS.Set(EDX, ECX); // edx contains the size of the arguments including $this XS.Compare(EDI, 0); XS.Jump(x86.ConditionalTestEnum.Zero, ".NO_THIS"); XS.Label(".HAS_THIS"); XS.Push(EDI); XS.Set(EDI, EDI, sourceIsIndirect: true); // get type of target object XS.Add(EDX, 4); // we have at least one int of $this //TODO: In future we might be able to replace the following call with a check //if the object is boxed and in that case assume its a struct // safe info from registers which get trashed XS.Push(EAX); XS.Push(EBX); XS.Push(ECX); XS.Push(EDX); XS.Push(EDI); XS.Call(LabelName.Get(VTablesImplRefs.IsStructRef)); XS.Pop(EDI); // restore values XS.Pop(EDX); XS.Pop(ECX); XS.Pop(EBX); XS.Pop(EAX); // now check if target turned out to be struct XS.Compare(EDI, 1); XS.Jump(x86.ConditionalTestEnum.Equal, ".Struct"); //structs are just the pointer so we are already done XS.Push(0); XS.Add(EDX, 4); XS.Jump(".NO_THIS"); XS.Label(".Struct"); XS.Add(ESP, ObjectUtils.FieldDataOffset, destinationIsIndirect: true); XS.Label(".NO_THIS"); XS.Set(EDI, EAX, sourceIsIndirect: true, sourceDisplacement: 4); XS.Set(EDI, EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.IntPtr System.Delegate._methodPtr")); XS.Set(EBX, 0); // initialise required extra space to 0 XS.Compare(ESI, EDX); XS.Jump(x86.ConditionalTestEnum.LessThanOrEqualTo, ".NO_RETURN_VALUE_SPACE"); XS.Set(EBX, ESI); XS.Sub(EBX, ECX); XS.Label(".NO_RETURN_VALUE_SPACE"); XS.Comment("Check if delegate has args"); XS.Compare(ECX, 0); XS.Jump(x86.ConditionalTestEnum.Zero, ".NO_ARGS"); XS.Label(".HAS_ARGS"); XS.Sub(ESP, ECX); XS.Push(EDI); XS.Set(EDI, ESP); XS.Add(EDI, 4); XS.Set(ESI, EBP); XS.Compare(EBX, 0); XS.Jump(x86.ConditionalTestEnum.Equal, ".NO_RETURN_EXTRA"); XS.Add(ESI, EBX); // to skip the extra space reserved for the return value XS.Jump(".AFTER_ADJUST_ESI"); XS.Label(".NO_RETURN_EXTRA"); XS.Add(ESI, 8); XS.Label(".AFTER_ADJUST_ESI"); new x86.Movs { Size = 8, Prefixes = x86.InstructionPrefixes.Repeat }; XS.Pop(EDI); XS.Label(".NO_ARGS"); XS.Sub(ESP, EBX); // make extra space for the return value XS.Call(EDI); XS.Comment("If there is a return value copy it to holding place now"); Ldarg.DoExecute(aAssembler, xMethodInfo, 0); XS.Add(ESP, 4); XS.Pop(EAX); XS.Add(EAX, (uint)returnSizeOffset); XS.Set(EAX, EAX, sourceIsIndirect: true); // got size of return value XS.Set(EDI, EBP); XS.Sub(EDI, EAX); XS.Label(".RETURN_VALUE_LOOP_START"); XS.Compare(EAX, 0); XS.Jump(x86.ConditionalTestEnum.LessThanOrEqualTo, ".RETURN_VALUE_LOOP_END"); XS.Pop(EBX); XS.Set(EDI, EBX, destinationIsIndirect: true); XS.Add(EDI, 4); XS.Sub(EAX, 4); XS.Jump(".RETURN_VALUE_LOOP_START"); XS.Label(".RETURN_VALUE_LOOP_END"); XS.PopAllRegisters(); XS.Increment(EDX); XS.Jump(".BEGIN_OF_LOOP"); } XS.Label(".END_OF_INVOKE"); XS.EnableInterrupts(); }
public static void Assemble(Cosmos.Assembler.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) { XS.Call(LabelName.Get(xCctor)); ILOp.EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } } if (objectType.IsValueType) { #region Valuetypes XS.Comment("ValueType"); /* * 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 */ // Size of return value - we need to make room for this on the stack. uint xStorageSize = Align(SizeOfType(objectType), 4); XS.Comment("StorageSize: " + xStorageSize); if (xStorageSize == 0) { throw new Exception("ValueType storage size cannot be 0."); } //var xStorageSize = aCtorDeclTypeInfo.StorageSize; uint xArgSize = 0; var xParameterList = constructor.GetParameters(); foreach (var xParam in xParameterList) { xArgSize = xArgSize + Align(SizeOfType(xParam.ParameterType), 4); } XS.Comment("ArgSize: " + xArgSize); // Set ESP so we can push the struct ptr int xShift = (int)(xArgSize - xStorageSize); XS.Comment("Shift: " + xShift); if (xShift < 0) { XS.Sub(XSRegisters.ESP, (uint)Math.Abs(xShift)); } else if (xShift > 0) { XS.Add(XSRegisters.ESP, (uint)xShift); } // push struct ptr XS.Push(XSRegisters.ESP); // Shift args foreach (var xParam in xParameterList) { uint xArgSizeForThis = Align(SizeOfType(xParam.ParameterType), 4); for (int i = 1; i <= xArgSizeForThis / 4; i++) { new CPUx86.Push { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)xStorageSize }; } } new Call(aAssembler).Execute(aMethod, xMethod); // Need to put these *after* the call because the Call pops the args from the stack // and we have mucked about on the stack, so this makes it right before the next // op. #endregion Valuetypes } else { // If not ValueType, then we need gc var xParams = constructor.GetParameters(); // array length + 8 bool xHasCalcSize = false; #region Special string handling // try calculating size: if (constructor.DeclaringType == typeof(string)) { if (xParams.Length == 1 && xParams[0].ParameterType == typeof(char[])) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); // EAX contains a memory handle now, lets dereference it to a pointer XS.Set(EAX, EAX, sourceIsIndirect: true); XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceDisplacement: 8); XS.Set(XSRegisters.EDX, 2); XS.Multiply(XSRegisters.EDX); XS.Push(XSRegisters.EAX); } else if (xParams.Length == 3 && (xParams[0].ParameterType == typeof(char[]) || xParams[0].ParameterType == typeof(char *)) && xParams[1].ParameterType == typeof(int) && xParams[2].ParameterType == typeof(int)) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.ShiftLeft(XSRegisters.EAX, 1); XS.Push(XSRegisters.EAX); } else if (xParams.Length == 2 && xParams[0].ParameterType == typeof(char) && xParams[1].ParameterType == typeof(int)) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.ShiftLeft(XSRegisters.EAX, 1); XS.Push(XSRegisters.EAX); } else { throw new NotImplementedException("In NewObj, a string ctor implementation is missing!"); } } #endregion Special string handling uint xMemSize = GetStorageSize(objectType); int xExtraSize = 12; // additional size for set values after alloc XS.Push((uint)(xMemSize + xExtraSize)); if (xHasCalcSize) { XS.Pop(XSRegisters.EAX); XS.Add(ESP, EAX, destinationIsIndirect: true); } // todo: probably we want to check for exceptions after calling Alloc XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Label(".AfterAlloc"); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack now 3 times. Once from the Alloc return value, twice from the pushes //? ?? 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); XS.Pop(XSRegisters.EAX); XS.Set(EAX, EAX, sourceIsIndirect: true); XS.Set(EBX, strTypeId, sourceIsIndirect: true); XS.Set(EAX, EBX, destinationIsIndirect: true); XS.Set(EAX, (uint)InstanceTypeEnum.NormalObject, destinationDisplacement: 4, size: RegisterSize.Int32); XS.Set(EAX, (uint)xGCFieldCount, destinationDisplacement: 8, size: RegisterSize.Int32); 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.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xSize + 4) }; } } XS.Call(LabelName.Get(constructor)); // should the complete error handling happen by ILOp.EmitExceptionLogic? if (aMethod != null) { // todo: only happening for real methods now, not for ctor's ? XS.Test(XSRegisters.ECX, 2); string xNoErrorLabel = currentLabel + ".NoError" + LabelName.LabelCount.ToString(); XS.Jump(CPUx86.ConditionalTestEnum.Equal, 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 XS.Add(XSRegisters.ESP, 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 }; //} new Comment(aAssembler, "[ Newobj.Execute cleanup end ]"); Jump_Exception(aMethod); XS.Label(xNoErrorLabel); } XS.Pop(XSRegisters.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); XS.Push(XSRegisters.EAX); } }
public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { var xAssembler = (Cosmos.Assembler.Assembler)aAssembler; var xMethodInfo = (Cosmos.IL2CPU.MethodInfo)aMethodInfo; var xMethodBaseAsInfo = xMethodInfo.MethodBase as global::System.Reflection.MethodInfo; if (xMethodBaseAsInfo.ReturnType != typeof(void)) { throw new Exception("Events with return type not yet supported!"); } XS.Comment("XXXXXXX"); XS.Exchange(XSRegisters.BX, XSRegisters.BX); /* * EAX contains the GetInvocationList() array at the index at which it was last used * EDX contains the index at which the EAX is * EBX contains the number of items in the array * ECX contains the argument size */ XS.ClearInterruptFlag(); XS.Label(".DEBUG"); //XS.Label("____DEBUG_FOR_MULTICAST___"); XS.Comment("move address of delegate to eax"); XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); var xGetInvocationListMethod = typeof(MulticastDelegate).GetMethod("GetInvocationList"); XS.Comment("push address of delgate to stack"); XS.Push(XSRegisters.EAX);//addrof this XS.Call(LabelName.Get(xGetInvocationListMethod)); XS.Comment("get address from return value -> eax"); XS.Pop(XSRegisters.EAX); ;//list XS.Comment("eax+=8 is where the offset where an array's count is"); XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceIsIndirect: true); XS.Add(XSRegisters.EAX, 8); //addrof list.Length XS.Comment("store count in ebx"); XS.Set(XSRegisters.EBX, XSRegisters.EAX, sourceIsIndirect: true); //list.count XS.Comment("eax+=8 is where the offset where an array's items start"); XS.Add(XSRegisters.EAX, 8); // Put pointer at the first item in the list. XS.Set(XSRegisters.EDI, 0); XS.Comment("ecx = ptr to delegate object"); XS.Set(XSRegisters.ECX, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0));//addrof the delegate XS.Comment("ecx points to the size of the delegated methods arguments"); XS.Set(XSRegisters.ECX, XSRegisters.ECX, sourceIsIndirect: true); XS.Set(XSRegisters.ECX, XSRegisters.ECX, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "$$ArgSize$$")); //the size of the arguments to the method? + 12??? -- 12 is the size of the current call stack.. i think XS.Xor(XSRegisters.EDX, XSRegisters.EDX); ; //make sure edx is 0 XS.Label(".BEGIN_OF_LOOP"); { XS.Compare(XSRegisters.EDX, XSRegisters.EBX); //are we at the end of this list XS.Jump(CPUx86.ConditionalTestEnum.GreaterThanOrEqualTo, ".END_OF_INVOKE_"); //then we better stop XS.PushAllRegisters(); XS.Comment("esi points to where we will copy the methods argumetns from"); XS.Set(XSRegisters.ESI, XSRegisters.ESP); XS.Comment("edi = ptr to delegate object"); XS.Set(XSRegisters.EDI, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceIsIndirect: true); // dereference handle XS.Comment("edi = ptr to delegate object should be a pointer to the delgates context ie (this) for the methods "); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.Object System.Delegate._target")); XS.Compare(XSRegisters.EDI, 0); XS.Jump(CPUx86.ConditionalTestEnum.Zero, ".NO_THIS"); XS.Push(XSRegisters.EDI); XS.Label(".NO_THIS"); XS.Comment("make space for us to copy the arguments too"); XS.Sub(XSRegisters.ESP, XSRegisters.ECX); XS.Comment("move the current delegate to edi"); XS.Set(XSRegisters.EDI, XSRegisters.EAX, sourceIsIndirect: true); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceIsIndirect: true); // dereference XS.Comment("move the methodptr from that delegate to edi "); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.IntPtr System.Delegate._methodPtr")); // XS.Comment("save methodptr on the stack"); XS.Push(XSRegisters.EDI); XS.Comment("move location to copy args to"); XS.Set(XSRegisters.EDI, XSRegisters.ESP); XS.Add(XSRegisters.EDI, 4); //new CPU.Comment("get above the saved methodptr"); //XS.Sub(XSRegisters.ESP, 4); //we allocated the argsize on the stack once, and it we need to get above the original args XS.Comment("we allocated argsize on the stack once"); XS.Comment("add 32 for the Pushad + 16 for the current stack + 4 for the return value"); //uint xToAdd = 32; // skip pushad data //xToAdd += 4; // method pointer XS.Set(XSRegisters.ESI, XSRegisters.EBP); XS.Add(XSRegisters.ESI, 8); // ebp+8 is first argument new CPUx86.Movs { Size = 8, Prefixes = CPUx86.InstructionPrefixes.Repeat }; XS.Pop(XSRegisters.EDI); XS.Label(".BeforeCall"); XS.Call(XSRegisters.EDI); XS.Comment("store return -- return stored into edi after popad"); XS.Comment("edi = ptr to delegate object"); XS.Set(XSRegisters.EDI, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); XS.Comment("edi = ptr to delegate object should be a pointer to the delgates context ie (this) for the methods "); XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceIsIndirect: true); // dereference handle XS.Set(XSRegisters.EDI, XSRegisters.EDI, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "System.Object System.Delegate._target")); //i really dont get the +12, MtW: that's for the object header XS.Label(".noTHIStoPop"); XS.PopAllRegisters(); XS.Increment(XSRegisters.EDX); XS.Add(XSRegisters.EAX, 4); XS.Jump(".BEGIN_OF_LOOP"); } XS.Label(".END_OF_INVOKE_"); XS.Comment("get the return value"); XS.Set(XSRegisters.EDX, XSRegisters.EBP, sourceDisplacement: Ldarg.GetArgumentDisplacement(xMethodInfo, 0)); //addrof the delegate XS.Set(XSRegisters.EDX, XSRegisters.EDX, sourceIsIndirect: true); // dereference handle XS.Set(XSRegisters.EDX, XSRegisters.EDX, sourceDisplacement: Ldfld.GetFieldOffset(xMethodInfo.MethodBase.DeclaringType, "$$ReturnsValue$$")); XS.Compare(XSRegisters.EDX, 0); XS.Jump(CPUx86.ConditionalTestEnum.Equal, ".noReturn"); //may have to expand the return... idk XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationDisplacement: 8); XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationDisplacement: 4); XS.Exchange(XSRegisters.EBP, XSRegisters.EDX, destinationIsIndirect: true); XS.Push(XSRegisters.EDX);//ebp XS.Set(XSRegisters.ESP, XSRegisters.EDI, destinationDisplacement: 12); XS.Label(".noReturn"); XS.EnableInterrupts(); }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) {//I asked jp2masa XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: 8); XS.Call(XSRegisters.EAX); }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xType = aMethod.MethodBase.DeclaringType; var xOpCode = (OpField)aOpCode; SysReflection.FieldInfo xField = xOpCode.Value; // call cctor: var xCctor = (xField.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); ILOp.EmitExceptionLogic(Assembler, aMethod, aOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } //Assembler.Stack.Pop(); //int aExtraOffset;// = 0; //bool xNeedsGC = xField.FieldType.IsClass && !xField.FieldType.IsValueType; var xSize = SizeOfType(xField.FieldType); //if( xNeedsGC ) //{ // aExtraOffset = 12; //} string xDataName = DataMember.GetStaticFieldName(xField); var xTypeNeedsGC = TypeIsReferenceType(xField.FieldType); if (xTypeNeedsGC) { XS.Push(xDataName, isIndirect: true, displacement: 4); XS.Push(0); return; } if (xSize >= 4) { for (int i = 1; i <= (xSize / 4); i++) { // Pop("eax"); // Move(Assembler, "dword [" + mDataName + " + 0x" + (i * 4).ToString("X") + "]", "eax"); new CPUx86.Push { DestinationRef = Cosmos.Assembler.ElementReference.New(xDataName), DestinationIsIndirect = true, DestinationDisplacement = (int)(xSize - (i * 4)) }; } switch (xSize % 4) { case 1: { XS.Set(XSRegisters.EAX, 0); XS.Set(XSRegisters.AL, xDataName, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); break; } case 2: { XS.Set(XSRegisters.EAX, 0); XS.Set(XSRegisters.AX, xDataName, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); break; } case 0: { break; } default: //EmitNotImplementedException( Assembler, GetServiceProvider(), "Ldsfld: Remainder size " + ( xSize % 4 ) + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel ); throw new NotImplementedException(); //break; } } else { switch (xSize) { case 1: { XS.Set(XSRegisters.EAX, 0); XS.Set(XSRegisters.AL, xDataName, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); break; } case 2: { XS.Set(XSRegisters.EAX, 0); XS.Set(XSRegisters.AX, xDataName, sourceIsIndirect: true); XS.Push(XSRegisters.EAX); break; } case 0: { break; } default: //EmitNotImplementedException( Assembler, GetServiceProvider(), "Ldsfld: Remainder size " + ( xSize % 4 ) + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel ); throw new NotImplementedException(); //break; } } }
public static void DoExecute(Cosmos.Assembler.Assembler Assembler, _MethodInfo aCurrentMethod, MethodBase aTargetMethod, ILOpCode aOp, string currentLabel, string nextLabel, bool debugEnabled) { var xMethodInfo = aTargetMethod as MethodInfo; string xNormalAddress = LabelName.Get(aTargetMethod); var xParameters = aTargetMethod.GetParameters(); // todo: implement exception support uint xExtraStackSize = GetStackSizeToReservate(aTargetMethod); if (!aTargetMethod.IsStatic) { uint xThisOffset = 0; foreach (var xItem in xParameters) { xThisOffset += Align(SizeOfType(xItem.ParameterType), 4); } var stackOffsetToCheck = xThisOffset; if (TypeIsReferenceType(aTargetMethod.DeclaringType)) { DoNullReferenceCheck(Assembler, debugEnabled, (int)stackOffsetToCheck + 4); } else { DoNullReferenceCheck(Assembler, debugEnabled, (int)stackOffsetToCheck); } } if (xExtraStackSize > 0) { XS.Sub(XSRegisters.ESP, (uint)xExtraStackSize); } XS.Call(xNormalAddress); uint xReturnSize = 0; if (xMethodInfo != null) { xReturnSize = SizeOfType(xMethodInfo.ReturnType); } if (aCurrentMethod != null) { EmitExceptionLogic(Assembler, aCurrentMethod, aOp, true, delegate { var xStackOffsetBefore = aOp.StackOffsetBeforeExecution.Value; uint xPopSize = 0; foreach (var type in aOp.StackPopTypes) { xPopSize += Align(SizeOfType(type), 4); } var xResultSize = xReturnSize; if (xResultSize % 4 != 0) { xResultSize += 4 - (xResultSize % 4); } ILOp.EmitExceptionCleanupAfterCall(Assembler, xResultSize, xStackOffsetBefore, xPopSize); }, nextLabel); } }
public static void DoExecute(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, string aFieldId, Type aDeclaringObject, bool aNeedsGC, bool debugEnabled) { var xType = aMethod.MethodBase.DeclaringType; var xFields = GetFieldsInfo(aDeclaringObject, false); var xFieldInfo = (from item in xFields where item.Id == aFieldId select item).Single(); var xActualOffset = Ldfld.GetFieldOffset(aDeclaringObject, aFieldId); var xSize = xFieldInfo.Size; XS.Comment("Field: " + xFieldInfo.Id); XS.Comment("Type: " + xFieldInfo.FieldType.ToString()); XS.Comment("Size: " + xFieldInfo.Size); XS.Comment("Offset: " + xActualOffset + " (includes object header)"); uint xRoundedSize = Align(xSize, 4); DoNullReferenceCheck(aAssembler, debugEnabled, xRoundedSize); XS.Comment("After Nullref check"); XS.Set(XSRegisters.ECX, XSRegisters.ESP, sourceDisplacement: (int)xRoundedSize); // ECX contains the object pointer now if (aNeedsGC) { // for reference types (or boxed types), ECX actually contains the handle now, so we need to convert it to a memory address XS.Comment("Dereference memory handle now"); XS.Set(XSRegisters.ECX, XSRegisters.ECX, sourceIsIndirect: true); } if (debugEnabled) { XS.Push(XSRegisters.ECX); XS.Pop(XSRegisters.ECX); } XS.Add(XSRegisters.ECX, (uint)(xActualOffset)); //TODO: Can't we use an x86 op to do a byte copy instead and be faster? for (int i = 0; i < (xSize / 4); i++) { XS.Pop(XSRegisters.EAX); XS.Set(XSRegisters.ECX, XSRegisters.EAX, destinationDisplacement: (int)((i * 4))); } switch (xSize % 4) { case 1: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.RegistersEnum.AL }; break; } case 2: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.RegistersEnum.AX }; break; } case 3: { XS.Pop(XSRegisters.EAX); // move 2 lower bytes new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.RegistersEnum.AX }; // shift third byte to lowest XS.ShiftRight(XSRegisters.EAX, 16); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4) + 2, SourceReg = CPUx86.RegistersEnum.AL }; break; } case 0: { break; } default: throw new Exception("Remainder size " + (xSize % 4) + " not supported!"); } #if !SKIP_GC_CODE if (aNeedsGC) { XS.Push(XSRegisters.ECX); XS.Push(XSRegisters.EAX); XS.Call(LabelName.Get(GCImplementationRefs.DecRefCountRef)); XS.Call(LabelName.Get(GCImplementationRefs.DecRefCountRef)); } #endif XS.Add(XSRegisters.ESP, 4); }
public static void DoExecute(Cosmos.Assembler.Assembler Assembler, MethodInfo aCurrentMethod, MethodBase aTargetMethod, ILOpCode aCurrent, string currentLabel, string nextLabel, bool debugEnabled) { //if (aTargetMethod.IsVirtual) { // Callvirt.DoExecute(Assembler, aCurrentMethod, aTargetMethod, aTargetMethodUID, aCurrentPosition); // return; //} var xMethodInfo = aTargetMethod as SysReflection.MethodInfo; // mTargetMethodInfo = GetService<IMetaDataInfoService>().GetMethodInfo(mMethod // , mMethod, mMethodDescription, null, mCurrentMethodInfo.DebugMode); string xNormalAddress; if (aTargetMethod.IsStatic || !aTargetMethod.IsVirtual || aTargetMethod.IsFinal) { xNormalAddress = LabelName.Get(aTargetMethod); } else { xNormalAddress = LabelName.Get(aTargetMethod); //throw new Exception("Call: non-concrete method called: '" + aTargetMethod.GetFullName() + "'"); } var xParameters = aTargetMethod.GetParameters(); int xArgCount = xParameters.Length; // todo: implement exception support uint xExtraStackSize = GetStackSizeToReservate(aTargetMethod); if (!aTargetMethod.IsStatic && debugEnabled) { uint xThisOffset = 0; foreach (var xItem in xParameters) { xThisOffset += Align(SizeOfType(xItem.ParameterType), 4); } var stackOffsetToCheck = xThisOffset; DoNullReferenceCheck(Assembler, debugEnabled, stackOffsetToCheck); } if (xExtraStackSize > 0) { XS.Sub(XSRegisters.ESP, (uint)xExtraStackSize); } XS.Call(xNormalAddress); uint xReturnSize = 0; if (xMethodInfo != null) { xReturnSize = SizeOfType(xMethodInfo.ReturnType); } if (aCurrentMethod != null) { EmitExceptionLogic(Assembler, aCurrentMethod, aCurrent, true, delegate() { var xStackOffsetBefore = aCurrent.StackOffsetBeforeExecution.Value; uint xPopSize = 0; foreach (var type in aCurrent.StackPopTypes) { xPopSize += Align(SizeOfType(type), 4); } var xResultSize = xReturnSize; if (xResultSize % 4 != 0) { xResultSize += 4 - (xResultSize % 4); } ILOp.EmitExceptionCleanupAfterCall(Assembler, xResultSize, xStackOffsetBefore, xPopSize); }, nextLabel); } if (xMethodInfo == null || SizeOfType(xMethodInfo.ReturnType) == 0) { return; } }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xType = aMethod.MethodBase.DeclaringType; var xOpCode = (ILOpCodes.OpField)aOpCode; FieldInfo xField = xOpCode.Value; var xIsReferenceType = IsReferenceType(xField.FieldType); // call cctor: var xCctor = (xField.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic)).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); EmitExceptionLogic(Assembler, aMethod, aOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } uint xSize = SizeOfType(xField.FieldType); XS.Comment("Type = '" + xField.FieldType.FullName + "'"); uint xOffset = 0; var xFields = xField.DeclaringType.GetFields(); foreach (FieldInfo xInfo in xFields) { if (xInfo == xField) { break; } xOffset += SizeOfType(xInfo.FieldType); } string xDataName = LabelName.GetStaticFieldName(xField); if (xIsReferenceType) { var name = ElementReference.New(xDataName).Name; XS.Add(ESP, 4); // GC clean up old object XS.Compare(name, 0, destinationIsIndirect: true, destinationDisplacement: 4); XS.Jump(CPU.ConditionalTestEnum.Equal, ".AfterGC"); XS.Push(name, isIndirect: true, displacement: 4); // push object as pointer to send to DecRootCount XS.Call(LabelName.Get(GCImplementationRefs.DecRootCountRef)); XS.Label(".AfterGC"); XS.Pop(EAX); XS.Set(name, EAX, destinationIsIndirect: true, destinationDisplacement: 4); // Update GC for new object XS.Compare(name, 0, destinationIsIndirect: true, destinationDisplacement: 4); XS.Jump(CPU.ConditionalTestEnum.Equal, ".SecondAfterGC"); XS.Push(name, isIndirect: true, displacement: 4); // push object as pointer/uint to send to IncRootCount XS.Call(LabelName.Get(GCImplementationRefs.IncRootCountRef)); XS.Label(".SecondAfterGC"); return; } // value types if (!xField.FieldType.IsPointer && !xField.FieldType.IsPrimitive && !xField.FieldType.IsEnum) { // let clean up object deal with it XS.Push(xDataName, isIndirect: true, displacement: 4); XS.Push(GetTypeIDLabel(xField.FieldType), isIndirect: true); XS.Call(LabelName.Get(GCImplementationRefs.DecRootCountsInStructRef)); } for (int i = 0; i < (xSize / 4); i++) { XS.Pop(EAX); new CPU.Mov { DestinationRef = ElementReference.New(xDataName, i * 4), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.EAX }; } switch (xSize % 4) { case 1: { XS.Pop(EAX); new CPU.Mov { DestinationRef = ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.AL }; break; } case 2: { XS.Pop(EAX); new CPU.Mov { DestinationRef = ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPU.RegistersEnum.AX }; break; } case 0: { break; } default: throw new NotImplementedException(); } if (!xField.FieldType.IsPointer && !xField.FieldType.IsPrimitive && !xField.FieldType.IsEnum) { // let clean up object deal with it XS.Push(xDataName, isIndirect: true, displacement: 4); XS.Push(GetTypeIDLabel(xField.FieldType), isIndirect: true); XS.Call(LabelName.Get(GCImplementationRefs.IncRootCountsInStructRef)); } }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { // IDT is already initialized but just for base hooks, and asm only. // ie Int 1, 3 and GPF // This routine updates the IDT now that we have C# running to allow C# hooks to handle // the other INTs // We are updating the IDT, disable interrupts XS.ClearInterruptFlag(); for (int i = 0; i < 256; i++) { // These are already mapped, don't remap them. // Maybe in the future we can look at ones that are present // and skip them, but some we may want to overwrite anyways. if (i == 1 || i == 3) { continue; } XS.Set(EAX, "__ISR_Handler_" + i.ToString("X2")); XS.Set("_NATIVE_IDT_Contents", AL, destinationDisplacement: (i * 8) + 0); XS.Set("_NATIVE_IDT_Contents", AH, destinationDisplacement: (i * 8) + 1); XS.Set("_NATIVE_IDT_Contents", 0x8, destinationDisplacement: (i * 8) + 2, size: RegisterSize.Byte8); XS.Set("_NATIVE_IDT_Contents", 0x8E, destinationDisplacement: (i * 8) + 5, size: RegisterSize.Byte8); XS.ShiftRight(EAX, 16); XS.Set("_NATIVE_IDT_Contents", AL, destinationDisplacement: (i * 8) + 6); XS.Set("_NATIVE_IDT_Contents", AH, destinationDisplacement: (i * 8) + 7); } XS.Jump("__AFTER__ALL__ISR__HANDLER__STUBS__"); var xInterruptsWithParam = new[] { 8, 10, 11, 12, 13, 14 }; for (int j = 0; j < 256; j++) { XS.Label("__ISR_Handler_" + j.ToString("X2")); XS.Call("__INTERRUPT_OCCURRED__"); if (Array.IndexOf(xInterruptsWithParam, j) == -1) { XS.Push(0); } XS.Push((uint)j); if (j != 0x20) { XS.PushAllRegisters(); XS.Sub(ESP, 4); XS.Set(EAX, ESP); // preserve old stack address for passing to interrupt handler // store floating point data XS.And(ESP, 0xfffffff0); // fxsave needs to be 16-byte alligned XS.Sub(ESP, 512); // fxsave needs 512 bytes XS.SSE.FXSave(ESP, isIndirect: true); // save the registers XS.Set(EAX, ESP, destinationIsIndirect: true); XS.Push(EAX); // XS.Push(EAX); // pass old stack address (pointer to InterruptContext struct) to the interrupt handler XS.JumpToSegment(8, "__ISR_Handler_" + j.ToString("X2") + "_SetCS"); XS.Label("__ISR_Handler_" + j.ToString("X2") + "_SetCS"); MethodBase xHandler = GetInterruptHandler((byte)j); if (xHandler == null) { xHandler = GetMethodDef(typeof(Cosmos.Core.INTs).Assembly, typeof(Cosmos.Core.INTs).FullName, "HandleInterrupt_Default", true); } XS.Call(LabelName.Get(xHandler)); XS.Pop(EAX); XS.SSE.FXRestore(ESP, isIndirect: true); XS.Set(ESP, EAX); // this restores the stack for the FX stuff, except the pointer to the FX data XS.Add(ESP, 4); // "pop" the pointer XS.PopAllRegisters(); } else { new LiteralAssemblerCode("pushad"); new LiteralAssemblerCode("mov eax, ds"); new LiteralAssemblerCode("push eax"); new LiteralAssemblerCode("mov eax, es"); new LiteralAssemblerCode("push eax"); new LiteralAssemblerCode("mov eax, fs"); new LiteralAssemblerCode("push eax"); new LiteralAssemblerCode("mov eax, gs"); new LiteralAssemblerCode("push eax"); new LiteralAssemblerCode("mov ax, 0x10"); new LiteralAssemblerCode("mov ds, ax"); new LiteralAssemblerCode("mov es, ax"); new LiteralAssemblerCode("mov fs, ax"); new LiteralAssemblerCode("mov gs, ax"); new LiteralAssemblerCode("mov eax, esp"); XS.Set("static_field__Cosmos_Core_INTs_mStackContext", EAX, destinationIsIndirect: true); XS.Call(LabelName.Get(GetMethodDef(typeof(Cosmos.Core.Processing.ProcessorScheduler).Assembly, typeof(Cosmos.Core.Processing.ProcessorScheduler).FullName, "SwitchTask", true))); XS.Set(EAX, "static_field__Cosmos_Core_INTs_mStackContext", sourceIsIndirect: true); new LiteralAssemblerCode("mov esp, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov gs, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov fs, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov es, eax"); new LiteralAssemblerCode("pop eax"); new LiteralAssemblerCode("mov ds, eax"); new LiteralAssemblerCode("popad"); } XS.Add(ESP, 8); XS.Label("__ISR_Handler_" + j.ToString("X2") + "_END"); XS.InterruptReturn(); } XS.Label("__INTERRUPT_OCCURRED__"); XS.Return(); XS.Label("__AFTER__ALL__ISR__HANDLER__STUBS__"); XS.Noop(); XS.Set(EAX, EBP, sourceDisplacement: 8); XS.Compare(EAX, 0); XS.Jump(ConditionalTestEnum.Zero, ".__AFTER_ENABLE_INTERRUPTS"); // reload interrupt list XS.Set(EAX, "_NATIVE_IDT_Pointer"); XS.Set(AsmMarker.Labels[AsmMarker.Type.Processor_IntsEnabled], 1, destinationIsIndirect: true, size: RegisterSize.Byte8); XS.LoadIdt(EAX, isIndirect: true); // Reenable interrupts XS.EnableInterrupts(); XS.Label(".__AFTER_ENABLE_INTERRUPTS"); }
public static void DoExecute(Assembler Assembler, _MethodInfo aMethod, MethodBase aTargetMethod, uint aTargetMethodUID, ILOpCode aOp, bool debugEnabled) { string xCurrentMethodLabel = GetLabel(aMethod, aOp.Position); Type xPopType = aOp.StackPopTypes.Last(); string xNormalAddress = ""; if (aTargetMethod.IsStatic || !aTargetMethod.IsVirtual || aTargetMethod.IsFinal) { xNormalAddress = LabelName.Get(aTargetMethod); } uint xReturnSize = 0; var xMethodInfo = aTargetMethod as MethodInfo; if (xMethodInfo != null) { xReturnSize = Align(SizeOfType(xMethodInfo.ReturnType), 4); } uint xExtraStackSize = Call.GetStackSizeToReservate(aTargetMethod, xPopType); uint xThisOffset = 0; var xParameters = aTargetMethod.GetParameters(); foreach (var xItem in xParameters) { xThisOffset += Align(SizeOfType(xItem.ParameterType), 4); } // This is finding offset to self? It looks like we dont need offsets of other // arguments, but only self. If so can calculate without calculating all fields // Might have to go to old data structure for the offset... // Can we add this method info somehow to the data passed in? // mThisOffset = mTargetMethodInfo.Arguments[0].Offset; XS.Comment("ThisOffset = " + xThisOffset); if (IsReferenceType(xPopType)) { DoNullReferenceCheck(Assembler, debugEnabled, (int)xThisOffset + 4); } else { DoNullReferenceCheck(Assembler, debugEnabled, (int)xThisOffset); } if (!String.IsNullOrEmpty(xNormalAddress)) { if (xExtraStackSize > 0) { XS.Sub(ESP, xExtraStackSize); } XS.Call(xNormalAddress); } else { /* * On the stack now: * $esp Params * $esp + mThisOffset This */ if ((xPopType.IsPointer) || (xPopType.IsByRef)) { xPopType = xPopType.GetElementType(); string xTypeId = GetTypeIDLabel(xPopType); XS.Push(xTypeId, isIndirect: true); } else { XS.Set(EAX, ESP, sourceDisplacement: (int)xThisOffset + 4); XS.Push(EAX, isIndirect: true); } XS.Push(aTargetMethodUID); XS.Call(LabelName.Get(VTablesImplRefs.GetMethodAddressForTypeRef)); if (xExtraStackSize > 0) { xThisOffset -= xExtraStackSize; } /* * On the stack now: * $esp Params * $esp + mThisOffset This */ XS.Pop(ECX); XS.Label(xCurrentMethodLabel + ".AfterAddressCheck"); if (IsReferenceType(xPopType)) { /* * On the stack now: * $esp + 0 Params * $esp + mThisOffset This */ // we need to see if $this is a boxed object, and if so, we need to box it XS.Set(EAX, ESP, sourceDisplacement: (int)xThisOffset + 4); XS.Compare(EAX, (int)ObjectUtils.InstanceTypeEnum.BoxedValueType, destinationIsIndirect: true, destinationDisplacement: 4, size: RegisterSize.Int32); /* * On the stack now: * $esp Params * $esp + mThisOffset This * * ECX contains the method to call * EAX contains the type pointer (not the handle!!) */ XS.Jump(CPU.ConditionalTestEnum.NotEqual, xCurrentMethodLabel + ".NotBoxedThis"); /* * On the stack now: * $esp Params * $esp + mThisOffset This * * ECX contains the method to call * EAX contains the type pointer (not the handle!!) */ XS.Add(EAX, (uint)ObjectUtils.FieldDataOffset); XS.Set(ESP, EAX, destinationDisplacement: (int)xThisOffset + 4); /* * On the stack now: * $esp Params * $esp + mThisOffset Pointer to address inside box * * ECX contains the method to call */ } XS.Label(xCurrentMethodLabel + ".NotBoxedThis"); if (xExtraStackSize > 0) { XS.Sub(ESP, xExtraStackSize); } XS.Call(ECX); XS.Label(xCurrentMethodLabel + ".AfterNotBoxedThis"); } EmitExceptionLogic(Assembler, aMethod, aOp, true, delegate { var xStackOffsetBefore = aOp.StackOffsetBeforeExecution.Value; uint xPopSize = 0; foreach (var type in aOp.StackPopTypes) { xPopSize += Align(SizeOfType(type), 4); } var xResultSize = xReturnSize; if (xResultSize % 4 != 0) { xResultSize += 4 - (xResultSize % 4); } EmitExceptionCleanupAfterCall(Assembler, xResultSize, xStackOffsetBefore, xPopSize); }); XS.Label(xCurrentMethodLabel + ".NoExceptionAfterCall"); XS.Comment("Argument Count = " + xParameters.Length); }
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) ?? Array.Empty <ConstructorInfo>()).SingleOrDefault(); if (xCctor != null) { XS.Call(LabelName.Get(xCctor)); EmitExceptionLogic(aAssembler, aMethod, xMethod, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } } if (objectType.IsValueType) { #region Valuetypes XS.Comment("ValueType"); XS.Comment("Type: " + objectType); /* * 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 */ // Size of return value - we need to make room for this on the stack. uint xStorageSize = Align(SizeOfType(objectType), 4); XS.Comment("StorageSize: " + xStorageSize); if (xStorageSize == 0) { throw new Exception("ValueType storage size cannot be 0."); } uint xArgSize = 0; var xParameterList = constructor.GetParameters(); foreach (var xParam in xParameterList) { xArgSize = xArgSize + Align(SizeOfType(xParam.ParameterType), 4); } XS.Comment("ArgSize: " + xArgSize); // set source of args copy XS.Set(ESI, ESP); // allocate space for struct XS.Sub(ESP, xStorageSize + 4); // set destination and count of args copy XS.Set(EDI, ESP); XS.Set(ECX, xArgSize / 4); // move the args to their new location new CPUx86.Movs { Size = 32, Prefixes = CPUx86.InstructionPrefixes.Repeat }; // set struct ptr XS.Set(EAX, ESP); XS.Add(EAX, xArgSize + 4); XS.Set(ESP, EAX, destinationDisplacement: (int)xArgSize); XS.Push(EAX); var xOpType = new OpType(xMethod.OpCode, xMethod.Position, xMethod.NextPosition, xMethod.Value.DeclaringType, xMethod.CurrentExceptionRegion); new Initobj(aAssembler).Execute(aMethod, xOpType); new Call(aAssembler).Execute(aMethod, xMethod); // Need to put these *after* the call because the Call pops the args from the stack // and we have mucked about on the stack, so this makes it right before the next // op. #endregion Valuetypes } else { // If not ValueType, then we need gc var xParams = constructor.GetParameters(); // array length + 8 bool xHasCalcSize = false; #region Special string handling // try calculating size: if (constructor.DeclaringType == typeof(string)) { if (xParams.Length == 1 && xParams[0].ParameterType == typeof(char[])) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceDisplacement: 4, sourceIsIndirect: true); // address XS.Set(EAX, EAX, sourceDisplacement: 8, sourceIsIndirect: true); // element count XS.Set(EDX, 2); // element size XS.Multiply(EDX); XS.Push(EAX); } else if (xParams.Length == 3 && (xParams[0].ParameterType == typeof(char[]) || xParams[0].ParameterType == typeof(char *)) && xParams[1].ParameterType == typeof(int) && xParams[2].ParameterType == typeof(int)) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.ShiftLeft(EAX, 1); XS.Push(EAX); } else if (xParams.Length == 2 && xParams[0].ParameterType == typeof(char) && xParams[1].ParameterType == typeof(int)) { xHasCalcSize = true; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.ShiftLeft(EAX, 1); XS.Push(EAX); } /* * TODO see if something is needed in stack / register to make them really work */ else if (xParams.Length == 3 && (xParams[0].ParameterType == typeof(sbyte *) && xParams[1].ParameterType == typeof(int) && xParams[2].ParameterType == typeof(int))) { xHasCalcSize = true; XS.Push(ESP, isIndirect: true); } else if (xParams.Length == 1 && xParams[0].ParameterType == typeof(sbyte *)) { xHasCalcSize = true; /* xParams[0] contains a C / ASCII Z string the following ASM is de facto the C strlen() function */ var xSByteCountLabel = currentLabel + ".SByteCount"; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.Or(ECX, 0xFFFFFFFF); XS.Label(xSByteCountLabel); XS.Increment(EAX); XS.Increment(ECX); XS.Compare(EAX, 0, destinationIsIndirect: true); XS.Jump(CPUx86.ConditionalTestEnum.NotEqual, xSByteCountLabel); XS.Push(ECX); } else { throw new NotImplementedException("In NewObj, a string ctor implementation is missing!"); } } #endregion Special string handling uint xMemSize = GetStorageSize(objectType); int xExtraSize = 12; // additional size for set values after alloc XS.Push((uint)(xMemSize + xExtraSize)); if (xHasCalcSize) { XS.Pop(EAX); XS.Add(ESP, EAX, destinationIsIndirect: true); } // todo: probably we want to check for exceptions after calling Alloc XS.Call(LabelName.Get(GCImplementationRefs.AllocNewObjectRef)); XS.Label(".AfterAlloc"); XS.Push(ESP, isIndirect: true); XS.Push(ESP, isIndirect: true); // it's on the stack now 3 times. Once from the Alloc return value, twice from the pushes // todo: use a cleaner approach here. this class shouldnt assemble the string string strTypeId = GetTypeIDLabel(constructor.DeclaringType); XS.Pop(EAX); XS.Set(EBX, strTypeId, sourceIsIndirect: true); XS.Set(EAX, EBX, destinationIsIndirect: true); XS.Set(EAX, (uint)ObjectUtils.InstanceTypeEnum.NormalObject, destinationDisplacement: 4, destinationIsIndirect: true, size: RegisterSize.Int32); XS.Set(EAX, xMemSize, destinationDisplacement: 8, destinationIsIndirect: true, size: RegisterSize.Int32); uint xSize = (uint)(from item in xParams let xQSize = Align(SizeOfType(item.ParameterType), 4) select(int) xQSize).Take(xParams.Length).Sum(); XS.Push(0); foreach (var xParam in xParams) { uint xParamSize = Align(SizeOfType(xParam.ParameterType), 4); XS.Comment($"Arg {xParam.Name}: {xParamSize}"); for (int i = 0; i < xParamSize; i += 4) { XS.Push(ESP, isIndirect: true, displacement: (int)(xSize + 8)); } } XS.Call(LabelName.Get(constructor)); // should the complete error handling happen by ILOp.EmitExceptionLogic? if (aMethod != null) { // todo: only happening for real methods now, not for ctor's ? XS.Test(ECX, 2); string xNoErrorLabel = currentLabel + ".NoError" + LabelName.LabelCount.ToString(); XS.Jump(CPUx86.ConditionalTestEnum.Equal, xNoErrorLabel); PushAlignedParameterSize(constructor); // an exception occurred, we need to cleanup the stack, and jump to the exit XS.Add(ESP, 4); new Comment(aAssembler, "[ Newobj.Execute cleanup end ]"); Jump_Exception(aMethod); XS.Label(xNoErrorLabel); } XS.Pop(EAX); PushAlignedParameterSize(constructor); XS.Push(EAX); XS.Push(0); } }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xType = aMethod.MethodBase.DeclaringType; var xOpCode = (ILOpCodes.OpField)aOpCode; SysReflection.FieldInfo xField = xOpCode.Value; var xIsReferenceType = TypeIsReferenceType(xField.FieldType); // call cctor: var xCctor = (xField.DeclaringType.GetConstructors(BindingFlags.Static | BindingFlags.NonPublic) ?? new ConstructorInfo[0]).SingleOrDefault(); if (xCctor != null && xCctor.DeclaringType != aMethod.MethodBase.DeclaringType) { XS.Call(LabelName.Get(xCctor)); ILOp.EmitExceptionLogic(Assembler, aMethod, aOpCode, true, null, ".AfterCCTorExceptionCheck"); XS.Label(".AfterCCTorExceptionCheck"); } //int aExtraOffset;// = 0; //bool xNeedsGC = xField.FieldType.IsClass && !xField.FieldType.IsValueType; uint xSize = SizeOfType(xField.FieldType); //if( xNeedsGC ) //{ // aExtraOffset = 12; //} new Comment(Assembler, "Type = '" + xField.FieldType.FullName /*+ "', NeedsGC = " + xNeedsGC*/); uint xOffset = 0; var xFields = xField.DeclaringType.GetFields(); foreach (SysReflection.FieldInfo xInfo in xFields) { if (xInfo == xField) { break; } xOffset += SizeOfType(xInfo.FieldType); } string xDataName = DataMember.GetStaticFieldName(xField); if (xIsReferenceType) { XS.Add(XSRegisters.ESP, 4); XS.Pop(XSRegisters.EAX); XS.Set(ElementReference.New(xDataName).Name, XSRegisters.EAX, destinationIsIndirect: true, destinationDisplacement: 4); return; } for (int i = 0; i < (xSize / 4); i++) { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = ElementReference.New(xDataName, i * 4), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.EAX }; } switch (xSize % 4) { case 1: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.AL }; break; } case 2: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationRef = Cosmos.Assembler.ElementReference.New(xDataName, (int)((xSize / 4) * 4)), DestinationIsIndirect = true, SourceReg = CPUx86.RegistersEnum.AX }; break; } case 0: { break; } default: //EmitNotImplementedException(Assembler, GetServiceProvider(), "Ldsfld: Remainder size " + (xSize % 4) + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel); throw new NotImplementedException(); //break; } }
public void Initialize() { uint xSig = 0x1BADB002; DataMembers.Add(new DataIfNotDefined("ELF_COMPILATION")); DataMembers.Add(new DataMember("MultibootSignature", new uint[] { xSig })); uint xFlags = 0x10007; DataMembers.Add(new DataMember("MultibootFlags", xFlags)); DataMembers.Add(new DataMember("MultibootChecksum", (int)(0 - (xFlags + xSig)))); DataMembers.Add(new DataMember("MultibootHeaderAddr", ElementReference.New("MultibootSignature"))); DataMembers.Add(new DataMember("MultibootLoadAddr", ElementReference.New("MultibootSignature"))); DataMembers.Add(new DataMember("MultibootLoadEndAddr", ElementReference.New("_end_code"))); DataMembers.Add(new DataMember("MultibootBSSEndAddr", ElementReference.New("_end_code"))); DataMembers.Add(new DataMember("MultibootEntryAddr", ElementReference.New("Kernel_Start"))); DataMembers.Add(new DataMember("", 0)); DataMembers.Add(new DataMember("", 800, 600, 32)); DataMembers.Add(new DataEndIfDefined()); DataMembers.Add(new DataIfDefined("ELF_COMPILATION")); xFlags = 0x00007; DataMembers.Add(new DataMember("MultibootSignature", new uint[] { xSig })); DataMembers.Add(new DataMember("MultibootFlags", xFlags)); DataMembers.Add(new DataMember("MultibootChecksum", (int)(0 - (xFlags + xSig)))); DataMembers.Add(new DataMember("", 0, 0, 0, 0, 0)); DataMembers.Add(new DataMember("", 0)); DataMembers.Add(new DataMember("", 800, 600, 32)); DataMembers.Add(new DataEndIfDefined()); //graphics info fields DataMembers.Add(new DataMember("MultibootGraphicsRuntime_VbeModeInfoAddr", 1 << 2)); DataMembers.Add(new DataMember("MultibootGraphicsRuntime_VbeControlInfoAddr", 1 << 0)); DataMembers.Add(new DataMember("MultibootGraphicsRuntime_VbeMode", 0)); // memory DataMembers.Add(new DataMember("MultiBootInfo_Memory_High", 0)); DataMembers.Add(new DataMember("MultiBootInfo_Memory_Low", 0)); DataMembers.Add(new DataMember("Before_Kernel_Stack", new byte[0x50000])); DataMembers.Add(new DataMember("Kernel_Stack", new byte[0])); DataMembers.Add(new DataMember("MultiBootInfo_Structure", new uint[1])); // constants DataMembers.Add(new DataMember(@"__uint2double_const", new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x41 })); DataMembers.Add(new DataMember(@"__ulong2double_const", 0x5F800000)); DataMembers.Add(new DataMember(@"__doublesignbit", 0x8000000000000000)); DataMembers.Add(new DataMember(@"__floatsignbit", 0x80000000)); if (mComPort > 0) { new Define("DEBUGSTUB"); } // This is our first entry point. Multiboot uses this as Cosmos entry point. new Label("Kernel_Start", isGlobal: true); XS.Set(XSRegisters.ESP, "Kernel_Stack"); // Displays "Cosmos" in top left. Used to make sure Cosmos is booted in case of hang. // ie bootloader debugging. This must be the FIRST code, even before setup so we know // we are being called properly by the bootloader and that if there are problems its // somwhere in our code, not the bootloader. WriteDebugVideo("Cosmos pre boot"); // For when using Bochs, causes a break ASAP on entry after initial Cosmos display. //new LiteralAssemblerCode("xchg bx, bx"); // CLI ASAP WriteDebugVideo("Clearing interrupts."); XS.ClearInterruptFlag(); WriteDebugVideo("Begin multiboot info."); new LiteralAssemblerCode("%ifndef EXCLUDE_MULTIBOOT_MAGIC"); new Comment(this, "MultiBoot compliant loader provides info in registers: "); new Comment(this, "EBX=multiboot_info "); new Comment(this, "EAX=0x2BADB002 - check if it's really Multiboot-compliant loader "); new Comment(this, " ;- copy mb info - some stuff for you "); new Comment(this, "BEGIN - Multiboot Info"); new Mov { DestinationRef = ElementReference.New("MultiBootInfo_Structure"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EBX }; XS.Add(XSRegisters.EBX, 4); XS.Set(XSRegisters.EAX, XSRegisters.EBX, sourceIsIndirect: true); new Mov { DestinationRef = ElementReference.New("MultiBootInfo_Memory_Low"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX }; XS.Add(XSRegisters.EBX, 4); XS.Set(XSRegisters.EAX, XSRegisters.EBX, sourceIsIndirect: true); new Mov { DestinationRef = ElementReference.New("MultiBootInfo_Memory_High"), DestinationIsIndirect = true, SourceReg = RegistersEnum.EAX }; new Comment(this, "END - Multiboot Info"); new LiteralAssemblerCode("%endif"); WriteDebugVideo("Creating GDT."); CreateGDT(); WriteDebugVideo("Configuring PIC"); ConfigurePIC(); WriteDebugVideo("Creating IDT."); CreateIDT(); new Comment("Set graphics fields"); new Mov { DestinationReg = XSRegisters.EBX, SourceRef = ElementReference.New("MultiBootInfo_Structure"), SourceIsIndirect = true }; new Mov { DestinationReg = XSRegisters.EAX, SourceReg = XSRegisters.EBX, SourceIsIndirect = true, SourceDisplacement = 72 }; new Mov { DestinationRef = ElementReference.New("MultibootGraphicsRuntime_VbeControlInfoAddr"), DestinationIsIndirect = true, SourceReg = XSRegisters.EAX }; new Mov { DestinationReg = XSRegisters.EAX, SourceReg = XSRegisters.EBX, SourceIsIndirect = true, SourceDisplacement = 76 }; new Mov { DestinationRef = ElementReference.New("MultibootGraphicsRuntime_VbeModeInfoAddr"), DestinationIsIndirect = true, SourceReg = XSRegisters.EAX }; new Mov { DestinationReg = XSRegisters.EAX, SourceReg = XSRegisters.EBX, SourceIsIndirect = true, SourceDisplacement = 80 }; new Mov { DestinationRef = ElementReference.New("MultibootGraphicsRuntime_VbeMode"), DestinationIsIndirect = true, SourceReg = XSRegisters.EAX }; //WriteDebugVideo("Initializing SSE."); //new Comment(this, "BEGIN - SSE Init"); //// CR4[bit 9]=1, CR4[bit 10]=1, CR0[bit 2]=0, CR0[bit 1]=1 //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR4); //XS.Or(XSRegisters.EAX, 0x100); //XS.Mov(XSRegisters.CR4, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR4); //XS.Or(XSRegisters.EAX, 0x200); //XS.Mov(XSRegisters.CR4, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR0); //XS.And(XSRegisters.EAX, 0xfffffffd); //XS.Mov(XSRegisters.CR0, XSRegisters.Registers.EAX); //XS.Mov(XSRegisters.EAX, XSRegisters.Registers.CR0); //XS.And(XSRegisters.EAX, 1); //XS.Mov(XSRegisters.CR0, XSRegisters.Registers.EAX); //new Comment(this, "END - SSE Init"); if (mComPort > 0) { WriteDebugVideo("Initializing DebugStub."); XS.Call(AsmMarker.Labels[AsmMarker.Type.DebugStub_Init]); } // Jump to Kernel entry point WriteDebugVideo("Jumping to kernel."); XS.Call(EntryPointName); new Comment(this, "Kernel done - loop till next IRQ"); XS.Label(".loop"); XS.ClearInterruptFlag(); XS.Halt(); XS.Jump(".loop"); if (mComPort > 0) { var xGen = new AsmGenerator(); var xGenerateAssembler = new Action <object>(i => { if (i is StreamReader) { var xAsm = xGen.Generate((StreamReader)i); CurrentInstance.Instructions.AddRange(xAsm.Instructions); CurrentInstance.DataMembers.AddRange(xAsm.DataMembers); } else if (i is string) { var xAsm = xGen.Generate((string)i); CurrentInstance.Instructions.AddRange(xAsm.Instructions); CurrentInstance.DataMembers.AddRange(xAsm.DataMembers); } else { throw new Exception("Object type '" + i.ToString() + "' not supported!"); } }); if (ReadDebugStubFromDisk) { foreach (var xFile in Directory.GetFiles(CosmosPaths.DebugStubSrc, "*.xs")) { xGenerateAssembler(xFile); } } else { foreach (var xManifestName in typeof(ReferenceHelper).Assembly.GetManifestResourceNames()) { if (!xManifestName.EndsWith(".xs", StringComparison.OrdinalIgnoreCase)) { continue; } using (var xStream = typeof(ReferenceHelper).Assembly.GetManifestResourceStream(xManifestName)) { using (var xReader = new StreamReader(xStream)) { xGenerateAssembler(xReader); } } } } OnAfterEmitDebugStub(); } else { XS.Label(AsmMarker.Labels[AsmMarker.Type.DebugStub_Step]); XS.Return(); } // Start emitting assembly labels CurrentInstance.EmitAsmLabels = true; }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xSize = Math.Max(SizeOfType(xStackItem), SizeOfType(aOpCode.StackPopTypes[1])); var xIsFloat = TypeIsFloat(xStackItem); var xBaseLabel = GetLabel(aMethod, aOpCode); var xNoDivideByZeroExceptionLabel = xBaseLabel + "_NoDivideByZeroException"; if (xSize > 8) { throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Div.cs->Error: StackSize > 8 not supported"); } else if (xSize > 4) { if (xIsFloat) { XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 8); XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true); XS.SSE2.DivSD(XMM1, XMM0); XS.SSE2.MoveSD(ESP, XMM1, destinationIsIndirect: true); } else { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelShiftRight = BaseLabel + "ShiftRightLoop"; string LabelNoLoop = BaseLabel + "NoLoop"; string LabelEnd = BaseLabel + "End"; // divisor // low XS.Pop(ESI); // high XS.Pop(EDI); XS.Xor(EAX, EAX); XS.Or(EAX, ESI); XS.Or(EAX, EDI); XS.Jump(ConditionalTestEnum.NotZero, xNoDivideByZeroExceptionLabel); XS.Call(GetLabel(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef)); XS.Label(xNoDivideByZeroExceptionLabel); // dividend // low XS.Pop(EAX); // high XS.Pop(EDX); // set flags XS.Or(EDI, EDI); // if high dword of divisor is already zero, we dont need the loop XS.Jump(ConditionalTestEnum.Zero, LabelNoLoop); // set ecx to zero for counting the shift operations XS.Xor(ECX, ECX); // push most significant bit of result XS.Set(EBX, EDI); XS.Xor(EBX, EDX); XS.Push(EBX); XS.Compare(EDI, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "divisor_no_neg"); XS.Negate(ESI); XS.AddWithCarry(EDI, 0); XS.Negate(EDI); XS.Label(BaseLabel + "divisor_no_neg"); XS.Compare(EDX, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "dividend_no_neg"); XS.Negate(EAX); XS.AddWithCarry(EDX, 0); XS.Negate(EDX); XS.Label(BaseLabel + "dividend_no_neg"); XS.Label(LabelShiftRight); // shift divisor 1 bit right XS.ShiftRightDouble(ESI, EDI, 1); XS.ShiftRight(EDI, 1); // increment shift counter XS.Increment(ECX); // set flags //XS.Or(EDI, EDI); XS.Set(EBX, ESI); XS.And(EBX, 0x80000000); XS.Or(EBX, EDI); // loop while high dword of divisor is not zero or most significant bit of low dword of divisor is set XS.Jump(ConditionalTestEnum.NotZero, LabelShiftRight); // shift the dividend now in one step XS.ShiftRightDouble(EAX, EDX, CL); // shift dividend CL bits right XS.ShiftRight(EDX, CL); // so we shifted both, so we have near the same relation as original values // divide this XS.IntegerDivide(ESI); // pop most significant bit of result XS.Pop(EBX); XS.Compare(EBX, 0x80000000); XS.Jump(ConditionalTestEnum.Below, BaseLabel + "_result_no_neg"); XS.Negate(EAX); XS.Label(BaseLabel + "_result_no_neg"); // sign extend XS.SignExtendAX(RegisterSize.Int32); // save result to stack XS.Push(EDX); XS.Push(EAX); //TODO: implement proper derivation correction and overflow detection XS.Jump(LabelEnd); XS.Label(LabelNoLoop); // save high dividend XS.Set(ECX, EAX); XS.Set(EAX, EDX); // extend that sign is in edx XS.SignExtendAX(RegisterSize.Int32); // divide high part XS.IntegerDivide(ESI); // save high result XS.Push(EAX); XS.Set(EAX, ECX); // divide low part XS.Divide(ESI); // save low result XS.Push(EAX); XS.Label(LabelEnd); } } else { if (xIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.DivSS(XMM1, XMM0); XS.SSE.MoveSS(ESP, XMM1, destinationIsIndirect: true); } else { XS.Pop(ECX); XS.Test(ECX, ECX); XS.Jump(ConditionalTestEnum.NotZero, xNoDivideByZeroExceptionLabel); XS.Call(GetLabel(ExceptionHelperRefs.ThrowDivideByZeroExceptionRef)); XS.Label(xNoDivideByZeroExceptionLabel); XS.Pop(EAX); XS.SignExtendAX(RegisterSize.Int32); XS.IntegerDivide(ECX); XS.Push(EAX); } } }