Beispiel #1
0
        public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
        {
            var xEndLabel = GetLabel(aMethod, aOpCode) + ".End";

            // size
            XS.Pop(ECX);
            // value
            XS.Pop(EBX);
            // address
            XS.Pop(EDI);

            XS.Compare(ECX, 0);
            XS.Jump(ConditionalTestEnum.Equal, xEndLabel);

            XS.Set(EDI, BL, destinationIsIndirect: true);

            XS.Compare(ECX, 1);
            XS.Jump(ConditionalTestEnum.Equal, xEndLabel);

            XS.Set(ESI, EDI);
            XS.Increment(EDI);
            XS.Decrement(ECX);

            new Movs {
                Prefixes = InstructionPrefixes.Repeat, Size = 8
            };

            XS.Label(xEndLabel);
        }
Beispiel #2
0
        public override void Execute(MethodInfo aMethod, ILOpCode aOpCode)
        {
            OpType xType            = ( OpType )aOpCode;
            string xTypeID          = GetTypeIDLabel(xType.Value);
            string mReturnNullLabel = GetLabel(aMethod, aOpCode) + "_ReturnNull";

            XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceIsIndirect: true);

            XS.Compare(XSRegisters.EAX, 0);
            XS.Jump(CPUx86.ConditionalTestEnum.Zero, mReturnNullLabel);

            // EAX contains a memory handle now. Lets convert it to a pointer
            XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceIsIndirect: true);

            //XS.Mov(XSRegisters.EAX, XSRegisters.EAX, sourceIsIndirect: true);
            XS.Push(XSRegisters.EAX, isIndirect: true);
            XS.Push(xTypeID, isIndirect: true);

            SysReflection.MethodBase xMethodIsInstance = ReflectionUtilities.GetMethodBase(typeof(VTablesImpl), "IsInstance", "System.UInt32", "System.UInt32");
//, new OpMethod( ILOpCode.Code.Call, aOpCode.Position, aOpCode.NextPosition, xMethodIsInstance, aOpCode.CurrentExceptionHandler));
            Call.DoExecute(Assembler, aMethod, xMethodIsInstance, aOpCode, GetLabel(aMethod, aOpCode), GetLabel(aMethod, aOpCode) + "_After_IsInstance_Call", DebugEnabled);

            new Label(GetLabel(aMethod, aOpCode) + "_After_IsInstance_Call");
            XS.Pop(XSRegisters.EAX);
            XS.Compare(XSRegisters.EAX, 0);
            XS.Jump(CPUx86.ConditionalTestEnum.Equal, mReturnNullLabel);
            // push nothing now, as we should return the object instance pointer.
            new CPUx86.Jump {
                DestinationLabel = GetLabel(aMethod, aOpCode.NextPosition)
            };
            XS.Label(mReturnNullLabel);
            XS.Add(XSRegisters.ESP, 4);
            XS.Push(0);
        }
Beispiel #3
0
        public static void InitializeArray(Array array, RuntimeFieldHandle fldHandle)
        {
            // Arguments:
            //    Array aArray, RuntimeFieldHandle aFieldHandle
            XS.Set(XSRegisters.EDI, XSRegisters.EBP, sourceDisplacement: 0xC); // array
            XS.Set(EDI, EDI, sourceIsIndirect: true);
            XS.Set(XSRegisters.ESI, XSRegisters.EBP, sourceDisplacement: 8);   // aFieldHandle
            XS.Add(XSRegisters.EDI, 8);
            XS.Push(EDI, isIndirect: true);
            XS.Add(XSRegisters.EDI, 4);
            XS.Set(EAX, EDI, sourceIsIndirect: true);
            XS.Multiply(ESP, isIndirect: true, size: RegisterSize.Int32);
            XS.Pop(XSRegisters.ECX);
            XS.Set(XSRegisters.ECX, XSRegisters.EAX);
            XS.Set(XSRegisters.EAX, 0);
            XS.Add(XSRegisters.EDI, 4);

            XS.Label(".StartLoop");
            XS.Set(DL, ESI, sourceIsIndirect: true);
            XS.Set(EDI, DL, destinationIsIndirect: true);
            XS.Add(XSRegisters.EAX, 1);
            XS.Add(XSRegisters.ESI, 1);
            XS.Add(XSRegisters.EDI, 1);
            XS.Compare(XSRegisters.EAX, XSRegisters.ECX);
            XS.Jump(CPUx86.ConditionalTestEnum.Equal, ".EndLoop");
            XS.Jump(".StartLoop");

            XS.Label(".EndLoop");
        }
Beispiel #4
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");
     }
 }
