Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Sub_Ovh implementation. #64

Merged
merged 2 commits into from
Nov 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 50 additions & 41 deletions source/Cosmos.IL2CPU/IL/Add_Ovf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,67 @@
using XSharp.Assembler.x86;
using XSharp;
using static XSharp.XSRegisters;
using System.Reflection;

/* Add.Ovf is signed integer addition with check for overflow */
namespace Cosmos.IL2CPU.X86.IL
{
[OpCode(ILOpCode.Code.Add_Ovf)]
public class Add_Ovf : ILOp
[OpCode(ILOpCode.Code.Add_Ovf)]
public class Add_Ovf : ILOp
{
public Add_Ovf(XSharp.Assembler.Assembler aAsmblr)
: base(aAsmblr)
{
public Add_Ovf(XSharp.Assembler.Assembler aAsmblr)
: base(aAsmblr)
{
}
}

public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
{
var xType = aOpCode.StackPopTypes[0];
var xSize = SizeOfType(xType);
var xIsFloat = TypeIsFloat(xType);
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
{
var xType = aOpCode.StackPopTypes[0];
var xSize = SizeOfType(xType);
var xIsFloat = TypeIsFloat(xType);

if (xIsFloat)
{
throw new Exception("Cosmos.IL2CPU.x86->IL->Add_Ovf.cs->Error: Expected signed integer operands but get float!");
}
if (xIsFloat)
{
throw new Exception("Cosmos.IL2CPU.x86->IL->Add_Ovf.cs->Error: Expected signed integer operands but get float!");
}

if (xSize > 8)
{
//EmitNotImplementedException( Assembler, aServiceProvider, "Size '" + xSize.Size + "' not supported (add)", aCurrentLabel, aCurrentMethodInfo, aCurrentOffset, aNextLabel );
throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Add_Ovf.cs->Error: StackSize > 8 not supported");
}
else
{
var xBaseLabel = GetLabel(aMethod, aOpCode) + ".";
var xSuccessLabel = xBaseLabel + "Success";
if (xSize > 4) // long
{
XS.Pop(EDX); // low part
XS.Pop(EAX); // high part
XS.Add(ESP, EDX, destinationIsIndirect: true);
XS.AddWithCarry(ESP, EAX, destinationDisplacement: 4);
if (xSize > 8)
{
//EmitNotImplementedException( Assembler, aServiceProvider, "Size '" + xSize.Size + "' not supported (add)", aCurrentLabel, aCurrentMethodInfo, aCurrentOffset, aNextLabel );
throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Add_Ovf.cs->Error: StackSize > 8 not supported");
}
else
{
var xBaseLabel = GetLabel(aMethod, aOpCode) + ".";
var xSuccessLabel = xBaseLabel + "Success";
if (xSize > 4) // long
{
XS.Pop(EDX); // low part
XS.Pop(EAX); // high part
XS.Add(ESP, EDX, destinationIsIndirect: true);
XS.AddWithCarry(ESP, EAX, destinationDisplacement: 4);

}
else //integer
{
}
else //integer
{

XS.Pop(EAX);
XS.Add(ESP, EAX, destinationIsIndirect: true);
}
XS.Pop(EAX);
XS.Add(ESP, EAX, destinationIsIndirect: true);
}

// Let's check if we add overflow and if so throw OverflowException
XS.Jump(ConditionalTestEnum.NoOverflow, xSuccessLabel);
ThrowOverflowException();
XS.Label(xSuccessLabel);
}
// Let's check if we add overflow and if so throw OverflowException
XS.Jump(ConditionalTestEnum.NoOverflow, xSuccessLabel);
if (xSize > 4) // Hack to stop stack corruption
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is something we will have to consider on exception handling. When throwing in the middle of an opcode, this will probably work for most of the simple cases, but not sure about more complex ones. I'm not sure about what the CLI spec defines for the stack, still have to read that, but if the following is valid IL:

try
{
    ldloc.0
    ldloc.1
    ldloc.2
    add.ovf
    add.ovf
}
catch
{
    // do something
}

And we throw at the first add.ovf, the stack is not in a good state to jump to the catch block (still has the other local on the stack, which was expected to be consumed by the second add.ovf). Roslyn seems to emit good IL for this (not sure if by spec, still have to check), so this should work for now.

Also, I think we should file an issue about this or add this info to #16.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to ECMA-335, the throw opcode description is this:

The throw instruction throws the exception object (type O) on the stack and empties the stack.

So I think we should always empty the stack when throwing an exception, we should add some common infrastructure to throw exceptions, probably part of #16, I'll add a note there.

{
XS.Add(ESP, 8);
}
else
{
XS.Add(ESP, 4);
}
Call.DoExecute(Assembler, aMethod, typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public), aOpCode, GetLabel(aMethod, aOpCode), xSuccessLabel, DebugEnabled);
XS.Label(xSuccessLabel);
}
}
}
}
13 changes: 11 additions & 2 deletions source/Cosmos.IL2CPU/IL/Add_Ovf_Un.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using XSharp.Assembler.x86;
using XSharp;
using static XSharp.XSRegisters;
using System.Reflection;

