diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 1350297ec3d..d76652edf36 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -166,8 +166,6 @@ Address | | | | Caller is still in the chunk. ************************************************/ -static const bool TEST_THAW_ONE_CHUNK_FRAME = false; // force thawing frames one-at-a-time for testing - #define CONT_JFR false // emit low-level JFR events that count slow/fast path for continuation performance debugging only #if CONT_JFR #define CONT_JFR_ONLY(code) code @@ -2306,7 +2304,7 @@ NOINLINE intptr_t* Thaw::thaw_fast(stackChunkOop chunk) { intptr_t* const chunk_sp = chunk->start_address() + chunk->sp(); bool partial, empty; - if (LIKELY(!TEST_THAW_ONE_CHUNK_FRAME && (full_chunk_size < threshold))) { + if (LIKELY(!ForceSingleFrameThaw && (full_chunk_size < threshold))) { prefetch_chunk_pd(chunk->start_address(), full_chunk_size); // prefetch anticipating memcpy starting at highest address partial = false; diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 80729c32a78..cd10a0174fa 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1903,6 +1903,9 @@ const int ObjectAlignmentInBytes = 8; develop(bool, UseContinuationFastPath, true, \ "Use fast-path frame walking in continuations") \ \ + develop(bool, ForceSingleFrameThaw, false, \ + "Force thawing one frame at a time") \ + \ develop(int, VerifyMetaspaceInterval, DEBUG_ONLY(500) NOT_DEBUG(0), \ "Run periodic metaspace verifications (0 - none, " \ "1 - always, >1 every nth interval)") \ diff --git a/test/jdk/jdk/internal/vm/Continuation/SingleFrameThaw.java b/test/jdk/jdk/internal/vm/Continuation/SingleFrameThaw.java new file mode 100644 index 00000000000..afdd71415ef --- /dev/null +++ b/test/jdk/jdk/internal/vm/Continuation/SingleFrameThaw.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2026, 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 id=Xcomp-noTieredCompilation + * @bug 8368175 + * @summary Exercise single frame thaw in fast path + * @requires vm.debug == true & vm.continuations + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @run main/othervm -XX:+ForceSingleFrameThaw -Xcomp -XX:-TieredCompilation SingleFrameThaw 1000 + */ + +/* + * @test id=Xcomp-TieredStopAtLevel3 + * @bug 8368175 + * @summary Exercise single frame thaw in fast path + * @requires vm.debug == true & vm.continuations + * @modules java.base/jdk.internal.vm + * @library /test/lib /test/hotspot/jtreg + * @run main/othervm -XX:+ForceSingleFrameThaw -Xcomp -XX:TieredStopAtLevel=3 SingleFrameThaw 1000 + */ + +import jdk.internal.vm.Continuation; +import jdk.internal.vm.ContinuationScope; + +import jdk.test.lib.Asserts; + +public class SingleFrameThaw { + static final ContinuationScope FOO = new ContinuationScope() {}; + static int counter; + + public static void main(String[] args) { + int iterations = args.length > 0 ? Integer.parseInt(args[0]) : 1000; + + Continuation cont = new Continuation(FOO, () -> { + for (int i = 0; i < iterations; i++) { + counter++; + Continuation.yield(FOO); + } + }); + + for (int i = 0; i < iterations; i++) { + Asserts.assertTrue(!cont.isDone(), "continuation done"); + cont.run(); + } + + Asserts.assertTrue(!cont.isDone(), "continuation done"); + cont.run(); + Asserts.assertTrue(cont.isDone(), "continuation not done"); + Asserts.assertTrue(counter == iterations, "wrong count"); + } +}