diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitOperator.java b/src/main/java/org/perlonjava/backend/jvm/EmitOperator.java index 08867fc82..7cecf6518 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitOperator.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitOperator.java @@ -541,9 +541,31 @@ static void handleGlobBuiltin(EmitterVisitor emitterVisitor, OperatorNode node) // Handles the 'range' operator, which creates a range of values. static void handleRangeOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node) { - // Accept both left and right operands in SCALAR context. - node.left.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); - node.right.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); + // Spill the left operand before evaluating the right side so non-local control flow + // propagation can't jump to returnLabel with an extra value on the JVM operand stack. + if (ENABLE_SPILL_BINARY_LHS) { + MethodVisitor mv = emitterVisitor.ctx.mv; + node.left.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); + + int leftSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); + boolean pooled = leftSlot >= 0; + if (!pooled) { + leftSlot = emitterVisitor.ctx.symbolTable.allocateLocalVariable(); + } + mv.visitVarInsn(Opcodes.ASTORE, leftSlot); + + node.right.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); + + mv.visitVarInsn(Opcodes.ALOAD, leftSlot); + mv.visitInsn(Opcodes.SWAP); + + if (pooled) { + emitterVisitor.ctx.javaClassInfo.releaseSpillSlot(); + } + } else { + node.left.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); + node.right.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); + } emitOperator(node, emitterVisitor); }