Beispiel #5
0
        public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
        {
            OpType xType                     = (OpType)aOpCode;
            string xTypeID                   = GetTypeIDLabel(xType.Value);
            string xCurrentMethodLabel       = GetLabel(aMethod, aOpCode);
            string xReturnNullLabel          = xCurrentMethodLabel + "_ReturnNull";
            string xAfterIsInstanceCallLabel = xCurrentMethodLabel + "_After_IsInstance_Call";
            string xNextPositionLabel        = GetLabel(aMethod, aOpCode.NextPosition);

            XS.Set(EAX, ESP, sourceIsIndirect: true, sourceDisplacement: 4);

            XS.Compare(EAX, 0);
            XS.Jump(ConditionalTestEnum.Zero, xReturnNullLabel);

            XS.Push(EAX, isIndirect: true);
            XS.Push(xTypeID, isIndirect: true);
            XS.Push(Convert.ToUInt32(xType.Value.IsInterface));

            Call.DoExecute(Assembler, aMethod, VTablesImplRefs.IsInstanceRef,
                           aOpCode, xCurrentMethodLabel, xAfterIsInstanceCallLabel, DebugEnabled);

            XS.Label(xAfterIsInstanceCallLabel);

            XS.Pop(EAX);
            XS.Compare(EAX, 0);
            XS.Jump(ConditionalTestEnum.Equal, xReturnNullLabel);
            XS.Jump(xNextPositionLabel);

            XS.Label(xReturnNullLabel);

            XS.Add(ESP, 8);
            XS.Push(0);
            XS.Push(0);
        }
Beispiel #6
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));
        }
Beispiel #7
0
        public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
        {
            XS.Pop(XSRegisters.ECX); // shift amount
            var xStackItem_ShiftAmount = aOpCode.StackPopTypes[0];
            var xStackItem_Value       = aOpCode.StackPopTypes[1];
            var xStackItem_Value_Size  = SizeOfType(xStackItem_Value);

#if DOTNETCOMPATIBLE
            if (xStackItem_Value.Size == 4)
#else
            if (xStackItem_Value_Size <= 4)
#endif
            {
                XS.ShiftLeft(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
            }
#if DOTNETCOMPATIBLE
            else if (xStackItem_Value.Size == 8)
#else
            else if (xStackItem_Value_Size <= 8)
#endif
            {
                string BaseLabel     = GetLabel(aMethod, aOpCode) + ".";
                string LowPartIsZero = BaseLabel + "LowPartIsZero";
                string End_Shl       = BaseLabel + "End_Shl";

                // [ESP] is low part
                // [ESP + 4] is high part

                // move low part to eax
                XS.Set(EAX, ESP, sourceIsIndirect: true);

                XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8);
                XS.Jump(CPUx86.ConditionalTestEnum.AboveOrEqual, LowPartIsZero);

                // shift higher part
                XS.ShiftLeftDouble(ESP, EAX, CL, destinationDisplacement: 4);
                // shift lower part
                // To retain the sign bit we must use ShiftLeftArithmetic and not ShiftLeft!
                XS.ShiftLeftArithmetic(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
                XS.Jump(End_Shl);

                XS.Label(LowPartIsZero);
                // remove bits >= 32, so that CL max value could be only 31
                XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8);
                // shift low part in EAX and move it in high part
                // To retain the sign bit we must use ShiftLeftArithmetic and not ShiftLeft!
                XS.ShiftLeftArithmetic(EAX, CL);
                XS.Set(ESP, EAX, destinationDisplacement: 4);
                // replace unknown low part with a zero, if <= 32
                XS.Set(XSRegisters.ESP, 0, destinationIsIndirect: true);

                XS.Label(End_Shl);
            }
            else
            {
                throw new NotSupportedException("A size bigger 8 not supported at Shl!");
            }
        }
Beispiel #8
0
 public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
 {
     ILOpCodes.OpSwitch OpSw = (ILOpCodes.OpSwitch)aOpCode;
     XS.Pop(XSRegisters.EAX);
     for (int i = 0; i < OpSw.BranchLocations.Length; i++)
     {
         XS.Compare(XSRegisters.EAX, ( uint )i);
         //string DestLabel = AssemblerNasm.TmpBranchLabel( aMethod, new ILOpCodes.OpBranch( ILOpCode.Code.Jmp, aOpCode.Position, OpSw.BranchLocations[ i ] ) );
         string xDestLabel = AppAssembler.TmpPosLabel(aMethod, OpSw.BranchLocations[i]);
         XS.Jump(CPUx86.ConditionalTestEnum.Equal, xDestLabel);
     }
 }
Beispiel #9
0
        public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
        {
            OpType xType                     = (OpType)aOpCode;
            string xTypeID                   = GetTypeIDLabel(xType.Value);
            string xCurrentMethodLabel       = GetLabel(aMethod, aOpCode);
            string xAfterIsInstanceCallLabel = xCurrentMethodLabel + "_After_IsInstance_Call";
            string xReturnNullLabel          = xCurrentMethodLabel + "_ReturnNull";
            string xNextPositionLabel        = GetLabel(aMethod, aOpCode.NextPosition);

            XS.Set(EAX, ESP, sourceDisplacement: 4);

            XS.Compare(EAX, 0);
            XS.Jump(CPUx86.ConditionalTestEnum.Zero, xReturnNullLabel);
            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(CPUx86.ConditionalTestEnum.Equal, xReturnNullLabel);

            XS.Jump(xNextPositionLabel);
            XS.Label(xReturnNullLabel);
            XS.Add(ESP, 8);

            //string xAllocInfoLabelName = LabelName.Get( GCImplementationRefs.AllocNewObjectRef );
            // TODO: Emit new exceptions
            //new Newobj( Assembler ).Execute( aMethod, aOpCode );

            //Newobj.Assemble( Assembler,
            //                typeof( InvalidCastException ).GetConstructor( new Type[ 0 ] ),
            //                GetService<IMetaDataInfoService>().GetTypeIdLabel( typeof( InvalidCastException ) ),
            //                mThisLabel,
            //                mMethodInfo,
            //                mCurrentILOffset,
            //                mThisLabel + "_After_NewException",
            //                GetService<IMetaDataInfoService>().GetTypeInfo( typeof( InvalidCastException ) ),
            //                GetService<IMetaDataInfoService>().GetMethodInfo( typeof( InvalidCastException ).GetConstructor( new Type[ 0 ] ), false ),
            //                GetServiceProvider(),
            //                xAllocInfo.LabelName );
            XS.Label(xCurrentMethodLabel + "_After_NewException");
            //Call.EmitExceptionLogic( Assembler, ( uint )mCurrentILOffset, mMethodInfo, mNextOpLabel, false, null );
        }
