Cosmos/source/Cosmos.IL2CPU/IL/Stfld.cs
José Pedro eff94b0f11 Improved code organization.
Added method tests.
Implemented Rethrow opcode.
2017-01-27 17:01:51 +00:00

111 lines
4.1 KiB
C#

using System;
using System.Linq;
using XSharp.Compiler;
using static XSharp.Compiler.XSRegisters;
using SysReflection = System.Reflection;
namespace Cosmos.IL2CPU.X86.IL {
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Stfld)]
public class Stfld : ILOp {
public Stfld(Cosmos.Assembler.Assembler aAsmblr) : base(aAsmblr) {
}
public override void Execute(MethodInfo aMethod, ILOpCode aOpCode) {
var xOpCode = (ILOpCodes.OpField)aOpCode;
var xField = xOpCode.Value;
XS.Comment("Operand type: " + aOpCode.StackPopTypes[1].ToString());
DoExecute(Assembler, aMethod, xField, DebugEnabled, TypeIsReferenceType(aOpCode.StackPopTypes[1]));
}
public static void DoExecute(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, string aFieldId, Type aDeclaringObject, bool aNeedsGC, bool debugEnabled) {
var xType = aMethod.MethodBase.DeclaringType;
var xFields = GetFieldsInfo(aDeclaringObject, false);
var xFieldInfo = (from item in xFields
where item.Id == aFieldId
select item).Single();
var xActualOffset = Ldfld.GetFieldOffset(aDeclaringObject, aFieldId);
var xSize = xFieldInfo.Size;
XS.Comment("Field: " + xFieldInfo.Id);
XS.Comment("Type: " + xFieldInfo.FieldType.ToString());
XS.Comment("Size: " + xFieldInfo.Size);
XS.Comment("Offset: " + xActualOffset + " (includes object header)");
uint xRoundedSize = Align(xSize, 4);
if (aNeedsGC)
{
DoNullReferenceCheck(aAssembler, debugEnabled, (int)xRoundedSize + 4);
}
else
{
DoNullReferenceCheck(aAssembler, debugEnabled, (int)xRoundedSize);
}
XS.Comment("After Nullref check");
if (aNeedsGC)
{
XS.Set(ECX, ESP, sourceDisplacement: (int)xRoundedSize + 4);
}
else
{
XS.Set(ECX, ESP, sourceDisplacement: (int)xRoundedSize);
}
if (xActualOffset != 0)
{
XS.Add(ECX, (uint)(xActualOffset));
}
//TODO: Can't we use an x86 op to do a byte copy instead and be faster?
for (int i = 0; i < (xSize / 4); i++) {
XS.Pop(EAX);
XS.Set(ECX, EAX, destinationDisplacement: (int)((i * 4)));
}
switch (xSize % 4) {
case 0: {
break;
}
case 1: {
XS.Pop(EAX);
XS.Set(ECX, AL, destinationDisplacement: (int)((xSize / 4) * 4));
//new CPUx86.Mov { DestinationReg = ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = AL };
break;
}
case 2: {
XS.Pop(EAX);
XS.Set(ECX, AX, destinationDisplacement: (int)((xSize / 4) * 4));
//new CPUx86.Mov { DestinationReg = ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = AX };
break;
}
case 3: {
XS.Pop(EAX);
// move 2 lower bytes
XS.Set(ECX, AX, destinationDisplacement: (int)((xSize / 4) * 4));
//new CPUx86.Mov { DestinationReg = ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = AX };
// shift third byte to lowest
XS.ShiftRight(EAX, 16);
XS.Set(ECX, AL, destinationDisplacement: (int)((xSize / 4) * 4 + 2));
//new CPUx86.Mov { DestinationReg = ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4) + 2, SourceReg = AL };
break;
}
default:
throw new Exception("Remainder size " + (xSize % 4) + " not supported!");
}
XS.Add(ESP, 4);
if (aNeedsGC)
{
XS.Add(ESP, 4);
}
}
public static void DoExecute(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, SysReflection.FieldInfo aField, bool debugEnabled, bool aNeedsGC)
{
DoExecute(aAssembler, aMethod, aField.GetFullName(), aField.DeclaringType, aNeedsGC, debugEnabled);
}
}
}