@@ -99,6 +99,44 @@ public static void emitBlock(EmitterVisitor emitterVisitor, BlockNode node) {
9999 element .accept (voidVisitor );
100100 }
101101
102+ // Check for non-local control flow after each statement in labeled blocks
103+ // Only for simple blocks to avoid ASM VerifyError
104+ if (node .isLoop && node .labelName != null && i < list .size () - 1 && list .size () <= 3 ) {
105+ // Check if block contains loop constructs (they handle their own control flow)
106+ boolean hasLoopConstruct = false ;
107+ for (Node elem : list ) {
108+ if (elem instanceof For1Node || elem instanceof For3Node ) {
109+ hasLoopConstruct = true ;
110+ break ;
111+ }
112+ }
113+
114+ if (!hasLoopConstruct ) {
115+ Label continueBlock = new Label ();
116+
117+ // if (!RuntimeControlFlowRegistry.hasMarker()) continue
118+ mv .visitMethodInsn (Opcodes .INVOKESTATIC ,
119+ "org/perlonjava/runtime/RuntimeControlFlowRegistry" ,
120+ "hasMarker" ,
121+ "()Z" ,
122+ false );
123+ mv .visitJumpInsn (Opcodes .IFEQ , continueBlock );
124+
125+ // Has marker: check if it matches this loop
126+ mv .visitLdcInsn (node .labelName );
127+ mv .visitMethodInsn (Opcodes .INVOKESTATIC ,
128+ "org/perlonjava/runtime/RuntimeControlFlowRegistry" ,
129+ "checkLoopAndGetAction" ,
130+ "(Ljava/lang/String;)I" ,
131+ false );
132+
133+ // If action != 0, jump to nextLabel (exit block)
134+ mv .visitJumpInsn (Opcodes .IFNE , nextLabel );
135+
136+ mv .visitLabel (continueBlock );
137+ }
138+ }
139+
102140 // NOTE: Registry checks are DISABLED in EmitBlock because:
103141 // 1. They cause ASM frame computation errors in nested/refactored code
104142 // 2. Bare labeled blocks (like TODO:) don't need non-local control flow
0 commit comments