diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index fdf874b2e0d8e..e946f3be9703d 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -6397,6 +6397,18 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Support for spin waits. + address generate_spin_wait() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "spin_wait"); + address start = __ pc(); + + __ spin_wait(); + __ ret(lr); + + return start; + } + #ifdef LINUX // ARMv8.1 LSE versions of the atomic stubs used by Atomic::PlatformXX. @@ -7715,6 +7727,8 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_updateBytesAdler32 = generate_updateBytesAdler32(); } + StubRoutines::aarch64::_spin_wait = generate_spin_wait(); + #ifdef LINUX generate_atomic_entry_points(); diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 1cbc3ed21d16f..9e16a1f9f8812 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -57,6 +57,10 @@ address StubRoutines::aarch64::_string_indexof_linear_uu = NULL; address StubRoutines::aarch64::_string_indexof_linear_ul = NULL; address StubRoutines::aarch64::_large_byte_array_inflate = NULL; address StubRoutines::aarch64::_method_entry_barrier = NULL; + +static void empty_spin_wait() { } +address StubRoutines::aarch64::_spin_wait = CAST_FROM_FN_PTR(address, empty_spin_wait); + bool StubRoutines::aarch64::_completed = false; /** diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index 67536dc1d2b12..295264b7aaf22 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -72,6 +72,8 @@ class aarch64 { static address _method_entry_barrier; + static address _spin_wait; + static bool _completed; public: @@ -177,6 +179,10 @@ class aarch64 { return _method_entry_barrier; } + static address spin_wait() { + return _spin_wait; + } + static bool complete() { return _completed; } diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index b3c60b6e62482..6b09069e09dd7 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -382,7 +382,20 @@ int os::extra_bang_size_in_bytes() { extern "C" { int SpinPause() { - return 0; + using spin_wait_func_ptr_t = void (*)(); + spin_wait_func_ptr_t func = CAST_TO_FN_PTR(spin_wait_func_ptr_t, StubRoutines::aarch64::spin_wait()); + assert(func != nullptr, "StubRoutines::aarch64::spin_wait must not be null."); + (*func)(); + // If StubRoutines::aarch64::spin_wait consists of only a RET, + // SpinPause can be considered as implemented. There will be a sequence + // of instructions for: + // - call of SpinPause + // - load of StubRoutines::aarch64::spin_wait stub pointer + // - indirect call of the stub + // - return from the stub + // - return from SpinPause + // So '1' always is returned. + return 1; } void _Copy_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { diff --git a/test/hotspot/jtreg/runtime/Thread/TestSpinPause.java b/test/hotspot/jtreg/runtime/Thread/TestSpinPause.java new file mode 100644 index 0000000000000..7935d8a1a4614 --- /dev/null +++ b/test/hotspot/jtreg/runtime/Thread/TestSpinPause.java @@ -0,0 +1,87 @@ +/* + * Copyright Amazon.com Inc. 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 TestSpinPause + * @summary JVM runtime can use SpinPause function for synchronized statements. + * Check different implementations of JVM SpinPause don't crash JVM. + * @bug 8278241 + * @library /test/lib + * + * @requires os.arch=="aarch64" + * + * @run main/othervm TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=none TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop -XX:OnSpinWaitInstCount=10 TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -Xint TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=none TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop -XX:OnSpinWaitInstCount=10 TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -Xint -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -Xcomp TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=none TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=nop -XX:OnSpinWaitInstCount=10 TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=isb -XX:OnSpinWaitInstCount=3 TestSpinPause + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:OnSpinWaitInst=yield -XX:OnSpinWaitInstCount=3 TestSpinPause + */ + +public class TestSpinPause { + private Integer[] valueHolder; + + private TestSpinPause () { + valueHolder = new Integer[] {Integer.valueOf(101)}; + } + + private void getSet() { + final int iterCount = 100; + for (int i = 0; i < iterCount; ++i) { + synchronized (valueHolder) { + Integer v = valueHolder[0]; + valueHolder[0] = Integer.reverse(v); + } + } + } + + public static void main(String[] args) throws Exception { + TestSpinPause test = new TestSpinPause(); + Thread t1 = new Thread(test::getSet); + Thread t2 = new Thread(test::getSet); + t1.start(); + t2.start(); + t1.join(); + t2.join(); + System.out.println("Done: " + test.valueHolder[0]); + } +} +