/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point or /// if the value is not 4 or 8 bytes in size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo objTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.DeclaringType); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); Types.FieldInfo theFieldInfo = conversionState.TheILLibrary.GetFieldInfo(objTypeInfo, theField.Name); int offset = theFieldInfo.OffsetInBytes; int stackSize = fieldTypeInfo.SizeOnStackInBytes; int memSize = fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : stackSize; StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); if (value.isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing fields of type float not supported yet!"); } //Get object pointer conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = stackSize.ToString() + "($sp)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); //Pop and mov value for (int i = 0; i < memSize; i += 2) { if (memSize - i == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Halfword, Dest = "$t0" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "$t0", Dest = (offset + i).ToString() + "($t2)" }); GlobalMethods.StoreData(conversionState, theOp, "$t2", "$t0", (offset + i), 1); } else { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Halfword, Dest = "$t0" }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = (offset + i).ToString() + "($t2)" }); GlobalMethods.StoreData(conversionState, theOp, "$t2", "$t0", (offset + i), 2); } } // Rounds down || Pop object pointer conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = ((((stackSize - memSize) / 2) * 2) + 4).ToString(), Dest = "$sp" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); Type elementType = null; bool pushValue = true; int sizeToPush = 4; bool signExtend = true; bool isFloat = false; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldelem: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelema: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); pushValue = false; } break; case OpCodes.Ldelem_R4: case OpCodes.Ldelem_R8: //TODO - Add more LdElem op variants support throw new NotSupportedException("Ldelem op variant not supported yet!"); case OpCodes.Ldelem_I1: sizeToPush = 1; elementType = typeof(sbyte); break; case OpCodes.Ldelem_I2: sizeToPush = 2; elementType = typeof(Int16); break; case OpCodes.Ldelem_U1: sizeToPush = 1; signExtend = false; elementType = typeof(byte); break; case OpCodes.Ldelem_U2: sizeToPush = 2; signExtend = false; elementType = typeof(UInt16); break; case OpCodes.Ldelem_Ref: signExtend = false; elementType = null; break; case OpCodes.Ldelem_U4: signExtend = false; elementType = typeof(UInt32); break; case OpCodes.Ldelem_I4: elementType = typeof(Int32); break; case OpCodes.Ldelem_I8: sizeToPush = 8; elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("LdElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Push the element onto the stack //Stack setup upon entering this op: (top-most downwards) // 0. Index of element to get as Int32 (word) // 1. Array object reference as address (word) Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); // 1. Check array reference is not null // 1.1. Move array ref into $t0 // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 1.1. Move array ref into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", BranchType = ASMOps.BranchOp.BranchNotZero, DestILPosition = currOpPosition, Extension = "Continue1", UnsignedTest = true }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue1" }); // 2. Check array element type is correct // 2.1. Move element type ref into $t0 // 2.2. Move element type ref from array object into $t1 // 2.3. Compare $t0 to $t1 // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into $t0 int elemTypeOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "elemType").OffsetInBytes; // 3. Check index to get is > -1 and < array length // 3.1. Move index into $t0 // 3.2. Move array length into $t1 // 3.2. Compare $t0 to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare $t0 to $t1 // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.1. Move index into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 3.2. Move array length into $t2 // - Calculate the offset of the field from the start of the array object int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; // - Move array ref into $t1 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($sp)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // - Move length value (offset($t1)) into $t1 //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = lengthOffset.ToString() + "($t1)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t1", "$t1", lengthOffset, 4); // 3.2. Compare $t0 to 0 // 3.3. Jump if greater than to next test condition (3.5) conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "$zero", BranchType = ASMOps.BranchOp.BranchGreaterThanEqual, DestILPosition = currOpPosition, Extension = "Continue3_1", UnsignedTest = false }); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.5. Compare $t0 to $t1 // 3.6. Jump if less than to continue execution further down conversionState.Append(new ASMOps.Branch() { Src1 = "$t0", Src2 = "$t1", BranchType = ASMOps.BranchOp.BranchLessThan, DestILPosition = currOpPosition, Extension = "Continue3_2", UnsignedTest = false }); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_2" }); // 4. Calculate address of element // 4.1. Pop index into $t1 // 4.2. Pop array ref into $t0 // 4.3. Move element type ref (from array ref) into $t0 // 4.4. Move IsValueType (from element ref type) into $t2 // 4.5. If IsValueType, continue to 4.6., else goto 4.8. // 4.6. Move Size (from element type ref) into $t0 // 4.7. Skip over 4.8. // 4.8. Move StackSize (from element type ref) into $t0 // 4.9. Mulitply $t0 by $t1 (index by element size) // 4.10. Move array ref into $t1 // 4.11. Add enough to go past Kernel.FOS_System.Array fields // 4.12. Add $t0 and $t1 (array ref + fields + (index * element size)) // 4.1. Pop index into $t1 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); // 4.2. Move array ref into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 4.3. Move element type ref (from array ref) into $t0 //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = elemTypeOffset.ToString() + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", elemTypeOffset, 4); // 4.4. Move IsValueType (from element ref type) into $t2 int isValueTypeOffset = conversionState.GetTypeFieldOffset("IsValueType"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = isValueTypeOffset.ToString() + "($t0)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t2", isValueTypeOffset, 1); // 4.5. If IsValueType, continue to 4.6., else goto 4.8. conversionState.Append(new ASMOps.Branch() { Src1 = "$t2", BranchType = ASMOps.BranchOp.BranchZero, DestILPosition = currOpPosition, Extension = "Continue4_1", UnsignedTest = true }); // 4.6. Move Size (from element type ref) into $t0 int sizeOffset = conversionState.GetTypeFieldOffset("Size"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = sizeOffset.ToString() + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", sizeOffset, 4); // 4.7. Skip over 4.8. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "Continue4_2" }); // 4.8. Move StackSize (from element type ref) into $t0 conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_1" }); int stackSizeOffset = conversionState.GetTypeFieldOffset("StackSize"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = stackSizeOffset + "($t0)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", stackSizeOffset, 4); // 4.9. Mulitply $t0 by $t1 (index by element size) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_2" }); conversionState.Append(new ASMOps.Mul() { Src1 = "$t1", Src2 = "$t0", Signed = true }); // 4.10. Pop array ref into $t1 conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); // 4.11. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { Types.FieldInfo highestOffsetFieldInfo = arrayTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderByDescending(x => x.OffsetInBytes).First(); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(highestOffsetFieldInfo.UnderlyingInfo.FieldType); allFieldsOffset = highestOffsetFieldInfo.OffsetInBytes + (fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : fieldTypeInfo.SizeOnStackInBytes); } #endregion conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = allFieldsOffset.ToString(), Dest = "$t1" }); // 4.12. Add $t0 and $t1 (array ref + fields + (index * element size)) conversionState.Append(new ASMOps.Add() { Src1 = "$t1", Src2 = "$t0", Dest = "$t0" }); // 5. Push the element onto the stack // 5.1. Push value at ($t0) (except for LdElemA op in which case just push address) if (pushValue) { switch (sizeToPush) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 1, signExtend); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.ImmediateToReg }); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 2, signExtend); break; case 4: //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 4); break; case 8: //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($t0)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t1", 0, 4); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "4($t0)", Dest = "$t2", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t2", 4, 4); break; } if (sizeToPush == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t2" }); } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t1" }); } else { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); } // 5.2. Pop index and array ref from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); // 5.3. Push element onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = sizeToPush > 4 ? 8 : 4, isFloat = isFloat, isNewGCObject = false, isGCManaged = pushValue ? (elementType == null || conversionState.TheILLibrary.GetTypeInfo(elementType).IsGCManaged) : false }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.FieldInfo theFieldInfo = conversionState.GetFieldInfo(theField.DeclaringType, theField.Name); Types.TypeInfo theFieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theFieldInfo.FieldType); string fieldId = theFieldInfo.ID; int size = /*theFieldTypeInfo.IsValueType ? theFieldTypeInfo.SizeOnHeapInBytes : */ theFieldTypeInfo.SizeOnStackInBytes; bool isFloat = Utilities.IsFloat(theField.FieldType); conversionState.AddExternalLabel(fieldId); StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing static fields of type float not supported yet!"); } conversionState.Append(new ASMOps.La() { Dest = "$t4", Label = fieldId }); if (size == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "$t1", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 2) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "$t1", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else if (size == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "0($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t0", Dest = "4($t4)", MoveType = ASMOps.Mov.MoveTypes.SrcRegToDestMemory }); } else { throw new ArgumentOutOfRangeException("Storing static field that has stack size greater than 8 not supported!"); } if (value.sizeOnStackInBytes - size > 0) { conversionState.Append(new ASMOps.Add() { Src1 = "$sp", Src2 = (value.sizeOnStackInBytes - size).ToString(), Dest = "$sp" }); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); Type elementType = null; bool pushValue = true; int sizeToPush = 4; bool signExtend = true; bool isFloat = false; switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Ldelem: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); } break; case OpCodes.Ldelema: { signExtend = false; //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); pushValue = false; } break; case OpCodes.Ldelem_R4: case OpCodes.Ldelem_R8: //TODO - Add more LdElem op variants support throw new NotSupportedException("Ldelem op variant not supported yet!"); case OpCodes.Ldelem_I1: sizeToPush = 1; elementType = typeof(sbyte); break; case OpCodes.Ldelem_I2: sizeToPush = 2; elementType = typeof(Int16); break; case OpCodes.Ldelem_U1: sizeToPush = 1; signExtend = false; elementType = typeof(byte); break; case OpCodes.Ldelem_U2: sizeToPush = 2; signExtend = false; elementType = typeof(UInt16); break; case OpCodes.Ldelem_Ref: signExtend = false; elementType = null; break; case OpCodes.Ldelem_U4: signExtend = false; elementType = typeof(UInt32); break; case OpCodes.Ldelem_I4: elementType = typeof(Int32); break; case OpCodes.Ldelem_I8: sizeToPush = 8; elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("LdElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Push the element onto the stack //Stack setup upon entering this op: (top-most downwards) // 0. Index of element to get as Int32 (dword) // 1. Array object reference as address (dword) Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); // 1. Check array reference is not null // 1.1. Move array ref into EAX // 1.2. Compare EAX (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 1.1. Move array ref into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+4]", Dest = "EAX" }); // 1.2. Compare EAX (array ref) to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "Continue1" }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue1" }); // 2. Check array element type is correct // 2.1. Move element type ref into EAX // 2.2. Move element type ref from array object into EBX // 2.3. Compare EAX to EBX // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into EAX int elemTypeOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "elemType").OffsetInBytes; //if (elementType != null) //{ // result.AppendLine(string.Format("mov EAX, {0}", conversionState.GetTypeIdString(conversionState.GetTypeID(elementType)))); // // 2.2. Move element type ref from array object into EBX // // - Calculate the offset of the field from the start of the array object // // - Move array ref into EBX //GlobalMethods.CheckAddrFromRegister(result, conversionState, "ESP", 4); // result.AppendLine("mov EBX, [ESP+4]"); // // - Move elemType ref ([EBX+offset]) into EBX // GlobalMethods.CheckAddrFromRegister(result, conversionState, "EBX", elemTypeOffset); // result.AppendLine(string.Format("mov EBX, [EBX+{0}]", elemTypeOffset)); // // 2.3. Compare EAX to EBX // result.AppendLine("cmp EAX, EBX"); // // 2.4. If the same, jump to continue execution further down // result.AppendLine("je " + ContinueExecutionLabel2); // // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException // result.AppendLine(string.Format("call {0}", conversionState.GetMethodID(conversionState.ThrowArrayTypeMismatchExceptionMethod))); // result.AppendLine(ContinueExecutionLabel2 + ":"); //} // 3. Check index to get is > -1 and < array length // 3.1. Move index into EAX // 3.2. Move array length into EBX // 3.2. Compare EAX to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare EAX to EBX // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.1. Move index into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP]", Dest = "EAX" }); // 3.2. Move array length into ECX // - Calculate the offset of the field from the start of the array object int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; // - Move array ref into EBX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+4]", Dest = "EBX" }); // - Move length value ([EBX+offset]) into EBX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EBX+" + lengthOffset.ToString() + "]", Dest = "EBX" }); // 3.2. Compare EAX to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 3.3. Jump if greater than to next test condition (3.5) conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpGreaterThanEqual, DestILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.5. Compare EAX to EBX conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "EBX" }); // 3.6. Jump if less than to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpLessThan, DestILPosition = currOpPosition, Extension = "Continue3_2" }); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_2" }); // 4. Calculate address of element // 4.1. Pop index into EBX // 4.2. Pop array ref into EAX // 4.3. Move element type ref (from array ref) into EAX // 4.4. Move IsValueType (from element ref type) into ECX // 4.5. If IsValueType, continue to 4.6., else goto 4.8. // 4.6. Move Size (from element type ref) into EAX // 4.7. Skip over 4.8. // 4.8. Move StackSize (from element type ref) into EAX // 4.9. Mulitply EAX by EBX (index by element size) // 4.10. Move array ref into EBX // 4.11. Add enough to go past Kernel.FOS_System.Array fields // 4.12. Add EAX and EBX (array ref + fields + (index * element size)) // 4.1. Pop index into EBX conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); // 4.2. Move array ref into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP]", Dest = "EAX" }); // 4.3. Move element type ref (from array ref) into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + elemTypeOffset.ToString() + "]", Dest = "EAX" }); // 4.4. Move IsValueType (from element ref type) into ECX int isValueTypeOffset = conversionState.GetTypeFieldOffset("IsValueType"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "ECX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[EAX+" + isValueTypeOffset.ToString() + "]", Dest = "CL" }); // 4.5. If IsValueType, continue to 4.6., else goto 4.8. conversionState.Append(new ASMOps.Cmp() { Arg1 = "ECX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "Continue4_1" }); // 4.6. Move Size (from element type ref) into EAX int sizeOffset = conversionState.GetTypeFieldOffset("Size"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + sizeOffset.ToString() + "]", Dest = "EAX" }); // 4.7. Skip over 4.8. conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "Continue4_2" }); // 4.8. Move StackSize (from element type ref) into EAX conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_1" }); int stackSizeOffset = conversionState.GetTypeFieldOffset("StackSize"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + stackSizeOffset + "]", Dest = "EAX" }); // 4.9. Mulitply EAX by EBX (index by element size) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_2" }); conversionState.Append(new ASMOps.Mul() { Arg = "EBX" }); // 4.10. Pop array ref into EBX conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EBX" }); // 4.11. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { Types.FieldInfo highestOffsetFieldInfo = arrayTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderByDescending(x => x.OffsetInBytes).First(); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(highestOffsetFieldInfo.UnderlyingInfo.FieldType); allFieldsOffset = highestOffsetFieldInfo.OffsetInBytes + (fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : fieldTypeInfo.SizeOnStackInBytes); } #endregion conversionState.Append(new ASMOps.Add() { Src = allFieldsOffset.ToString(), Dest = "EBX" }); // 4.12. Add EAX and EBX (array ref + fields + (index * element size)) conversionState.Append(new ASMOps.Add() { Src = "EBX", Dest = "EAX" }); // 5. Push the element onto the stack // 5.1. Push value at [EAX] (except for LdElemA op in which case just push address) if (pushValue) { switch (sizeToPush) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EBX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[EAX]", Dest = "BL" }); if (signExtend) { throw new NotSupportedException("Sign extend byte to 4 bytes in LdElem not supported!"); } break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "0", Dest = "EBX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "[EAX]", Dest = "BX" }); if (signExtend) { conversionState.Append(new ASMOps.Cwde()); } break; case 4: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX]", Dest = "EBX" }); break; case 8: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX]", Dest = "EBX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+4]", Dest = "ECX" }); break; } if (sizeToPush == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "ECX" }); } conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EBX" }); } else { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } // 5.2. Pop index and array ref from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); // 5.3. Push element onto our stack conversionState.CurrentStackFrame.Stack.Push(new StackItem() { sizeOnStackInBytes = sizeToPush > 4 ? 8 : 4, isFloat = isFloat, isNewGCObject = false, isGCManaged = pushValue ? (elementType == null || conversionState.TheILLibrary.GetTypeInfo(elementType).IsGCManaged) : false }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { Type elementType = null; //bool pushValue = true; int sizeToPop = 4; bool isFloat = false; int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Stelem: { //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); } break; case OpCodes.Stelem_R4: case OpCodes.Stelem_R8: //TODO - Add more StElem op variants support throw new NotSupportedException("Stelem op variant not supported yet!"); case OpCodes.Stelem_I1: sizeToPop = 1; elementType = typeof(sbyte); break; case OpCodes.Stelem_I2: sizeToPop = 2; elementType = typeof(Int16); break; case OpCodes.Stelem_Ref: elementType = null; break; case OpCodes.Stelem_I4: elementType = typeof(Int32); break; case OpCodes.Stelem_I8: sizeToPop = 8; elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("StElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Pop the value from the stack into the element //Stack setup upon entering this op: (top-most downwards) // 0. Value to store (word or 2 words) // 1. Index of element to get as Int32 (word) // 2. Array object reference as address (word) Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); // 1. Check array reference is not null // 1.1. Move array ref into $t0 // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 1.1. Move array ref into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (sizeToPop == 8 ? 12 : 8).ToString() + "($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 1.2. Compare $t0 (array ref) to 0 // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchNotZero, Src1 = "$t0", DestILPosition = currOpPosition, Extension = "Continue1" }); // 1.4. Otherwise, call Exceptions.Throw1NullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue1" }); // 2. Check array element type is correct // 2.1. Move element type ref into $t0 // 2.2. Move element type ref from array object into $t1 // 2.3. Compare $t0 to $t1 // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into $t0 //if (elementType != null) //{ // result.AppendLine(string.Format("mov $t0, {0}", conversionState.GetTypeIdString(conversionState.GetTypeID(elementType)))); //} //else //{ // //Should be the same for all classes since they are (indirectly) derived from ObjectWithType // int typeOffset = conversionState.GetFieldOffset(arrayDBType, "_Type"); // // - Move value (which is a ref) into $t0 // GlobalMethods.CheckAddrFromRegister(conversionState, "$sp", 0); // result.AppendLine("mov $t0, 0($sp)"); // // - Move value type ref (from value (ref)) into $t0 // GlobalMethods.CheckAddrFromRegister(conversionState, "$t0", typeOffset); // result.AppendLine(string.Format("mov $t0, {0}($t0)", typeOffset)); //} //// 2.2. Move element type ref from array object into $t1 //// - Move array ref into $t1 //GlobalMethods.CheckAddrFromRegister(conversionState, "$sp", sizeToPop == 8 ? 12 : 8); //result.AppendLine(string.Format("mov $t1, {0}($sp)", sizeToPop == 8 ? 12 : 8)); //// - Move elemType ref (offset($t1)) into $t1 int elemTypeOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "elemType").OffsetInBytes; //GlobalMethods.CheckAddrFromRegister(conversionState, "$t1", elemTypeOffset); //result.AppendLine(string.Format("mov $t1, {0}($t1)", elemTypeOffset)); //// 2.3. Compare $t0 to $t1 //result.AppendLine("cmp $t0, $t1"); //// 2.4. If the same, jump to continue execution further down //result.AppendLine("je " + ContinueExecutionLabel2); //// 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //result.AppendLine(string.Format("call {0}", conversionState.GetMethodID(conversionState.ThrowArrayTypeMismatchExceptionMethod))); //result.AppendLine(ContinueExecutionLabel2 + ":"); // 3. Check index to get is > -1 and < array length // 3.1. Move index into $t0 // 3.2. Move array length into $t1 // 3.2. Compare $t0 to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare $t0 to $t1 // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.1. Move index into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (sizeToPop == 8 ? 8 : 4).ToString() + "($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 3.2. Move array length into $t2 // - Calculate the offset of the field from the start of the array object int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; // - Move array ref into $t1 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = (sizeToPop == 8 ? 12 : 8).ToString() + "($sp)", Dest = "$t1", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // - Move length value (offset($t1)) into $t1 //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = lengthOffset.ToString() + "($t1)", Dest = "$t1" }); GlobalMethods.LoadData(conversionState, theOp, "$t1", "$t1", lengthOffset, 4); // 3.2. Compare $t0 to 0 // 3.3. Jump if greater than to next test condition (3.5) conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchGreaterThanEqual, Src1 = "$t0", Src2 = "$zero", DestILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.5. Compare $t0 to $t1 // 3.6. Jump if less than to continue execution further down conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchLessThan, Src1 = "$t0", Src2 = "$t1", DestILPosition = currOpPosition, Extension = "Continue3_2" }); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_2" }); // 4. Calculate address of element // 4.0. Pop value into $t2:$t1 // 4.1. Pop index into $t3 // 4.2. Pop array ref into $t0 // 4.3. Move element type ref (from array ref) into $t0 // 4.4. Push $t0 // 4.5. Move IsValueType (from element ref type) into $t0 // 4.6. If IsValueType, continue to 4.6., else goto 4.9. // 4.7. Pop $t0 // 4.8. Move Size (from element type ref) into $t0 // 4.9. Skip over 4.9. and 4.10. // 4.10. Pop $t0 // 4.11. Move StackSize (from element type ref) into $t0 // 4.12. Mulitply $t0 by $t3 (index by element size) // 4.13. Move array ref into $t3 // 4.14. Add enough to go past Kernel.FOS_System.Array fields // 4.15. Add $t0 and $t1 (array ref + fields + (index * element size)) // 4.0. Pop value into $t2:$t1 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t2" }); if (sizeToPop == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t1" }); } // 4.1. Pop index into $t3 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); // 4.2. Move array ref into $t0 conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "0($sp)", Dest = "$t0", MoveType = ASMOps.Mov.MoveTypes.SrcMemoryToDestReg }); // 4.3. Move element type ref (from array ref) into $t0 //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = elemTypeOffset.ToString() + "($t0)", Dest = "$t0" }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", elemTypeOffset, 4); // 4.4. Push $t0 conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Word, Src = "$t0" }); // 4.5. Move IsValueType (from element ref type) into $t0 int isValueTypeOffset = conversionState.GetTypeFieldOffset("IsValueType"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = isValueTypeOffset.ToString() + "($t0)", Dest = "$t0" }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", isValueTypeOffset, 1); // 4.6. If IsValueType, continue to 4.7., else goto 4.9. conversionState.Append(new ASMOps.And() { Src1 = "$t0", Src2 = "1", Dest = "$t4" }); conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.BranchZero, Src1 = "$t4", DestILPosition = currOpPosition, Extension = "Continue4_1" }); // 4.7. Pop $t0 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); // 4.8. Move Size (from element type ref) into $t0 int sizeOffset = conversionState.GetTypeFieldOffset("Size"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = sizeOffset.ToString() + "($t0)", Dest = "$t0" }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", sizeOffset, 4); // 4.9. Skip over 4.9. and 4.10. conversionState.Append(new ASMOps.Branch() { BranchType = ASMOps.BranchOp.Branch, DestILPosition = currOpPosition, Extension = "Continue4_2" }); // 4.10. Pop $t0 conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_1" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t0" }); // 4.11. Move StackSize (from element type ref) into $t0 int stackSizeOffset = conversionState.GetTypeFieldOffset("StackSize"); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = stackSizeOffset.ToString() + "($t0)", Dest = "$t0" }); GlobalMethods.LoadData(conversionState, theOp, "$t0", "$t0", stackSizeOffset, 4); // 4.12. Mulitply $t0 by $t3 (index by element size) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_2" }); conversionState.Append(new ASMOps.Mul() { Src1 = "$t3", Src2 = "$t0" }); conversionState.Append(new ASMOps.Mflo() { Dest = "$t0" }); // 4.13. Pop array ref into $t3 conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "$t3" }); // 4.14. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { Types.FieldInfo highestOffsetFieldInfo = arrayTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderByDescending(x => x.OffsetInBytes).First(); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(highestOffsetFieldInfo.UnderlyingInfo.FieldType); allFieldsOffset = highestOffsetFieldInfo.OffsetInBytes + (fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : fieldTypeInfo.SizeOnStackInBytes); } #endregion conversionState.Append(new ASMOps.Add() { Src1 = "$t3", Src2 = allFieldsOffset.ToString(), Dest = "$t3" }); // 4.15. Add $t0 and $t3 (array ref + fields + (index * element size)) conversionState.Append(new ASMOps.Add() { Src1 = "$t3", Src2 = "$t0", Dest = "$t0" }); // 5. Pop the element from the stack to array // 5.1. Move value in $t1:$t2 to 0($t0) if (sizeToPop == 8) { //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t2", Dest = "0($t0)" }); GlobalMethods.StoreData(conversionState, theOp, "$t0", "$t2", 0, 4); //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t1", Dest = "4($t0)" }); GlobalMethods.StoreData(conversionState, theOp, "$t0", "$t1", 4, 4); } else if (sizeToPop == 4) { //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "$t2", Dest = "0($t0)" }); GlobalMethods.StoreData(conversionState, theOp, "$t0", "$t2", 0, 4); } else if (sizeToPop == 2) { //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Halfword, Src = "$t2", Dest = "0($t0)" }); GlobalMethods.StoreData(conversionState, theOp, "$t0", "$t2", 0, 2); } else if (sizeToPop == 1) { //conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "$t2", Dest = "0($t0)" }); GlobalMethods.StoreData(conversionState, theOp, "$t0", "$t2", 0, 1); } // 5.2. Pop index, array ref and value from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point or /// if the value is not 4 or 8 bytes in size. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.TypeInfo objTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.DeclaringType); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theField.FieldType); Types.FieldInfo theFieldInfo = conversionState.TheILLibrary.GetFieldInfo(objTypeInfo, theField.Name); int offset = theFieldInfo.OffsetInBytes; int stackSize = fieldTypeInfo.SizeOnStackInBytes; int memSize = fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : stackSize; StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); StackItem objPointer = conversionState.CurrentStackFrame.Stack.Pop(); if (value.isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing fields of type float is not supported yet!"); } //Get object pointer conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + stackSize.ToString() + "]", Dest = "ECX" }); //Pop and mov value int i = 0; for (; i < memSize; i += 2) { if (memSize - i == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "AX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[ECX+" + (offset + i).ToString() + "]" }); } else { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Word, Dest = "AX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[ECX+" + (offset + i).ToString() + "]" }); } } // + 4 to pop object pointer conversionState.Append(new ASMOps.Add() { Src = ((i % 4) + 4).ToString(), Dest = "ESP" }); }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if the value to store is floating point. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); FieldInfo theField = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveField(metadataToken); Types.FieldInfo theFieldInfo = conversionState.GetFieldInfo(theField.DeclaringType, theField.Name); Types.TypeInfo theFieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(theFieldInfo.FieldType); string fieldId = theFieldInfo.ID; int size = theFieldTypeInfo.IsValueType ? theFieldTypeInfo.SizeOnHeapInBytes : theFieldTypeInfo.SizeOnStackInBytes; bool isFloat = Utilities.IsFloat(theField.FieldType); conversionState.AddExternalLabel(fieldId); StackItem value = conversionState.CurrentStackFrame.Stack.Pop(); if (isFloat) { //SUPPORT - floats throw new NotSupportedException("Storing static fields of type float not supported yet!"); } if (size == 1) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[" + fieldId + "]" }); } else if (size == 2) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[" + fieldId + "]" }); } else if (size >= 4) { for (int i = 0; i < size; i += 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); switch (size - i) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[" + fieldId + "+" + i + "]" }); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[" + fieldId + "+" + i + "]" }); break; case 3: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "AL", Dest = "[" + fieldId + "+" + i + "]" }); conversionState.Append(new ASMOps.Shr() { Src = "16", Dest = "EAX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "AX", Dest = "[" + fieldId + "+" + (i + 1) + "]" }); break; default: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EAX", Dest = "[" + fieldId + "+" + i + "]" }); break; } } } else { throw new ArgumentOutOfRangeException("Storing static field with unsupported size! Size: " + size.ToString()); } }
/// <summary> /// See base class documentation. /// </summary> /// <param name="theOp">See base class documentation.</param> /// <param name="conversionState">See base class documentation.</param> /// <returns>See base class documentation.</returns> /// <exception cref="System.NotSupportedException"> /// Thrown if constant is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { Type elementType = null; Types.TypeInfo elemTypeInfo = null; //bool pushValue = true; int sizeOnHeap = 4; int sizeOnStack = 4; bool isFloat = false; int currOpPosition = conversionState.PositionOf(theOp); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); conversionState.AddExternalLabel(conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID); switch ((OpCodes)theOp.opCode.Value) { case OpCodes.Stelem: { //Load the metadata token used to get the type info int metadataToken = Utilities.ReadInt32(theOp.ValueBytes, 0); //Get the type info for the element type elementType = conversionState.Input.TheMethodInfo.UnderlyingInfo.Module.ResolveType(metadataToken); elemTypeInfo = conversionState.TheILLibrary.GetTypeInfo(elementType); sizeOnStack = elemTypeInfo.SizeOnStackInBytes; sizeOnHeap = elemTypeInfo.IsValueType ? elemTypeInfo.SizeOnHeapInBytes : elemTypeInfo.SizeOnStackInBytes; } break; case OpCodes.Stelem_R4: case OpCodes.Stelem_R8: //TODO - Add more StElem op variants support throw new NotSupportedException("Stelem op variant not supported yet!"); case OpCodes.Stelem_I1: sizeOnHeap = 1; elementType = typeof(sbyte); break; case OpCodes.Stelem_I2: sizeOnHeap = 2; elementType = typeof(Int16); break; case OpCodes.Stelem_Ref: elementType = null; break; case OpCodes.Stelem_I4: elementType = typeof(Int32); break; case OpCodes.Stelem_I8: sizeOnHeap = 8; sizeOnStack = 8; elementType = typeof(Int64); break; } if (isFloat) { //TODO - Support floats throw new NotSupportedException("StElem for floats not supported yet!"); } //Get element from array and push the value onto the stack // (or for LdElemA push the address of the value) //This involves: // 1. Check array reference is not null // - If it is, throw NullReferenceException // 2. Check array element type is correct // - If not, throw ArrayTypeMismatchException // 3. Check index to get is > -1 and < array length // - If not, throw IndexOutOfRangeException // 4. Calculate address of element // 5. Pop the value from the stack into the element //Stack setup upon entering this op: (top-most downwards) // 0. Value to store (dword or 2 dwords) // 1. Index of element to get as Int32 (dword) // 2. Array object reference as address (dword) Types.TypeInfo arrayTypeInfo = conversionState.GetArrayTypeInfo(); // 1. Check array reference is not null // 1.1. Move array ref into EAX // 1.2. Compare EAX (array ref) to 0 // 1.3. If not zero, jump to continue execution further down // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException // 1.1. Move array ref into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + (sizeOnStack + 4) + "]", Dest = "EAX" }); // 1.2. Compare EAX (array ref) to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 1.3. If not zero, jump to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "Continue1" }); // 1.4. Otherwise, call Exceptions.ThrowNullReferenceException conversionState.Append(new ASMOps.Call() { Target = "GetEIP" }); conversionState.AddExternalLabel("GetEIP"); conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowNullReferenceExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue1" }); // 2. Check array element type is correct // 2.1. Move element type ref into EAX // 2.2. Move element type ref from array object into EBX // 2.3. Compare EAX to EBX // 2.4. If the same, jump to continue execution further down // 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //string ContinueExecutionLabel2 = ContinueExecutionLabelBase + "2"; //// 2.1. Move element type ref into EAX //if (elementType != null) //{ // result.AppendLine(string.Format("mov EAX, {0}", conversionState.GetTypeIdString(conversionState.GetTypeID(elementType)))); //} //else //{ // //Should be the same for all classes since they are (indirectly) derived from ObjectWithType // int typeOffset = conversionState.GetFieldOffset(arrayDBType, "_Type"); // // - Move value (which is a ref) into EAX // GlobalMethods.CheckAddrFromRegister(conversionState, "ESP", 0); // result.AppendLine("mov EAX, [ESP]"); // // - Move value type ref (from value (ref)) into EAX // GlobalMethods.CheckAddrFromRegister(conversionState, "EAX", typeOffset); // result.AppendLine(string.Format("mov EAX, [EAX+{0}]", typeOffset)); //} //// 2.2. Move element type ref from array object into EBX //// - Move array ref into EBX //GlobalMethods.CheckAddrFromRegister(conversionState, "ESP", sizeToPop == 8 ? 12 : 8); //result.AppendLine(string.Format("mov EBX, [ESP+{0}]", sizeToPop == 8 ? 12 : 8)); //// - Move elemType ref ([EBX+offset]) into EBX int elemTypeOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "elemType").OffsetInBytes; //GlobalMethods.CheckAddrFromRegister(conversionState, "EBX", elemTypeOffset); //result.AppendLine(string.Format("mov EBX, [EBX+{0}]", elemTypeOffset)); //// 2.3. Compare EAX to EBX //result.AppendLine("cmp EAX, EBX"); //// 2.4. If the same, jump to continue execution further down //result.AppendLine("je " + ContinueExecutionLabel2); //// 2.5. Otherwise, call Exceptions.ThrowArrayTypeMismatchException //result.AppendLine(string.Format("call {0}", conversionState.GetMethodID(conversionState.ThrowArrayTypeMismatchExceptionMethod))); //result.AppendLine(ContinueExecutionLabel2 + ":"); // 3. Check index to get is > -1 and < array length // 3.1. Move index into EAX // 3.2. Move array length into EBX // 3.2. Compare EAX to 0 // 3.3. Jump if greater than to next test condition (3.5) // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.5. Compare EAX to EBX // 3.6. Jump if less than to continue execution further down // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException // 3.1. Move index into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + sizeOnStack + "]", Dest = "EAX" }); // 3.2. Move array length into ECX // - Calculate the offset of the field from the start of the array object int lengthOffset = conversionState.TheILLibrary.GetFieldInfo(arrayTypeInfo, "length").OffsetInBytes; // - Move array ref into EBX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + (sizeOnStack + 4) + "]", Dest = "EBX" }); // - Move length value ([EBX+offset]) into EBX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EBX+" + lengthOffset.ToString() + "]", Dest = "EBX" }); // 3.2. Compare EAX to 0 conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); // 3.3. Jump if greater than to next test condition (3.5) conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpGreaterThanEqual, DestILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.4. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_1" }); // 3.5. Compare EAX to EBX conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "EBX" }); // 3.6. Jump if less than to continue execution further down conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpLessThan, DestILPosition = currOpPosition, Extension = "Continue3_2" }); // 3.7. Otherwise, call Exceptions.ThrowIndexOutOfRangeException conversionState.Append(new ASMOps.Call() { Target = conversionState.GetThrowIndexOutOfRangeExceptionMethodInfo().ID }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue3_2" }); // 4. Calculate address of element // 4.1. Move index into EDX // 4.2. Move array ref into EAX // 4.3. Move element type ref (from array ref) into EAX // 4.4. Push EAX // 4.5. Move IsValueType (from element ref type) into EAX // 4.6. If IsValueType, continue to 4.7., else goto 4.10. // 4.7. Pop EAX // 4.8. Move Size (from element type ref) into EAX // 4.9. Skip over 4.9. and 4.10. // 4.10. Pop EAX // 4.11. Move StackSize (from element type ref) into EAX // 4.12. Mulitply EAX by EDX (index by element size) // 4.13. Move array ref into EDX // 4.14. Add enough to go past Kernel.FOS_System.Array fields // 4.15. Add EAX and EBX (array ref + fields + (index * element size)) // 4.1. Move index into EDX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + sizeOnStack + "]", Dest = "EDX" }); // 4.2. Move array ref into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + (sizeOnStack + 4) + "]", Dest = "EAX" }); // 4.3. Move element type ref (from array ref) into EAX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + elemTypeOffset.ToString() + "]", Dest = "EAX" }); // 4.4. Push EAX conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); // 4.5. Move IsValueType (from element ref type) into EAX int isValueTypeOffset = conversionState.GetTypeFieldOffset("IsValueType"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "[EAX+" + isValueTypeOffset.ToString() + "]", Dest = "AL" }); // 4.6. If IsValueType, continue to 4.7., else goto 4.9. conversionState.Append(new ASMOps.Test() { Arg1 = "EAX", Arg2 = "1" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "Continue4_1" }); // 4.7. Pop EAX conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); // 4.8. Move Size (from element type ref) into EAX int sizeOffset = conversionState.GetTypeFieldOffset("Size"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + sizeOffset.ToString() + "]", Dest = "EAX" }); // 4.9. Skip over 4.9. and 4.10. conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "Continue4_2" }); // 4.10. Pop EAX conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_1" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); // 4.11. Move StackSize (from element type ref) into EAX int stackSizeOffset = conversionState.GetTypeFieldOffset("StackSize"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + stackSizeOffset.ToString() + "]", Dest = "EAX" }); // 4.12. Mulitply EAX by EDX (index by element size) conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "Continue4_2" }); conversionState.Append(new ASMOps.Mul() { Arg = "EDX" }); // 4.13. Move array ref into EDX conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Dest = "EDX", Src = "[ESP+" + (sizeOnStack + 4) + "]" }); // 4.14. Add enough to go past Kernel.FOS_System.Array fields int allFieldsOffset = 0; #region Offset calculation { Types.FieldInfo highestOffsetFieldInfo = arrayTypeInfo.FieldInfos.Where(x => !x.IsStatic).OrderByDescending(x => x.OffsetInBytes).First(); Types.TypeInfo fieldTypeInfo = conversionState.TheILLibrary.GetTypeInfo(highestOffsetFieldInfo.UnderlyingInfo.FieldType); allFieldsOffset = highestOffsetFieldInfo.OffsetInBytes + (fieldTypeInfo.IsValueType ? fieldTypeInfo.SizeOnHeapInBytes : fieldTypeInfo.SizeOnStackInBytes); } #endregion conversionState.Append(new ASMOps.Add() { Src = allFieldsOffset.ToString(), Dest = "EDX" }); // 4.15. Add EAX and EDX (array ref + fields + (index * element size)) conversionState.Append(new ASMOps.Add() { Src = "EDX", Dest = "EAX" }); // 5. Pop the element from the stack to array // 5.1. Pop value bytes from stack to array // 5.2. Add 8 to ESP to remove Index and Array ref for (int i = 0; i < sizeOnStack; i += 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "ECX" }); switch (sizeOnHeap) { case 1: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "CL", Dest = "[EAX+" + i + "]" }); break; case 2: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "CX", Dest = "[EAX+" + i + "]" }); break; case 3: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Byte, Src = "CL", Dest = "[EAX+" + i + "]" }); conversionState.Append(new ASMOps.Shr() { Src = "16", Dest = "ECX" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Word, Src = "CX", Dest = "[EAX+" + (i + 1) + "]" }); break; default: conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "ECX", Dest = "[EAX+" + i + "]" }); break; } sizeOnHeap -= 4; } // 5.2. Add 8 to ESP to remove Index and Array ref conversionState.Append(new ASMOps.Add() { Src = "8", Dest = "ESP" }); // 5.2. Pop index, array ref and value from our stack conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); conversionState.CurrentStackFrame.Stack.Pop(); }