/* Add.Ovf is unsigned integer addition with check for overflow */
namespace Cosmos.IL2CPU.X86.IL
Expand Down Expand Up @@ -50,9 +51,17 @@ public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)

// Let's check if we add overflow and if so throw OverflowException
XS.Jump(ConditionalTestEnum.NotCarry, xSuccessLabel);
ThrowOverflowException();
if (xSize > 4) // Hack to stop stack corruption
{
XS.Add(ESP, 8);
}
else
{
XS.Add(ESP, 4);
}
Call.DoExecute(Assembler, aMethod, typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public), aOpCode, GetLabel(aMethod, aOpCode), xSuccessLabel, DebugEnabled);
XS.Label(xSuccessLabel);
}
}
}
}
}
73 changes: 59 additions & 14 deletions source/Cosmos.IL2CPU/IL/Sub_Ovf.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,66 @@
using System;
using CPUx86 = XSharp.Assembler.x86;
using XSharp.Assembler.x86;

using XSharp;
using static XSharp.XSRegisters;
using System.Reflection;

namespace Cosmos.IL2CPU.X86.IL
{
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Sub_Ovf)]
public class Sub_Ovf: ILOp
{
public Sub_Ovf(XSharp.Assembler.Assembler aAsmblr):base(aAsmblr) {
}
[Cosmos.IL2CPU.OpCode(ILOpCode.Code.Sub_Ovf)]
public class Sub_Ovf : ILOp
{
public Sub_Ovf(XSharp.Assembler.Assembler aAsmblr) : base(aAsmblr)
{
}

public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode)
{
var xType = aOpCode.StackPopTypes[0];
var xSize = SizeOfType(xType);
var xIsFloat = TypeIsFloat(xType);
if (xIsFloat)
{
throw new Exception("Cosmos.IL2CPU.x86->IL->Sub_Ovf.cs->Error: Expected signed integer operands but get float!");
}

if (xSize > 8)
{
throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Sub_Ovf.cs->Error: StackSize > 8 not supported");
}
else
{
var xBaseLabel = GetLabel(aMethod, aOpCode) + ".";
var xSuccessLabel = xBaseLabel + "Success";
if (xSize > 4) // long
{
XS.Pop(EAX);//low part
XS.Pop(EDX);//high part
XS.Sub(ESP, EAX, destinationIsIndirect: true);
XS.SubWithCarry(ESP, EDX, destinationDisplacement: 4);

}
else //integer
{
XS.Pop(ECX);//first integer
XS.Pop(EAX);//second integer
XS.Sub(EAX, ECX);
XS.Push(EAX);//push result on stack
}

public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) {
//if (Assembler.Stack.Peek().IsFloat) {
// throw new NotImplementedException("Sub_Ovf: TODO need to call Sub IL");
//}
throw new NotImplementedException();
}
}
}
// Let's check if we add overflow and if so throw OverflowException
XS.Jump(ConditionalTestEnum.NoOverflow, xSuccessLabel);
if (xSize > 4) // Hack to stop stack corruption
{
XS.Add(ESP, 8);
}
else
{
XS.Add(ESP, 4);
}
Call.DoExecute(Assembler, aMethod, typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public), aOpCode, GetLabel(aMethod, aOpCode), xSuccessLabel, DebugEnabled);
XS.Label(xSuccessLabel);
}
}
}
}
55 changes: 49 additions & 6 deletions source/Cosmos.IL2CPU/IL/Sub_Ovf_Un.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using CPUx86 = XSharp.Assembler.x86;
using XSharp.Assembler.x86;

