public void TestEmitJump() { var offset_i8 = sbyte.MaxValue; var offset_i32 = int.MaxValue; foreach (OpCode op in Enum.GetValues(typeof(OpCode))) { using (var script = new ScriptBuilder()) { if (op < OpCode.JMP || op > OpCode.JMPLE_L) { Assert.ThrowsException <ArgumentOutOfRangeException>(() => script.EmitJump(op, offset_i8)); Assert.ThrowsException <ArgumentOutOfRangeException>(() => script.EmitJump(op, offset_i32)); } else { script.EmitJump(op, offset_i8); script.EmitJump(op, offset_i32); if ((int)op % 2 == 0) { CollectionAssert.AreEqual(new[] { (byte)op, (byte)offset_i8, (byte)(op + 1) }.Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); } else { CollectionAssert.AreEqual(new[] { (byte)op }.Concat(BitConverter.GetBytes((int)offset_i8)).Concat(new[] { (byte)op }).Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); } } } } offset_i8 = sbyte.MinValue; offset_i32 = int.MinValue; foreach (OpCode op in Enum.GetValues(typeof(OpCode))) { using (var script = new ScriptBuilder()) { if (op < OpCode.JMP || op > OpCode.JMPLE_L) { Assert.ThrowsException <ArgumentOutOfRangeException>(() => script.EmitJump(op, offset_i8)); Assert.ThrowsException <ArgumentOutOfRangeException>(() => script.EmitJump(op, offset_i32)); } else { script.EmitJump(op, offset_i8); script.EmitJump(op, offset_i32); if ((int)op % 2 == 0) { CollectionAssert.AreEqual(new[] { (byte)op, (byte)offset_i8, (byte)(op + 1) }.Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); } else { CollectionAssert.AreEqual(new[] { (byte)op }.Concat(BitConverter.GetBytes((int)offset_i8)).Concat(new[] { (byte)op }).Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); } } } } }
public void TestBreakPointStepOver() { using (var engine = new ExecutionEngine(null, Crypto.Default, null, null)) using (var script = new ScriptBuilder()) { /* ┌ */ script.EmitJump(OpCode.CALL, 5); /* │ ┌> */ script.Emit(OpCode.NOT); /* │ │ */ script.Emit(OpCode.RET); /* └>X│ */ script.Emit(OpCode.PUSH0); /* └┘ */ script.Emit(OpCode.RET); engine.LoadScript(script.ToArray()); var debugger = new Debugger(engine); debugger.AddBreakPoint(engine.CurrentContext.ScriptHash, 5); debugger.StepOver(); Assert.AreEqual(5, engine.CurrentContext.InstructionPointer); Assert.AreEqual(VMState.BREAK, engine.State); debugger.Execute(); Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); Assert.AreEqual(VMState.HALT, engine.State); } }
public void TestEmitJump() { var offset = RandomHelper.RandInt16(); foreach (OpCode op in Enum.GetValues(typeof(OpCode))) { using (var script = new ScriptBuilder()) { if (op != OpCode.JMP && op != OpCode.JMPIF && op != OpCode.JMPIFNOT && op != OpCode.CALL) { Assert.ThrowsException <ArgumentException>(() => script.EmitJump(op, offset)); } else { script.EmitJump(op, offset); CollectionAssert.AreEqual(new byte[] { (byte)op }.Concat(BitConverter.GetBytes(offset)).ToArray(), script.ToArray()); } } } }
public void TestStepInto() { using (var engine = new ExecutionEngine()) using (var script = new ScriptBuilder()) { /* ┌ CALL * │ ┌> NOT * │ │ RET * └> │ PUSH0 * └─┘ RET */ script.EmitJump(OpCode.CALL, 5); script.Emit(OpCode.NOT); script.Emit(OpCode.RET); script.Emit(OpCode.PUSH0); script.Emit(OpCode.RET); engine.LoadScript(script.ToArray()); var debugger = new Debugger(engine); var context = engine.CurrentContext; Assert.AreEqual(context, engine.CurrentContext); Assert.AreEqual(context, engine.EntryContext); Assert.IsNull(engine.CurrentContext.CallingScript); Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); Assert.AreEqual(VMState.BREAK, debugger.StepInto()); Assert.AreNotEqual(context, engine.CurrentContext); Assert.AreEqual(context, engine.EntryContext); Assert.AreEqual(engine.EntryContext.Script, engine.CurrentContext.CallingScript); Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); Assert.AreEqual(VMState.BREAK, debugger.StepInto()); Assert.AreEqual(VMState.BREAK, debugger.StepInto()); Assert.AreEqual(context, engine.CurrentContext); Assert.AreEqual(context, engine.EntryContext); Assert.IsNull(engine.CurrentContext.CallingScript); Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); Assert.AreEqual(VMState.BREAK, debugger.StepInto()); Assert.AreEqual(VMState.HALT, debugger.StepInto()); Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); Assert.AreEqual(VMState.HALT, engine.State); // Test step into again Assert.AreEqual(VMState.HALT, debugger.StepInto()); Assert.AreEqual(VMState.HALT, engine.State); } }
public void Test_Optimize_ConstExecution_ROT() { using (var scriptBefore = new ScriptBuilder()) { scriptBefore.Emit(VM.OpCode.PUSH1); scriptBefore.Emit(VM.OpCode.PUSH2); scriptBefore.Emit(VM.OpCode.PUSH3); scriptBefore.Emit(VM.OpCode.ROT); using (var scriptAfter = new ScriptBuilder()) { scriptAfter.Emit(VM.OpCode.PUSH2); scriptAfter.Emit(VM.OpCode.PUSH3); scriptAfter.Emit(VM.OpCode.PUSH1); var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty <int>(), OptimizeParserType.DELETE_CONST_EXECUTION); CollectionAssert.AreEqual(scriptAfter.ToArray(), optimized); } } using (var scriptBefore = new ScriptBuilder()) { scriptBefore.Emit(VM.OpCode.PUSH1); scriptBefore.Emit(VM.OpCode.PUSH2); scriptBefore.Emit(VM.OpCode.PUSHNULL); scriptBefore.Emit(VM.OpCode.ROT); using (var scriptAfter = new ScriptBuilder()) { scriptAfter.Emit(VM.OpCode.PUSH2); scriptAfter.Emit(VM.OpCode.PUSHNULL); scriptAfter.Emit(VM.OpCode.PUSH1); var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty <int>(), OptimizeParserType.DELETE_CONST_EXECUTION); CollectionAssert.AreEqual(scriptAfter.ToArray(), optimized); } } using (var scriptBefore = new ScriptBuilder()) { scriptBefore.Emit(VM.OpCode.PUSH5); scriptBefore.Emit(VM.OpCode.PUSH4); scriptBefore.EmitJump(VM.OpCode.JMP, 3); scriptBefore.Emit(VM.OpCode.PUSH1); scriptBefore.Emit(VM.OpCode.PUSH2); scriptBefore.Emit(VM.OpCode.PUSH3); scriptBefore.Emit(VM.OpCode.ROT); var optimized = NefOptimizeTool.Optimize(scriptBefore.ToArray(), Array.Empty <int>(), OptimizeParserType.DELETE_CONST_EXECUTION); CollectionAssert.AreEqual(scriptBefore.ToArray(), optimized); } }
private void ProcessJump(ScriptBuilder sb) { if (Arguments.Length != 1) { throw new CompilerException(LineNumber, ERR_INCORRECT_NUMBER); } if (!Arguments[0].IsLabel()) { throw new CompilerException(LineNumber, ERR_INVALID_ARGUMENT); } else { sb.EmitJump(Opcode.JMP, Arguments[0].AsLabel()); } }
private void InsertJump(Instruction i, VM.Opcode opcode) { byte reg; // for conditional jumps, fetch the appropriate register for the conditional value if (opcode != VM.Opcode.JMP) { reg = FetchRegister(i.a.target); } else { reg = 0; } _output.EmitJump(opcode, i.b.target, reg); }
public void TestStepInto() { using (var engine = new ExecutionEngine()) using (var script = new ScriptBuilder()) { /* ┌ */ script.EmitJump(OpCode.CALL, 5); /* │ ┌> */ script.Emit(OpCode.NOT); /* │ │ */ script.Emit(OpCode.RET); /* └> │ */ script.Emit(OpCode.PUSH0); /* └─┘ */ script.Emit(OpCode.RET); engine.LoadScript(script.ToArray()); var debugger = new Debugger(engine); var context = engine.CurrentContext; Assert.AreEqual(context, engine.CurrentContext); Assert.AreEqual(context, engine.EntryContext); debugger.StepInto(); Assert.AreNotEqual(context, engine.CurrentContext); Assert.AreEqual(context, engine.EntryContext); debugger.StepInto(); debugger.StepInto(); Assert.AreEqual(context, engine.CurrentContext); Assert.AreEqual(context, engine.EntryContext); debugger.StepInto(); debugger.StepInto(); Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); Assert.AreEqual(VMState.HALT, engine.State); } }
public void TestBreakPointStepOver() { using (var engine = new ExecutionEngine()) using (var script = new ScriptBuilder()) { /* ┌ CALL * │ ┌> NOT * │ │ RET * └>X│ PUSH0 * └┘ RET */ script.EmitJump(OpCode.CALL, 5); script.Emit(OpCode.NOT); script.Emit(OpCode.RET); script.Emit(OpCode.PUSH0); script.Emit(OpCode.RET); engine.LoadScript(script.ToArray()); var debugger = new Debugger(engine); Assert.IsNull(engine.CurrentContext.CallingScript); Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); debugger.AddBreakPoint(engine.CurrentContext.Script, 5); Assert.AreEqual(VMState.BREAK, debugger.StepOver()); Assert.AreEqual(engine.EntryContext.Script, engine.CurrentContext.CallingScript); Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); Assert.AreEqual(5, engine.CurrentContext.InstructionPointer); Assert.AreEqual(VMState.BREAK, engine.State); debugger.Execute(); Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); Assert.AreEqual(VMState.HALT, engine.State); } }
public void TestStepOver() { using (var engine = new ExecutionEngine()) using (var script = new ScriptBuilder()) { /* ┌ */ script.EmitJump(OpCode.CALL, 5); /* │ ┌> */ script.Emit(OpCode.NOT); /* │ │ */ script.Emit(OpCode.RET); /* └> │ */ script.Emit(OpCode.PUSH0); /* └─┘ */ script.Emit(OpCode.RET); engine.LoadScript(script.ToArray()); var debugger = new Debugger(engine); Assert.IsNull(engine.CurrentContext.CallingScript); Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); Assert.AreEqual(VMState.BREAK, debugger.StepOver()); Assert.IsNull(engine.CurrentContext.CallingScript); Assert.AreEqual(3, engine.CurrentContext.InstructionPointer); Assert.AreEqual(VMState.BREAK, engine.State); Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); debugger.Execute(); Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); Assert.AreEqual(VMState.HALT, engine.State); // Test step over again Assert.AreEqual(VMState.HALT, debugger.StepOver()); Assert.AreEqual(VMState.HALT, engine.State); } }