Skip to content
This repository has been archived by the owner on Nov 22, 2023. It is now read-only.

New flow-control Opcodes #254

Merged
merged 9 commits into from
Dec 8, 2019
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
217 changes: 159 additions & 58 deletions src/neo-vm/ExecutionEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,25 +101,14 @@ public VMState Execute()
return State;
}

internal protected void ExecuteNext()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool ExecuteCall(int position)
{
if (InvocationStack.Count == 0)
{
State = VMState.HALT;
}
else
{
try
{
Instruction instruction = CurrentContext.CurrentInstruction;
if (!PreExecuteInstruction() || !ExecuteInstruction() || !PostExecuteInstruction(instruction))
State = VMState.FAULT;
}
catch
{
State = VMState.FAULT;
}
}
if (position < 0 || position > CurrentContext.Script.Length) return false;
ExecutionContext context_call = CurrentContext.Clone();
context_call.InstructionPointer = position;
LoadContext(context_call);
return true;
}

private bool ExecuteInstruction()
Expand Down Expand Up @@ -184,42 +173,132 @@ private bool ExecuteInstruction()
// Control
case OpCode.NOP: break;
case OpCode.JMP:
{
return ExecuteJump(true, instruction.TokenI8);
shargon marked this conversation as resolved.
Show resolved Hide resolved
}
case OpCode.JMP_L:
{
return ExecuteJump(true, instruction.TokenI32);
}
case OpCode.JMPIF:
{
if (!TryPop(out StackItem x)) return false;
return ExecuteJump(x.ToBoolean(), instruction.TokenI8);
}
case OpCode.JMPIF_L:
{
if (!TryPop(out StackItem x)) return false;
return ExecuteJump(x.ToBoolean(), instruction.TokenI32);
}
case OpCode.JMPIFNOT:
{
int offset = context.InstructionPointer + instruction.TokenI16;
if (offset < 0 || offset > context.Script.Length) return false;
bool fValue = true;
if (instruction.OpCode > OpCode.JMP)
{
if (!TryPop(out StackItem x)) return false;
fValue = x.ToBoolean();
if (instruction.OpCode == OpCode.JMPIFNOT)
fValue = !fValue;
}
if (fValue)
context.InstructionPointer = offset;
else
context.InstructionPointer += 3;
return true;
if (!TryPop(out StackItem x)) return false;
return ExecuteJump(!x.ToBoolean(), instruction.TokenI8);
}
case OpCode.JMPIFNOT_L:
{
if (!TryPop(out StackItem x)) return false;
return ExecuteJump(!x.ToBoolean(), instruction.TokenI32);
}
case OpCode.JMPEQ:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() == x2.ToBigInteger(), instruction.TokenI8);
}
case OpCode.JMPEQ_L:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() == x2.ToBigInteger(), instruction.TokenI32);
}
case OpCode.JMPNE:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() != x2.ToBigInteger(), instruction.TokenI8);
}
case OpCode.JMPNE_L:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() != x2.ToBigInteger(), instruction.TokenI32);
}
case OpCode.JMPGT:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() > x2.ToBigInteger(), instruction.TokenI8);
}
case OpCode.JMPGT_L:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() > x2.ToBigInteger(), instruction.TokenI32);
}
case OpCode.JMPGE:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() >= x2.ToBigInteger(), instruction.TokenI8);
}
case OpCode.JMPGE_L:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() >= x2.ToBigInteger(), instruction.TokenI32);
}
case OpCode.JMPLT:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() < x2.ToBigInteger(), instruction.TokenI8);
}
case OpCode.JMPLT_L:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() < x2.ToBigInteger(), instruction.TokenI32);
}
case OpCode.JMPLE:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() <= x2.ToBigInteger(), instruction.TokenI8);
}
case OpCode.JMPLE_L:
{
if (!TryPop(out PrimitiveType x2)) return false;
if (!TryPop(out PrimitiveType x1)) return false;
return ExecuteJump(x1.ToBigInteger() <= x2.ToBigInteger(), instruction.TokenI32);
}
case OpCode.CALL:
{
if (!ExecuteCall(checked(context.InstructionPointer + instruction.TokenI8)))
return false;
break;
}
case OpCode.CALL_L:
{
if (!ExecuteCall(checked(context.InstructionPointer + instruction.TokenI32)))
return false;
break;
}
case OpCode.CALLA:
{
int position;
if (instruction.OpCode == OpCode.CALLA)
{
if (!TryPop(out Pointer x)) return false;
position = x.Position;
}
else
{
position = context.InstructionPointer + instruction.TokenI16;
}
ExecutionContext context_call = context.Clone();
context_call.InstructionPointer = position;
if (context_call.InstructionPointer < 0 || context_call.InstructionPointer > context_call.Script.Length) return false;
LoadContext(context_call);
if (!TryPop(out Pointer x)) return false;
if (!ExecuteCall(x.Position)) return false;
break;
}
case OpCode.THROW:
{
return false;
}
case OpCode.THROWIF:
case OpCode.THROWIFNOT:
{
if (!TryPop(out StackItem x)) return false;
if (x.ToBoolean() ^ (instruction.OpCode == OpCode.THROWIFNOT)) return false;
break;
}
case OpCode.RET:
Expand Down Expand Up @@ -915,24 +994,46 @@ private bool ExecuteInstruction()
break;
}

// Exceptions
case OpCode.THROW:
{
return false;
}
case OpCode.THROWIFNOT:
{
if (!TryPop(out StackItem x)) return false;
if (!x.ToBoolean()) return false;
break;
}
default:
return false;
}
context.MoveNext();
return true;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool ExecuteJump(bool condition, int offset)
{
offset = checked(CurrentContext.InstructionPointer + offset);
if (offset < 0 || offset > CurrentContext.Script.Length) return false;
if (condition)
CurrentContext.InstructionPointer = offset;
else
CurrentContext.MoveNext();
return true;
}

internal protected void ExecuteNext()
{
if (InvocationStack.Count == 0)
{
State = VMState.HALT;
}
else
{
try
{
Instruction instruction = CurrentContext.CurrentInstruction;
if (!PreExecuteInstruction() || !ExecuteInstruction() || !PostExecuteInstruction(instruction))
State = VMState.FAULT;
}
catch
{
State = VMState.FAULT;
}
}
}

protected virtual void LoadContext(ExecutionContext context)
{
if (InvocationStack.Count >= MaxInvocationStackSize)
Expand Down
9 changes: 9 additions & 0 deletions src/neo-vm/Instruction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ public int TokenI32
}
}

public sbyte TokenI8
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return (sbyte)Operand.Span[0];
}
}

public string TokenString
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
Loading