using System; using System.Linq; using Indy.IL2CPU.Assembler; using Indy.IL2CPU.Assembler.X86; using CPUx86 = Indy.IL2CPU.Assembler.X86; using Indy.IL2CPU.Compiler; namespace Indy.IL2CPU.IL.X86 { public class X86MethodFooterOp : MethodFooterOp { public readonly uint TotalArgsSize = 0; public readonly uint ReturnSize = 0; public readonly MethodInformation.Variable[] Locals; public readonly MethodInformation.Argument[] Args; public readonly bool DebugMode; public readonly bool MethodIsNonDebuggable; public readonly int LocAllocItemCount; public X86MethodFooterOp(ILReader aReader, MethodInformation aMethodInfo) : base(aReader, aMethodInfo) { if (aMethodInfo != null) { // if (aMethodInfo.Locals.Length > 0) { // TotalLocalsSize += aMethodInfo.Locals[aMethodInfo.Locals.Length - 1].Offset + aMethodInfo.Locals[aMethodInfo.Locals.Length - 1].Size; // } Locals = aMethodInfo.Locals.ToArray(); Args = aMethodInfo.Arguments.ToArray(); ReturnSize = aMethodInfo.ReturnSize; DebugMode = aMethodInfo.DebugMode; MethodIsNonDebuggable = aMethodInfo.IsNonDebuggable; LocAllocItemCount = 0; if (aMethodInfo.MethodData.ContainsKey(Localloc.LocAllocCountMethodDataEntry)) { LocAllocItemCount = (int)aMethodInfo.MethodData[Localloc.LocAllocCountMethodDataEntry]; } } } public override void DoAssemble() { uint xArgSize = 0; foreach (var xItem in Args) { xArgSize += xItem.Size; } var xDecRefInfo = GetService().GetMethodInfo(GCImplementationRefs.DecRefCountRef, false); var xHeapFreeInfo = GetService().GetMethodInfo(typeof (RuntimeEngine).GetMethod("Heap_Free"), false); AssembleFooter(ReturnSize, Assembler, Locals, Args, xArgSize, DebugMode, MethodIsNonDebuggable, (uint) LocAllocItemCount, GetService().GetFieldStorageSize, xDecRefInfo.LabelName, xHeapFreeInfo.LabelName); } public static void AssembleFooter(uint aReturnSize, Assembler.Assembler aAssembler, MethodInformation.Variable[] aLocals, MethodInformation.Argument[] aArgs, uint aTotalArgsSize, bool aDebugMode, bool aIsNonDebuggable, uint aLocAllocItemCount, Func aGetStorageSizeDelegate, string aDecRefLabel, string aHeapFreeLabel) { uint xReturnSize = aReturnSize; if (xReturnSize % 4 > 0) { xReturnSize += 4 - xReturnSize % 4; } new Label(EndOfMethodLabelNameNormal); new CPUx86.Move { DestinationReg = CPUx86.Registers.ECX, SourceValue = 0 }; if (aReturnSize > 0) { //var xArgSize = (from item in aArgs // let xSize = item.Size + item.Offset // select xSize).FirstOrDefault(); //new Comment(String.Format("ReturnSize = {0}, ArgumentSize = {1}", // aReturnSize, // xArgSize)); //int xOffset = 4; //if(xArgSize>0) { // xArgSize -= xReturnSize; // xOffset = xArgSize; //} int xOffset = 4; if (aArgs.Length > 0) { // old code: //xOffset = aArgs.First().Offset + 4; //if (xOffset < 0) //{ // xOffset = 0; //} // new code: xOffset = (int)((from item in aArgs select item.Offset + item.Size).First()); } for (int i = 0; i < xReturnSize / 4; i++) { new CPUx86.Pop { DestinationReg = CPUx86.Registers.EAX }; new CPUx86.Move { DestinationReg = CPUx86.Registers.EBP, DestinationIsIndirect = true, DestinationDisplacement = (int)(xOffset + ((i + 1) * 4) + 4 - xReturnSize), SourceReg = Registers.EAX }; } } new CPUx86.Jump { DestinationLabel = EndOfMethodLabelNameException }; new Label(EndOfMethodLabelNameException); for (int i = 0; i < aLocAllocItemCount;i++ ) { new CPUx86.Call { DestinationLabel = aHeapFreeLabel }; } if (aDebugMode && aIsNonDebuggable) { new CPUx86.Call { DestinationLabel = "DebugPoint_DebugResume" }; } if ((from xLocal in aLocals where xLocal.IsReferenceType select 1).Count() > 0 || (from xArg in aArgs where xArg.IsReferenceType select 1).Count() > 0) { new CPUx86.Push { DestinationReg = Registers.ECX }; foreach (MethodInformation.Variable xLocal in aLocals) { if (xLocal.IsReferenceType) { Op.Ldloc(aAssembler, xLocal, false, aGetStorageSizeDelegate(xLocal.VariableType)); new CPUx86.Call { DestinationLabel = aDecRefLabel }; } } foreach (MethodInformation.Argument xArg in aArgs) { if (xArg.IsReferenceType) { Op.Ldarg(aAssembler, xArg, false); //, aGetStorageSizeDelegate(xArg.ArgumentType) new CPUx86.Call { DestinationLabel = aDecRefLabel }; } } new CPUx86.Pop { DestinationReg = CPUx86.Registers.ECX }; } for (int j = aLocals.Length - 1; j >= 0; j--) { int xLocalSize = aLocals[j].Size; new CPUx86.Add { DestinationReg = CPUx86.Registers.ESP, SourceValue = (uint)xLocalSize }; } //new CPUx86.Add(CPUx86.Registers_Old.ESP, "0x4"); new CPUx86.Pop { DestinationReg = CPUx86.Registers.EBP }; var xRetSize = ((int)aTotalArgsSize) - ((int)xReturnSize); if(xRetSize<0) { xRetSize = 0; } new CPUx86.Return { DestinationValue = (uint)xRetSize }; } } }