Beispiel #10
0
        public override void Execute(MethodInfo aMethod, ILOpCode aOpCode)
        {
            string xCurrentMethodLabel = GetLabel(aMethod, aOpCode);
            OpType xType   = ( OpType )aOpCode;
            string xTypeID = GetTypeIDLabel(xType.Value);

            //mTypeId = GetService<IMetaDataInfoService>().GetTypeIdLabel( mCastAsType );
            // todo: throw an exception when the class does not support the cast!
            string mReturnNullLabel = xCurrentMethodLabel + "_ReturnNull";

            XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceIsIndirect: true);
            XS.Compare(XSRegisters.EAX, 0);
            XS.Jump(CPU.ConditionalTestEnum.Zero, mReturnNullLabel);

            XS.Set(XSRegisters.EAX, XSRegisters.EAX, sourceIsIndirect: true);
            XS.Push(XSRegisters.EAX, isIndirect: true);
            XS.Push(xTypeID, isIndirect: true);
            MethodBase xMethodIsInstance = VTablesImplRefs.IsInstanceRef;

            // new OpMethod( ILOpCode.Code.Call, 0, 0, xMethodIsInstance, aOpCode.CurrentExceptionHandler ) );
            Call.DoExecute(Assembler, aMethod, xMethodIsInstance, aOpCode, xCurrentMethodLabel, xCurrentMethodLabel + "_After_IsInstance_Call", DebugEnabled);
            XS.Label(xCurrentMethodLabel + "_After_IsInstance_Call");
            XS.Pop(XSRegisters.EAX);
            XS.Compare(XSRegisters.EAX, 0);
            XS.Jump(CPU.ConditionalTestEnum.Equal, mReturnNullLabel);
            new CPU.Jump {
                DestinationLabel = GetLabel(aMethod, aOpCode.NextPosition)
            };

            XS.Label(mReturnNullLabel);
            XS.Add(XSRegisters.ESP, 4);
            //string xAllocInfoLabelName = LabelName.Get( GCImplementationRefs.AllocNewObjectRef );
#warning TODO: Emit new exceptions
            //new Newobj( Assembler ).Execute( aMethod, aOpCode );

            //Newobj.Assemble( Assembler,
            //                typeof( InvalidCastException ).GetConstructor( new Type[ 0 ] ),
            //                GetService<IMetaDataInfoService>().GetTypeIdLabel( typeof( InvalidCastException ) ),
            //                mThisLabel,
            //                mMethodInfo,
            //                mCurrentILOffset,
            //                mThisLabel + "_After_NewException",
            //                GetService<IMetaDataInfoService>().GetTypeInfo( typeof( InvalidCastException ) ),
            //                GetService<IMetaDataInfoService>().GetMethodInfo( typeof( InvalidCastException ).GetConstructor( new Type[ 0 ] ), false ),
            //                GetServiceProvider(),
            //                xAllocInfo.LabelName );
            XS.Label(xCurrentMethodLabel + "_After_NewException");
            //Call.EmitExceptionLogic( Assembler, ( uint )mCurrentILOffset, mMethodInfo, mNextOpLabel, false, null );
        }
Beispiel #11
0
        public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
        {
            DoNullReferenceCheck(Assembler, DebugEnabled, 0);
            var    xType            = ((OpType)aOpCode).Value;
            string xBaseLabel       = GetLabel(aMethod, aOpCode) + ".";
            string xTypeID          = GetTypeIDLabel(xType);
            uint   xTypeSize        = SizeOfType(xType);
            string mReturnNullLabel = xBaseLabel + "_ReturnNull";

            XS.Compare(XSRegisters.ESP, 0, destinationIsIndirect: true);
            XS.Jump(CPU.ConditionalTestEnum.Zero, mReturnNullLabel);

            XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceIsIndirect: true);
            XS.Push(XSRegisters.EAX, isIndirect: true);
            XS.Push(xTypeID, isIndirect: true);
            XS.Push(Convert.ToUInt32(xType.IsInterface));
            Call.DoExecute(Assembler, aMethod, VTablesImplRefs.IsInstanceRef, aOpCode, GetLabel(aMethod, aOpCode), xBaseLabel + "_After_IsInstance_Call", DebugEnabled);

            XS.Label(xBaseLabel + "_After_IsInstance_Call");
            XS.Pop(XSRegisters.EAX);
            XS.Compare(XSRegisters.EAX, 0);
            XS.Jump(CPU.ConditionalTestEnum.Equal, mReturnNullLabel);
            XS.Pop(XSRegisters.EAX);
            uint xSize = xTypeSize;

            if (xSize % 4 > 0)
            {
                xSize += 4 - (xSize % 4);
            }
            int xItems = (int)xSize / 4;

            for (int i = xItems - 1; i >= 0; i--)
            {
                new CPU.Push {
                    DestinationReg = CPU.RegistersEnum.EAX, DestinationIsIndirect = true, DestinationDisplacement = ((i * 4) + ObjectUtils.FieldDataOffset)
                };
            }
            new CPU.Jump {
                DestinationLabel = GetLabel(aMethod, aOpCode.NextPosition)
            };
            XS.Label(mReturnNullLabel);
            XS.Add(XSRegisters.ESP, 4);
            XS.Push(0);
        }
