public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); if (methodToCall is MethodInfo) { Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged, isValue = retTypeInfo.IsValueType }; int bytesToAdd = 0; List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } if (bytesToAdd > 0) { if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (methodToCall is ConstructorInfo) { ConstructorInfo aConstructor = (ConstructorInfo)methodToCall; if (aConstructor.IsStatic) { //Static constructors do not have parameters or return values } else { ParameterInfo[] allParams = methodToCall.GetParameters(); foreach (ParameterInfo aParam in allParams) { 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 any argument or the return value is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); conversionState.AddExternalLabel(methodToCallInfo.ID); //The method to call is a method base //A method base can be either a method info i.e. a normal method //or a constructor method. The two types are treated separately. if(methodToCall is MethodInfo) { //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer (ESP register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); //Go through each one if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack conversionState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the eax register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in eax //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } } } //No params to skip over but we might still need to store return value else if (returnItem.sizeOnStackInBytes != 0) { //The return value will be the top item on the stack. //So all we need to do is push the return item onto our stack. conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if(methodToCall is ConstructorInfo) { ConstructorInfo aConstructor = (ConstructorInfo)methodToCall; if (aConstructor.IsStatic) { //Static constructors do not have parameters or return values //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); } else { //Append the actual call conversionState.Append(new ASMOps.Call() { Target = methodToCallInfo.ID }); //After a call, we need to remove the parameters from the stack //This is most easily done by just adding the total number of bytes for params //to the stack pointer (ESP register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called ParameterInfo[] allParams = methodToCall.GetParameters(); //Go through each one foreach (ParameterInfo aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam.ParameterType).SizeOnStackInBytes; } //Add 4 bytes for the instance ref bytesToAdd += 4; //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); } } } }
public override void PerformStackOperations(ILPreprocessState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); if (methodToCall is MethodInfo) { if (typeof(Delegate).IsAssignableFrom(((MethodInfo)methodToCall).DeclaringType)) { List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged }; int bytesToAdd = 4; foreach (Type aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else { string methodIDValueWanted = methodToCallInfo.IDValue.ToString(); int currOpPosition = conversionState.PositionOf(theOp); Types.TypeInfo declaringTypeInfo = conversionState.TheILLibrary.GetTypeInfo(methodToCall.DeclaringType); Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged }; int bytesToAdd = 0; List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { conversionState.CurrentStackFrame.Stack.Pop(); bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } if (bytesToAdd > 0) { if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } else if (returnItem.sizeOnStackInBytes != 0) { conversionState.CurrentStackFrame.Stack.Push(returnItem); } } } }
/// <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 any argument or the return value is a floating point number. /// </exception> public override void Convert(ILConversionState conversionState, ILOp theOp) { MethodBase methodToCall = theOp.MethodToCall; Types.MethodInfo methodToCallInfo = conversionState.TheILLibrary.GetMethodInfo(methodToCall); conversionState.AddExternalLabel(conversionState.GetThrowNullReferenceExceptionMethodInfo().ID); //The method to call is a method base //A method base can be either a method info i.e. a normal method //or a constructor method. The two types are treated separately. if(methodToCall is MethodInfo) { //Need to do callvirt related stuff to load address of method to call // - Check for invoke of a delegate - if so, treat rather differently from normal callvirt if (typeof(Delegate).IsAssignableFrom(((MethodInfo)methodToCall).DeclaringType)) { //Callvirt to delegate method // - We only support calls to Invoke at the moment if (methodToCall.Name != "Invoke") { throw new NotSupportedException("Callvirt to Delegate method not supported! Method name: " + methodToCall.Name); } int bytesForAllParams = ((MethodInfo)methodToCall).GetParameters().Select(x => conversionState.TheILLibrary.GetTypeInfo(x.ParameterType).SizeOnStackInBytes).Sum(); // - Move into eax address of function to call from stack - delegate reference is function pointer //All the parameters for the method that was called List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); int bytesForParams = allParams.Select(x => conversionState.TheILLibrary.GetTypeInfo(x).SizeOnStackInBytes).Sum(); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + bytesForParams + "]", Dest = "EAX" }); //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = "EAX" }); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer (ESP register). //Stores the number of bytes to add // - Initially at least 4 for the delegate (method) ref/pointer int bytesToAdd = 4; //Go through all params that must be removed foreach (Type aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack conversionState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the eax register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in eax //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } } } else { //Normal callvirt // - Get object ref from loaded args // - Check object ref not null // - Get type table entry from object ref // - Get method table from type table entry // - Scan method table for the method we want // - If found, load method address // - Else, check for parent type method table // - If no parent type method table, throw exception // - Else, scan parent type method table string methodIDValueWanted = methodToCallInfo.IDValue.ToString(); int currOpPosition = conversionState.PositionOf(theOp); Types.TypeInfo declaringTypeInfo = conversionState.TheILLibrary.GetTypeInfo(methodToCall.DeclaringType); //DB_Type declaringDBType = DebugDatabase.GetType(conversionState.GetTypeID(methodToCall.DeclaringType)); //Get object ref int bytesForAllParams = ((MethodInfo)methodToCall).GetParameters().Select(x => conversionState.TheILLibrary.GetTypeInfo(x.ParameterType).SizeOnStackInBytes).Sum(); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[ESP+" + bytesForAllParams + "]", Dest = "EAX" }); //Check object ref conversionState.Append(new ASMOps.Cmp() { Arg1 = "EAX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotZero, DestILPosition = currOpPosition, Extension = "NotNull" }); 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 = "NotNull" }); //Get type ref int typeOffset = conversionState.TheILLibrary.GetFieldInfo(declaringTypeInfo, "_Type").OffsetInBytes; conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + typeOffset.ToString() + "]", Dest = "EAX" }); //Get method table ref int methodTablePtrOffset = conversionState.GetTypeFieldOffset("MethodTablePtr"); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+" + methodTablePtrOffset.ToString() + "]", Dest = "EAX" }); //Loop through entries conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "LoopMethodTable" }); //Load ID Val for current entry conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX]", Dest = "EBX" }); //Compare to wanted ID value conversionState.Append(new ASMOps.Cmp() { Arg1 = "EBX", Arg2 = methodIDValueWanted }); //If equal, load method address into EAX conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpNotEqual, DestILPosition = currOpPosition, Extension = "NotEqual" }); conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+4]", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "Call" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotEqual" }); //Else, compare to 0 to check for end of table conversionState.Append(new ASMOps.Cmp() { Arg1 = "EBX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "EndOfTable" }); //Not 0? Move to next entry then loop again conversionState.Append(new ASMOps.Add() { Src = "8", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "LoopMethodTable" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "EndOfTable" }); //Compare address value to 0 //If not zero, there is a parent method table to check conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "[EAX+4]", Dest = "EBX" }); conversionState.Append(new ASMOps.Cmp() { Arg1 = "EBX", Arg2 = "0" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.JumpZero, DestILPosition = currOpPosition, Extension = "NotFound" }); //Load parent method table and loop conversionState.Append(new ASMOps.Mov() { Size = ASMOps.OperandSize.Dword, Src = "EBX", Dest = "EAX" }); conversionState.Append(new ASMOps.Jmp() { JumpType = ASMOps.JmpOp.Jump, DestILPosition = currOpPosition, Extension = "LoopMethodTable" }); conversionState.Append(new ASMOps.Label() { ILPosition = currOpPosition, Extension = "NotFound" }); //Throw exception! 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 = "Call" }); //Allocate space on the stack for the return value as necessary Type retType = ((MethodInfo)methodToCall).ReturnType; Types.TypeInfo retTypeInfo = conversionState.TheILLibrary.GetTypeInfo(retType); StackItem returnItem = new StackItem() { isFloat = Utilities.IsFloat(retType), sizeOnStackInBytes = retTypeInfo.SizeOnStackInBytes, isGCManaged = retTypeInfo.IsGCManaged }; //We do not push the return value onto the stack unless it has size > 0 //We do not push the return value onto our stack at this point - it is pushed after the call is done if (returnItem.sizeOnStackInBytes != 0) { if (returnItem.isFloat) { //SUPPORT - floats throw new NotSupportedException("Cannot handle float return values!"); } else if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "0" }); } else { throw new NotSupportedException("Invalid return stack operand size!"); } } //Append the actual call conversionState.Append(new ASMOps.Call() { Target = "EAX" }); //After a call, we need to remove the return value and parameters from the stack //This is most easily done by just adding the total number of bytes for params and //return value to the stack pointer (ESP register). //Stores the number of bytes to add int bytesToAdd = 0; //All the parameters for the method that was called List<Type> allParams = ((MethodInfo)methodToCall).GetParameters().Select(x => x.ParameterType).ToList(); //Go through each one if (!methodToCall.IsStatic) { allParams.Insert(0, methodToCall.DeclaringType); } foreach (Type aParam in allParams) { //Pop the paramter off our stack //(Note: Return value was never pushed onto our stack. See above) conversionState.CurrentStackFrame.Stack.Pop(); //Add the size of the paramter to the total number of bytes to pop bytesToAdd += conversionState.TheILLibrary.GetTypeInfo(aParam).SizeOnStackInBytes; } //If the number of bytes to add to skip over params is > 0 if (bytesToAdd > 0) { //If there is a return value on the stack if (returnItem.sizeOnStackInBytes != 0) { //We need to store the return value then pop all the params //We now push the return value onto our stack as, //after all is said and done below, it will be the //top item on the stack conversionState.CurrentStackFrame.Stack.Push(returnItem); //SUPPORT - floats (with above) //Pop the return value into the eax register //We will push it back on after params are skipped over. if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EAX" }); conversionState.Append(new ASMOps.Pop() { Size = ASMOps.OperandSize.Dword, Dest = "EDX" }); } } //Skip over the params conversionState.Append(new ASMOps.Add() { Src = bytesToAdd.ToString(), Dest = "ESP" }); //If necessary, push the return value onto the stack. if (returnItem.sizeOnStackInBytes != 0) { //SUPPORT - floats (with above) //The return value was stored in eax //So push it back onto the stack if (returnItem.sizeOnStackInBytes == 4) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } else if (returnItem.sizeOnStackInBytes == 8) { conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EDX" }); conversionState.Append(new ASMOps.Push() { Size = ASMOps.OperandSize.Dword, Src = "EAX" }); } } } //No params to skip over but we might still need to store return value else if (returnItem.sizeOnStackInBytes != 0) { //The return value will be the top item on the stack. //So all we need to do is push the return item onto our stack. conversionState.CurrentStackFrame.Stack.Push(returnItem); } } } else if(methodToCall is ConstructorInfo) { throw new NotSupportedException("How the hell are we getting callvirts to constructor methods?!"); } }