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

VM - Jump table #3116

Closed
wants to merge 11 commits into from
1,458 changes: 34 additions & 1,424 deletions src/Neo.VM/ExecutionEngine.cs

Large diffs are not rendered by default.

396 changes: 396 additions & 0 deletions src/Neo.VM/JumpTable.Control.cs

Large diffs are not rendered by default.

213 changes: 213 additions & 0 deletions src/Neo.VM/JumpTable.Push.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// JumpTable.Push.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.VM.Types;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;

namespace Neo.VM
{
public partial class JumpTable
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHINT8(ExecutionEngine engine, Instruction instruction)
{
engine.Push(new BigInteger(instruction.Operand.Span));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHINT16(ExecutionEngine engine, Instruction instruction)
{
engine.Push(new BigInteger(instruction.Operand.Span));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHINT32(ExecutionEngine engine, Instruction instruction)
{
engine.Push(new BigInteger(instruction.Operand.Span));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHINT64(ExecutionEngine engine, Instruction instruction)
{
engine.Push(new BigInteger(instruction.Operand.Span));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHINT128(ExecutionEngine engine, Instruction instruction)
{
engine.Push(new BigInteger(instruction.Operand.Span));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHINT256(ExecutionEngine engine, Instruction instruction)
{
engine.Push(new BigInteger(instruction.Operand.Span));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHT(ExecutionEngine engine, Instruction instruction)
{
engine.Push(StackItem.True);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHF(ExecutionEngine engine, Instruction instruction)
{
engine.Push(StackItem.False);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHA(ExecutionEngine engine, Instruction instruction)
{
var position = checked(engine.CurrentContext!.InstructionPointer + instruction.TokenI32);
if (position < 0 || position > engine.CurrentContext.Script.Length)
throw new InvalidOperationException($"Bad pointer address(Instruction instruction) {position}");
engine.Push(new Pointer(engine.CurrentContext.Script, position));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHNULL(ExecutionEngine engine, Instruction instruction)
{
engine.Push(StackItem.Null);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHDATA1(ExecutionEngine engine, Instruction instruction)
{
engine.Limits.AssertMaxItemSize(instruction.Operand.Length);
engine.Push(instruction.Operand);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHDATA2(ExecutionEngine engine, Instruction instruction)
{
engine.Limits.AssertMaxItemSize(instruction.Operand.Length);
engine.Push(instruction.Operand);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHDATA4(ExecutionEngine engine, Instruction instruction)
{
engine.Limits.AssertMaxItemSize(instruction.Operand.Length);
engine.Push(instruction.Operand);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSHM1(ExecutionEngine engine, Instruction instruction)
{
engine.Push(-1);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH0(ExecutionEngine engine, Instruction instruction)
{
engine.Push(0);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH1(ExecutionEngine engine, Instruction instruction)
{
engine.Push(1);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH2(ExecutionEngine engine, Instruction instruction)
{
engine.Push(2);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH3(ExecutionEngine engine, Instruction instruction)
{
engine.Push(3);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH4(ExecutionEngine engine, Instruction instruction)
{
engine.Push(4);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH5(ExecutionEngine engine, Instruction instruction)
{
engine.Push(5);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH6(ExecutionEngine engine, Instruction instruction)
{
engine.Push(6);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH7(ExecutionEngine engine, Instruction instruction)
{
engine.Push(7);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH8(ExecutionEngine engine, Instruction instruction)
{
engine.Push(8);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH9(ExecutionEngine engine, Instruction instruction)
{
engine.Push(9);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH10(ExecutionEngine engine, Instruction instruction)
{
engine.Push(10);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH11(ExecutionEngine engine, Instruction instruction)
{
engine.Push(11);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH12(ExecutionEngine engine, Instruction instruction)
{
engine.Push(12);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH13(ExecutionEngine engine, Instruction instruction)
{
engine.Push(13);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH14(ExecutionEngine engine, Instruction instruction)
{
engine.Push(14);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH15(ExecutionEngine engine, Instruction instruction)
{
engine.Push(15);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void PUSH16(ExecutionEngine engine, Instruction instruction)
{
engine.Push(16);
}
}
}
106 changes: 106 additions & 0 deletions src/Neo.VM/JumpTable.Splice.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// JumpTable.Splice.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using System;
using System.Runtime.CompilerServices;

namespace Neo.VM
{
public partial class JumpTable
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void NEWBUFFER(ExecutionEngine engine, Instruction instruction)
{
int length = (int)engine.Pop().GetInteger();
engine.Limits.AssertMaxItemSize(length);
engine.Push(new Types.Buffer(length));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void MEMCPY(ExecutionEngine engine, Instruction instruction)
{
int count = (int)engine.Pop().GetInteger();
if (count < 0)
throw new InvalidOperationException($"The value {count} is out of range.");
int si = (int)engine.Pop().GetInteger();
if (si < 0)
throw new InvalidOperationException($"The value {si} is out of range.");
ReadOnlySpan<byte> src = engine.Pop().GetSpan();
if (checked(si + count) > src.Length)
throw new InvalidOperationException($"The value {count} is out of range.");
int di = (int)engine.Pop().GetInteger();
if (di < 0)
throw new InvalidOperationException($"The value {di} is out of range.");
Types.Buffer dst = engine.Pop<Types.Buffer>();
if (checked(di + count) > dst.Size)
throw new InvalidOperationException($"The value {count} is out of range.");
src.Slice(si, count).CopyTo(dst.InnerBuffer.Span[di..]);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void CAT(ExecutionEngine engine, Instruction instruction)
{
var x2 = engine.Pop().GetSpan();
var x1 = engine.Pop().GetSpan();
int length = x1.Length + x2.Length;
engine.Limits.AssertMaxItemSize(length);
Types.Buffer result = new(length, false);
x1.CopyTo(result.InnerBuffer.Span);
x2.CopyTo(result.InnerBuffer.Span[x1.Length..]);
engine.Push(result);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void SUBSTR(ExecutionEngine engine, Instruction instruction)
{
int count = (int)engine.Pop().GetInteger();
if (count < 0)
throw new InvalidOperationException($"The value {count} is out of range.");
int index = (int)engine.Pop().GetInteger();
if (index < 0)
throw new InvalidOperationException($"The value {index} is out of range.");
var x = engine.Pop().GetSpan();
if (index + count > x.Length)
throw new InvalidOperationException($"The value {count} is out of range.");
Types.Buffer result = new(count, false);
x.Slice(index, count).CopyTo(result.InnerBuffer.Span);
engine.Push(result);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void LEFT(ExecutionEngine engine, Instruction instruction)
{
int count = (int)engine.Pop().GetInteger();
if (count < 0)
throw new InvalidOperationException($"The value {count} is out of range.");
var x = engine.Pop().GetSpan();
if (count > x.Length)
throw new InvalidOperationException($"The value {count} is out of range.");
Types.Buffer result = new(count, false);
x[..count].CopyTo(result.InnerBuffer.Span);
engine.Push(result);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void RIGHT(ExecutionEngine engine, Instruction instruction)
{
int count = (int)engine.Pop().GetInteger();
if (count < 0)
throw new InvalidOperationException($"The value {count} is out of range.");
var x = engine.Pop().GetSpan();
if (count > x.Length)
throw new InvalidOperationException($"The value {count} is out of range.");
Types.Buffer result = new(count, false);
x[^count..^0].CopyTo(result.InnerBuffer.Span);
engine.Push(result);
}
}
}
59 changes: 59 additions & 0 deletions src/Neo.VM/JumpTable.Types.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (C) 2015-2024 The Neo Project.
//
// JumpTable.Types.cs file belongs to the neo project and is free
// software distributed under the MIT software license, see the
// accompanying file LICENSE in the main directory of the
// repository or http://www.opensource.org/licenses/mit-license.php
// for more details.
//
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Neo.VM.Types;
using System;
using System.Runtime.CompilerServices;

namespace Neo.VM
{
public partial class JumpTable
{
public virtual void ISNULL(ExecutionEngine engine, Instruction instruction)
{
var x = engine.Pop();
engine.Push(x.IsNull);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void ISTYPE(ExecutionEngine engine, Instruction instruction)
{
var x = engine.Pop();
var type = (StackItemType)instruction.TokenU8;
if (type == StackItemType.Any || !Enum.IsDefined(typeof(StackItemType), type))
throw new InvalidOperationException($"Invalid type: {type}");
engine.Push(x.Type == type);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void CONVERT(ExecutionEngine engine, Instruction instruction)
{
var x = engine.Pop();
engine.Push(x.ConvertTo((StackItemType)instruction.TokenU8));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void ABORTMSG(ExecutionEngine engine, Instruction instruction)
{
var msg = engine.Pop().GetString();
throw new Exception($"{OpCode.ABORTMSG} is executed. Reason: {msg}");
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public virtual void ASSERTMSG(ExecutionEngine engine, Instruction instruction)
{
var msg = engine.Pop().GetString();
var x = engine.Pop().GetBoolean();
if (!x)
throw new Exception($"{OpCode.ASSERTMSG} is executed with false result. Reason: {msg}");
}
}
}
Loading