Beispiel #12
0
        public static void Assemble(XSharp.Assembler.Assembler aAssembler, OpType aOpType, uint aElementSize, bool debugEnabled, _MethodInfo aMethod, ILOpCode aOpCode)
        {
            XS.Comment("Arraytype: " + aOpType.StackPopTypes.Last().FullName);
            XS.Comment("Size: " + aElementSize);

            DoNullReferenceCheck(aAssembler, debugEnabled, 8);

            //Do check for index out of range
            var xBaseLabel = GetLabel(aMethod, aOpCode);
            var xNoIndexOutOfRangeExeptionLabel = xBaseLabel + "_NoIndexOutOfRangeException";
            var xIndexOutOfRangeExeptionLabel   = xBaseLabel + "_IndexOutOfRangeException";

            XS.Pop(EBX);                                     //get Position _, array, 0, index -> _, array, 0
            XS.Push(ESP, true, 4);                           // _, array, 0 => _, array, 0, array
            XS.Push(ESP, true, 12);                          // _, array, 0, array => _, array, 0, array, 0
            Ldlen.Assemble(aAssembler, debugEnabled, false); // _, array, 0, array, 0 -> _, array, 0, length
            XS.Pop(EAX);                                     //Length of array _, array, 0, length -> _, array, 0
            XS.Compare(EAX, EBX);
            XS.Jump(CPUx86.ConditionalTestEnum.LessThanOrEqualTo, xIndexOutOfRangeExeptionLabel);

            XS.Compare(EBX, 0);
            XS.Jump(CPUx86.ConditionalTestEnum.GreaterThanOrEqualTo, xNoIndexOutOfRangeExeptionLabel);

            XS.Label(xIndexOutOfRangeExeptionLabel);
            XS.Pop(EAX);
            XS.Pop(EAX);
            Call.DoExecute(aAssembler, aMethod, ExceptionHelperRefs.ThrowIndexOutOfRangeException, aOpCode, xNoIndexOutOfRangeExeptionLabel, debugEnabled);

            XS.Label(xNoIndexOutOfRangeExeptionLabel);
            XS.Push(EBX); //_, array, 0 -> _, array, 0, index

            // calculate element offset into array memory (including header)
            XS.Pop(EAX);
            XS.Set(EDX, aElementSize);
            XS.Multiply(EDX);
            XS.Add(EAX, (uint)(ObjectUtils.FieldDataOffset + 4));

            // pop the array now
            XS.Add(ESP, 4);
            XS.Pop(EDX);

            XS.Add(EDX, EAX);
            XS.Push(EDX);
        }
Beispiel #13
0
        public override void Execute(MethodInfo aMethod, ILOpCode aOpCode)
        {
            string xBaseLabel             = GetLabel(aMethod, aOpCode) + ".";
            var    xStackItem_ShiftAmount = aOpCode.StackPopTypes[0];
            var    xStackItem_Value       = aOpCode.StackPopTypes[1];

            if (TypeIsFloat(xStackItem_Value))
            {
                throw new NotImplementedException("Floats not yet supported!");
            }
            var xStackItem_Value_Size = SizeOfType(xStackItem_Value);

            if (xStackItem_Value_Size <= 4)
            {
                XS.Pop(XSRegisters.EAX); // shift amount
                XS.Pop(XSRegisters.EBX); // value
                XS.Set(XSRegisters.CL, XSRegisters.AL);
                XS.ShiftRight(XSRegisters.EBX, CL);
                XS.Push(XSRegisters.EBX);
                return;
            }
            if (xStackItem_Value_Size <= 8)
            {
                XS.Pop(XSRegisters.EDX);
                XS.Set(XSRegisters.EAX, 0);
                XS.Label(xBaseLabel + "__StartLoop");
                XS.Compare(XSRegisters.EDX, XSRegisters.EAX);
                XS.Jump(CPUx86.ConditionalTestEnum.Equal, xBaseLabel + "__EndLoop");
                XS.Set(EBX, ESP, sourceIsIndirect: true);
                XS.Set(XSRegisters.CL, 1);
                XS.ShiftRight(XSRegisters.EBX, CL);
                XS.Set(ESP, EBX, destinationIsIndirect: true);
                XS.Set(XSRegisters.CL, 1);
                XS.RotateThroughCarryRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.Add(XSRegisters.EAX, 1);
                new CPUx86.Jump {
                    DestinationLabel = xBaseLabel + "__StartLoop"
                };

                XS.Label(xBaseLabel + "__EndLoop");
                return;
            }
        }