using XSharp;
using static XSharp.XSRegisters;
using System.Reflection;

namespace Cosmos.IL2CPU.X86.IL
{
Expand All @@ -12,10 +14,51 @@ public Sub_Ovf_Un(XSharp.Assembler.Assembler aAsmblr):base(aAsmblr) {
}

public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) {
//if (Assembler.Stack.Peek().IsFloat) {
// throw new NotImplementedException("Sub_Ovf_Un: TODO need to call Sub IL");
//}
throw new NotImplementedException();
// TODO overflow check for float
var xType = aOpCode.StackPopTypes[0];
var xSize = SizeOfType(xType);
var xIsFloat = TypeIsFloat(xType);

if (xIsFloat)
{
throw new Exception("Cosmos.IL2CPU.x86->IL->Add_Ovf_Un.cs->Error: Expected unsigned integer operands but get float!");
}

if (xSize > 8)
{
//EmitNotImplementedException( Assembler, aServiceProvider, "Size '" + xSize.Size + "' not supported (add)", aCurrentLabel, aCurrentMethodInfo, aCurrentOffset, aNextLabel );
throw new NotImplementedException("Cosmos.IL2CPU.x86->IL->Add_Ovf_Un.cs->Error: StackSize > 8 not supported");
}
else
{
var xBaseLabel = GetLabel(aMethod, aOpCode) + ".";
var xSuccessLabel = xBaseLabel + "Success";
if (xSize > 4) // long
{
XS.Pop(EDX); // low part
XS.Pop(EAX); // high part
XS.Sub(ESP, EDX, destinationIsIndirect: true);
XS.SubWithCarry(ESP, EAX, destinationDisplacement: 4);
}
else //integer
{
XS.Pop(EAX);
XS.Sub(ESP, EAX, destinationIsIndirect: true);
}

// Let's check if we add overflow and if so throw OverflowException
XS.Jump(ConditionalTestEnum.NotCarry, xSuccessLabel);
if (xSize > 4) // Hack to stop stack corruption
{
XS.Add(ESP, 8);
}
else
{
XS.Add(ESP, 4);
}
Call.DoExecute(Assembler, aMethod, typeof(ExceptionHelper).GetMethod("ThrowOverflow", BindingFlags.Static | BindingFlags.Public), aOpCode, GetLabel(aMethod, aOpCode), xSuccessLabel, DebugEnabled);
XS.Label(xSuccessLabel);
}
}
}
}
}
10 changes: 10 additions & 0 deletions source/Cosmos.IL2CPU/ILOpCodes/OpNone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,15 @@ public override int GetNumberOfStackPops(MethodBase aMethod)
return 1;
case Code.Add:
case Code.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.Mul:
case Code.Mul_Ovf:
case Code.Mul_Ovf_Un:
case Code.Div:
case Code.Div_Un:
case Code.Sub:
case Code.Sub_Ovf:
case Code.Sub_Ovf_Un:
case Code.Rem:
case Code.Rem_Un:
case Code.Xor:
Expand Down Expand Up @@ -208,12 +211,15 @@ public override int GetNumberOfStackPushes(MethodBase aMethod)
return 1;
case Code.Add:
case Code.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.Mul:
case Code.Mul_Ovf:
case Code.Mul_Ovf_Un:
case Code.Div:
case Code.Div_Un:
case Code.Sub:
case Code.Sub_Ovf:
case Code.Sub_Ovf_Un:
case Code.Rem:
case Code.Rem_Un:
case Code.Xor:
Expand Down Expand Up @@ -529,12 +535,16 @@ protected override void DoInterpretStackTypes(ref bool aSituationChanged)
switch (OpCode)
{
case Code.Add:
case Code.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.Mul:
case Code.Mul_Ovf:
case Code.Mul_Ovf_Un:
case Code.Div:
case Code.Div_Un:
case Code.Sub:
case Code.Sub_Ovf:
case Code.Sub_Ovf_Un:
case Code.Rem:
case Code.Rem_Un:
case Code.Xor:
Expand Down