diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index f130f4f8106..2e5a58a9c71 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -3778,6 +3778,20 @@ bool LibraryCallKit::inline_native_Continuation_pinning(bool unpin) { Node* test_pin_count_over_underflow = _gvn.transform(new BoolNode(pin_count_cmp, BoolTest::eq)); IfNode* iff_pin_count_over_underflow = create_and_map_if(control(), test_pin_count_over_underflow, PROB_MIN, COUNT_UNKNOWN); + // True branch, pin count over/underflow. + Node* pin_count_over_underflow = _gvn.transform(new IfTrueNode(iff_pin_count_over_underflow)); + { + // Trap (but not deoptimize (Action_none)) and continue in the interpreter + // which will throw IllegalStateException for pin count over/underflow. + // No memory changed so far - we can use memory create by reset_memory() + // at the beginning of this intrinsic. No need to call reset_memory() again. + PreserveJVMState pjvms(this); + set_control(pin_count_over_underflow); + uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_none); + assert(stopped(), "invariant"); + } + // False branch, no pin count over/underflow. Increment or decrement pin count and store back. Node* valid_pin_count = _gvn.transform(new IfFalseNode(iff_pin_count_over_underflow)); set_control(valid_pin_count); @@ -3789,20 +3803,7 @@ bool LibraryCallKit::inline_native_Continuation_pinning(bool unpin) { next_pin_count = _gvn.transform(new AddINode(pin_count, _gvn.intcon(1))); } - Node* updated_pin_count_memory = store_to_memory(control(), pin_count_offset, next_pin_count, T_INT, MemNode::unordered); - - // True branch, pin count over/underflow. - Node* pin_count_over_underflow = _gvn.transform(new IfTrueNode(iff_pin_count_over_underflow)); - { - // Trap (but not deoptimize (Action_none)) and continue in the interpreter - // which will throw IllegalStateException for pin count over/underflow. - PreserveJVMState pjvms(this); - set_control(pin_count_over_underflow); - set_all_memory(input_memory_state); - uncommon_trap_exact(Deoptimization::Reason_intrinsic, - Deoptimization::Action_none); - assert(stopped(), "invariant"); - } + store_to_memory(control(), pin_count_offset, next_pin_count, T_INT, MemNode::unordered); // Result of top level CFG and Memory. RegionNode* result_rgn = new RegionNode(PATH_LIMIT); @@ -3812,7 +3813,7 @@ bool LibraryCallKit::inline_native_Continuation_pinning(bool unpin) { result_rgn->init_req(_true_path, _gvn.transform(valid_pin_count)); result_rgn->init_req(_false_path, _gvn.transform(continuation_is_null)); - result_mem->init_req(_true_path, _gvn.transform(updated_pin_count_memory)); + result_mem->init_req(_true_path, _gvn.transform(reset_memory())); result_mem->init_req(_false_path, _gvn.transform(input_memory_state)); // Set output state. diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestContinuationPinningAndEA.java b/test/hotspot/jtreg/compiler/intrinsics/TestContinuationPinningAndEA.java new file mode 100644 index 00000000000..e2ce8312eb3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/TestContinuationPinningAndEA.java @@ -0,0 +1,77 @@ +/* + * 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 8347997 + * @summary Test that Continuation.pin() and unpin() intrinsics work with EA. + * @modules java.base/jdk.internal.vm + * @run main TestContinuationPinningAndEA + */ + +import jdk.internal.vm.Continuation; + +public class TestContinuationPinningAndEA { + + static class FailsEA { + final Object o; + + public FailsEA() throws Throwable { + o = new Object(); + Continuation.pin(); + Continuation.unpin(); + } + } + + static class Crashes { + final Object o; + + public Crashes() throws Throwable { + Continuation.pin(); + Continuation.unpin(); + o = new Object(); + } + } + + static void test_FailsEA() throws Throwable { + for (int i = 0; i < 10_000; ++i) { + new FailsEA(); + } + } + + static void test_Crashes() throws Throwable { + for (int i = 0; i < 10_000; ++i) { + new Crashes(); + } + } + + public static void main(String[] args) throws Throwable { + int iterations = 100; + for (int i = 0; i < iterations; ++i) { + test_FailsEA(); + } + for (int i = 0; i < iterations; ++i) { + test_Crashes(); + } + } +}