Beispiel #14
0
        public static void CheckOverflowForSmall(uint xResultSize, bool xSourceIsSigned, bool xResultIsSigned, Assembler assembler, _MethodInfo aMethod, ILOpCode aOpCode, string xSuccessLabel, string xOverflowLabel)
        {
            XS.Set(EAX, ESP, sourceIsIndirect: true);
            // only look at bits which are part of result
            // normally check that they are all either 0 or 1
            // if same size but casting between signed and unsigned, then first bit must be zero
            byte bitCount = (byte)((xResultSize) * 8 - 1);

            XS.ShiftRight(EAX, bitCount);
            XS.Compare(EAX, 0);
            XS.Jump(ConditionalTestEnum.Equal, xSuccessLabel);
            if (xSourceIsSigned)
            {
                if (xResultIsSigned)
                {
                    XS.Not(EAX); // if negative then all must be 1s
                    XS.Compare(EAX, 0);
                    XS.Jump(ConditionalTestEnum.Equal, xSuccessLabel);
                }
                else
                {
                    XS.Jump(xOverflowLabel);
                }
            }
            else // source was unsigned
            {
                if (xResultIsSigned)
                {
                    XS.Jump(xOverflowLabel); //too big
                }
                else
                {
                    XS.Compare(EAX, 1); // only lowest bit is set, which is heighest of next
                    XS.Jump(ConditionalTestEnum.Equal, xSuccessLabel);
                }
            }
            XS.Label(xOverflowLabel);
            XS.Pop(EAX); // clear stack
            Call.DoExecute(assembler, aMethod, ExceptionHelperRefs.ThrowOverflowExceptionRef, aOpCode, xSuccessLabel, false);
            XS.Label(xSuccessLabel);
        }
Beispiel #15
0
        public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
        {
            //TODO: What if the last ILOp in a method was Conv_Ovf_I_Un or an other?
            var xSource        = aOpCode.StackPopTypes[0];
            var xSourceSize    = SizeOfType(xSource);
            var xSourceIsFloat = TypeIsFloat(xSource);

            if (xSourceIsFloat)
            {
                ThrowNotImplementedException("Conv_Ovf_I_Un throws an ArgumentException, because float is not implemented!");
            }

            switch (xSourceSize)
            {
            case 1:
            case 2:
            case 4:
                break;

            case 8:
            {
                string NoOverflowLabel = GetLabel(aMethod, aOpCode) + "__NoOverflow";
                XS.Pop(XSRegisters.EAX);
                // EBX is high part and should be zero for unsigned, so we test it on zero
                {
                    XS.Pop(XSRegisters.EBX);
                    XS.Compare(XSRegisters.EBX, 0);
                    XS.Jump(CPUx86.ConditionalTestEnum.Equal, NoOverflowLabel);
                    ThrowNotImplementedException("Conv_Ovf_I_Un throws an overflow exception, which is not implemented!");
                }
                XS.Label(NoOverflowLabel);
                XS.Push(XSRegisters.EAX);
                break;
            }

            default:
                ThrowNotImplementedException("Conv_Ovf_I_Un not implemented for this size!");
                break;
            }
        }
Beispiel #16
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);
        }
Beispiel #17
0
        public static void DoExecute(uint xSourceSize, bool SourceIsSigned, Assembler assembler, _MethodInfo aMethod, ILOpCode aOpCode)
        {
            var xBaseLabel    = GetLabel(aMethod, aOpCode) + ".";
            var xSuccessLabel = xBaseLabel + "Success";

            switch (xSourceSize)
            {
            case 1:
            case 2:
            case 4:
                XS.Pop(EAX);
                XS.SignExtendAX(RegisterSize.Int32);
                XS.Push(EDX);
                XS.Push(EAX);
                break;

            case 8:
                if (SourceIsSigned)
                {
                    XS.Set(EAX, ESP, sourceIsIndirect: true);
                    XS.And(EAX, 0b1000000000000000000000000000);
                    XS.Compare(EAX, 0);
                    XS.Jump(XSharp.Assembler.x86.ConditionalTestEnum.Equal, xSuccessLabel);
                    XS.Pop(EAX); // remove long from stack
                    XS.Pop(EAX);
                    Call.DoExecute(assembler, aMethod, ExceptionHelperRefs.ThrowOverflowExceptionRef, aOpCode, xSuccessLabel, false);
                    XS.Label(xSuccessLabel);
                }
                else
                {
                    XS.Noop();
                }
                break;

            default:
                throw new NotImplementedException();
            }
        }
Beispiel #18
0
 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");
     }
 }
