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

Commit

Permalink
New slot opcodes (#264)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikzhang committed Dec 14, 2019
1 parent 94bab92 commit 8b9b914
Show file tree
Hide file tree
Showing 62 changed files with 3,918 additions and 746 deletions.
16 changes: 8 additions & 8 deletions src/neo-vm/ExecutionContext.cs
Expand Up @@ -25,10 +25,11 @@ public sealed class ExecutionContext
/// </summary>
public EvaluationStack EvaluationStack { get; }

/// <summary>
/// Alternative stack
/// </summary>
public EvaluationStack AltStack { get; }
public Slot StaticFields { get; internal set; }

public Slot LocalVariables { get; internal set; }

public Slot Arguments { get; internal set; }

/// <summary>
/// Instruction pointer
Expand Down Expand Up @@ -62,22 +63,21 @@ public Instruction NextInstruction
/// <param name="script">Script</param>
/// <param name="rvcount">Number of items to be returned</param>
internal ExecutionContext(Script script, int rvcount, ReferenceCounter referenceCounter)
: this(script, rvcount, new EvaluationStack(referenceCounter), new EvaluationStack(referenceCounter), new Dictionary<Type, object>())
: this(script, rvcount, new EvaluationStack(referenceCounter), new Dictionary<Type, object>())
{
}

private ExecutionContext(Script script, int rvcount, EvaluationStack stack, EvaluationStack alt, Dictionary<Type, object> states)
private ExecutionContext(Script script, int rvcount, EvaluationStack stack, Dictionary<Type, object> states)
{
this.RVCount = rvcount;
this.Script = script;
this.EvaluationStack = stack;
this.AltStack = alt;
this.states = states;
}

internal ExecutionContext Clone()
{
return new ExecutionContext(Script, 0, EvaluationStack, AltStack, states);
return new ExecutionContext(Script, 0, EvaluationStack, states) { StaticFields = StaticFields };
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
156 changes: 141 additions & 15 deletions src/neo-vm/ExecutionEngine.cs
Expand Up @@ -311,10 +311,12 @@ private bool ExecuteInstruction()
if (rvcount > 0)
context_pop.EvaluationStack.CopyTo(stack_eval);
}
if (InvocationStack.Count == 0 || context_pop.AltStack != CurrentContext.AltStack)
if (InvocationStack.Count == 0 || context_pop.StaticFields != CurrentContext.StaticFields)
{
context_pop.AltStack.Clear();
context_pop.StaticFields?.ClearReferences();
}
context_pop.LocalVariables?.ClearReferences();
context_pop.Arguments?.ClearReferences();
if (InvocationStack.Count == 0)
{
State = VMState.HALT;
Expand Down Expand Up @@ -419,32 +421,139 @@ private bool ExecuteInstruction()
if (!context.EvaluationStack.Reverse((int)n.ToBigInteger())) return false;
break;
}
case OpCode.DUPFROMALTSTACKBOTTOM:
case OpCode.ISNULL:
{
Push(context.AltStack.Peek(-1));
if (!TryPop(out StackItem x)) return false;
Push(x.IsNull);
break;
}
case OpCode.DUPFROMALTSTACK:

//Slot
case OpCode.INITSSLOT:
{
Push(context.AltStack.Peek());
if (context.StaticFields != null) return false;
if (instruction.TokenU8 == 0) return false;
context.StaticFields = new Slot(instruction.TokenU8, ReferenceCounter);
break;
}
case OpCode.TOALTSTACK:
case OpCode.INITSLOT:
{
if (!TryPop(out StackItem x)) return false;
context.AltStack.Push(x);
if (context.LocalVariables != null || context.Arguments != null) return false;
if (instruction.TokenU16 == 0) return false;
if (instruction.TokenU8 > 0)
{
context.LocalVariables = new Slot(instruction.TokenU8, ReferenceCounter);
}
if (instruction.TokenU8_1 > 0)
{
StackItem[] items = new StackItem[instruction.TokenU8_1];
for (int i = instruction.TokenU8_1 - 1; i >= 0; i--)
if (!TryPop(out items[i]))
return false;
context.Arguments = new Slot(items, ReferenceCounter);
}
break;
}
case OpCode.FROMALTSTACK:
case OpCode.LDSFLD0:
case OpCode.LDSFLD1:
case OpCode.LDSFLD2:
case OpCode.LDSFLD3:
case OpCode.LDSFLD4:
case OpCode.LDSFLD5:
case OpCode.LDSFLD6:
{
if (!context.AltStack.TryPop(out StackItem x)) return false;
Push(x);
if (!ExecuteLoadFromSlot(context.StaticFields, instruction.OpCode - OpCode.LDSFLD0))
return false;
break;
}
case OpCode.ISNULL:
case OpCode.LDSFLD:
{
if (!TryPop(out StackItem x)) return false;
Push(x.IsNull);
if (!ExecuteLoadFromSlot(context.StaticFields, instruction.TokenU8)) return false;
break;
}
case OpCode.STSFLD0:
case OpCode.STSFLD1:
case OpCode.STSFLD2:
case OpCode.STSFLD3:
case OpCode.STSFLD4:
case OpCode.STSFLD5:
case OpCode.STSFLD6:
{
if (!ExecuteStoreToSlot(context.StaticFields, instruction.OpCode - OpCode.STSFLD0))
return false;
break;
}
case OpCode.STSFLD:
{
if (!ExecuteStoreToSlot(context.StaticFields, instruction.TokenU8)) return false;
break;
}
case OpCode.LDLOC0:
case OpCode.LDLOC1:
case OpCode.LDLOC2:
case OpCode.LDLOC3:
case OpCode.LDLOC4:
case OpCode.LDLOC5:
case OpCode.LDLOC6:
{
if (!ExecuteLoadFromSlot(context.LocalVariables, instruction.OpCode - OpCode.LDLOC0))
return false;
break;
}
case OpCode.LDLOC:
{
if (!ExecuteLoadFromSlot(context.LocalVariables, instruction.TokenU8)) return false;
break;
}
case OpCode.STLOC0:
case OpCode.STLOC1:
case OpCode.STLOC2:
case OpCode.STLOC3:
case OpCode.STLOC4:
case OpCode.STLOC5:
case OpCode.STLOC6:
{
if (!ExecuteStoreToSlot(context.LocalVariables, instruction.OpCode - OpCode.STLOC0))
return false;
break;
}
case OpCode.STLOC:
{
if (!ExecuteStoreToSlot(context.LocalVariables, instruction.TokenU8)) return false;
break;
}
case OpCode.LDARG0:
case OpCode.LDARG1:
case OpCode.LDARG2:
case OpCode.LDARG3:
case OpCode.LDARG4:
case OpCode.LDARG5:
case OpCode.LDARG6:
{
if (!ExecuteLoadFromSlot(context.Arguments, instruction.OpCode - OpCode.LDARG0))
return false;
break;
}
case OpCode.LDARG:
{
if (!ExecuteLoadFromSlot(context.Arguments, instruction.TokenU8)) return false;
break;
}
case OpCode.STARG0:
case OpCode.STARG1:
case OpCode.STARG2:
case OpCode.STARG3:
case OpCode.STARG4:
case OpCode.STARG5:
case OpCode.STARG6:
{
if (!ExecuteStoreToSlot(context.Arguments, instruction.OpCode - OpCode.STARG0))
return false;
break;
}
case OpCode.STARG:
{
if (!ExecuteStoreToSlot(context.Arguments, instruction.TokenU8)) return false;
break;
}

Expand Down Expand Up @@ -984,6 +1093,14 @@ private bool ExecuteJump(bool condition, int offset)
return true;
}

