Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/main/java/org/perlonjava/codegen/EmitBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ public static void emitBlock(EmitterVisitor emitterVisitor, BlockNode node) {
nextLabel,
redoLabel,
nextLabel,
emitterVisitor.ctx.javaClassInfo.stackLevelManager.getStackLevel(),
emitterVisitor.ctx.contextType,
isBareBlock,
isBareBlock);
Expand Down
22 changes: 2 additions & 20 deletions src/main/java/org/perlonjava/codegen/EmitControlFlow.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,6 @@ static void handleNextOperator(EmitterContext ctx, OperatorNode node) {
return;
}

// Local control flow: use fast GOTO (existing code)
ctx.logDebug("visit(next): asmStackLevel: " + ctx.javaClassInfo.stackLevelManager.getStackLevel());

// Clean up the stack before jumping by popping values up to the loop's stack level
ctx.javaClassInfo.resetStackLevel();

// Handle return values based on context
if (loopLabels.context != RuntimeContextType.VOID) {
if (operator.equals("next") || operator.equals("last")) {
Expand Down Expand Up @@ -167,9 +161,6 @@ static void handleReturnOperator(EmitterVisitor emitterVisitor, OperatorNode nod
}
}

// Clean up tracked stack before return
ctx.javaClassInfo.resetStackLevel();

boolean hasOperand = !(node.operand == null || (node.operand instanceof ListNode list && list.elements.isEmpty()));

if (!hasOperand) {
Expand Down Expand Up @@ -204,9 +195,6 @@ static void handleGotoSubroutine(EmitterVisitor emitterVisitor, OperatorNode sub

ctx.logDebug("visit(goto &sub): Emitting TAILCALL marker");

// Clean up tracked stack before creating the marker
ctx.javaClassInfo.resetStackLevel();

subNode.accept(emitterVisitor.with(RuntimeContextType.SCALAR));
int codeRefSlot = ctx.javaClassInfo.acquireSpillSlot();
boolean pooledCodeRef = codeRefSlot >= 0;
Expand Down Expand Up @@ -332,8 +320,6 @@ static void handleGotoLabel(EmitterVisitor emitterVisitor, OperatorNode node) {
"(Lorg/perlonjava/runtime/RuntimeScalar;Lorg/perlonjava/runtime/RuntimeArray;Ljava/lang/String;I)V",
false);

ctx.javaClassInfo.resetStackLevel(); // Clean up stack before jumping

if (pooledTarget) {
ctx.javaClassInfo.releaseSpillSlot();
}
Expand Down Expand Up @@ -388,8 +374,7 @@ static void handleGotoLabel(EmitterVisitor emitterVisitor, OperatorNode node) {
}
ctx.mv.visitVarInsn(Opcodes.ASTORE, markerSlot);

// Clean stack and jump to returnLabel with the marker on stack.
ctx.javaClassInfo.resetStackLevel();
// Jump to returnLabel with the marker on stack.
ctx.mv.visitVarInsn(Opcodes.ALOAD, markerSlot);
if (pooledMarker) {
ctx.javaClassInfo.releaseSpillSlot();
Expand Down Expand Up @@ -437,8 +422,7 @@ static void handleGotoLabel(EmitterVisitor emitterVisitor, OperatorNode node) {
}
ctx.mv.visitVarInsn(Opcodes.ASTORE, markerSlot);

// Clean stack and jump to returnLabel with the marker on stack.
ctx.javaClassInfo.resetStackLevel();
// Jump to returnLabel with the marker on stack.
ctx.mv.visitVarInsn(Opcodes.ALOAD, markerSlot);
if (pooledMarker) {
ctx.javaClassInfo.releaseSpillSlot();
Expand All @@ -449,8 +433,6 @@ static void handleGotoLabel(EmitterVisitor emitterVisitor, OperatorNode node) {
}

// Local goto: use fast GOTO (existing code)
// Clean up stack before jumping to maintain stack consistency
ctx.javaClassInfo.resetStackLevel();

// Emit the goto instruction
ctx.mv.visitJumpInsn(Opcodes.GOTO, targetLabel.gotoLabel);
Expand Down
1 change: 0 additions & 1 deletion src/main/java/org/perlonjava/codegen/EmitForeach.java
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,6 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) {
continueLabel,
redoLabel,
loopEnd,
emitterVisitor.ctx.javaClassInfo.stackLevelManager.getStackLevel(),
RuntimeContextType.VOID);
currentLoopLabels.controlFlowHandler = controlFlowHandler;

Expand Down
7 changes: 0 additions & 7 deletions src/main/java/org/perlonjava/codegen/EmitLogicalOperator.java
Original file line number Diff line number Diff line change
Expand Up @@ -281,17 +281,10 @@ private static void emitLogicalOperatorSimple(EmitterVisitor emitterVisitor, Bin
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/RuntimeBase", getBoolean, "()Z", false);
mv.visitJumpInsn(compareOpcode, endLabel);

// The condition value has been consumed by getBoolean() and the conditional jump.
// Keep StackLevelManager in sync with the actual operand stack (empty) so that
// downstream non-local control flow (return/last/next/redo/goto) doesn't emit POPs
// based on stale stack accounting.
emitterVisitor.ctx.javaClassInfo.resetStackLevel();

node.right.accept(emitterVisitor.with(RuntimeContextType.SCALAR));
mv.visitInsn(Opcodes.POP);

mv.visitLabel(endLabel);
emitterVisitor.ctx.javaClassInfo.resetStackLevel();
return;
}

Expand Down
3 changes: 0 additions & 3 deletions src/main/java/org/perlonjava/codegen/EmitStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ public static void emitFor3(EmitterVisitor emitterVisitor, For3Node node) {
continueLabel,
redoLabel,
endLabel,
emitterVisitor.ctx.javaClassInfo.stackLevelManager.getStackLevel(),
RuntimeContextType.VOID,
true,
isUnlabeledTarget);
Expand Down Expand Up @@ -245,7 +244,6 @@ static void emitDoWhile(EmitterVisitor emitterVisitor, For3Node node) {
continueLabel,
redoLabel,
endLabel,
emitterVisitor.ctx.javaClassInfo.stackLevelManager.getStackLevel(),
RuntimeContextType.VOID,
false); // isTrueLoop = false (do-while is not a true loop)

Expand All @@ -266,7 +264,6 @@ static void emitDoWhile(EmitterVisitor emitterVisitor, For3Node node) {
continueLabel,
redoLabel,
endLabel,
emitterVisitor.ctx.javaClassInfo.stackLevelManager.getStackLevel(),
RuntimeContextType.VOID,
false);
emitRegistryCheck(mv, loopLabels, redoLabel, continueLabel, endLabel);
Expand Down
11 changes: 1 addition & 10 deletions src/main/java/org/perlonjava/codegen/EmitSubroutine.java
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,7 @@ static void handleApplyOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod
// If RuntimeCode.apply() returned a RuntimeControlFlowList marker, handle it here.
if (ENABLE_CONTROL_FLOW_CHECKS
&& emitterVisitor.ctx.javaClassInfo.returnLabel != null
&& emitterVisitor.ctx.javaClassInfo.controlFlowTempSlot >= 0
&& emitterVisitor.ctx.javaClassInfo.stackLevelManager.getStackLevel() <= 1) {
&& emitterVisitor.ctx.javaClassInfo.controlFlowTempSlot >= 0) {

Label notControlFlow = new Label();
Label propagateToCaller = new Label();
Expand All @@ -399,11 +398,6 @@ static void handleApplyOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod
emitterVisitor.ctx.javaClassInfo.storeSpillRef(mv, baseSpills[i]);
}

// We just removed the entire base stack from the JVM operand stack via ASTORE.
// Keep StackLevelManager in sync; otherwise later emitPopInstructions() may POP the wrong values
// (including control-flow markers), producing invalid stackmap frames.
emitterVisitor.ctx.javaClassInfo.resetStackLevel();

// Load and check if it's a control flow marker
mv.visitVarInsn(Opcodes.ALOAD, emitterVisitor.ctx.javaClassInfo.controlFlowTempSlot);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
Expand Down Expand Up @@ -463,7 +457,6 @@ static void handleApplyOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod
if (loopLabels.lastLabel == emitterVisitor.ctx.javaClassInfo.returnLabel) {
mv.visitJumpInsn(Opcodes.GOTO, propagateToCaller);
} else {
emitterVisitor.ctx.javaClassInfo.stackLevelManager.emitPopInstructions(mv, loopLabels.asmStackLevel);
if (loopLabels.context != RuntimeContextType.VOID) {
EmitOperator.emitUndef(mv);
}
Expand All @@ -478,7 +471,6 @@ static void handleApplyOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod
if (loopLabels.nextLabel == emitterVisitor.ctx.javaClassInfo.returnLabel) {
mv.visitJumpInsn(Opcodes.GOTO, propagateToCaller);
} else {
emitterVisitor.ctx.javaClassInfo.stackLevelManager.emitPopInstructions(mv, loopLabels.asmStackLevel);
if (loopLabels.context != RuntimeContextType.VOID) {
EmitOperator.emitUndef(mv);
}
Expand All @@ -490,7 +482,6 @@ static void handleApplyOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod
if (loopLabels.redoLabel == emitterVisitor.ctx.javaClassInfo.returnLabel) {
mv.visitJumpInsn(Opcodes.GOTO, propagateToCaller);
} else {
emitterVisitor.ctx.javaClassInfo.stackLevelManager.emitPopInstructions(mv, loopLabels.asmStackLevel);
mv.visitJumpInsn(Opcodes.GOTO, loopLabels.redoLabel);
}

Expand Down
10 changes: 1 addition & 9 deletions src/main/java/org/perlonjava/codegen/GotoLabels.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,15 @@ public class GotoLabels {
*/
public Label gotoLabel;

/**
* The stack level at the point where this label is defined
*/
public int asmStackLevel;

/**
* Creates a new GotoLabels instance.
*
* @param labelName The name of the label in source code
* @param gotoLabel The ASM Label object for bytecode generation
* @param asmStackLevel The stack level at label definition
*/
public GotoLabels(String labelName, Label gotoLabel, int asmStackLevel) {
public GotoLabels(String labelName, Label gotoLabel) {
this.labelName = labelName;
this.gotoLabel = gotoLabel;
this.asmStackLevel = asmStackLevel;
}

/**
Expand All @@ -46,7 +39,6 @@ public String toString() {
return "GotoLabels{" +
"labelName='" + labelName + '\'' +
", gotoLabel=" + gotoLabel +
", asmStackLevel=" + asmStackLevel +
'}';
}
}
27 changes: 6 additions & 21 deletions src/main/java/org/perlonjava/codegen/JavaClassInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,6 @@ public SpillRef(int slot, boolean pooled) {
}
}

/**
* Manages the stack level for the class.
*/
public StackLevelManager stackLevelManager;

/**
* A stack of loop labels for managing nested loops.
*/
Expand All @@ -84,7 +79,6 @@ public JavaClassInfo() {
this.javaClassName = EmitterMethodCreator.generateClassName();
this.returnLabel = null;
this.returnValueSlot = -1;
this.stackLevelManager = new StackLevelManager();
this.loopLabelStack = new ArrayDeque<>();
this.gotoLabelStack = new ArrayDeque<>();
this.spillSlots = new int[0];
Expand Down Expand Up @@ -143,7 +137,7 @@ public void releaseSpillRef(SpillRef ref) {
* @param lastLabel the label for exiting the loop
*/
public void pushLoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int context) {
loopLabelStack.push(new LoopLabels(labelName, nextLabel, redoLabel, lastLabel, stackLevelManager.getStackLevel(), context));
loopLabelStack.push(new LoopLabels(labelName, nextLabel, redoLabel, lastLabel, context));
}

/**
Expand All @@ -153,16 +147,15 @@ public void pushLoopLabels(String labelName, Label nextLabel, Label redoLabel, L
* @param nextLabel the label for the next iteration
* @param redoLabel the label for redoing the current iteration
* @param lastLabel the label for exiting the loop
* @param stackLevel the current stack level
* @param context the context type
* @param isTrueLoop whether this is a true loop (for/while/until) or pseudo-loop (do-while/bare)
*/
public void pushLoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int stackLevel, int context, boolean isTrueLoop) {
loopLabelStack.push(new LoopLabels(labelName, nextLabel, redoLabel, lastLabel, stackLevel, context, isTrueLoop));
public void pushLoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int context, boolean isTrueLoop) {
loopLabelStack.push(new LoopLabels(labelName, nextLabel, redoLabel, lastLabel, context, isTrueLoop));
}

public void pushLoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int stackLevel, int context, boolean isTrueLoop, boolean isUnlabeledControlFlowTarget) {
loopLabelStack.push(new LoopLabels(labelName, nextLabel, redoLabel, lastLabel, stackLevel, context, isTrueLoop, isUnlabeledControlFlowTarget));
public void pushLoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int context, boolean isTrueLoop, boolean isUnlabeledControlFlowTarget) {
loopLabelStack.push(new LoopLabels(labelName, nextLabel, redoLabel, lastLabel, context, isTrueLoop, isUnlabeledControlFlowTarget));
}

/**
Expand Down Expand Up @@ -242,7 +235,7 @@ public LoopLabels findInnermostTrueLoopLabels() {
}

public void pushGotoLabels(String labelName, Label gotoLabel) {
gotoLabelStack.push(new GotoLabels(labelName, gotoLabel, stackLevelManager.getStackLevel()));
gotoLabelStack.push(new GotoLabels(labelName, gotoLabel));
}

public GotoLabels findGotoLabelsByName(String labelName) {
Expand All @@ -258,13 +251,6 @@ public void popGotoLabels() {
gotoLabelStack.pop();
}

/**
* Resets the stack level to its initial state.
*/
public void resetStackLevel() {
stackLevelManager.reset();
}

/**
* Returns a string representation of the JavaClassInfo object.
*
Expand All @@ -275,7 +261,6 @@ public String toString() {
return "JavaClassInfo{\n" +
" javaClassName='" + javaClassName + "',\n" +
" returnLabel=" + (returnLabel != null ? returnLabel.toString() : "null") + ",\n" +
" asmStackLevel=" + stackLevelManager.getStackLevel() + ",\n" +
" loopLabelStack=" + loopLabelStack + "\n" +
" gotoLabelStack=" + gotoLabelStack + "\n" +
"}";
Expand Down
19 changes: 5 additions & 14 deletions src/main/java/org/perlonjava/codegen/LoopLabels.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,6 @@ public class LoopLabels {
*/
public int context;

/**
* The stack level at the point where these loop labels are defined
*/
public int asmStackLevel;

/**
* Whether this is a "true" loop (for/while/until) vs a pseudo-loop (do-while/bare block).
* True loops allow last/next/redo. Pseudo-loops cause compile errors.
Expand All @@ -70,11 +65,10 @@ public class LoopLabels {
* @param nextLabel The ASM Label for 'next' operations
* @param redoLabel The ASM Label for 'redo' operations
* @param lastLabel The ASM Label for 'last' operations
* @param asmStackLevel The stack level at label definition
* @param context The context type for this loop
*/
public LoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int asmStackLevel, int context) {
this(labelName, nextLabel, redoLabel, lastLabel, asmStackLevel, context, true, true);
public LoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int context) {
this(labelName, nextLabel, redoLabel, lastLabel, context, true, true);
}

/**
Expand All @@ -84,20 +78,18 @@ public LoopLabels(String labelName, Label nextLabel, Label redoLabel, Label last
* @param nextLabel The ASM Label for 'next' operations
* @param redoLabel The ASM Label for 'redo' operations
* @param lastLabel The ASM Label for 'last' operations
* @param asmStackLevel The stack level at label definition
* @param context The context type for this loop
* @param isTrueLoop Whether this is a true loop (for/while/until) or pseudo-loop (do-while/bare)
*/
public LoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int asmStackLevel, int context, boolean isTrueLoop) {
this(labelName, nextLabel, redoLabel, lastLabel, asmStackLevel, context, isTrueLoop, true);
public LoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int context, boolean isTrueLoop) {
this(labelName, nextLabel, redoLabel, lastLabel, context, isTrueLoop, true);
}

public LoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int asmStackLevel, int context, boolean isTrueLoop, boolean isUnlabeledControlFlowTarget) {
public LoopLabels(String labelName, Label nextLabel, Label redoLabel, Label lastLabel, int context, boolean isTrueLoop, boolean isUnlabeledControlFlowTarget) {
this.labelName = labelName;
this.nextLabel = nextLabel;
this.redoLabel = redoLabel;
this.lastLabel = lastLabel;
this.asmStackLevel = asmStackLevel;
this.context = context;
this.isTrueLoop = isTrueLoop;
this.isUnlabeledControlFlowTarget = isUnlabeledControlFlowTarget;
Expand All @@ -116,7 +108,6 @@ public String toString() {
", nextLabel=" + nextLabel +
", redoLabel=" + redoLabel +
", lastLabel=" + lastLabel +
", asmStackLevel=" + asmStackLevel +
", context=" + context +
'}';
}
Expand Down
Loading