Beispiel #19
0
        public override void Execute(MethodInfo aMethod, ILOpCode aOpCode)
        {
            var xStackItem_ShiftAmount = aOpCode.StackPopTypes[0];
            var xStackItem_Value       = aOpCode.StackPopTypes[1];
            var xStackItem_Value_Size  = SizeOfType(xStackItem_Value);

            XS.Pop(XSRegisters.ECX); // shift amount
#if DOTNETCOMPATIBLE
            if (xStackItem_Value.Size == 4)
#else
            if (xStackItem_Value_Size <= 4)
#endif
            {
                XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
            }
#if DOTNETCOMPATIBLE
            else if (xStackItem_Value_Size == 8)
#else
            else if (xStackItem_Value_Size <= 8)
#endif
            {
                string BaseLabel      = GetLabel(aMethod, aOpCode) + ".";
                string HighPartIsZero = BaseLabel + "HighPartIsZero";
                string End_Shr        = BaseLabel + "End_Shr";

                // [ESP] is low part
                // [ESP + 4] is high part

                // move high part in EAX
                XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);

                XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8);
                XS.Jump(CPU.ConditionalTestEnum.AboveOrEqual, HighPartIsZero);

                // shift lower part
                XS.ShiftRightDouble(ESP, EAX, CL, destinationIsIndirect: true);
                // shift higher part
                XS.ShiftRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.Jump(End_Shr);

                XS.Label(HighPartIsZero);
                // remove bits >= 32, so that CL max value could be only 31
                XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8);

                // shift high part and move it in low part
                XS.ShiftRight(XSRegisters.EAX, XSRegisters.CL);
                XS.Set(ESP, EAX, destinationIsIndirect: true);
                // replace unknown high part with a zero
                new CPUx86.Mov {
                    DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 0
                };

                XS.Label(End_Shr);
            }
            else
            {
                throw new NotSupportedException("A size bigger 8 not supported at Shr!");
            }

            /*string xLabelName = AppAssembler.TmpPosLabel(aMethod, aOpCode);
             * var xStackItem_ShiftAmount = Assembler.Stack.Pop();
             * var xStackItem_Value = Assembler.Stack.Peek();
             * if( xStackItem_Value.Size <= 4 )
             * {
             *  XS.Pop(XSRegisters.ECX); // shift amount
             *  XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true);
             * }
             * else if( xStackItem_Value.Size <= 8 )
             * {
             *                  XS.Pop(XSRegisters.ECX); // shift amount
             *                  // [ESP] is high part
             *                  // [ESP + 4] is low part
             *                  XS.Mov(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);
             *                  // shift low part
             *                  new CPUx86.ShiftRightDouble { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX, ArgumentReg = CPUx86.Registers.CL };
             *                  // shift high part
             *                  XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
             * }*/

#if false
            XS.Pop(XSRegisters.ECX); // shift amount
            string xBaseLabel             = GetLabel(aMethod, aOpCode) + ".";
            var    xStackItem_ShiftAmount = aOpCode.StackPopTypes[0];
            var    xStackItem_Value       = aOpCode.StackPopTypes[1];

            if (TypeIsFloat(xStackItem_Value))
            {
                throw new NotImplementedException("Floats not yet supported!");
            }
            var xStackItem_Value_Size = SizeOfType(xStackItem_Value);
            if (xStackItem_Value_Size <= 4)
            {
                XS.Pop(XSRegisters.EAX); // shift amount
                XS.Pop(XSRegisters.EBX); // value
                XS.Set(XSRegisters.CL, XSRegisters.AL);
                XS.ShiftRight(XSRegisters.EBX, CL);
                XS.Push(XSRegisters.EBX);
                return;
            }
            if (xStackItem_Value_Size <= 8)
            {
                string BaseLabel      = GetLabel(aMethod, aOpCode) + ".";
                string HighPartIsZero = BaseLabel + "HighPartIsZero";
                string End_Shr        = BaseLabel + "End_Shr";

                // [ESP] is low part
                // [ESP + 4] is high part

                // move high part in EAX
                XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);

                XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8);
                XS.Jump(CPU.ConditionalTestEnum.AboveOrEqual, HighPartIsZero);

                // shift lower part
                XS.ShiftRightDouble(ESP, EAX, CL, destinationIsIndirect: true);
                // shift higher part
                XS.ShiftRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.Jump(End_Shr);

                XS.Label(HighPartIsZero);
                // remove bits >= 32, so that CL max value could be only 31
                XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8);

                // shift high part and move it in low part
                XS.ShiftRight(XSRegisters.EAX, XSRegisters.CL);
                XS.Set(ESP, EAX, destinationIsIndirect: true);
                // replace unknown high part with a zero, if <= 32
                new CPUx86.Mov {
                    DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 0
                };

                XS.Label(End_Shr);

#if false
                XS.Pop(XSRegisters.EDX);
                XS.Set(XSRegisters.EAX, 0);
                XS.Label(xBaseLabel + "__StartLoop");
                XS.Compare(XSRegisters.EDX, XSRegisters.EAX);
                XS.Jump(CPUx86.ConditionalTestEnum.Equal, xBaseLabel + "__EndLoop");
                XS.Set(EBX, ESP, sourceIsIndirect: true);
                XS.Set(XSRegisters.CL, 1);
                XS.ShiftRight(XSRegisters.EBX, CL);
                XS.Set(ESP, EBX, destinationIsIndirect: true);
                XS.Set(XSRegisters.CL, 1);
                XS.RotateThroughCarryRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.Add(XSRegisters.EAX, 1);
                new CPUx86.Jump {
                    DestinationLabel = xBaseLabel + "__StartLoop"
                };


                XS.Label(xBaseLabel + "__EndLoop");
#endif
                return;
#endif
        }
    }
        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!");
            }
        }
