public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { XS.Mov(XSRegisters.EAX, XSRegisters.CPUx86.Registers.CR0); XS.And(XSRegisters.EAX, 0x7FFFFFFF); XS.Mov(XSRegisters.CR0, XSRegisters.CPUx86.Registers.EAX); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xIsSingleCompare = true; switch (aOpCode.OpCode) { case ILOpCode.Code.Beq: case ILOpCode.Code.Bge: case ILOpCode.Code.Bgt: case ILOpCode.Code.Bge_Un: case ILOpCode.Code.Bgt_Un: case ILOpCode.Code.Ble: case ILOpCode.Code.Ble_Un: case ILOpCode.Code.Bne_Un: case ILOpCode.Code.Blt: case ILOpCode.Code.Blt_Un: xIsSingleCompare = false; break; } var xStackContent = aOpCode.StackPopTypes[0]; var xStackContentSize = SizeOfType(xStackContent); if (xStackContentSize > 8) { throw new Exception("Cosmos.IL2CPU.x86->IL->Branch.cs->Error: StackSize > 8 not supported"); } CPU.ConditionalTestEnum xTestOp; // all conditions are inverted here? switch (aOpCode.OpCode) { case ILOpCode.Code.Beq: xTestOp = CPU.ConditionalTestEnum.Zero; break; case ILOpCode.Code.Bge: xTestOp = CPU.ConditionalTestEnum.GreaterThanOrEqualTo; break; case ILOpCode.Code.Bgt: xTestOp = CPU.ConditionalTestEnum.GreaterThan; break; case ILOpCode.Code.Ble: xTestOp = CPU.ConditionalTestEnum.LessThanOrEqualTo; break; case ILOpCode.Code.Blt: xTestOp = CPU.ConditionalTestEnum.LessThan; break; case ILOpCode.Code.Bne_Un: xTestOp = CPU.ConditionalTestEnum.NotEqual; break; case ILOpCode.Code.Bge_Un: xTestOp = CPU.ConditionalTestEnum.AboveOrEqual; break; case ILOpCode.Code.Bgt_Un: xTestOp = CPU.ConditionalTestEnum.Above; break; case ILOpCode.Code.Ble_Un: xTestOp = CPU.ConditionalTestEnum.BelowOrEqual; break; case ILOpCode.Code.Blt_Un: xTestOp = CPU.ConditionalTestEnum.Below; break; case ILOpCode.Code.Brfalse: xTestOp = CPU.ConditionalTestEnum.Zero; break; case ILOpCode.Code.Brtrue: xTestOp = CPU.ConditionalTestEnum.NotZero; break; default: throw new Exception("Cosmos.IL2CPU.x86->IL->Branch.cs->Error: Unknown OpCode for conditional branch."); } if (!xIsSingleCompare) { if (xStackContentSize <= 4) { //if (xStackContent.IsFloat) //{ // throw new Exception("Cosmos.IL2CPU.x86->IL->Branch.cs->Error: Comparison of floats (System.Single) is not yet supported!"); //} //else //{ XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EBX); XS.Compare(XSRegisters.EBX, XSRegisters.EAX); new ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; //} } else { //if (xStackContent.IsFloat) //{ // throw new Exception("Cosmos.IL2CPU.x86->IL->Branch.cs->Error: Comparison of doubles (System.Double) is not yet supported!"); //} //else //{ var xNoJump = GetLabel(aMethod, aOpCode) + "__NoBranch"; // value 2 EBX:EAX XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EBX); // value 1 EDX:ECX XS.Pop(XSRegisters.ECX); XS.Pop(XSRegisters.EDX); switch (xTestOp) { case ConditionalTestEnum.Zero: // Equal case ConditionalTestEnum.NotEqual: // NotZero XS.Xor(XSRegisters.EAX, XSRegisters.ECX); new ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Xor(XSRegisters.EBX, XSRegisters.EDX); new ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; break; case ConditionalTestEnum.GreaterThanOrEqualTo: XS.Compare(XSRegisters.EDX, XSRegisters.EBX); XS.Jump(ConditionalTestEnum.LessThan, xNoJump); new ConditionalJump { Condition = ConditionalTestEnum.GreaterThan, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Compare(XSRegisters.ECX, XSRegisters.EAX); XS.Jump(ConditionalTestEnum.Below, xNoJump); break; case ConditionalTestEnum.GreaterThan: XS.Compare(XSRegisters.EDX, XSRegisters.EBX); XS.Jump(ConditionalTestEnum.LessThan, xNoJump); new ConditionalJump { Condition = ConditionalTestEnum.GreaterThan, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Compare(XSRegisters.ECX, XSRegisters.EAX); XS.Jump(ConditionalTestEnum.BelowOrEqual, xNoJump); break; case ConditionalTestEnum.LessThanOrEqualTo: XS.Compare(XSRegisters.EDX, XSRegisters.EBX); new ConditionalJump { Condition = ConditionalTestEnum.LessThan, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Jump(ConditionalTestEnum.GreaterThan, xNoJump); XS.Compare(XSRegisters.ECX, XSRegisters.EAX); new ConditionalJump { Condition = ConditionalTestEnum.BelowOrEqual, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; break; case ConditionalTestEnum.LessThan: XS.Compare(XSRegisters.EDX, XSRegisters.EBX); new ConditionalJump { Condition = ConditionalTestEnum.LessThan, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Jump(ConditionalTestEnum.GreaterThan, xNoJump); XS.Compare(XSRegisters.ECX, XSRegisters.EAX); new ConditionalJump { Condition = ConditionalTestEnum.Below, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; break; // from here all unsigned case ConditionalTestEnum.AboveOrEqual: XS.Compare(XSRegisters.EDX, XSRegisters.EBX); new ConditionalJump { Condition = ConditionalTestEnum.Above, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Compare(XSRegisters.ECX, XSRegisters.EAX); XS.Jump(ConditionalTestEnum.Below, xNoJump); break; case ConditionalTestEnum.Above: XS.Compare(XSRegisters.EDX, XSRegisters.EBX); new ConditionalJump { Condition = ConditionalTestEnum.Above, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Compare(XSRegisters.ECX, XSRegisters.EAX); XS.Jump(ConditionalTestEnum.BelowOrEqual, xNoJump); break; case ConditionalTestEnum.BelowOrEqual: XS.Compare(XSRegisters.EDX, XSRegisters.EBX); new ConditionalJump { Condition = ConditionalTestEnum.Above, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Jump(ConditionalTestEnum.Below, xNoJump); XS.Compare(XSRegisters.ECX, XSRegisters.EAX); new ConditionalJump { Condition = ConditionalTestEnum.Above, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; break; case ConditionalTestEnum.Below: XS.Compare(XSRegisters.EDX, XSRegisters.EBX); new ConditionalJump { Condition = ConditionalTestEnum.Above, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Jump(ConditionalTestEnum.Below, xNoJump); XS.Compare(XSRegisters.ECX, XSRegisters.EAX); new ConditionalJump { Condition = ConditionalTestEnum.AboveOrEqual, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; break; default: throw new Exception("Unknown OpCode for conditional branch in 64-bit."); } XS.Label(xNoJump); //} } } else { //if (xStackContent.IsFloat) //{ // throw new Exception("Cosmos.IL2CPU.x86->IL->Branch.cs->Error: Simple comparison of floating point numbers is not yet supported!"); //} //else //{ // todo: improve code clarity if (xStackContentSize <= 4) { XS.Pop(XSRegisters.EAX); if (xTestOp == ConditionalTestEnum.Zero) { XS.Compare(XSRegisters.EAX, 0); new ConditionalJump { Condition = ConditionalTestEnum.Equal, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; } else if (xTestOp == ConditionalTestEnum.NotZero) { XS.Compare(XSRegisters.EAX, 0); new ConditionalJump { Condition = ConditionalTestEnum.NotEqual, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; } else { throw new NotSupportedException("Cosmos.IL2CPU.x86->IL->Branch.cs->Error: Situation not supported yet! (In the Simple Comparison)"); } } else { if (TypeIsReferenceType(xStackContent)) { XS.Add(XSRegisters.ESP, 4); XS.Pop(XSRegisters.EAX); } else { XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EBX); } switch (xTestOp) { case ConditionalTestEnum.Zero: // Equal case ConditionalTestEnum.NotZero: // NotEqual if (TypeIsReferenceType(xStackContent)) { XS.Xor(XSRegisters.EAX, 0); new ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; } else { XS.Xor(XSRegisters.EAX, 0); new ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; XS.Xor(XSRegisters.EBX, 0); new ConditionalJump { Condition = xTestOp, DestinationLabel = AppAssembler.TmpBranchLabel(aMethod, aOpCode) }; } break; default: throw new NotImplementedException("Cosmos.IL2CPU.X86.IL.Branch: Simple branch " + aOpCode.OpCode + " not implemented for operand "); } } } //} }
/* void Copy(Array sourceArray, ebp + 0x1C * int sourceIndex, ebp + 0x18 * Array destinationArray, ebp + 0x14 * int destinationIndex, ebp + 0x10 * int length, ebp + 0xC * bool reliable); ebp + 0x8 */ public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = SourceArrayDisplacement }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; // dereference memory handle to pointer new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceValue = 12, Size = 32 }; // pointer is at the element size new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; // element size new CPUx86.Mov { DestinationReg = CPUx86.Registers.EBX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = SourceIndexDisplacement }; new CPUx86.Multiply { DestinationReg = CPUx86.Registers.EBX }; new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 16 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESI, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = SourceArrayDisplacement }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESI, SourceReg = CPUx86.Registers.ESI, SourceIsIndirect = true }; // dereference memory handle to pointer new CPUx86.Add { DestinationReg = CPUx86.Registers.ESI, SourceReg = CPUx86.Registers.EAX }; // source ptr new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = DestinationArrayDisplacement }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EDX, SourceIsIndirect = true }; // dereference memory handle to pointer new CPUx86.Push { DestinationReg = CPUx86.Registers.EDX }; new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceValue = 12, Size = 32 }; // pointer is at element size new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; // dereference handle to pointer new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = DestinationIndexDisplacement }; new CPUx86.Multiply { DestinationReg = CPUx86.Registers.ECX }; new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 16 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = DestinationArrayDisplacement }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EDI, SourceIsIndirect = true }; // dereference handle to pointer new CPUx86.Add { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EAX }; // calculate byte count to copy new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = DestinationArrayDisplacement }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; // dereference memory handle to pointer new CPUx86.Add { DestinationReg = CPUx86.Registers.EAX, SourceValue = 12 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EAX, SourceIsIndirect = true }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EBP, SourceIsIndirect = true, SourceDisplacement = LengthDisplacement }; new CPUx86.Multiply { DestinationReg = CPUx86.Registers.EDX }; XS.Set(XSRegisters.OldToNewRegister(CPUx86.Registers.ECX), XSRegisters.OldToNewRegister(CPUx86.Registers.EAX)); new CPUx86.Movs { Size = 8, Prefixes = CPUx86.InstructionPrefixes.Repeat }; }
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); if (aNeedsGC) { DoNullReferenceCheck(aAssembler, debugEnabled, (int)xRoundedSize + 4); } else { DoNullReferenceCheck(aAssembler, debugEnabled, (int)xRoundedSize); } XS.Comment("After Nullref check"); if (aNeedsGC) { XS.Set(XSRegisters.ECX, XSRegisters.ESP, sourceDisplacement: (int)xRoundedSize + 4); } else { XS.Set(XSRegisters.ECX, XSRegisters.ESP, sourceDisplacement: (int)xRoundedSize); } if (xActualOffset != 0) { 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!"); } XS.Add(XSRegisters.ESP, 4); if (aNeedsGC) { XS.Add(XSRegisters.ESP, 4); } }
public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { XS.EnableInterrupts(); }
/* void Copy( * Array sourceArray, ebp + 36 * int sourceIndex, ebp + 28 * Array destinationArray, ebp + 24 * int destinationIndex, ebp + 16 * int length, ebp + 12 * bool reliable); ebp + 8 */ public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { var xArrayCopyReverseLabel = "ArrayCopy_Reverse"; var xArrayCopyReverseLoopLabel = "ArrayCopy_Reverse_Loop"; var xArrayCopyEndLabel = "ArrayCopy_End"; XS.Comment("Source"); XS.Comment("Element size"); XS.Set(EAX, EBP, sourceDisplacement: SourceArrayDisplacement); XS.Add(EAX, ObjectUtils.FieldDataOffset); XS.Set(EAX, EAX, sourceIsIndirect: true); // element size XS.Comment("Source ptr"); XS.Set(EBX, EBP, sourceDisplacement: SourceIndexDisplacement); XS.Multiply(EBX); XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // first element XS.Set(ESI, EBP, sourceDisplacement: SourceArrayDisplacement); XS.Add(ESI, EAX); // source ptr XS.Comment("Destination"); XS.Comment("Element size"); XS.Set(EAX, EBP, sourceDisplacement: DestinationArrayDisplacement); XS.Add(EAX, ObjectUtils.FieldDataOffset); XS.Set(EAX, EAX, sourceIsIndirect: true); // element size XS.Comment("Destination ptr"); XS.Set(ECX, EBP, sourceDisplacement: DestinationIndexDisplacement); XS.Multiply(ECX); XS.Add(EAX, ObjectUtils.FieldDataOffset + 4); // first element XS.Set(EDI, EBP, sourceDisplacement: DestinationArrayDisplacement); XS.Add(EDI, EAX); // destination ptr XS.Compare(EDI, ESI); XS.Jump(ConditionalTestEnum.Equal, xArrayCopyEndLabel); XS.Comment("Copy byte count"); XS.Comment("Element size"); XS.Set(EAX, EBP, sourceDisplacement: DestinationArrayDisplacement); XS.Add(EAX, ObjectUtils.FieldDataOffset); XS.Set(EAX, EAX, sourceIsIndirect: true); // element size XS.Comment("Count"); XS.Set(EDX, EBP, sourceDisplacement: LengthDisplacement); // if length is 0, jump to end XS.Compare(EDX, 0); XS.Jump(ConditionalTestEnum.Equal, xArrayCopyEndLabel); XS.Multiply(EDX); XS.Set(ECX, EAX); XS.Compare(EDI, ESI); XS.Jump(ConditionalTestEnum.GreaterThan, xArrayCopyReverseLabel); new Movs { Size = 8, Prefixes = InstructionPrefixes.Repeat }; XS.Jump(xArrayCopyEndLabel); XS.Label(xArrayCopyReverseLabel); XS.Add(ESI, ECX); XS.Add(EDI, ECX); XS.Label(xArrayCopyReverseLoopLabel); XS.Decrement(ESI); XS.Decrement(EDI); XS.Decrement(ECX); XS.Set(AL, ESI, sourceIsIndirect: true); XS.Set(EDI, AL, destinationIsIndirect: true); XS.Compare(ECX, 0); XS.Jump(ConditionalTestEnum.NotEqual, xArrayCopyReverseLoopLabel); XS.Label(xArrayCopyEndLabel); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { XS.Jump(AppAssembler.TmpBranchLabel(aMethod, aOpCode)); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xType = aMethod.MethodBase.DeclaringType; var xOpCode = (OpField)aOpCode; 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 override void AssembleNew(Assembler aAssembler, object aMethodInfo) { XS.Push(ILOp.GetTypeIDLabel(typeof(string))); }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { DoNullReferenceCheck(Assembler, DebugEnabled, 0); XS.Pop(XSRegisters.EAX); XS.Push(XSRegisters.EAX, isIndirect: true); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { XS.Push(0); XS.Push(0); }
public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { XS.ClearInterruptFlag(); }
public override void AssembleNew(Assembler.Assembler aAssembler, object aMethodInfo) { XS.Set(XSRegisters.EDX, XSRegisters.EBP, sourceDisplacement: 0x08); XS.ReadFromPortDX(XSRegisters.EAX); 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 Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItemIsFloat = TypeIsFloat(xStackItem); if (xStackItemSize > 8) { throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Clt_Un.cs->Error: StackSizes > 8 not supported"); } string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelTrue = BaseLabel + "True"; string LabelFalse = BaseLabel + "False"; if (xStackItemSize > 4) { XS.Set(XSRegisters.ESI, 1); // esi = 1 XS.Xor(XSRegisters.EDI, XSRegisters.EDI); // edi = 0 if (xStackItemIsFloat) { // value 2 XS.FPU.FloatLoad(ESP, destinationIsIndirect: true, size: RegisterSize.Long64); // value 1 new FloatLoad { DestinationReg = RegistersEnum.ESP, Size = 64, DestinationDisplacement = 8, DestinationIsIndirect = true }; XS.FPU.FloatCompareAndSet(ST1); // if carry is set, ST(0) < ST(i) new ConditionalMove { Condition = ConditionalTestEnum.Below, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; // pops fpu stack XS.FPU.FloatStoreAndPop(ST0); XS.FPU.FloatStoreAndPop(ST0); XS.Add(XSRegisters.ESP, 16); } else { XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EDX); //value2: EDX:EAX XS.Pop(XSRegisters.EBX); XS.Pop(XSRegisters.ECX); //value1: ECX:EBX XS.Sub(XSRegisters.EBX, XSRegisters.EAX); XS.SubWithCarry(XSRegisters.ECX, XSRegisters.EDX); //result = value1 - value2 new ConditionalMove { Condition = ConditionalTestEnum.Below, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; } XS.Push(XSRegisters.EDI); } else { if (xStackItemIsFloat) { #warning THIS NEEDS TO BE TESTED!!! XS.Comment("TEST TODO"); XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); new CompareSS { DestinationReg = RegistersEnum.XMM1, SourceReg = RegistersEnum.XMM0, pseudoOpcode = (byte)ComparePseudoOpcodes.LessThan }; XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.And(ESP, 1, destinationIsIndirect: true); } else { XS.Pop(XSRegisters.ECX); XS.Pop(XSRegisters.EAX); XS.Push(XSRegisters.ECX); XS.Compare(EAX, ESP, sourceIsIndirect: true); XS.Jump(ConditionalTestEnum.Below, LabelTrue); XS.Jump(LabelFalse); XS.Label(LabelTrue); XS.Add(XSRegisters.ESP, 4); XS.Push(1); new Jump { DestinationLabel = GetLabel(aMethod, aOpCode.NextPosition) }; XS.Label(LabelFalse); XS.Add(XSRegisters.ESP, 4); XS.Push(0); } } }
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) { 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; // 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); 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 override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xStackTop = aOpCode.StackPopTypes[0]; var xStackTop2 = aOpCode.StackPopTypes[0]; var xStackTopSize = SizeOfType(xStackTop); var xStackTop2Size = SizeOfType(xStackTop2); if (xStackTopSize != xStackTop2Size) { throw new Exception("Different size for substract: " + aMethod.MethodBase + "!"); } var xStackTopIsFloat = TypeIsFloat(xStackTop); switch (xStackTopSize) { case 1: case 2: case 4: if (xStackTopIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); XS.SSE.SubSS(XMM0, XMM1); XS.SSE.MoveSS(ESP, XMM1, destinationIsIndirect: true); } else { XS.Pop(XSRegisters.ECX); XS.Pop(XSRegisters.EAX); XS.Sub(XSRegisters.EAX, XSRegisters.ECX); XS.Push(XSRegisters.EAX); } break; case 8: if (xStackTopIsFloat) { new FloatLoad { DestinationReg = RegistersEnum.ESP, Size = 64, DestinationIsIndirect = true, DestinationDisplacement = 8 }; new FloatSub { DestinationReg = RegistersEnum.ESP, DestinationIsIndirect = true, Size = 64 }; XS.Add(ESP, 8); XS.FPU.FloatStoreAndPop(ESP, isIndirect: true, size: RegisterSize.Long64); } else { XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EDX); XS.Sub(ESP, EAX, destinationIsIndirect: true); XS.SubWithCarry(ESP, EDX, destinationDisplacement: 4); } break; default: throw new NotImplementedException("not implemented"); } }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { XS.Set(XSRegisters.EDX, XSRegisters.EBP, sourceDisplacement: 0x0C); XS.Set(XSRegisters.EAX, XSRegisters.EBP, sourceDisplacement: 0x08); XS.WriteToPortDX(XSRegisters.EAX); }
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 xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xStackItemIsFloat = TypeIsFloat(xStackItem); if (xStackItemSize > 8) { //EmitNotImplementedException( Assembler, GetServiceProvider(), "Cgt: StackSizes>8 not supported", CurInstructionLabel, mMethodInfo, mCurrentOffset, NextInstructionLabel ); throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Cgt.cs->Error: StackSizes > 8 not supported"); //return; } string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelTrue = BaseLabel + "True"; string LabelFalse = BaseLabel + "False"; var xNextLabel = GetLabel(aMethod, aOpCode.NextPosition); if (xStackItemSize > 4) { XS.Set(XSRegisters.ESI, 1); // esi = 1 XS.Xor(XSRegisters.EDI, XSRegisters.EDI); // edi = 0 if (xStackItemIsFloat) { // value 1 new FloatLoad { DestinationReg = RegistersEnum.ESP, Size = 64, DestinationDisplacement = 8, DestinationIsIndirect = true }; // value 2 XS.FPU.FloatLoad(ESP, destinationIsIndirect: true, size: RegisterSize.Long64); XS.FPU.FloatCompareAndSet(ST1); // if carry is set, ST(0) < ST(i) new ConditionalMove { Condition = ConditionalTestEnum.Below, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; // pops fpu stack XS.FPU.FloatStoreAndPop(ST0); XS.FPU.FloatStoreAndPop(ST0); XS.Add(XSRegisters.ESP, 16); } else { XS.Pop(XSRegisters.EAX); XS.Pop(XSRegisters.EDX); //value2: EDX:EAX XS.Pop(XSRegisters.EBX); XS.Pop(XSRegisters.ECX); //value1: ECX:EBX XS.Compare(XSRegisters.ECX, XSRegisters.EDX); XS.Jump(ConditionalTestEnum.GreaterThan, LabelTrue); XS.Jump(ConditionalTestEnum.LessThan, LabelFalse); XS.Compare(XSRegisters.EBX, XSRegisters.EAX); XS.Label(LabelTrue); new ConditionalMove { Condition = ConditionalTestEnum.GreaterThan, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI }; XS.Label(LabelFalse); } XS.Push(XSRegisters.EDI); /* * XS.Jump(ConditionalTestEnum.GreaterThan, LabelTrue); * XS.Label(LabelFalse); * XS.Push(0); * XS.Jump(xNextLabel); * XS.Label(LabelTrue ); * XS.Push(1);*/ } else { if (xStackItemIsFloat) { XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true); XS.Add(XSRegisters.ESP, 4); XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true); new CompareSS { DestinationReg = RegistersEnum.XMM1, SourceReg = RegistersEnum.XMM0, pseudoOpcode = (byte)ComparePseudoOpcodes.NotLessThanOrEqualTo }; XS.SSE2.MoveD(XMM1, EBX); XS.And(XSRegisters.EBX, 1); XS.Set(ESP, EBX, destinationIsIndirect: true); } else { XS.Pop(XSRegisters.EAX); XS.Compare(EAX, ESP, sourceIsIndirect: true); XS.Jump(ConditionalTestEnum.LessThan, LabelTrue); XS.Jump(LabelFalse); XS.Label(LabelTrue); XS.Add(XSRegisters.ESP, 4); XS.Push(1); XS.Jump(xNextLabel); XS.Label(LabelFalse); XS.Add(XSRegisters.ESP, 4); XS.Push(0); } } }
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xStackItem = aOpCode.StackPopTypes[0]; var xStackItemSize = SizeOfType(xStackItem); var xSize = Math.Max(xStackItemSize, SizeOfType(aOpCode.StackPopTypes[1])); if (xSize > 4) { if (TypeIsFloat(xStackItem)) { new CPUx86.SSE.MoveSS { DestinationReg = CPUx86.Registers.XMM0, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 8 }; new CPUx86.SSE.MoveSS { DestinationReg = CPUx86.Registers.XMM1, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; new CPUx86.SSE.XorPS { DestinationReg = CPUx86.Registers.XMM2, SourceReg = CPUx86.Registers.XMM2 }; new CPUx86.SSE.DivPS { DestinationReg = CPUx86.Registers.XMM0, SourceReg = CPUx86.Registers.XMM1 }; new CPUx86.SSE.MoveSS { SourceReg = CPUx86.Registers.XMM2, DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; } else { string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelShiftRight = BaseLabel + "ShiftRightLoop"; string LabelNoLoop = BaseLabel + "NoLoop"; string LabelEnd = BaseLabel + "End"; // divisor //low new CPUx86.Mov { DestinationReg = CPUx86.Registers.ESI, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; //high new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 4 }; //dividend // low new CPUx86.Mov { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 8 }; //high new CPUx86.Mov { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 12 }; // pop both 8 byte values new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 16 }; // set flags new CPUx86.Or { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EDI }; // if high dword of divisor is already zero, we dont need the loop new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.Zero, DestinationLabel = LabelNoLoop }; // set ecx to zero for counting the shift operations new CPUx86.Xor { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.ECX }; new Label(LabelShiftRight); // shift divisor 1 bit right new CPUx86.ShiftRightDouble { DestinationReg = CPUx86.Registers.ESI, SourceReg = CPUx86.Registers.EDI, ArgumentValue = 1 }; new CPUx86.ShiftRight { DestinationReg = CPUx86.Registers.EDI, SourceValue = 1 }; // increment shift counter new CPUx86.INC { DestinationReg = CPUx86.Registers.ECX }; // set flags new CPUx86.Or { DestinationReg = CPUx86.Registers.EDI, SourceReg = CPUx86.Registers.EDI }; // loop while high dword of divisor till it is zero new CPUx86.ConditionalJump { Condition = CPUx86.ConditionalTestEnum.NotZero, DestinationLabel = LabelShiftRight }; // shift the divident now in one step // shift divident CL bits right new CPUx86.ShiftRightDouble { DestinationReg = CPUx86.Registers.EAX, SourceReg = CPUx86.Registers.EDX, ArgumentReg = CPUx86.Registers.CL }; new CPUx86.ShiftRight { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.CL }; // so we shifted both, so we have near the same relation as original values // divide this new CPUx86.Divide { DestinationReg = CPUx86.Registers.ESI }; // save remainder to stack new CPUx86.Push { DestinationValue = 0 }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EDX }; //TODO: implement proper derivation correction and overflow detection new CPUx86.Jump { DestinationLabel = LabelEnd }; new Label(LabelNoLoop); //save high dividend XS.Set(XSRegisters.OldToNewRegister(CPUx86.Registers.ECX), XSRegisters.OldToNewRegister(CPUx86.Registers.EAX)); XS.Set(XSRegisters.OldToNewRegister(CPUx86.Registers.EAX), XSRegisters.OldToNewRegister(CPUx86.Registers.EDX)); // zero EDX, so that high part is zero -> reduce overflow case new CPUx86.Xor { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EDX }; // divide high part new CPUx86.Divide { DestinationReg = CPUx86.Registers.ESI }; XS.Set(XSRegisters.OldToNewRegister(CPUx86.Registers.EAX), XSRegisters.OldToNewRegister(CPUx86.Registers.ECX)); // divide low part new CPUx86.Divide { DestinationReg = CPUx86.Registers.ESI }; // save remainder result new CPUx86.Push { DestinationValue = 0 }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EDX }; new Label(LabelEnd); } } else { if (TypeIsFloat(xStackItem)) { new CPUx86.SSE.MoveSS { DestinationReg = CPUx86.Registers.XMM0, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; new CPUx86.SSE.MoveSS { DestinationReg = CPUx86.Registers.XMM1, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true }; new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; new CPUx86.SSE.XorPS { DestinationReg = CPUx86.Registers.XMM2, SourceReg = CPUx86.Registers.XMM2 }; new CPUx86.SSE.DivPS { DestinationReg = CPUx86.Registers.XMM0, SourceReg = CPUx86.Registers.XMM1 }; new CPUx86.Sub { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; new CPUx86.SSE.MoveSS { SourceReg = CPUx86.Registers.XMM2, DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true }; } else { new CPUx86.Pop { DestinationReg = CPUx86.Registers.ECX }; new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; // gets devised by ecx new CPUx86.Xor { DestinationReg = CPUx86.Registers.EDX, SourceReg = CPUx86.Registers.EDX }; new CPUx86.Divide { DestinationReg = CPUx86.Registers.ECX }; // => EAX / ECX new CPUx86.Push { DestinationReg = CPUx86.Registers.EDX }; } } }
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); } } }
public override void AssembleNew(Cosmos.Assembler.Assembler aAssembler, object aMethodInfo) { XS.Halt(); }
public static void DoExecute(uint xStackContentSize, string aBaseLabel) { //TODO: Throw System.OverflowException if the result won't fit in the type. if (xStackContentSize > 4) { // div of both == LEFT_LOW * RIGHT_LOW + ((LEFT_LOW * RIGHT_HIGH + RIGHT_LOW * LEFT_HIGH) << 32) string Simple32Multiply = aBaseLabel + "Simple32Multiply"; string MoveReturnValue = aBaseLabel + "MoveReturnValue"; // right value // low // SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true // high // SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 4 // left value // low // SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 8 // high // SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = 12 // compair LEFT_HIGH, RIGHT_HIGH , on zero only simple multiply is used //mov RIGHT_HIGH to eax, is useable on Full 64 multiply XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); XS.Or(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 12); XS.Jump(ConditionalTestEnum.Zero, Simple32Multiply); // Full 64 Multiply // copy again, or could change EAX //TODO is there an opcode that does OR without change EAX? XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4); // eax contains already RIGHT_HIGH // multiply with LEFT_LOW XS.Multiply(XSRegisters.ESP, displacement: 8); // save result of LEFT_LOW * RIGHT_HIGH XS.Set(XSRegisters.ECX, XSRegisters.EAX); //mov RIGHT_LOW to eax XS.Set(EAX, ESP, sourceIsIndirect: true); // multiply with LEFT_HIGH XS.Multiply(XSRegisters.ESP, displacement: 12); // add result of LEFT_LOW * RIGHT_HIGH + RIGHT_LOW + LEFT_HIGH XS.Add(XSRegisters.ECX, XSRegisters.EAX); //mov RIGHT_LOW to eax XS.Set(EAX, ESP, sourceIsIndirect: true); // multiply with LEFT_LOW XS.Multiply(XSRegisters.ESP, displacement: 8); // add LEFT_LOW * RIGHT_HIGH + RIGHT_LOW + LEFT_HIGH to high dword of last result XS.Add(XSRegisters.EDX, XSRegisters.ECX); XS.Jump(MoveReturnValue); XS.Label(Simple32Multiply); //mov RIGHT_LOW to eax XS.Set(EAX, ESP, sourceIsIndirect: true); // multiply with LEFT_LOW XS.Multiply(XSRegisters.ESP, displacement: 8); XS.Label(MoveReturnValue); // move high result to left high XS.Set(ESP, EDX, destinationDisplacement: 12); // move low result to left low XS.Set(ESP, EAX, destinationDisplacement: 8); // pop right 64 value XS.Add(XSRegisters.ESP, 8); } else { XS.Pop(XSRegisters.EAX); XS.Multiply(ESP, isIndirect: true, size: RegisterSize.Int32); XS.Add(XSRegisters.ESP, 4); XS.Push(XSRegisters.EAX); } }
public override void AssembleNew(Assembler.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(Assembler.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(Assembler.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(Assembler.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 Assembler.x86.Movs { Size = 8, Prefixes = Assembler.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(Assembler.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 Execute(MethodInfo aMethod, ILOpCode aOpCode) { var xOpVar = (OpVar)aOpCode; var xDisplacement = Ldarg.GetArgumentDisplacement(aMethod, xOpVar.Value); new Mov { DestinationReg = RegistersEnum.EBX, SourceValue = (uint)(xDisplacement) }; XS.Set(XSRegisters.OldToNewRegister(RegistersEnum.EAX), XSRegisters.OldToNewRegister(RegistersEnum.EBP)); new CPUx86.Add { DestinationReg = RegistersEnum.EAX, SourceReg = RegistersEnum.EBX }; new CPUx86.Push { DestinationReg = RegistersEnum.EAX }; // if (aMethod.MethodBase.DeclaringType.FullName == "Cosmos.Kernel.Plugs.Console" // && aMethod.MethodBase.Name == "Write" // && aMethod.MethodBase.GetParameters()[0].ParameterType == typeof(int)) // { // Console.Write(""); // } // Cosmos.IL2CPU.ILOpCodes.OpVar xOpVar = ( Cosmos.IL2CPU.ILOpCodes.OpVar )aOpCode; // var xMethodInfo = aMethod.MethodBase as System.Reflection.MethodInfo; // uint xReturnSize = 0; // if( xMethodInfo != null ) // { // xReturnSize = Align( SizeOfType( xMethodInfo.ReturnType ), 4 ); // } // uint xOffset = 8; // var xCorrectedOpValValue = xOpVar.Value; // if( !aMethod.MethodBase.IsStatic && xOpVar.Value > 0 ) // { // // if the method has a $this, the OpCode value includes the this at index 0, but GetParameters() doesnt include the this // xCorrectedOpValValue -= 1; // } // var xParams = aMethod.MethodBase.GetParameters(); // for( int i = xParams.Length - 1; i > xCorrectedOpValValue; i-- ) // { // var xSize = Align( SizeOfType( xParams[ i ].ParameterType ), 4 ); // xOffset += xSize; // } // var xCurArgSize = Align( SizeOfType( xParams[ xCorrectedOpValValue ].ParameterType ), 4 ); // uint xArgSize = 0; // foreach( var xParam in xParams ) // { // xArgSize += Align( SizeOfType( xParam.ParameterType ), 4 ); // } // xReturnSize = 0; // uint xExtraSize = 0; // if( xReturnSize > xArgSize ) // { // xExtraSize = xArgSize - xReturnSize; // } // xOffset += xExtraSize; //#warning TODO: check this // new CPUx86.Push { DestinationReg = CPUx86.Registers.EBP }; // for( int i = 0; i < ( xCurArgSize / 4 ); i++ ) // { // new CPUx86.Push { DestinationValue = ( uint )( xCurArgSize - ( ( i + 1 ) * 4 ) ) }; // } // Assembler.Stack.Push( ( int )xCurArgSize, xParams[ xCorrectedOpValValue ].ParameterType ); // //for( int i = 0; i < ( mSize / 4 ); i++ ) // //{ // // mVirtualAddresses[ i ] = ( mOffset + ( ( i + 1 ) * 4 ) + 4 ); // //} // //mAddress = aMethodInfo.Arguments[ aIndex ].VirtualAddresses.First(); // Assembler.Stack.Push( new StackContents.Item( 4, typeof( uint ) ) ); // //new CPUx86.Push { DestinationValue = ( uint )mAddress }; // // // Assembler.Stack.Push( new StackContents.Item( 4, typeof( uint ) ) ); // new Add( Assembler ).Execute( aMethod, aOpCode ); }
public override void AssembleNew(Assembler.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); 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).GetTypeInfo().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(); 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("static_field__Cosmos_Core_CPU_mInterruptsEnabled", 1, destinationIsIndirect: true, size: RegisterSize.Byte8); XS.LoadIdt(EAX, isIndirect: true); // Reenable interrupts XS.EnableInterrupts(); XS.Label(".__AFTER_ENABLE_INTERRUPTS"); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xValue = aOpCode.StackPopTypes[0]; var xValueIsFloat = TypeIsFloat(xValue); var xValueSize = SizeOfType(xValue); if (xValueSize > 8) { //EmitNotImplementedException( Assembler, aServiceProvider, "Size '" + xSize.Size + "' not supported (add)", aCurrentLabel, aCurrentMethodInfo, aCurrentOffset, aNextLabel ); throw new NotImplementedException(); } //TODO if on stack a float it is first truncated, http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.conv_r_un.aspx if (!xValueIsFloat) { switch (xValueSize) { case 1: case 2: case 4: /* * Code generated by C# / Visual Studio 2015 * mov eax,dword ptr [anInt] * mov dword ptr [ebp-0E0h],eax * cvtsi2sd xmm0,dword ptr [ebp-0E0h] * mov ecx,dword ptr [ebp-0E0h] * shr ecx,1Fh * addsd xmm0,mmword ptr __xmm@41f00000000000000000000000000000 (01176B40h)[ecx*8] * movsd mmword ptr [aDouble],xmm0 # This for now means to copy our converted double to ESP */ string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelSign_Bit_Unset = BaseLabel + "LabelSign_Bit_Unset"; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.Set(EBP, EAX, destinationDisplacement: -0xE0, destinationIsIndirect: true); XS.SSE2.ConvertSI2SD(XMM0, EBP, sourceDisplacement: -0xE0, sourceIsIndirect: true); XS.Set(ECX, EBP, sourceDisplacement: -0xE0, sourceIsIndirect: true); // OK now we put in ECX the last bit of our unsigned value, we call it "SIGN_BIT" but is a little improper... XS.ShiftRight(ECX, 31); /* * if the 'SIGN_BIT' is 0 it means that our uint could have been placed in a normal int so ConvertSI2SD did already * the right thing: we have finished * if the value is 1 we need to do that addition with that weird constant to obtain the real value as double */ XS.Compare(ECX, 0x00); XS.Jump(ConditionalTestEnum.Equal, LabelSign_Bit_Unset); XS.LiteralCode(@"addsd xmm0, [__uint2double_const]"); XS.Label(LabelSign_Bit_Unset); // We have converted our value to double put it on ESP // expand stack, that moved data is valid stack XS.Sub(ESP, 4); XS.SSE2.MoveSD(ESP, XMM0, destinationIsIndirect: true); break; case 8: BaseLabel = GetLabel(aMethod, aOpCode) + "."; LabelSign_Bit_Unset = BaseLabel + "LabelSign_Bit_Unset"; /* * mov EAX, ESP + 4 * fild qword ptr [esp] * shr EAX, 31 * cmp ESP, 0 * jpe LabelSign_Bit_Unset * LabelSign_Bit_Unset: * fadd dword ptr __ulong2double_const2 * fstp ESP */ // Save the high part of the ulong in EAX (we cannot move all of ESP as it has 64 bit size) XS.Set(EAX, ESP, sourceIsIndirect: true, sourceDisplacement: 4); XS.FPU.IntLoad(ESP, isIndirect: true, size: RegisterSize.Long64); XS.Test(EAX, EAX); XS.Jump(ConditionalTestEnum.NotSign, LabelSign_Bit_Unset); // If the sign is set we remove it using the constant __ulong2double_const4 XS.LiteralCode(@"fadd dword [__ulong2double_const]"); XS.Label(LabelSign_Bit_Unset); // Convert the value to double and move it into the stack XS.FPU.FloatStoreAndPop(ESP, isIndirect: true, size: RegisterSize.Long64); break; default: //EmitNotImplementedException( Assembler, GetServiceProvider(), "Conv_I: SourceSize " + xSource + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel ); throw new NotImplementedException("Conv_R_Un with type " + xValue + " not supported!"); } } else { throw new NotImplementedException("Conv_R_Un with type " + xValue + " not supported!"); } }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { XS.Set(XSRegisters.EAX, LabelName.Get(CPUUpdateIDTAsm.GetMethodDef(typeof(Cosmos.Core.Processing.ProcessorScheduler).Assembly, typeof(Cosmos.Core.Processing.ProcessorScheduler).FullName, "EntryPoint", true))); XS.Push(XSRegisters.EAX); }