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; new Comment("Field: " + xFieldInfo.Id); new Comment("Type: " + xFieldInfo.FieldType.ToString()); new Comment("Size: " + xFieldInfo.Size); new Comment("Offset: " + xActualOffset + " (includes object header)"); uint xRoundedSize = Align(xSize, 4); DoNullReferenceCheck(aAssembler, debugEnabled, xRoundedSize); new Comment("After Nullref check"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.ESP, SourceIsIndirect = true, SourceDisplacement = (int)xRoundedSize }; // ECX contains the object pointer now if (aNeedsGC) { // for reference types (or boxed types), ECX actually contains the handle now, so we need to convert it to a memory address new Comment("Dereference memory handle now"); new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, SourceReg = CPUx86.Registers.ECX, SourceIsIndirect = true }; } if (debugEnabled) { new CPUx86.Push { DestinationReg = CPUx86.RegistersEnum.ECX }; new CPUx86.Pop { DestinationReg = CPUx86.RegistersEnum.ECX }; } new CPUx86.Add { DestinationReg = CPUx86.Registers.ECX, SourceValue = (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++) { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((i * 4)), SourceReg = CPUx86.Registers.EAX }; } switch (xSize % 4) { case 1: { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.Registers.AL }; break; } case 2: { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.Registers.AX }; break; } case 3: { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; // move 2 lower bytes new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.Registers.AX }; // shift third byte to lowest new CPUx86.ShiftRight { DestinationReg = CPUx86.Registers.EAX, SourceValue = 16 }; new CPUx86.Mov { DestinationReg = CPUx86.Registers.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4) + 2, SourceReg = CPUx86.Registers.AL }; break; } case 0: { break; } default: throw new Exception("Remainder size " + (xSize % 4) + " not supported!"); } #if !SKIP_GC_CODE if (aNeedsGC) { new CPUx86.Push { DestinationReg = CPUx86.Registers.ECX }; new CPUx86.Push { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Call { DestinationLabel = LabelName.Get(GCImplementationRefs.DecRefCountRef) }; new CPUx86.Call { DestinationLabel = LabelName.Get(GCImplementationRefs.DecRefCountRef) }; } #endif new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = 4 }; }
public static void DoExecute(Cosmos.Assembler.Assembler aAssembler, MethodInfo aMethod, string aFieldId, Type aDeclaringObject, bool aNeedsGC, bool debugEnabled) { var xType = aMethod.MethodBase.DeclaringType; var xFields = GetFieldsInfo(aDeclaringObject, false); var xFieldInfo = (from item in xFields where item.Id == aFieldId select item).Single(); var xActualOffset = Ldfld.GetFieldOffset(aDeclaringObject, aFieldId); var xSize = xFieldInfo.Size; XS.Comment("Field: " + xFieldInfo.Id); XS.Comment("Type: " + xFieldInfo.FieldType.ToString()); XS.Comment("Size: " + xFieldInfo.Size); XS.Comment("Offset: " + xActualOffset + " (includes object header)"); uint xRoundedSize = Align(xSize, 4); if (aNeedsGC) { DoNullReferenceCheck(aAssembler, debugEnabled, (int)xRoundedSize + 4); } else { DoNullReferenceCheck(aAssembler, debugEnabled, (int)xRoundedSize); } XS.Comment("After Nullref check"); if (aNeedsGC) { XS.Set(XSRegisters.ECX, XSRegisters.ESP, sourceDisplacement: (int)xRoundedSize + 4); } else { XS.Set(XSRegisters.ECX, XSRegisters.ESP, sourceDisplacement: (int)xRoundedSize); } if (xActualOffset != 0) { XS.Add(XSRegisters.ECX, (uint)(xActualOffset)); } //TODO: Can't we use an x86 op to do a byte copy instead and be faster? for (int i = 0; i < (xSize / 4); i++) { XS.Pop(XSRegisters.EAX); XS.Set(XSRegisters.ECX, XSRegisters.EAX, destinationDisplacement: (int)((i * 4))); } switch (xSize % 4) { case 1: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.RegistersEnum.AL }; break; } case 2: { XS.Pop(XSRegisters.EAX); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.RegistersEnum.AX }; break; } case 3: { XS.Pop(XSRegisters.EAX); // move 2 lower bytes new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4), SourceReg = CPUx86.RegistersEnum.AX }; // shift third byte to lowest XS.ShiftRight(XSRegisters.EAX, 16); new CPUx86.Mov { DestinationReg = CPUx86.RegistersEnum.ECX, DestinationIsIndirect = true, DestinationDisplacement = (int)((xSize / 4) * 4) + 2, SourceReg = CPUx86.RegistersEnum.AL }; break; } case 0: { break; } default: throw new Exception("Remainder size " + (xSize % 4) + " not supported!"); } XS.Add(XSRegisters.ESP, 4); if (aNeedsGC) { XS.Add(XSRegisters.ESP, 4); } }