Beispiel #21
0
        public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
        {
            var xStackItem_ShiftAmount = aOpCode.StackPopTypes[0];
            var xStackItem_Value       = aOpCode.StackPopTypes[1];
            var xStackItem_Value_Size  = SizeOfType(xStackItem_Value);

            XS.Pop(XSRegisters.ECX); // shift amount
#if DOTNETCOMPATIBLE
            if (xStackItem_Value.Size == 4)
#else
            if (xStackItem_Value_Size <= 4)
#endif
            {
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                //XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
                XS.ShiftRightArithmetic(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
            }
#if DOTNETCOMPATIBLE
            else if (xStackItem_Value_Size == 8)
#else
            else if (xStackItem_Value_Size <= 8)
#endif
            {
                string BaseLabel      = GetLabel(aMethod, aOpCode) + ".";
                string HighPartIsZero = BaseLabel + "HighPartIsZero";
                string End_Shr        = BaseLabel + "End_Shr";

                // [ESP] is low part
                // [ESP + 4] is high part

                // move high part in EAX
                XS.Set(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);

                XS.Compare(XSRegisters.CL, 32, size: RegisterSize.Byte8);
                XS.Jump(CPU.ConditionalTestEnum.AboveOrEqual, HighPartIsZero);

                // shift lower part
                XS.ShiftRightDouble(ESP, EAX, CL, destinationIsIndirect: true);
                // shift higher part
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                //XS.ShiftRight(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.ShiftRightArithmetic(ESP, CL, destinationDisplacement: 4, size: RegisterSize.Int32);
                XS.Jump(End_Shr);

                XS.Label(HighPartIsZero);

                // remove bits >= 32, so that CL max value could be only 31
                XS.And(XSRegisters.CL, 0x1f, size: RegisterSize.Byte8);

                // shift high part and move it in low part
                // To retain the sign bit we must use ShiftRightArithmetic and not ShiftRight!
                XS.ShiftRightArithmetic(XSRegisters.EAX, XSRegisters.CL);
                XS.Set(ESP, EAX, destinationIsIndirect: true);
                // replace unknown high part with a zero
                XS.Set(ESP, 0, destinationIsIndirect: true, destinationDisplacement: 4);
                //new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ESP, DestinationIsIndirect = true, DestinationDisplacement = 4, SourceValue = 0};

                XS.Label(End_Shr);
            }
            else
            {
                throw new NotSupportedException("A size bigger 8 not supported at Shr!");
            }

            /*string xLabelName = AppAssembler.TmpPosLabel(aMethod, aOpCode);
             * var xStackItem_ShiftAmount = Assembler.Stack.Pop();
             * var xStackItem_Value = Assembler.Stack.Peek();
             * if( xStackItem_Value.Size <= 4 )
             * {
             *  XS.Pop(XSRegisters.ECX); // shift amount
             *  XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true);
             * }
             * else if( xStackItem_Value.Size <= 8 )
             * {
             *                  XS.Pop(XSRegisters.ECX); // shift amount
             *                  // [ESP] is high part
             *                  // [ESP + 4] is low part
             *                  XS.Mov(XSRegisters.EAX, XSRegisters.ESP, sourceDisplacement: 4);
             *                  // shift low part
             *                  new CPUx86.ShiftRightDouble { DestinationReg = CPUx86.Registers.ESP, DestinationIsIndirect = true, SourceReg = CPUx86.Registers.EAX, ArgumentReg = CPUx86.Registers.CL };
             *                  // shift high part
             *                  XS.ShiftRight(XSRegisters.ESP, XSRegisters.CL, destinationIsIndirect: true, size: RegisterSize.Int32);
             * }*/
        }
Beispiel #22
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) ?? 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);
            }
        }
Beispiel #23
0
        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)
            {
                // Using SSE registers (that do NOT branch!) This is needed only for long now
#if false
                XS.Set(XSRegisters.ESI, 1);
                // esi = 1
                XS.Xor(XSRegisters.EDI, XSRegisters.EDI);
                // edi = 0
#endif
                if (xStackItemIsFloat)
                {
                    // Please note that SSE supports double operations only from version 2
                    XS.SSE2.MoveSD(XMM0, ESP, sourceIsIndirect: true);
                    // Increment ESP to get the value of the next double
                    XS.Add(ESP, 8);
                    XS.SSE2.MoveSD(XMM1, ESP, sourceIsIndirect: true);
                    XS.SSE2.CompareSD(XMM1, XMM0, comparision: LessThan);
                    XS.MoveD(EBX, XMM1);
                    XS.And(EBX, 1);
                    // We need to move the stack pointer of 4 Byte to "eat" the second double that is yet in the stack or we get a corrupted stack!
                    XS.Add(ESP, 4);
                    XS.Set(ESP, EBX, destinationIsIndirect: true);
                }
                else
                {
                    XS.Set(ESI, 1);
                    // esi = 1
                    XS.Xor(EDI, EDI);
                    // edi = 0
                    XS.Pop(EAX);
                    XS.Pop(EDX);
                    //value2: EDX:EAX
                    XS.Pop(EBX);
                    XS.Pop(ECX);
                    //value1: ECX:EBX
                    XS.Sub(EBX, EAX);
                    XS.SubWithCarry(ECX, EDX);
                    //result = value1 - value2
                    new ConditionalMove {
                        Condition = ConditionalTestEnum.Below, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI
                    };
                    XS.Push(XSRegisters.EDI);
                }
            }
            else
            {
                if (xStackItemIsFloat)
                {
                    XS.Comment("TEST TODO");
                    XS.SSE.MoveSS(XMM0, ESP, sourceIsIndirect: true);
                    XS.Add(ESP, 4);
                    XS.SSE.MoveSS(XMM1, ESP, sourceIsIndirect: true);
                    XS.SSE.CompareSS(XMM1, XMM0, comparision: LessThan);
                    XS.MoveD(EBX, XMM1);
                    XS.And(ESP, 1, destinationIsIndirect: true);
                    XS.Set(ESP, EBX, destinationIsIndirect: true);
                }
                else
                {
                    XS.Pop(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);
                }
            }
        }
