From 223554f30dab5d7de708b8bb695c624d564bdb69 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=8B=E5=BD=95=E7=A5=A5?= <wanglx@smartsteps.com>
Date: Tue, 10 Oct 2023 16:53:00 +0800
Subject: [PATCH 1/3] [OpJumpFalse, OpAndJump, OpOrJump, OpJump], these four
 instructions have been changed to use 4 bytes to avoid precision loss and
 panic when the number of instructions exceeds the maximum of 16 bits (65535)

---
 instructions.go   |  6 ++++++
 parser/opcodes.go | 10 ++++++----
 vm.go             | 14 +++++++-------
 3 files changed, 19 insertions(+), 11 deletions(-)

diff --git a/instructions.go b/instructions.go
index eb1fbf27..27f7af39 100644
--- a/instructions.go
+++ b/instructions.go
@@ -28,6 +28,12 @@ func MakeInstruction(opcode parser.Opcode, operands ...int) []byte {
 			n := uint16(o)
 			instruction[offset] = byte(n >> 8)
 			instruction[offset+1] = byte(n)
+		case 4:
+			n := uint32(o)
+			instruction[offset] = byte(n >> 24)
+			instruction[offset+1] = byte(n >> 16)
+			instruction[offset+2] = byte(n >> 8)
+			instruction[offset+3] = byte(n)
 		}
 		offset += width
 	}
diff --git a/parser/opcodes.go b/parser/opcodes.go
index d97f4896..c1e94c1f 100644
--- a/parser/opcodes.go
+++ b/parser/opcodes.go
@@ -106,10 +106,10 @@ var OpcodeOperands = [...][]int{
 	OpNotEqual:      {},
 	OpMinus:         {},
 	OpLNot:          {},
-	OpJumpFalsy:     {2},
-	OpAndJump:       {2},
-	OpOrJump:        {2},
-	OpJump:          {2},
+	OpJumpFalsy:     {4},
+	OpAndJump:       {4},
+	OpOrJump:        {4},
+	OpJump:          {4},
 	OpNull:          {},
 	OpGetGlobal:     {2},
 	OpSetGlobal:     {2},
@@ -149,6 +149,8 @@ func ReadOperands(numOperands []int, ins []byte) (operands []int, offset int) {
 			operands = append(operands, int(ins[offset]))
 		case 2:
 			operands = append(operands, int(ins[offset+1])|int(ins[offset])<<8)
+		case 4:
+			operands = append(operands, int(ins[offset+3])|int(ins[offset+2])<<8|int(ins[offset+1])<<16|int(ins[offset])<<24)
 		}
 		offset += width
 	}
diff --git a/vm.go b/vm.go
index 64bd23bc..2f8f6fc5 100644
--- a/vm.go
+++ b/vm.go
@@ -218,30 +218,30 @@ func (v *VM) run() {
 				return
 			}
 		case parser.OpJumpFalsy:
-			v.ip += 2
+			v.ip += 4
 			v.sp--
 			if v.stack[v.sp].IsFalsy() {
-				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8
+				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8 | int(v.curInsts[v.ip-2])<<16 | int(v.curInsts[v.ip-3])<<24
 				v.ip = pos - 1
 			}
 		case parser.OpAndJump:
-			v.ip += 2
+			v.ip += 4
 			if v.stack[v.sp-1].IsFalsy() {
-				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8
+				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8 | int(v.curInsts[v.ip-2])<<16 | int(v.curInsts[v.ip-3])<<24
 				v.ip = pos - 1
 			} else {
 				v.sp--
 			}
 		case parser.OpOrJump:
-			v.ip += 2
+			v.ip += 4
 			if v.stack[v.sp-1].IsFalsy() {
 				v.sp--
 			} else {
-				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8
+				pos := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8 | int(v.curInsts[v.ip-2])<<16 | int(v.curInsts[v.ip-3])<<24
 				v.ip = pos - 1
 			}
 		case parser.OpJump:
-			pos := int(v.curInsts[v.ip+2]) | int(v.curInsts[v.ip+1])<<8
+			pos := int(v.curInsts[v.ip+4]) | int(v.curInsts[v.ip+3])<<8 | int(v.curInsts[v.ip+2])<<16 | int(v.curInsts[v.ip+1])<<24
 			v.ip = pos - 1
 		case parser.OpSetGlobal:
 			v.ip += 2

From 8572e8f2d1a4f554fe7bd4eb9001f3c704e3dfbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=8B=E5=BD=95=E7=A5=A5?= <wanglx@smartsteps.com>
Date: Tue, 19 Dec 2023 18:22:44 +0800
Subject: [PATCH 2/3] update test cases

---
 compiler_test.go | 38 +++++++++++++++++++-------------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/compiler_test.go b/compiler_test.go
