diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java index ff65fc5f9cd..725c7f8063b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -1192,11 +1192,7 @@ public class Gen extends JCTree.Visitor { code.resolve(c.falseJumps); } } - Chain exit = loopEnv.info.exit; - if (exit != null) { - code.resolve(exit); - exit.state.defined.excludeFrom(code.nextreg); - } + code.resolve(loopEnv.info.exit); } public void visitForeachLoop(JCEnhancedForLoop tree) { @@ -1206,11 +1202,7 @@ public class Gen extends JCTree.Visitor { public void visitLabelled(JCLabeledStatement tree) { Env localEnv = env.dup(tree, new GenContext()); genStat(tree.body, localEnv, CRT_STATEMENT); - Chain exit = localEnv.info.exit; - if (exit != null) { - code.resolve(exit); - exit.state.defined.excludeFrom(code.nextreg); - } + code.resolve(localEnv.info.exit); } public void visitSwitch(JCSwitch tree) { @@ -1413,11 +1405,7 @@ public class Gen extends JCTree.Visitor { } // Resolve all breaks. - Chain exit = switchEnv.info.exit; - if (exit != null) { - code.resolve(exit); - exit.state.defined.excludeFrom(limit); - } + code.resolve(switchEnv.info.exit); // If we have not set the default offset, we do so now. if (code.get4(tableBase) == -1) { @@ -2537,7 +2525,14 @@ public class Gen extends JCTree.Visitor { /** code generation contexts, * to be used as type parameter for environments. */ - static class GenContext { + final class GenContext { + + /** + * The top defined local variables for exit or continue branches to merge into. + * It may contain uninitialized variables to be initialized by branched code, + * so we cannot use Code.State.defined bits. + */ + final int limit; /** A chain for all unresolved jumps that exit the current environment. */ @@ -2563,15 +2558,26 @@ public class Gen extends JCTree.Visitor { */ ListBuffer gaps = null; + GenContext() { + var code = Gen.this.code; + this.limit = code == null ? 0 : code.nextreg; + } + /** Add given chain to exit chain. */ void addExit(Chain c) { + if (c != null) { + c.state.defined.excludeFrom(limit); + } exit = Code.mergeChains(c, exit); } /** Add given chain to cont chain. */ void addCont(Chain c) { + if (c != null) { + c.state.defined.excludeFrom(limit); + } cont = Code.mergeChains(c, cont); } } diff --git a/test/langtools/tools/javac/flow/LVTHarness.java b/test/langtools/tools/javac/flow/LVTHarness.java index 7afe90c1991..996b611d304 100644 --- a/test/langtools/tools/javac/flow/LVTHarness.java +++ b/test/langtools/tools/javac/flow/LVTHarness.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -157,6 +157,7 @@ public class LVTHarness { if (i < infoFromRanges.size()) { error(infoFromLVT, infoFromRanges, method.methodName().stringValue()); + System.err.println(method.toDebugString()); } } diff --git a/test/langtools/tools/javac/BranchToFewerDefines.java b/test/langtools/tools/javac/stackmap/BranchToFewerDefines.java similarity index 97% rename from test/langtools/tools/javac/BranchToFewerDefines.java rename to test/langtools/tools/javac/stackmap/BranchToFewerDefines.java index dabdff64d32..7a0c69e4ae5 100644 --- a/test/langtools/tools/javac/BranchToFewerDefines.java +++ b/test/langtools/tools/javac/stackmap/BranchToFewerDefines.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8067429 + * @bug 8067429 8332934 * @summary java.lang.VerifyError: Inconsistent stackmap frames at branch target * @author srikanth * diff --git a/test/langtools/tools/javac/stackmap/DoLoopLocalEscapeThroughContinueTest.java b/test/langtools/tools/javac/stackmap/DoLoopLocalEscapeThroughContinueTest.java new file mode 100644 index 00000000000..dbc73ca73c0 --- /dev/null +++ b/test/langtools/tools/javac/stackmap/DoLoopLocalEscapeThroughContinueTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8332934 + * @summary Incorrect defined locals escaped from continue in do loop + * @library /tools/lib /test/lib + * @run main DoLoopLocalEscapeThroughContinueTest + */ + +import jdk.test.lib.ByteCodeLoader; +import jdk.test.lib.compiler.InMemoryJavaCompiler; + +import java.lang.classfile.ClassFile; +import java.lang.invoke.MethodHandles; + +public class DoLoopLocalEscapeThroughContinueTest { + public static void main(String... args) throws Throwable { + String source = """ + static void main(String[] k) { + do { + int b = 1; + continue; + } while (Math.random() > 0.5D) ; + switch (2) { + case 3: + double d; + case 4: + k.toString(); + } + } + """; + var bytes = InMemoryJavaCompiler.compile("Test", source, "-XDdebug.code"); + System.out.println(ClassFile.of().parse(bytes).toDebugString()); + var clz = ByteCodeLoader.load("Test", bytes); + MethodHandles.privateLookupIn(clz, MethodHandles.lookup()).ensureInitialized(clz); // force verification + } +} diff --git a/test/langtools/tools/javac/SwitchExitStateTest.java b/test/langtools/tools/javac/stackmap/SwitchExitStateTest.java similarity index 93% rename from test/langtools/tools/javac/SwitchExitStateTest.java rename to test/langtools/tools/javac/stackmap/SwitchExitStateTest.java index 4b9e0d61e07..74b443a5803 100644 --- a/test/langtools/tools/javac/SwitchExitStateTest.java +++ b/test/langtools/tools/javac/stackmap/SwitchExitStateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @bug 8160699 + * @bug 8160699 8332934 * @summary Verify that having finished executing a switch statement live locals are exactly the same as it was upon entry of the switch. * @run main SwitchExitStateTest */