increase size of jump operands (#438)

* [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)

* update test cases

* update test cases

---------

Co-authored-by: 王录祥 <wanglx@smartsteps.com>
This commit is contained in:
wlxwlxwlx 2023-12-21 02:13:23 +08:00 committed by GitHub
parent da09c300a5
commit 18b953c7be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 38 deletions

View file

@ -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),
@ -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),

View file

@ -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
}

View file

@ -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
}

14
vm.go
View file

@ -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