private bool ExecuteLoadFromSlot(Slot slot, int index)
{
if (slot is null) return false;
if (index < 0 || index >= slot.Count) return false;
Push(slot[index]);
return true;
}

internal protected void ExecuteNext()
{
if (InvocationStack.Count == 0)
Expand All @@ -1005,6 +1122,15 @@ internal protected void ExecuteNext()
}
}

private bool ExecuteStoreToSlot(Slot slot, int index)
{
if (slot is null) return false;
if (index < 0 || index >= slot.Count) return false;
if (!TryPop(out StackItem item)) return false;
slot[index] = item;
return true;
}

protected virtual void LoadContext(ExecutionContext context)
{
if (InvocationStack.Count >= MaxInvocationStackSize)
Expand Down
27 changes: 27 additions & 0 deletions src/neo-vm/Instruction.cs
Expand Up @@ -66,6 +66,15 @@ public string TokenString
}
}

public ushort TokenU16
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return BinaryPrimitives.ReadUInt16LittleEndian(Operand.Span);
}
}

public uint TokenU32
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -75,6 +84,24 @@ public uint TokenU32
}
}

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

public byte TokenU8_1
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return Operand.Span[1];
}
}

static Instruction()
{
foreach (FieldInfo field in typeof(OpCode).GetFields(BindingFlags.Public | BindingFlags.Static))
Expand Down

0 comments on commit 8b9b914

Please sign in to comment.