Beispiel #24
0
        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 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();
        }
Beispiel #26
0
        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_Un: StackSizes>8 not supported", CurInstructionLabel, mMethodInfo, mCurrentOffset, NextInstructionLabel );
                throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Cgt_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 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.Above, LabelTrue);
                    XS.Jump(ConditionalTestEnum.Below, LabelFalse);
                    XS.Compare(XSRegisters.EBX, XSRegisters.EAX);
                    XS.Label(LabelTrue);
                    new ConditionalMove {
                        Condition = ConditionalTestEnum.Above, DestinationReg = RegistersEnum.EDI, SourceReg = RegistersEnum.ESI
                    };
                    XS.Label(LabelFalse);
                }
                XS.Push(XSRegisters.EDI);

                /*
                 * XS.Jump(ConditionalTestEnum.Above, LabelTrue);
                 * XS.Label(LabelFalse);
                 * XS.Push(0);
                 * new CPUx86.Jump { DestinationLabel = GetLabel(aMethod, aOpCode.NextPosition) };
                 * 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.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);
                }
            }
        }
Beispiel #27
0
        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 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 ");
                    }
                }
            }
            //}
        }
Beispiel #29
0
        public static void Assemble(Assembler aAssembler, uint aElementSize, _MethodInfo aMethod, ILOpCode aOpCode, bool debugEnabled)
        {
            DoNullReferenceCheck(aAssembler, debugEnabled, (int)(8 + Align(aElementSize, 4)));

            uint xStackSize = aElementSize;

            if (xStackSize % 4 != 0)
            {
                xStackSize += 4 - xStackSize % 4;
            }
            // Do index out of range check
            var xBaseLabel = GetLabel(aMethod, aOpCode);
            var xNoIndexOutOfRangeExeptionLabel = xBaseLabel + "_NoIndexOutOfRangeException";
            var xIndexOutOfRangeExeptionLabel   = xBaseLabel + "_IndexOutOfRangeException";

            XS.Push(ESP, displacement: 4 + 4 + (int)xStackSize); // _, array, 0, index, value * n  => _, array, 0, index, value * n, array
            XS.Push(0);                                          // _, array, 0, index, value * n, array => _, array, 0, index, value * n, array, 0
            Ldlen.Assemble(aAssembler, debugEnabled, false);     // _, array, 0, index, value * n, array, 0 -> _, array, 0, index, value * n, length
            XS.Pop(EAX);                                         //Length of array _, array, 0, index, value * n, length -> _, array, 0, index, value * n
            XS.Compare(EAX, ESP, sourceIsIndirect: true, sourceDisplacement: (int)xStackSize);
            XS.Jump(CPUx86.ConditionalTestEnum.LessThanOrEqualTo, xIndexOutOfRangeExeptionLabel);

            XS.Compare(EAX, 0);
            XS.Jump(CPUx86.ConditionalTestEnum.GreaterThanOrEqualTo, xNoIndexOutOfRangeExeptionLabel);

            XS.Label(xIndexOutOfRangeExeptionLabel);
            Call.DoExecute(aAssembler, aMethod, ExceptionHelperRefs.ThrowIndexOutOfRangeException, aOpCode, xNoIndexOutOfRangeExeptionLabel, debugEnabled);

            XS.Label(xNoIndexOutOfRangeExeptionLabel);

            // calculate element offset into array memory (including header)
            XS.Set(EAX, ESP, sourceDisplacement: (int)xStackSize); // the index
            XS.Set(EDX, aElementSize);
            XS.Multiply(EDX);
            XS.Add(EAX, ObjectUtils.FieldDataOffset + 4);

            XS.Set(EDX, ESP, sourceDisplacement: (int)xStackSize + 8); // the array
            XS.Add(EDX, EAX);
            XS.Push(EDX);

            XS.Pop(ECX);
            for (int i = (int)(aElementSize / 4) - 1; i >= 0; i -= 1)
            {
                new Comment(aAssembler, "Start 1 dword");
                XS.Pop(EBX);
                XS.Set(ECX, EBX, destinationIsIndirect: true);
                XS.Add(ECX, 4);
            }
            switch (aElementSize % 4)
            {
            case 1:
            {
                new Comment(aAssembler, "Start 1 byte");
                XS.Pop(EBX);
                XS.Set(ECX, BL, destinationIsIndirect: true);
                break;
            }

            case 2:
            {
                new Comment(aAssembler, "Start 1 word");
                XS.Pop(EBX);
                XS.Set(ECX, BX, destinationIsIndirect: true);
                break;
            }

            case 0:
            {
                break;
            }

            default:
                throw new Exception("Remainder size " + (aElementSize % 4) + " not supported!");
            }
            XS.Add(ESP, 12);
        }
        /* 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);
        }