index 28cc901b..077d0adb 100644
--- a/compiler_test.go
+++ b/compiler_test.go
@@ -204,11 +204,11 @@ func TestCompiler_Compile(t *testing.T) {
 	expectCompile(t, `if true { 10 }; 3333`,
 		bytecode(
 			concatInsts(
-				tengo.MakeInstruction(parser.OpTrue),         // 0000
-				tengo.MakeInstruction(parser.OpJumpFalsy, 8), // 0001
-				tengo.MakeInstruction(parser.OpConstant, 0),  // 0004
-				tengo.MakeInstruction(parser.OpPop),          // 0007
-				tengo.MakeInstruction(parser.OpConstant, 1),  // 0008
+				tengo.MakeInstruction(parser.OpTrue),          // 0000
+				tengo.MakeInstruction(parser.OpJumpFalsy, 10), // 0001
+				tengo.MakeInstruction(parser.OpConstant, 0),   // 0004
+				tengo.MakeInstruction(parser.OpPop),           // 0007
+				tengo.MakeInstruction(parser.OpConstant, 1),   // 0008
 				tengo.MakeInstruction(parser.OpPop),
 				tengo.MakeInstruction(parser.OpSuspend)), // 0011
 			objectsArray(
@@ -219,10 +219,10 @@ func TestCompiler_Compile(t *testing.T) {
 		bytecode(
 			concatInsts(
 				tengo.MakeInstruction(parser.OpTrue),          // 0000
-				tengo.MakeInstruction(parser.OpJumpFalsy, 11), // 0001
+				tengo.MakeInstruction(parser.OpJumpFalsy, 15), // 0001
 				tengo.MakeInstruction(parser.OpConstant, 0),   // 0004
 				tengo.MakeInstruction(parser.OpPop),           // 0007
-				tengo.MakeInstruction(parser.OpJump, 15),      // 0008
+				tengo.MakeInstruction(parser.OpJump, 19),      // 0008
 				tengo.MakeInstruction(parser.OpConstant, 1),   // 0011
 				tengo.MakeInstruction(parser.OpPop),           // 0014
 				tengo.MakeInstruction(parser.OpConstant, 2),   // 0015
@@ -577,12 +577,12 @@ func TestCompiler_Compile(t *testing.T) {
 				intObject(1),
 				intObject(2),
 				compiledFunction(0, 0,
-					tengo.MakeInstruction(parser.OpTrue),         // 0000
-					tengo.MakeInstruction(parser.OpJumpFalsy, 9), // 0001
-					tengo.MakeInstruction(parser.OpConstant, 0),  // 0004
-					tengo.MakeInstruction(parser.OpReturn, 1),    // 0007
-					tengo.MakeInstruction(parser.OpConstant, 1),  // 0009
-					tengo.MakeInstruction(parser.OpReturn, 1))))) // 0012
+					tengo.MakeInstruction(parser.OpTrue),          // 0000
+					tengo.MakeInstruction(parser.OpJumpFalsy, 11), // 0001
+					tengo.MakeInstruction(parser.OpConstant, 0),   // 0004
+					tengo.MakeInstruction(parser.OpReturn, 1),     // 0007
+					tengo.MakeInstruction(parser.OpConstant, 1),   // 0009
+					tengo.MakeInstruction(parser.OpReturn, 1)))))  // 0012
 
 	expectCompile(t, `func() { 1; if(true) { 2 } else { 3 }; 4 }`,
 		bytecode(
@@ -599,10 +599,10 @@ func TestCompiler_Compile(t *testing.T) {
 					tengo.MakeInstruction(parser.OpConstant, 0),   // 0000
 					tengo.MakeInstruction(parser.OpPop),           // 0003
 					tengo.MakeInstruction(parser.OpTrue),          // 0004
-					tengo.MakeInstruction(parser.OpJumpFalsy, 15), // 0005
+					tengo.MakeInstruction(parser.OpJumpFalsy, 19), // 0005
 					tengo.MakeInstruction(parser.OpConstant, 1),   // 0008
 					tengo.MakeInstruction(parser.OpPop),           // 0011
-					tengo.MakeInstruction(parser.OpJump, 19),      // 0012
+					tengo.MakeInstruction(parser.OpJump, 23),      // 0012
 					tengo.MakeInstruction(parser.OpConstant, 2),   // 0015
 					tengo.MakeInstruction(parser.OpPop),           // 0018
 					tengo.MakeInstruction(parser.OpConstant, 3),   // 0019
@@ -932,7 +932,7 @@ func() {
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpBinaryOp, 38),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 31),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 35),
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 2),
 				tengo.MakeInstruction(parser.OpBinaryOp, 11),
@@ -954,7 +954,7 @@ func() {
 				tengo.MakeInstruction(parser.OpSetGlobal, 1),
 				tengo.MakeInstruction(parser.OpGetGlobal, 1),
 				tengo.MakeInstruction(parser.OpIteratorNext),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 37),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 41),
 				tengo.MakeInstruction(parser.OpGetGlobal, 1),
 				tengo.MakeInstruction(parser.OpIteratorKey),
 				tengo.MakeInstruction(parser.OpSetGlobal, 2),
@@ -973,11 +973,11 @@ func() {
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 0),
 				tengo.MakeInstruction(parser.OpEqual),
-				tengo.MakeInstruction(parser.OpAndJump, 23),
+				tengo.MakeInstruction(parser.OpAndJump, 25),
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpNotEqual),
-				tengo.MakeInstruction(parser.OpOrJump, 34),
+				tengo.MakeInstruction(parser.OpOrJump, 38),
 				tengo.MakeInstruction(parser.OpGetGlobal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpBinaryOp, 38),

From 8c9101ef9018e8122f079c31cdb31e7716ffd4c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=8E=8B=E5=BD=95=E7=A5=A5?= <wanglx@smartsteps.com>
Date: Tue, 19 Dec 2023 18:35:11 +0800
Subject: [PATCH 3/3] update test cases

---
 compiler_test.go | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/compiler_test.go b/compiler_test.go
index 077d0adb..5caf2b03 100644
--- a/compiler_test.go
+++ b/compiler_test.go
@@ -1089,7 +1089,7 @@ func() {
 			intObject(4),
 			compiledFunction(0, 0,
 				tengo.MakeInstruction(parser.OpTrue),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 9),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 11),
 				tengo.MakeInstruction(parser.OpConstant, 0),
 				tengo.MakeInstruction(parser.OpReturn, 1),
 				tengo.MakeInstruction(parser.OpConstant, 1),
@@ -1123,7 +1123,7 @@ func() {
 				tengo.MakeInstruction(parser.OpGetLocal, 0),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpEqual),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 19),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 21),
 				tengo.MakeInstruction(parser.OpConstant, 2),
 				tengo.MakeInstruction(parser.OpReturn, 1),
 				tengo.MakeInstruction(parser.OpConstant, 1),
@@ -1156,7 +1156,7 @@ func() {
 			intObject(4),
 			compiledFunction(0, 0,
 				tengo.MakeInstruction(parser.OpTrue),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 9),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 11),
 				tengo.MakeInstruction(parser.OpConstant, 0),
 				tengo.MakeInstruction(parser.OpReturn, 1),
 				tengo.MakeInstruction(parser.OpConstant, 1),
@@ -1180,7 +1180,7 @@ func() {
 			intObject(123),
 			compiledFunction(0, 0,
 				tengo.MakeInstruction(parser.OpTrue),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 6),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 8),
 				tengo.MakeInstruction(parser.OpReturn, 0),
 				tengo.MakeInstruction(parser.OpReturn, 0),
 				tengo.MakeInstruction(parser.OpConstant, 0),
@@ -1200,12 +1200,12 @@ if a := 1; a {
 			tengo.MakeInstruction(parser.OpConstant, 0),
 			tengo.MakeInstruction(parser.OpSetGlobal, 0),
 			tengo.MakeInstruction(parser.OpGetGlobal, 0),
-			tengo.MakeInstruction(parser.OpJumpFalsy, 27),
+			tengo.MakeInstruction(parser.OpJumpFalsy, 31),
 			tengo.MakeInstruction(parser.OpConstant, 1),
 			tengo.MakeInstruction(parser.OpSetGlobal, 0),
 			tengo.MakeInstruction(parser.OpGetGlobal, 0),
 			tengo.MakeInstruction(parser.OpSetGlobal, 1),
-			tengo.MakeInstruction(parser.OpJump, 39),
+			tengo.MakeInstruction(parser.OpJump, 43),
 			tengo.MakeInstruction(parser.OpConstant, 2),
 			tengo.MakeInstruction(parser.OpSetGlobal, 0),
 			tengo.MakeInstruction(parser.OpGetGlobal, 0),
@@ -1238,12 +1238,12 @@ func() {
 				tengo.MakeInstruction(parser.OpConstant, 0),
 				tengo.MakeInstruction(parser.OpDefineLocal, 0),
 				tengo.MakeInstruction(parser.OpGetLocal, 0),
-				tengo.MakeInstruction(parser.OpJumpFalsy, 22),
+				tengo.MakeInstruction(parser.OpJumpFalsy, 26),
 				tengo.MakeInstruction(parser.OpConstant, 1),
 				tengo.MakeInstruction(parser.OpSetLocal, 0),
 				tengo.MakeInstruction(parser.OpGetLocal, 0),
 				tengo.MakeInstruction(parser.OpDefineLocal, 1),
-				tengo.MakeInstruction(parser.OpJump, 31),
+				tengo.MakeInstruction(parser.OpJump, 35),
 				tengo.MakeInstruction(parser.OpConstant, 2),
 				tengo.MakeInstruction(parser.OpSetLocal, 0),
 				tengo.MakeInstruction(parser.OpGetLocal, 0),