From ff76620487c307514c435443bbaebc9a6c473f5d Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Wed, 9 Mar 2022 19:42:47 +0000 Subject: [PATCH 001/237] 8282641: Make jdb "threadgroup" command with no args reset the current threadgroup back to the default Reviewed-by: kevinw, amenkov --- .../sun/tools/example/debug/tty/Commands.java | 4 ++-- .../tools/example/debug/tty/TTYResources.java | 8 +++---- .../example/debug/tty/TTYResources_ja.java | 3 +-- .../example/debug/tty/TTYResources_zh_CN.java | 3 +-- .../threadgroup002/threadgroup002.java | 22 +++++++++++++++---- 5 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java index 15091d310d5..121038a6d72 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/Commands.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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 @@ -501,7 +501,7 @@ class Commands { void commandThreadGroup(StringTokenizer t) { if (!t.hasMoreTokens()) { - MessageOutput.println("Threadgroup name not specified."); + ThreadInfo.setThreadGroup(null); // reset to default (top level ThreadGroup) return; } String name = t.nextToken(); diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java index 8ba3c42c83a..adec7aa98cf 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -312,7 +312,6 @@ public class TTYResources extends java.util.ListResourceBundle { {"Thread has been resumed", "Thread has been resumed"}, {"Thread not suspended", "Thread not suspended"}, {"thread group number description name", "{0,number,integer}. {1} {2}"}, - {"Threadgroup name not specified.", "Threadgroup name not specified."}, {" option not valid until the VM is started with the run command", " option not valid until the VM is started with the run command"}, {"Threads must be suspended", "Threads must be suspended"}, @@ -354,7 +353,7 @@ public class TTYResources extends java.util.ListResourceBundle { "\n" + "run [class [args]] -- start execution of application's main class\n" + "\n" + - "threads [threadgroup] -- list threads\n" + + "threads [threadgroup] -- list threads in threadgroup. Use current threadgroup if none specified.\n" + "thread -- set default thread\n" + "suspend [thread id(s)] -- suspend threads (default: all)\n" + "resume [thread id(s)] -- resume threads (default: all)\n" + @@ -377,7 +376,8 @@ public class TTYResources extends java.util.ListResourceBundle { "fields -- list a class's fields\n" + "\n" + "threadgroups -- list threadgroups\n" + - "threadgroup -- set current threadgroup\n" + + "threadgroup -- set current threadgroup to \n" + + "threadgroup -- set current threadgroup back to the top level threadgroup\n" + "\n" + "stop [go|thread] [] \n" + " -- set a breakpoint\n" + diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java index 1f0dd4a3e22..330fc33a820 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_ja.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -302,7 +302,6 @@ public class TTYResources_ja extends java.util.ListResourceBundle { {"Thread has been resumed", "\u30B9\u30EC\u30C3\u30C9\u304C\u518D\u958B\u3057\u307E\u3057\u305F"}, {"Thread not suspended", "\u30B9\u30EC\u30C3\u30C9\u306F\u4E2D\u65AD\u3057\u3066\u3044\u307E\u305B\u3093"}, {"thread group number description name", "{0,number,integer}. {1} {2}"}, - {"Threadgroup name not specified.", "\u30B9\u30EC\u30C3\u30C9\u30B0\u30EB\u30FC\u30D7\u540D\u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002"}, {" option not valid until the VM is started with the run command", "\u30AA\u30D7\u30B7\u30E7\u30F3\u306F\u3001VM\u304Crun\u30B3\u30DE\u30F3\u30C9\u3067\u958B\u59CB\u3055\u308C\u308B\u307E\u3067\u7121\u52B9\u3067\u3059"}, {"Threads must be suspended", "\u30B9\u30EC\u30C3\u30C9\u3092\u4E2D\u65AD\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059"}, diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java index 88c1cd3e878..6c4be977705 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources_zh_CN.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -302,7 +302,6 @@ public class TTYResources_zh_CN extends java.util.ListResourceBundle { {"Thread has been resumed", "\u5DF2\u6062\u590D\u7EBF\u7A0B"}, {"Thread not suspended", "\u672A\u6302\u8D77\u7EBF\u7A0B"}, {"thread group number description name", "{0,number,integer}\u3002{1} {2}"}, - {"Threadgroup name not specified.", "\u672A\u6307\u5B9A\u7EBF\u7A0B\u7EC4\u540D\u3002"}, {" option not valid until the VM is started with the run command", "\u5728\u4F7F\u7528 run \u547D\u4EE4\u542F\u52A8 VM \u524D\uFF0C \u9009\u9879\u65E0\u6548"}, {"Threads must be suspended", "\u5FC5\u987B\u6302\u8D77\u7EBF\u7A0B"}, diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java index cb8004643d3..72bbf358474 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdb/threadgroup/threadgroup002/threadgroup002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2022, 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 @@ -29,11 +29,15 @@ * VM Testbase keywords: [jpda, jdb] * VM Testbase readme: * DECSRIPTION - * This is a test for jdb 'threadgroup ' command. + * This is a test for jdb 'threadgroup ' command and + * also for the 'threadgroup' command with no argument. * The main thread creates 3 threadgroups of 5 threads each. * All threads are locked in their 'run' method on a lock that the main - * thread holds. The test passes if jdb correctly switches between - * three user-defined threadgroups using 'threadgroup' command. + * thread holds. The test then makes sure jdb correctly switches between + * the three user-defined threadgroups using 'threadgroup' command. It then + * resets the current threadgroup back to the default top level threadgroup + * by using the 'threadgroup' command with no argument. It then tests that + * all 3 created threadgroups can be found in the 'threads' output. * COMMENTS * This test functionally equals to nsk/jdb/threadgroup/threadgroup001 * test and replaces it. @@ -45,6 +49,7 @@ * nsk.jdb.threadgroup.threadgroup002.threadgroup002 * -arch=${os.family}-${os.simpleArch} * -waittime=5 + * -verbose * -debugee.vmkind=java * -transport.address=dynamic * -jdb=${test.jdk}/bin/jdb @@ -100,6 +105,15 @@ public class threadgroup002 extends JdbTest { } } + // Test switching back to the default top level group. + reply = jdb.receiveReplyFor(JdbCommand.threadgroup); + reply = jdb.receiveReplyFor(JdbCommand.threads); + grep = new Paragrep(reply); + count = grep.find(threadgroup002a.THREADGROUP_NAME); + if (count != threadgroup002a.numThreadGroups) { + failure("jdb cannot switch to default top level threadgroup"); + } + jdb.contToExit(1); } } -- GitLab From 8aba4de98477a3bcfcde8db71e0d797965f774c7 Mon Sep 17 00:00:00 2001 From: Rajat Mahajan Date: Thu, 10 Mar 2022 05:09:29 +0000 Subject: [PATCH 002/237] 8249592: Robot.mouseMove moves cursor to incorrect location when display scale varies and Java runs in DPI Unaware mode Reviewed-by: serb, aivanov --- .../native/libawt/windows/awt_Robot.cpp | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp index 33457ebef32..0afce8727e0 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Robot.cpp @@ -28,20 +28,33 @@ #include "awt_Component.h" #include -static int signum(int i) { - // special version of signum which returns 1 when value is 0 - return i >= 0 ? 1 : -1; -} - static void MouseMove(jint x, jint y) { INPUT mouseInput = {0}; mouseInput.type = INPUT_MOUSE; mouseInput.mi.time = 0; - mouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE; - mouseInput.mi.dx = (x * 65536 /::GetSystemMetrics(SM_CXSCREEN)) + signum(x); - mouseInput.mi.dy = (y * 65536 /::GetSystemMetrics(SM_CYSCREEN)) + signum(y); + + // The following calculations take into account a multi-monitor setup using + // a virtual screen for all monitors combined. + // More details from Microsoft are here -- + // https://docs.microsoft.com/en-us/windows/win32/gdi/the-virtual-screen + + x -= ::GetSystemMetrics(SM_XVIRTUALSCREEN); + y -= ::GetSystemMetrics(SM_YVIRTUALSCREEN); + + mouseInput.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | + MOUSEEVENTF_VIRTUALDESK; + + int scW = ::GetSystemMetrics(SM_CXVIRTUALSCREEN); + int scH = ::GetSystemMetrics(SM_CYVIRTUALSCREEN); + + // The following calculation to deduce mouse coordinates is based on + // empirical data + mouseInput.mi.dx = (x * 65536 + scW - 1) / scW; + mouseInput.mi.dy = (y * 65536 + scH - 1) / scH; + ::SendInput(1, &mouseInput, sizeof(mouseInput)); + } static void MousePress(jint buttonMask) -- GitLab From 5b78a82e9d4b73e5bf3c6e099564206ecbda889b Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 10 Mar 2022 09:22:21 +0000 Subject: [PATCH 003/237] 7017094: ParsedSynthStyle: parameter name "direction" should be changed to "tabIndex" Reviewed-by: jdv, aivanov, prr --- .../classes/javax/swing/plaf/synth/ParsedSynthStyle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/ParsedSynthStyle.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/ParsedSynthStyle.java index 3173b40ab6a..ff559ee1d4f 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/synth/ParsedSynthStyle.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/ParsedSynthStyle.java @@ -1935,9 +1935,9 @@ class ParsedSynthStyle extends DefaultSynthStyle { } public void paintTabbedPaneTabBackground(SynthContext context, - Graphics g, int x, int y, int w, int h, int direction) { + Graphics g, int x, int y, int w, int h, int tabIndex) { getPainter(context, "tabbedpanetabbackground", -1). - paintTabbedPaneTabBackground(context, g, x, y, w, h, direction); + paintTabbedPaneTabBackground(context, g, x, y, w, h, tabIndex); } public void paintTabbedPaneTabBackground(SynthContext context, -- GitLab From 6a3a7b94a4c342ce12ad553f1ba2818ca3a77f36 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 10 Mar 2022 09:26:36 +0000 Subject: [PATCH 004/237] 6218162: DefaultTableColumnModel.getColumn() method should mention ArrayIndexOutOfBoundsException Reviewed-by: aivanov, prr --- .../classes/javax/swing/table/DefaultTableColumnModel.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java b/src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java index 71c39b7e8bb..ab5ff974eb9 100644 --- a/src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java +++ b/src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -290,6 +290,9 @@ public class DefaultTableColumnModel implements TableColumnModel, * @param columnIndex the index of the column desired * @return the TableColumn object for the column * at columnIndex + * @throws ArrayIndexOutOfBoundsException if columnIndex + * is out of range: + * (columnIndex < 0 || columnIndex >= getColumnCount()) */ public TableColumn getColumn(int columnIndex) { return tableColumns.elementAt(columnIndex); -- GitLab From 83d771869046c2a2bf251ee5aebaceba60555e65 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 10 Mar 2022 11:28:29 +0000 Subject: [PATCH 005/237] 8282893: Remove MacroAssembler::push/pop_callee_saved_registers Reviewed-by: redestad --- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 15 --------------- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 4 ---- 2 files changed, 19 deletions(-) diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 10a1cb4b6a1..7659598fcb7 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -332,21 +332,6 @@ void MacroAssembler::movptr(Address dst, intptr_t src) { movl(dst, src); } - -void MacroAssembler::pop_callee_saved_registers() { - pop(rcx); - pop(rdx); - pop(rdi); - pop(rsi); -} - -void MacroAssembler::push_callee_saved_registers() { - push(rsi); - push(rdi); - push(rdx); - push(rcx); -} - void MacroAssembler::pushoop(jobject obj) { push_literal32((int32_t)obj, oop_Relocation::spec_for_immediate()); } diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 3593874866c..3bffad9940b 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -521,10 +521,6 @@ class MacroAssembler: public Assembler { // Round up to a power of two void round_to(Register reg, int modulus); - // Callee saved registers handling - void push_callee_saved_registers(); - void pop_callee_saved_registers(); - // allocation void eden_allocate( Register thread, // Current thread -- GitLab From 9c88c5bb63fb67f301e843d1bd5700d7e5e95204 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Thu, 10 Mar 2022 13:50:05 +0000 Subject: [PATCH 006/237] 8282948: JDK-8274980 missed correct handling of MACOSX_BUNDLE_BUILD_VERSION Reviewed-by: erikj --- make/autoconf/jdk-version.m4 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4 index 5e64ce9a064..b18e8a504ab 100644 --- a/make/autoconf/jdk-version.m4 +++ b/make/autoconf/jdk-version.m4 @@ -549,7 +549,12 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], elif test "x$with_macosx_bundle_build_version" != x; then MACOSX_BUNDLE_BUILD_VERSION="$with_macosx_bundle_build_version" else - MACOSX_BUNDLE_BUILD_VERSION="$VERSION_BUILD" + if test "x$VERSION_BUILD" != x; then + MACOSX_BUNDLE_BUILD_VERSION="$VERSION_BUILD" + else + MACOSX_BUNDLE_BUILD_VERSION=0 + fi + # If VERSION_OPT consists of only numbers and periods, add it. if [ [[ $VERSION_OPT =~ ^[0-9\.]+$ ]] ]; then MACOSX_BUNDLE_BUILD_VERSION="$MACOSX_BUNDLE_BUILD_VERSION.$VERSION_OPT" -- GitLab From 7c8ea9f05b35069e2b5b43e1a0e46f7dbe374e4c Mon Sep 17 00:00:00 2001 From: Tyler Steele Date: Thu, 10 Mar 2022 15:09:19 +0000 Subject: [PATCH 007/237] 8282509: [exploded image] ResolvedClassTest fails with similar output Reviewed-by: mdoerr, dlong --- test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java b/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java index 44b21cb6815..92263bf10cf 100644 --- a/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java +++ b/test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java @@ -125,9 +125,9 @@ public class ResolvedClassTest { analyzer.shouldHaveExitValue(0); - analyzer.shouldNotContain("java.lang.invoke.Invokers$Holder::linkToTargetMethod (9 bytes) not inlineable"); + analyzer.shouldNotMatch("java\\.lang\\.invoke\\..+::linkToTargetMethod \\(9 bytes\\) not inlineable"); - analyzer.shouldContain("java.lang.invoke.Invokers$Holder::linkToTargetMethod (9 bytes) force inline by annotation"); + analyzer.shouldMatch("java\\.lang\\.invoke\\..+::linkToTargetMethod \\(9 bytes\\) force inline by annotation"); analyzer.shouldContain("java/lang/invoke/MethodHandle::invokeBasic (not loaded) not inlineable"); } -- GitLab From 26747990053ab8f378d7f64cd7e565e530af88fc Mon Sep 17 00:00:00 2001 From: Alex Blewitt Date: Thu, 10 Mar 2022 15:27:29 +0000 Subject: [PATCH 008/237] 8282878: Removed _JavaThread from PhaseTraceTime Reviewed-by: shade, thartmann --- src/hotspot/share/c1/c1_Compilation.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp index ac415edb1f5..baabbbd147b 100644 --- a/src/hotspot/share/c1/c1_Compilation.cpp +++ b/src/hotspot/share/c1/c1_Compilation.cpp @@ -77,7 +77,6 @@ static int totalInstructionNodes = 0; class PhaseTraceTime: public TraceTime { private: - JavaThread* _thread; CompileLog* _log; TimerName _timer; -- GitLab From 1668c02ee83cc4f7bd7b2fe5bb7ef59b5dbda081 Mon Sep 17 00:00:00 2001 From: Anton Litvinov Date: Thu, 10 Mar 2022 16:37:55 +0000 Subject: [PATCH 009/237] 8277922: Unable to click JCheckBox in JTable through Java Access Bridge Reviewed-by: aivanov, serb --- .../share/classes/javax/swing/JTable.java | 21 +- ...ooleanRendererHasAccessibleActionTest.java | 192 ++++++++++++++++++ 2 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java diff --git a/src/java.desktop/share/classes/javax/swing/JTable.java b/src/java.desktop/share/classes/javax/swing/JTable.java index 9af6a1ba616..c70ec2f935e 100644 --- a/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/src/java.desktop/share/classes/javax/swing/JTable.java @@ -5481,6 +5481,21 @@ public class JTable extends JComponent implements TableModelListener, Scrollable return this; } + + @Override + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new AccessibleBooleanRenderer(); + } + return accessibleContext; + } + + class AccessibleBooleanRenderer extends JCheckBox.AccessibleJCheckBox { + @Override + public AccessibleAction getAccessibleAction() { + return null; + } + } } /** @@ -8396,7 +8411,11 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @return the AccessibleAction, or null */ public AccessibleAction getAccessibleAction() { - return getCurrentAccessibleContext().getAccessibleAction(); + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + return ac.getAccessibleAction(); + } + return null; } /** diff --git a/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java b/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java new file mode 100644 index 00000000000..79f16e3c366 --- /dev/null +++ b/test/jdk/javax/accessibility/JTable/BooleanRendererHasAccessibleActionTest.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2022, 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 8277922 + @key headful + @summary TableCellRenderer of JTable cell with Boolean data should not + support any AccessibleAction. + */ + +import java.awt.AWTException; +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Robot; +import java.lang.reflect.InvocationTargetException; +import javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleTable; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableCellRenderer; + +public class BooleanRendererHasAccessibleActionTest { + private volatile JFrame frame; + private volatile JTable table; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + final BooleanRendererHasAccessibleActionTest test = + new BooleanRendererHasAccessibleActionTest(); + + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.createGUI(); + } + }); + Robot robot = new Robot(); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.runTest(); + } + }); + } finally { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + test.dispose(); + } + }); + } + } + + private void createGUI() { + frame = new JFrame("BooleanRendererHasAccessibleActionTest"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + Container content = frame.getContentPane(); + content.setLayout(new BorderLayout()); + + String[] tblColNames = {"Column 1", "Column 2", "Column 3"}; + Object[][] tblData = { + {Boolean.TRUE, "Text 1", Boolean.FALSE}, + {Boolean.FALSE, "Text 2", Boolean.TRUE} + }; + final DefaultTableModel tblModel = new DefaultTableModel( + tblData, tblColNames) { + @Override + public Class getColumnClass(int column) { + return getValueAt(0, column).getClass(); + } + }; + table = new JTable(tblModel); + table.setPreferredScrollableViewportSize(new Dimension(400, 100)); + + JScrollPane tblScroller = new JScrollPane(table); + tblScroller.setHorizontalScrollBarPolicy( + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + tblScroller.setVerticalScrollBarPolicy( + JScrollPane.VERTICAL_SCROLLBAR_ALWAYS + ); + content.add(tblScroller, BorderLayout.CENTER); + + frame.pack(); + frame.setVisible(true); + } + + private void dispose() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + private void runTest() { + if (table == null) { + throw new RuntimeException("'table' should not be null"); + } + + testAccessibleActionInCellRenderer(0, 0, true); + testAccessibleActionInCellRenderer(1, 0, true); + testAccessibleActionInCellRenderer(0, 2, true); + testAccessibleActionInCellRenderer(1, 2, true); + + testAccessibleActionInCell(0, 0, true); + testAccessibleActionInCell(1, 0, true); + testAccessibleActionInCell(0, 2, true); + testAccessibleActionInCell(1, 2, true); + + System.out.println("Test passed."); + } + + private void testAccessibleActionInCellRenderer(int row, int column, + boolean shouldBeNull) { + System.out.println(String.format( + "testAccessibleActionInCellRenderer():" + + " row='%d', column='%d', shouldBeNull='%b'", + row, column, shouldBeNull)); + + TableCellRenderer cellRenderer = table.getCellRenderer(row, column); + if (!(cellRenderer instanceof Accessible)) { + throw new RuntimeException("'cellRenderer' is not Accessible"); + } + + AccessibleContext cellRendererAc = + ((Accessible) cellRenderer).getAccessibleContext(); + if (cellRendererAc == null) { + throw new RuntimeException("'cellRendererAc' should not be null"); + } + + AccessibleAction cellRendererAa = cellRendererAc.getAccessibleAction(); + if ((shouldBeNull && (cellRendererAa != null)) || + (!shouldBeNull && (cellRendererAa == null))) { + throw new RuntimeException( + "Test failed. 'cellRendererAa' is not as should be"); + } + } + + private void testAccessibleActionInCell(int row, int column, + boolean shouldBeNull) { + System.out.println(String.format("testAccessibleActionInCell():" + + " row='%d', column='%d', shouldBeNull='%b'", + row, column, shouldBeNull)); + + AccessibleContext tblAc = table.getAccessibleContext(); + AccessibleTable accessibleTbl = tblAc.getAccessibleTable(); + if (accessibleTbl == null) { + throw new RuntimeException("'accessibleTbl' should not be null"); + } + + Accessible cellAccessible = accessibleTbl.getAccessibleAt(row, column); + AccessibleContext cellAc = cellAccessible.getAccessibleContext(); + if (cellAc == null) { + throw new RuntimeException("'cellAc' should not be null"); + } + + AccessibleAction cellAa = cellAc.getAccessibleAction(); + if ((shouldBeNull && (cellAa != null)) || + (!shouldBeNull && (cellAa == null))) { + throw new RuntimeException( + "Test failed. 'cellAa' is not as should be"); + } + } +} -- GitLab From e8a1ce00b2981a698b4ba3e09a8b2d49d0051ccb Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 10 Mar 2022 16:38:44 +0000 Subject: [PATCH 010/237] 8280881: (fs) UnixNativeDispatcher.close0 may throw UnixException Reviewed-by: alanb --- .../sun/nio/fs/LinuxDosFileAttributeView.java | 6 ++--- .../classes/sun/nio/fs/LinuxWatchService.java | 10 +++---- .../unix/classes/sun/nio/fs/UnixCopyFile.java | 10 +++---- .../sun/nio/fs/UnixDirectoryStream.java | 4 +-- .../sun/nio/fs/UnixFileAttributeViews.java | 4 +-- .../classes/sun/nio/fs/UnixFileStore.java | 4 +-- .../sun/nio/fs/UnixFileSystemProvider.java | 13 +++++----- .../sun/nio/fs/UnixNativeDispatcher.java | 26 ++++++++++++++++--- .../sun/nio/fs/UnixSecureDirectoryStream.java | 21 ++++++++------- .../fs/UnixUserDefinedFileAttributeView.java | 14 +++++----- 10 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java b/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java index a60f2ad45f9..70d701c1ef7 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -182,7 +182,7 @@ class LinuxDosFileAttributeView x.rethrowAsIOException(file); return null; // keep compiler happy } finally { - close(fd); + close(fd, e -> null); } } @@ -277,7 +277,7 @@ class LinuxDosFileAttributeView } catch (UnixException x) { x.rethrowAsIOException(file); } finally { - close(fd); + close(fd, e -> null); } } } diff --git a/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java b/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java index 3e53b59ff90..43719e0d5be 100644 --- a/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java +++ b/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -70,7 +70,7 @@ class LinuxWatchService socketpair(sp); configureBlocking(sp[0], false); } catch (UnixException x) { - UnixNativeDispatcher.close(ifd); + UnixNativeDispatcher.close(ifd, e -> null); throw new IOException(x.errorString()); } @@ -296,9 +296,9 @@ class LinuxWatchService // free resources unsafe.freeMemory(address); - UnixNativeDispatcher.close(socketpair[0]); - UnixNativeDispatcher.close(socketpair[1]); - UnixNativeDispatcher.close(ifd); + UnixNativeDispatcher.close(socketpair[0], e -> null); + UnixNativeDispatcher.close(socketpair[1], e -> null); + UnixNativeDispatcher.close(ifd, e -> null); } /** diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java b/src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java index 3f98c81b3bf..5412748b06c 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixCopyFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -186,7 +186,7 @@ class UnixCopyFile { } if (sfd >= 0) { source.getFileSystem().copyNonPosixAttributes(sfd, dfd); - close(sfd); + close(sfd, e -> null); } } // copy time stamps last @@ -210,7 +210,7 @@ class UnixCopyFile { done = true; } finally { if (dfd >= 0) - close(dfd); + close(dfd, e -> null); if (!done) { // rollback try { rmdir(target); } catch (UnixException ignore) { } @@ -288,7 +288,7 @@ class UnixCopyFile { } complete = true; } finally { - close(fo); + close(fo, e -> null); // copy of file or attributes failed so rollback if (!complete) { @@ -298,7 +298,7 @@ class UnixCopyFile { } } } finally { - close(fi); + close(fi, e -> null); } } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java b/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java index 44b1c70abbb..3bab00b9782 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -67,7 +67,7 @@ class UnixDirectoryStream this.filter = filter; } - protected final UnixPath directory() { + final UnixPath directory() { return dir; } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java index 0744be1296d..2ffb3099dbc 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileAttributeViews.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -160,7 +160,7 @@ class UnixFileAttributeViews { } } } finally { - close(fd); + close(fd, e -> null); } } } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java index 7947c416a65..0d793dc69bb 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileStore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -197,7 +197,7 @@ abstract class UnixFileStore if (e.errno() == UnixConstants.XATTR_NOT_FOUND) return true; } finally { - UnixNativeDispatcher.close(fd); + UnixNativeDispatcher.close(fd, e -> null); } return false; } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java index 44a61827137..99703d94755 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -431,13 +431,14 @@ public abstract class UnixFileSystemProvider dfd2 = dup(dfd1); dp = fdopendir(dfd1); } catch (UnixException x) { + IOException ioe = x.errno() == UnixConstants.ENOTDIR ? + new NotDirectoryException(dir.getPathForExceptionMessage()) : + x.asIOException(dir); if (dfd1 != -1) - UnixNativeDispatcher.close(dfd1); + UnixNativeDispatcher.close(dfd1, e -> null); if (dfd2 != -1) - UnixNativeDispatcher.close(dfd2); - if (x.errno() == UnixConstants.ENOTDIR) - throw new NotDirectoryException(dir.getPathForExceptionMessage()); - x.rethrowAsIOException(dir); + UnixNativeDispatcher.close(dfd2, e -> null); + throw ioe; } return new UnixSecureDirectoryStream(dir, dp, dfd2, filter); } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java index 90be5cefae3..4080c08c32e 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -25,6 +25,8 @@ package sun.nio.fs; +import java.util.function.Function; + /** * Unix system and library calls. */ @@ -90,12 +92,30 @@ class UnixNativeDispatcher { /** * close(int filedes). If fd is -1 this is a no-op. */ - static void close(int fd) { + static void close(int fd) throws UnixException { if (fd != -1) { close0(fd); } } - private static native void close0(int fd); + private static native void close0(int fd) throws UnixException; + + /** + * close(fd). If close fails then the given exception supplier function is + * invoked to produce an exception to throw. If the function returns null + * then no exception is thrown. If close fails and the exception supplier + * function is null, then no exception is thrown. + */ + static + void close(int fd, Function mapper) throws X { + try { + close(fd); + } catch (UnixException e) { + if (mapper != null) { + X ex = mapper.apply(e); + if (ex != null) throw ex; + } + } + } /** * void rewind(FILE* stream); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java b/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java index 226effad3ef..bedf847c6e7 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -61,7 +61,7 @@ class UnixSecureDirectoryStream ds.writeLock().lock(); try { if (ds.closeImpl()) { - UnixNativeDispatcher.close(dfd); + UnixNativeDispatcher.close(dfd, e -> e.asIOException(ds.directory())); } } finally { ds.writeLock().unlock(); @@ -117,13 +117,14 @@ class UnixSecureDirectoryStream newdfd2 = dup(newdfd1); ptr = fdopendir(newdfd1); } catch (UnixException x) { + IOException ioe = x.errno() == UnixConstants.ENOTDIR ? + new NotDirectoryException(file.toString()) : + x.asIOException(file); if (newdfd1 != -1) - UnixNativeDispatcher.close(newdfd1); + UnixNativeDispatcher.close(newdfd1, e -> null); if (newdfd2 != -1) - UnixNativeDispatcher.close(newdfd2); - if (x.errno() == UnixConstants.ENOTDIR) - throw new NotDirectoryException(file.toString()); - x.rethrowAsIOException(file); + UnixNativeDispatcher.close(newdfd1, e -> null); + throw ioe; } return new UnixSecureDirectoryStream(child, ptr, newdfd2, null); } finally { @@ -422,7 +423,7 @@ class UnixSecureDirectoryStream } } finally { if (file != null) - UnixNativeDispatcher.close(fd); + UnixNativeDispatcher.close(fd, e-> null); } } finally { ds.readLock().unlock(); @@ -504,7 +505,7 @@ class UnixSecureDirectoryStream x.rethrowAsIOException(file); } finally { if (file != null && fd >= 0) - UnixNativeDispatcher.close(fd); + UnixNativeDispatcher.close(fd, e-> null); } } finally { ds.readLock().unlock(); @@ -527,7 +528,7 @@ class UnixSecureDirectoryStream x.rethrowAsIOException(file); } finally { if (file != null && fd >= 0) - UnixNativeDispatcher.close(fd); + UnixNativeDispatcher.close(fd, e-> null); } } finally { ds.readLock().unlock(); diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java b/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java index 2b62d18cb6f..f568517a2bd 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixUserDefinedFileAttributeView.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -133,7 +133,7 @@ abstract class UnixUserDefinedFileAttributeView null, "Unable to get list of extended attributes: " + x.getMessage()); } finally { - close(fd); + close(fd, e -> null); } } @@ -157,7 +157,7 @@ abstract class UnixUserDefinedFileAttributeView null, "Unable to get size of extended attribute '" + name + "': " + x.getMessage()); } finally { - close(fd); + close(fd, e -> null); } } @@ -221,7 +221,7 @@ abstract class UnixUserDefinedFileAttributeView throw new FileSystemException(file.getPathForExceptionMessage(), null, "Error reading extended attribute '" + name + "': " + msg); } finally { - close(fd); + close(fd, e -> null); } } @@ -283,7 +283,7 @@ abstract class UnixUserDefinedFileAttributeView null, "Error writing extended attribute '" + name + "': " + x.getMessage()); } finally { - close(fd); + close(fd, e -> null); } } @@ -305,7 +305,7 @@ abstract class UnixUserDefinedFileAttributeView throw new FileSystemException(file.getPathForExceptionMessage(), null, "Unable to delete extended attribute '" + name + "': " + x.getMessage()); } finally { - close(fd); + close(fd, e -> null); } } @@ -346,4 +346,4 @@ abstract class UnixUserDefinedFileAttributeView buffer.release(); } } -} \ No newline at end of file +} -- GitLab From fdce97df5f03d9aa37d85f271d08971ec47db01d Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 10 Mar 2022 17:36:51 +0000 Subject: [PATCH 011/237] 8267820: (fs) Files.copy should attempt to copy POSIX attributes when target file in custom file system Reviewed-by: lancea, alanb --- .../classes/java/nio/file/CopyMoveHelper.java | 48 ++++++++++++++----- test/jdk/java/nio/file/Files/CopyAndMove.java | 19 ++++---- test/jdk/jdk/nio/zipfs/TestPosix.java | 12 +++-- test/jdk/jdk/nio/zipfs/test.policy | 1 + test/jdk/jdk/nio/zipfs/test.policy.posix | 1 + 5 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java b/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java index ab9281807fd..e5ca66fa631 100644 --- a/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java +++ b/src/java.base/share/classes/java/nio/file/CopyMoveHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, 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 @@ -105,11 +105,20 @@ class CopyMoveHelper { LinkOption[] linkOptions = (opts.followLinks) ? new LinkOption[0] : new LinkOption[] { LinkOption.NOFOLLOW_LINKS }; + // retrieve source posix view, null if unsupported + final PosixFileAttributeView sourcePosixView = + Files.getFileAttributeView(source, PosixFileAttributeView.class); + // attributes of source file - BasicFileAttributes attrs = Files.readAttributes(source, - BasicFileAttributes.class, - linkOptions); - if (attrs.isSymbolicLink()) + BasicFileAttributes sourceAttrs = sourcePosixView != null ? + Files.readAttributes(source, + PosixFileAttributes.class, + linkOptions) : + Files.readAttributes(source, + BasicFileAttributes.class, + linkOptions); + + if (sourceAttrs.isSymbolicLink()) throw new IOException("Copying of symbolic links not supported"); // delete target if it exists and REPLACE_EXISTING is specified @@ -119,7 +128,7 @@ class CopyMoveHelper { throw new FileAlreadyExistsException(target.toString()); // create directory or copy file - if (attrs.isDirectory()) { + if (sourceAttrs.isDirectory()) { Files.createDirectory(target); } else { try (InputStream in = Files.newInputStream(source)) { @@ -127,14 +136,29 @@ class CopyMoveHelper { } } - // copy basic attributes to target + // copy basic and, if supported, POSIX attributes to target if (opts.copyAttributes) { - BasicFileAttributeView view = - Files.getFileAttributeView(target, BasicFileAttributeView.class); + BasicFileAttributeView targetView = null; + if (sourcePosixView != null) { + targetView = Files.getFileAttributeView(target, + PosixFileAttributeView.class); + } + + // target might not support posix even if source does + if (targetView == null) { + targetView = Files.getFileAttributeView(target, + BasicFileAttributeView.class); + } + try { - view.setTimes(attrs.lastModifiedTime(), - attrs.lastAccessTime(), - attrs.creationTime()); + targetView.setTimes(sourceAttrs.lastModifiedTime(), + sourceAttrs.lastAccessTime(), + sourceAttrs.creationTime()); + + if (sourceAttrs instanceof PosixFileAttributes sourcePosixAttrs && + targetView instanceof PosixFileAttributeView targetPosixView) { + targetPosixView.setPermissions(sourcePosixAttrs.permissions()); + } } catch (Throwable x) { // rollback try { diff --git a/test/jdk/java/nio/file/Files/CopyAndMove.java b/test/jdk/java/nio/file/Files/CopyAndMove.java index 981fb332fc0..e91f3e3713b 100644 --- a/test/jdk/java/nio/file/Files/CopyAndMove.java +++ b/test/jdk/java/nio/file/Files/CopyAndMove.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6917021 7006126 6950237 8006645 8201407 + * @bug 4313887 6838333 6917021 7006126 6950237 8006645 8201407 8267820 * @summary Unit test for java.nio.file.Files copy and move methods (use -Dseed=X to set PRNG seed) * @library .. /test/lib * @build jdk.test.lib.Platform jdk.test.lib.RandomFactory @@ -672,16 +672,15 @@ public class CopyAndMove { checkBasicAttributes(basicAttributes, readAttributes(source, BasicFileAttributes.class, linkOptions)); + // check POSIX attributes are copied + if (!Platform.isWindows() && testPosixAttributes) { + checkPosixAttributes( + readAttributes(source, PosixFileAttributes.class, linkOptions), + readAttributes(target, PosixFileAttributes.class, linkOptions)); + } + // verify other attributes when same provider if (source.getFileSystem().provider() == target.getFileSystem().provider()) { - - // check POSIX attributes are copied - if (!Platform.isWindows() && testPosixAttributes) { - checkPosixAttributes( - readAttributes(source, PosixFileAttributes.class, linkOptions), - readAttributes(target, PosixFileAttributes.class, linkOptions)); - } - // check DOS attributes are copied if (Platform.isWindows()) { checkDosAttributes( diff --git a/test/jdk/jdk/nio/zipfs/TestPosix.java b/test/jdk/jdk/nio/zipfs/TestPosix.java index 2be70758fbc..f629dfef222 100644 --- a/test/jdk/jdk/nio/zipfs/TestPosix.java +++ b/test/jdk/jdk/nio/zipfs/TestPosix.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, SAP SE. All rights reserved. + * Copyright (c) 2019, 2022, SAP SE. 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 @@ -69,11 +69,11 @@ import static org.testng.Assert.fail; /** * @test * @bug 8213031 8273935 + * @summary Test POSIX ZIP file operations. * @modules jdk.zipfs * jdk.jartool * @run testng TestPosix * @run testng/othervm/java.security.policy=test.policy.posix TestPosix - * @summary Test POSIX zip file operations. */ public class TestPosix { private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") @@ -528,9 +528,11 @@ public class TestPosix { } // check entries on copied zipfs - no permission data should exist - try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE_COPY, ENV_DEFAULT)) { - checkEntries(zip, checkExpects.noPermDataInZip); - } + if (System.getProperty("os.name").toLowerCase().contains("windows")) + try (FileSystem zip = FileSystems.newFileSystem(ZIP_FILE_COPY, + ENV_DEFAULT)) { + checkEntries(zip, checkExpects.noPermDataInZip); + } } /** diff --git a/test/jdk/jdk/nio/zipfs/test.policy b/test/jdk/jdk/nio/zipfs/test.policy index 1e91f1f8dcf..d0492d0fc7a 100644 --- a/test/jdk/jdk/nio/zipfs/test.policy +++ b/test/jdk/jdk/nio/zipfs/test.policy @@ -3,4 +3,5 @@ grant { permission java.util.PropertyPermission "test.jdk","read"; permission java.util.PropertyPermission "test.src","read"; permission java.util.PropertyPermission "user.dir","read"; + permission java.lang.RuntimePermission "accessUserInformation"; }; diff --git a/test/jdk/jdk/nio/zipfs/test.policy.posix b/test/jdk/jdk/nio/zipfs/test.policy.posix index 601ef439ab4..77415b0f4ba 100644 --- a/test/jdk/jdk/nio/zipfs/test.policy.posix +++ b/test/jdk/jdk/nio/zipfs/test.policy.posix @@ -5,4 +5,5 @@ grant { permission java.util.PropertyPermission "test.src","read"; permission java.util.PropertyPermission "user.dir","read"; permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.module"; + permission java.lang.RuntimePermission "accessUserInformation"; }; -- GitLab From 879b6445e33ad3a07461d01ea8f28a09979a4313 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Thu, 10 Mar 2022 18:23:41 +0000 Subject: [PATCH 012/237] 8282897: Fix call parameter to GetStringChars() in HostLocaleProviderAdapter_md.c Reviewed-by: shade, naoto --- .../libjava/HostLocaleProviderAdapter_md.c | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c index b7c2bcc28db..5d5f3ab476e 100644 --- a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c +++ b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c @@ -243,7 +243,7 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getDateTimePattern (JNIEnv *env, jclass cls, jint dateStyle, jint timeStyle, jstring jlangtag) { WCHAR pattern[BUFLEN]; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, NULL); pattern[0] = L'\0'; @@ -274,7 +274,7 @@ JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterIm (JNIEnv *env, jclass cls, jstring jlangtag) { const jchar *langtag; jint ret; - langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, 0); ret = getCalendarID(langtag); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -362,7 +362,7 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte jstring ret; WCHAR * pattern; - langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, NULL); pattern = getNumberPattern(langtag, numberStyle); CHECK_NULL_RETURN(pattern, NULL); @@ -383,7 +383,7 @@ JNIEXPORT jboolean JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapt (JNIEnv *env, jclass cls, jstring jlangtag) { DWORD num; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, JNI_FALSE); got = getLocaleInfoWrapper(langtag, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER, @@ -402,7 +402,7 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte (JNIEnv *env, jclass cls, jstring jlangtag, jstring currencySymbol) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, currencySymbol); got = getLocaleInfoWrapper(langtag, LOCALE_SCURRENCY, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -423,7 +423,7 @@ JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterI (JNIEnv *env, jclass cls, jstring jlangtag, jchar decimalSeparator) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, decimalSeparator); got = getLocaleInfoWrapper(langtag, LOCALE_SDECIMAL, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -444,7 +444,7 @@ JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterI (JNIEnv *env, jclass cls, jstring jlangtag, jchar groupingSeparator) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, groupingSeparator); got = getLocaleInfoWrapper(langtag, LOCALE_STHOUSAND, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -465,7 +465,7 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte (JNIEnv *env, jclass cls, jstring jlangtag, jstring infinity) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, infinity); got = getLocaleInfoWrapper(langtag, LOCALE_SPOSINFINITY, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -486,7 +486,7 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte (JNIEnv *env, jclass cls, jstring jlangtag, jstring internationalCurrencySymbol) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, internationalCurrencySymbol); got = getLocaleInfoWrapper(langtag, LOCALE_SINTLSYMBOL, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -507,7 +507,7 @@ JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterI (JNIEnv *env, jclass cls, jstring jlangtag, jchar minusSign) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, minusSign); got = getLocaleInfoWrapper(langtag, LOCALE_SNEGATIVESIGN, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -528,7 +528,7 @@ JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterI (JNIEnv *env, jclass cls, jstring jlangtag, jchar monetaryDecimalSeparator) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, monetaryDecimalSeparator); got = getLocaleInfoWrapper(langtag, LOCALE_SMONDECIMALSEP, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -549,7 +549,7 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte (JNIEnv *env, jclass cls, jstring jlangtag, jstring nan) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, nan); got = getLocaleInfoWrapper(langtag, LOCALE_SNAN, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -570,7 +570,7 @@ JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterI (JNIEnv *env, jclass cls, jstring jlangtag, jchar percent) { WCHAR buf[BUFLEN]; int got; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, percent); got = getLocaleInfoWrapper(langtag, LOCALE_SPERCENT, buf, BUFLEN); (*env)->ReleaseStringChars(env, jlangtag, langtag); @@ -592,7 +592,7 @@ JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterI WCHAR buf[BUFLEN]; const jchar *langtag; int got; - langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, perMill); got = getLocaleInfoWrapper(langtag, LOCALE_SPERMILLE, buf, BUFLEN); @@ -615,7 +615,7 @@ JNIEXPORT jchar JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterI WCHAR buf[BUFLEN]; const jchar *langtag; int got; - langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, zeroDigit); got = getLocaleInfoWrapper(langtag, LOCALE_SNATIVEDIGITS, buf, BUFLEN); @@ -639,7 +639,7 @@ JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterIm const jchar *langtag; int got = 0; - langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, -1); switch (type) { case sun_util_locale_provider_HostLocaleProviderAdapterImpl_CD_FIRSTDAYOFWEEK: @@ -756,7 +756,7 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte return NULL; } - pjChar = (*env)->GetStringChars(env, jStr, JNI_FALSE); + pjChar = (*env)->GetStringChars(env, jStr, NULL); CHECK_NULL_RETURN(pjChar, NULL); got = getLocaleInfoWrapper(pjChar, lcType, buf, BUFLEN); (*env)->ReleaseStringChars(env, jStr, pjChar); @@ -833,7 +833,7 @@ jint getCalendarID(const jchar *langtag) { void replaceCalendarArrayElems(JNIEnv *env, jstring jlangtag, jint calid, jobjectArray jarray, DWORD* pTypes, int offset, int length, int style, BOOL bCal) { WCHAR name[BUFLEN]; - const jchar *langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar *langtag = (*env)->GetStringChars(env, jlangtag, NULL); jstring tmp_string; CALTYPE isGenitive = 0; @@ -1023,7 +1023,7 @@ BOOL CALLBACK EnumCalendarInfoProc(LPWSTR lpCalInfoStr, CALID calid, LPWSTR lpRe } jobjectArray getErasImpl(JNIEnv *env, jstring jlangtag, jint calid, jint style, jobjectArray eras) { - const jchar * langtag = (*env)->GetStringChars(env, jlangtag, JNI_FALSE); + const jchar * langtag = (*env)->GetStringChars(env, jlangtag, NULL); WCHAR buf[BUFLEN]; jobjectArray ret = eras; CALTYPE type; -- GitLab From 1f295239b97cccfff24df259215d34c712065867 Mon Sep 17 00:00:00 2001 From: John Jiang Date: Thu, 10 Mar 2022 18:25:06 +0000 Subject: [PATCH 013/237] 8282932: a space is needed for the unsupported protocol exception message in ProtocolVersion Reviewed-by: xuelei, mullan --- .../share/classes/sun/security/ssl/ProtocolVersion.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java b/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java index e4cb5637c60..32c112a4991 100644 --- a/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java +++ b/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2022, 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 @@ -290,7 +290,7 @@ enum ProtocolVersion { ProtocolVersion pv = ProtocolVersion.nameOf(pn); if (pv == null) { throw new IllegalArgumentException( - "Unsupported protocol" + pn); + "Unsupported protocol: " + pn); } pvs.add(pv); -- GitLab From b13cacc575f58c206c928f2756698b027ee07b6f Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 10 Mar 2022 18:25:53 +0000 Subject: [PATCH 014/237] 8254574: PrintWriter handling of InterruptedIOException should be removed Reviewed-by: alanb --- .../share/classes/java/io/PrintStream.java | 21 +++++-------------- .../share/classes/java/io/PrintWriter.java | 10 ++++----- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/java.base/share/classes/java/io/PrintStream.java b/src/java.base/share/classes/java/io/PrintStream.java index 0281ed66ca8..d18afa97d54 100644 --- a/src/java.base/share/classes/java/io/PrintStream.java +++ b/src/java.base/share/classes/java/io/PrintStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -464,22 +464,11 @@ public class PrintStream extends FilterOutputStream } /** - * Flushes the stream and checks its error state. The internal error state - * is set to {@code true} when the underlying output stream throws an - * {@code IOException} other than {@code InterruptedIOException}, - * and when the {@code setError} method is invoked. If an operation - * on the underlying output stream throws an - * {@code InterruptedIOException}, then the {@code PrintStream} - * converts the exception back into an interrupt by doing: - *
{@code
-     *     Thread.currentThread().interrupt();
-     * }
- * or the equivalent. + * Flushes the stream if it's not closed and checks its error state. * * @return {@code true} if and only if this stream has encountered an - * {@code IOException} other than - * {@code InterruptedIOException}, or the - * {@code setError} method has been invoked + * {@code IOException}, or the {@code setError} method has been + * invoked */ public boolean checkError() { if (out != null) @@ -504,7 +493,7 @@ public class PrintStream extends FilterOutputStream } /** - * Clears the internal error state of this stream. + * Clears the error state of this stream. * *

This method will cause subsequent invocations of {@link * #checkError()} to return {@code false} until another write diff --git a/src/java.base/share/classes/java/io/PrintWriter.java b/src/java.base/share/classes/java/io/PrintWriter.java index 874a03cce3b..249efc4d99a 100644 --- a/src/java.base/share/classes/java/io/PrintWriter.java +++ b/src/java.base/share/classes/java/io/PrintWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -428,9 +428,9 @@ public class PrintWriter extends Writer { /** * Flushes the stream if it's not closed and checks its error state. * - * @return {@code true} if the print stream has encountered an error, - * either on the underlying output stream or during a format - * conversion. + * @return {@code true} if and only if this stream has encountered an + * {@code IOException}, or the {@code setError} method has been + * invoked */ public boolean checkError() { if (out != null) { @@ -445,7 +445,7 @@ public class PrintWriter extends Writer { } /** - * Indicates that an error has occurred. + * Sets the error state of the stream to {@code true}. * *

This method will cause subsequent invocations of {@link * #checkError()} to return {@code true} until {@link -- GitLab From 7b91bbba82e871edaf133343415e254972c6ddc7 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Thu, 10 Mar 2022 18:53:59 +0000 Subject: [PATCH 015/237] 8282170: JVMTI SetBreakpoint metaspace allocation test Reviewed-by: cjplummer, lmesnik --- .../SetBreakpoint/TestManyBreakpoints.java | 82 +++++++++++++ .../SetBreakpoint/libTestManyBreakpoints.cpp | 111 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java create mode 100644 test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp diff --git a/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java b/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java new file mode 100644 index 00000000000..bc935ea99d1 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/TestManyBreakpoints.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022, 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 8144992 + * @requires vm.jvmti + * @modules java.base/jdk.internal.org.objectweb.asm + * @run main/othervm/native -agentlib:TestManyBreakpoints + * -Xlog:gc+metaspace + * -Xint + * -XX:MetaspaceSize=16K -XX:MaxMetaspaceSize=64M + * TestManyBreakpoints + */ + +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Label; +import jdk.internal.org.objectweb.asm.MethodVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + +public class TestManyBreakpoints { + + static final int BATCHES = 50; + static final int METHODS = 1000; + + public static void main(String[] args) throws Exception { + for (int c = 0; c < BATCHES; c++) { + System.out.println("Batch " + c); + TestClassLoader loader = new TestClassLoader(); + Class.forName("Target", true, loader); + } + } + + private static class TestClassLoader extends ClassLoader implements Opcodes { + static byte[] TARGET_BYTES = generateTarget(); + + private static byte[] generateTarget() { + ClassWriter cw = new ClassWriter(0); + + cw.visit(52, ACC_SUPER | ACC_PUBLIC, "Target", null, "java/lang/Object", null); + for (int m = 0; m < METHODS; m++) { + MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "m" + m, "()V", null, null); + mv.visitCode(); + mv.visitInsn(RETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + cw.visitEnd(); + return cw.toByteArray(); + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals("Target")) { + return defineClass(name, TARGET_BYTES, 0, TARGET_BYTES.length); + } else { + return super.findClass(name); + } + } + } + +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp b/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp new file mode 100644 index 00000000000..dcb8f87ddd7 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/SetBreakpoint/libTestManyBreakpoints.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2022, 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. + */ + +#include +#include + +#include "jvmti.h" + +#define TARGET_CLASS_NAME "LTarget;" + +static jvmtiEnv *jvmti = NULL; + +static void +check_jvmti_status(JNIEnv* jni, jvmtiError err, const char* msg) { + if (err != JVMTI_ERROR_NONE) { + printf("check_jvmti_status: %s, JVMTI function returned error: %d\n", msg, err); + jni->FatalError(msg); + } +} + +void JNICALL classprepare(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass) { + char* buf; + jvmtiError err; + + err = jvmti->GetClassSignature(klass, &buf, NULL); + check_jvmti_status(jni_env, err, "classprepare: GetClassSignature error"); + + if (strncmp(buf, TARGET_CLASS_NAME, strlen(TARGET_CLASS_NAME)) == 0) { + jint nMethods; + jmethodID* methods; + int i; + + err = jvmti->GetClassMethods(klass, &nMethods, &methods); + check_jvmti_status(jni_env, err, "classprepare: GetClassMethods error"); + printf("Setting breakpoints in %s\n", buf); + fflush(stdout); + for (i = 0; i < nMethods; i++) { + err = jvmti->SetBreakpoint(methods[i], 0); + check_jvmti_status(jni_env, err, "classprepare: SetBreakpoint error"); + } + } +} + + +void JNICALL breakpoint(jvmtiEnv* jvmti_env, JNIEnv* jni_env, jthread thread, jmethodID method, jlocation location) { + // Do nothing +} + +JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { + jvmtiCapabilities capa; + jvmtiEventCallbacks cbs; + jint err; + + err = vm->GetEnv((void**)&jvmti, JVMTI_VERSION_1_0); + if (err != JNI_OK) { + printf("Agent_OnLoad: GetEnv error\n"); + return JNI_ERR; + } + + memset(&capa, 0, sizeof(capa)); + capa.can_generate_breakpoint_events = 1; + capa.can_generate_single_step_events = 1; + err = jvmti->AddCapabilities(&capa); + if (err != JNI_OK) { + printf("Agent_OnLoad: AddCapabilities error\n"); + return JNI_ERR; + } + + memset(&cbs, 0, sizeof(cbs)); + cbs.ClassPrepare = classprepare; + cbs.Breakpoint = breakpoint; + err = jvmti->SetEventCallbacks(&cbs, sizeof(cbs)); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventCallbacks error\n"); + return JNI_ERR; + } + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventNotificationMode CLASS_PREPARE error\n"); + return JNI_ERR; + } + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, NULL); + if (err != JNI_OK) { + printf("Agent_OnLoad: SetEventNotificationMode BREAKPOINT error\n"); + return JNI_ERR; + } + + return JNI_OK; +} -- GitLab From f5217b475e2bfcbc649dd1e067222bf500429663 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Thu, 10 Mar 2022 19:08:10 +0000 Subject: [PATCH 016/237] 8282852: Debug agent asserts in classTrack_addPreparedClass() Reviewed-by: amenkov, lmesnik --- .../share/native/libjdwp/classTrack.c | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c b/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c index de9918780bf..613b02c8d1e 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/classTrack.c @@ -110,21 +110,28 @@ classTrack_addPreparedClass(JNIEnv *env_unused, jclass klass) jvmtiError error; jvmtiEnv* env = trackingEnv; + char* signature; + error = classSignature(klass, &signature, NULL); + if (error != JVMTI_ERROR_NONE) { + EXIT_ERROR(error,"signature"); + } + if (gdata && gdata->assertOn) { - // Check this is not already tagged. + // Check if already tagged. jlong tag; error = JVMTI_FUNC_PTR(trackingEnv, GetTag)(env, klass, &tag); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "Unable to GetTag with class trackingEnv"); } - JDI_ASSERT(tag == NOT_TAGGED); + if (tag != NOT_TAGGED) { + // If tagged, the old tag better be the same as the new. + char* oldSignature = (char*)jlong_to_ptr(tag); + JDI_ASSERT(strcmp(signature, oldSignature) == 0); + jvmtiDeallocate(signature); + return; + } } - char* signature; - error = classSignature(klass, &signature, NULL); - if (error != JVMTI_ERROR_NONE) { - EXIT_ERROR(error,"signature"); - } error = JVMTI_FUNC_PTR(trackingEnv, SetTag)(env, klass, ptr_to_jlong(signature)); if (error != JVMTI_ERROR_NONE) { jvmtiDeallocate(signature); -- GitLab From bb7ee5a04ae21a9f9dc6c59a990f7e571e832f0d Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Thu, 10 Mar 2022 19:13:55 +0000 Subject: [PATCH 017/237] 8282314: nsk/jvmti/SuspendThread/suspendthrd003 may leak memory Reviewed-by: dholmes, cjplummer, amenkov, lmesnik, mseledtsov --- .../nsk/jvmti/SuspendThread/suspendthrd003.java | 5 ++++- test/hotspot/jtreg/vmTestbase/nsk/share/Log.java | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003.java index fd98b382d2a..e2a48a948e9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/SuspendThread/suspendthrd003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -88,6 +88,9 @@ public class suspendthrd003 extends DebugeeClass { int res = -1; long start_time = System.currentTimeMillis(); while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { + // Start each loop with a clear log buffer so we only + // track the run that can potentially fail: + log.clearLogBuffer(); count++; // Original suspendthrd001 test block starts here: diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java index 109c3ddd8f7..e171f6daa82 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/Log.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -477,6 +477,13 @@ public class Log extends FinalizableObject { ///////////////////////////////////////////////////////////////// + /** + * Clear all messages from log buffer. + */ + public synchronized void clearLogBuffer() { + logBuffer.clear(); + } + /** * Print all messages from log buffer which were hidden because * of non-verbose mode, -- GitLab From a5a1a32db65b98f0d7bae20cf054be2fbbf2cf3a Mon Sep 17 00:00:00 2001 From: Yi Yang Date: Fri, 11 Mar 2022 02:27:01 +0000 Subject: [PATCH 018/237] 8282883: Use JVM_LEAF to avoid ThreadStateTransition for some simple JVM entries Reviewed-by: dholmes, shade --- src/hotspot/share/prims/jvm.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index d8a5a025b9d..f18fe51616c 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -487,7 +487,7 @@ JVM_ENTRY_NO_ENV(jint, JVM_ActiveProcessorCount(void)) return os::active_processor_count(); JVM_END -JVM_ENTRY_NO_ENV(jboolean, JVM_IsUseContainerSupport(void)) +JVM_LEAF(jboolean, JVM_IsUseContainerSupport(void)) #ifdef LINUX if (UseContainerSupport) { return JNI_TRUE; @@ -690,7 +690,7 @@ JVM_ENTRY(void, JVM_ReportFinalizationComplete(JNIEnv * env, jobject finalizee)) MANAGEMENT_ONLY(FinalizerService::on_complete(JNIHandles::resolve_non_null(finalizee), THREAD);) JVM_END -JVM_ENTRY(jboolean, JVM_IsFinalizationEnabled(JNIEnv * env)) +JVM_LEAF(jboolean, JVM_IsFinalizationEnabled(JNIEnv * env)) return InstanceKlass::is_finalization_enabled(); JVM_END @@ -3035,7 +3035,7 @@ JVM_ENTRY(void, JVM_SetThreadPriority(JNIEnv* env, jobject jthread, jint prio)) JVM_END -JVM_ENTRY(void, JVM_Yield(JNIEnv *env, jclass threadClass)) +JVM_LEAF(void, JVM_Yield(JNIEnv *env, jclass threadClass)) if (os::dont_yield()) return; HOTSPOT_THREAD_YIELD(); os::naked_yield(); @@ -3643,11 +3643,11 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env, #endif // INCLUDE_CDS JVM_END -JVM_ENTRY(jboolean, JVM_IsCDSDumpingEnabled(JNIEnv* env)) +JVM_LEAF(jboolean, JVM_IsCDSDumpingEnabled(JNIEnv* env)) return Arguments::is_dumping_archive(); JVM_END -JVM_ENTRY(jboolean, JVM_IsSharingEnabled(JNIEnv* env)) +JVM_LEAF(jboolean, JVM_IsSharingEnabled(JNIEnv* env)) return UseSharedSpaces; JVM_END @@ -3673,7 +3673,7 @@ JVM_ENTRY_NO_ENV(jlong, JVM_GetRandomSeedForDumping()) } JVM_END -JVM_ENTRY(jboolean, JVM_IsDumpingClassList(JNIEnv *env)) +JVM_LEAF(jboolean, JVM_IsDumpingClassList(JNIEnv *env)) #if INCLUDE_CDS return ClassListWriter::is_enabled() || DynamicDumpSharedSpaces; #else @@ -3782,7 +3782,7 @@ JVM_ENTRY(jobjectArray, JVM_DumpThreads(JNIEnv *env, jclass threadClass, jobject JVM_END // JVM monitoring and management support -JVM_ENTRY_NO_ENV(void*, JVM_GetManagement(jint version)) +JVM_LEAF(void*, JVM_GetManagement(jint version)) return Management::get_jmm_interface(version); JVM_END @@ -3871,7 +3871,7 @@ JVM_ENTRY(jobjectArray, JVM_GetVmArguments(JNIEnv *env)) return (jobjectArray) JNIHandles::make_local(THREAD, result_h()); JVM_END -JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name)) +JVM_LEAF(jint, JVM_FindSignal(const char *name)) return os::get_signal_number(name); JVM_END -- GitLab From 88f0938c943bfacf748ddb0588a301c2cf7e941e Mon Sep 17 00:00:00 2001 From: Yi Yang Date: Fri, 11 Mar 2022 02:28:07 +0000 Subject: [PATCH 019/237] 8272493: Suboptimal code generation around Preconditions.checkIndex intrinsic with AVX2 Reviewed-by: redestad, thartmann --- src/hotspot/share/opto/library_call.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 31d56fcd70e..f5c19d8123c 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -1092,7 +1092,6 @@ bool LibraryCallKit::inline_preconditions_checkIndex(BasicType bt) { result = _gvn.transform(result); set_result(result); replace_in_map(index, result); - clear_upper_avx(); return true; } -- GitLab From 1a5a496aee0f4c33cb67b0853bbf23313fd6ec7d Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Fri, 11 Mar 2022 08:43:04 +0000 Subject: [PATCH 020/237] 8282763: G1: G1CardSetContainer remove intrusive-list details. Reviewed-by: tschatzl, kbarrett, ayang --- .../share/gc/g1/g1CardSetContainers.hpp | 29 ++----------------- .../gc/g1/g1CardSetContainers.inline.hpp | 1 + 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index 4f861baf4eb..6736a18ab02 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -30,11 +30,6 @@ #include "runtime/atomic.hpp" #include "utilities/bitMap.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/spinYield.hpp" - -#include "logging/log.hpp" - -#include "runtime/thread.inline.hpp" // A helper class to encode a few card indexes within a CardSetPtr. // @@ -143,18 +138,12 @@ public: // To maintain these constraints, live objects should have ((_ref_count & 0x1) == 1), // which requires that we increment the reference counts by 2 starting at _ref_count = 3. // -// When such an object is on a free list, we reuse the same field for linking -// together those free objects. -// // All but inline pointers are of this kind. For those, card entries are stored // directly in the CardSetPtr of the ConcurrentHashTable node. class G1CardSetContainer { -private: - union { - G1CardSetContainer* _next; - uintptr_t _ref_count; - }; - + uintptr_t _ref_count; +protected: + ~G1CardSetContainer() = default; public: G1CardSetContainer() : _ref_count(3) { } @@ -166,18 +155,6 @@ public: // to check the value after attempting to decrement. uintptr_t decrement_refcount(); - G1CardSetContainer* next() { - return _next; - } - - G1CardSetContainer** next_addr() { - return &_next; - } - - void set_next(G1CardSetContainer* next) { - _next = next; - } - // Log of largest card index that can be stored in any G1CardSetContainer static uint LogCardsPerRegionLimit; }; diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp index 13e70302b02..73d84fbf934 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp @@ -29,6 +29,7 @@ #include "gc/g1/g1GCPhaseTimes.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/spinYield.hpp" inline G1CardSetInlinePtr::CardSetPtr G1CardSetInlinePtr::merge(CardSetPtr orig_value, uint card_in_region, uint idx, uint bits_per_card) { assert((idx & (SizeFieldMask >> SizeFieldPos)) == idx, "Index %u too large to fit into size field", idx); -- GitLab From cab9def1c1ab28b0b1a8cf268d0853f6e2bfa77f Mon Sep 17 00:00:00 2001 From: Julian Waters Date: Fri, 11 Mar 2022 09:12:19 +0000 Subject: [PATCH 021/237] 8282700: Properly handle several --without options during configure Reviewed-by: ihse --- make/autoconf/jdk-version.m4 | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4 index b18e8a504ab..41f4b1fb121 100644 --- a/make/autoconf/jdk-version.m4 +++ b/make/autoconf/jdk-version.m4 @@ -72,7 +72,9 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # Setup username (for use in adhoc version strings etc) AC_ARG_WITH([build-user], [AS_HELP_STRING([--with-build-user], [build username to use in version strings])]) - if test "x$with_build_user" != x; then + if test "x$with_build_user" = xyes || test "x$with_build_user" = xno; then + AC_MSG_ERROR([--with-build-user must have a value]) + elif test "x$with_build_user" != x; then USERNAME="$with_build_user" else # Outer [ ] to quote m4. @@ -84,7 +86,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_ARG_WITH(jdk-rc-name, [AS_HELP_STRING([--with-jdk-rc-name], [Set JDK RC name. This is used for FileDescription and ProductName properties of MS Windows binaries. @<:@not specified@:>@])]) - if test "x$with_jdk_rc_name" = xyes; then + if test "x$with_jdk_rc_name" = xyes || test "x$with_jdk_rc_name" = xno; then AC_MSG_ERROR([--with-jdk-rc-name must have a value]) elif [ ! [[ $with_jdk_rc_name =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-jdk-rc-name contains non-printing characters: $with_jdk_rc_name]) @@ -101,7 +103,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_ARG_WITH(vendor-name, [AS_HELP_STRING([--with-vendor-name], [Set vendor name. Among others, used to set the 'java.vendor' and 'java.vm.vendor' system properties. @<:@not specified@:>@])]) - if test "x$with_vendor_name" = xyes; then + if test "x$with_vendor_name" = xyes || test "x$with_vendor_name" = xno; then AC_MSG_ERROR([--with-vendor-name must have a value]) elif [ ! [[ $with_vendor_name =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-vendor-name contains non-printing characters: $with_vendor_name]) @@ -115,7 +117,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # The vendor URL, if any AC_ARG_WITH(vendor-url, [AS_HELP_STRING([--with-vendor-url], [Set the 'java.vendor.url' system property @<:@not specified@:>@])]) - if test "x$with_vendor_url" = xyes; then + if test "x$with_vendor_url" = xyes || test "x$with_vendor_url" = xno; then AC_MSG_ERROR([--with-vendor-url must have a value]) elif [ ! [[ $with_vendor_url =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-vendor-url contains non-printing characters: $with_vendor_url]) @@ -129,7 +131,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # The vendor bug URL, if any AC_ARG_WITH(vendor-bug-url, [AS_HELP_STRING([--with-vendor-bug-url], [Set the 'java.vendor.url.bug' system property @<:@not specified@:>@])]) - if test "x$with_vendor_bug_url" = xyes; then + if test "x$with_vendor_bug_url" = xyes || test "x$with_vendor_bug_url" = xno; then AC_MSG_ERROR([--with-vendor-bug-url must have a value]) elif [ ! [[ $with_vendor_bug_url =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-vendor-bug-url contains non-printing characters: $with_vendor_bug_url]) @@ -143,7 +145,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # The vendor VM bug URL, if any AC_ARG_WITH(vendor-vm-bug-url, [AS_HELP_STRING([--with-vendor-vm-bug-url], [Sets the bug URL which will be displayed when the VM crashes @<:@not specified@:>@])]) - if test "x$with_vendor_vm_bug_url" = xyes; then + if test "x$with_vendor_vm_bug_url" = xyes || test "x$with_vendor_vm_bug_url" = xno; then AC_MSG_ERROR([--with-vendor-vm-bug-url must have a value]) elif [ ! [[ $with_vendor_vm_bug_url =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-vendor-vm-bug-url contains non-printing characters: $with_vendor_vm_bug_url]) @@ -160,7 +162,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # override parts with more specific flags, since these are processed later. AC_ARG_WITH(version-string, [AS_HELP_STRING([--with-version-string], [Set version string @<:@calculated@:>@])]) - if test "x$with_version_string" = xyes; then + if test "x$with_version_string" = xyes || test "x$with_version_string" = xno; then AC_MSG_ERROR([--with-version-string must have a value]) elif test "x$with_version_string" != x; then # Additional [] needed to keep m4 from mangling shell constructs. @@ -293,7 +295,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], [with_version_feature_present=true], [with_version_feature_present=false]) if test "x$with_version_feature_present" = xtrue; then - if test "x$with_version_feature" = xyes; then + if test "x$with_version_feature" = xyes || test "x$with_version_feature" = xno; then AC_MSG_ERROR([--with-version-feature must have a value]) else JDKVER_CHECK_AND_SET_NUMBER(VERSION_FEATURE, $with_version_feature) @@ -480,7 +482,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], # The version date AC_ARG_WITH(version-date, [AS_HELP_STRING([--with-version-date], [Set version date @<:@current source value@:>@])]) - if test "x$with_version_date" = xyes; then + if test "x$with_version_date" = xyes || test "x$with_version_date" = xno; then AC_MSG_ERROR([--with-version-date must have a value]) elif test "x$with_version_date" != x; then if [ ! [[ $with_version_date =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]] ]; then @@ -499,7 +501,10 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_MSG_ERROR([--with-vendor-version-string must have a value]) elif [ ! [[ $with_vendor_version_string =~ ^[[:graph:]]*$ ]] ]; then AC_MSG_ERROR([--with--vendor-version-string contains non-graphical characters: $with_vendor_version_string]) - else + elif test "x$with_vendor_version_string" != xno; then + # Set vendor version string if --without is not passed + # Check not required if an empty value is passed, since VENDOR_VERSION_STRING + # would then be set to "" VENDOR_VERSION_STRING="$with_vendor_version_string" fi @@ -507,7 +512,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_ARG_WITH(macosx-bundle-name-base, [AS_HELP_STRING([--with-macosx-bundle-name-base], [Set the MacOSX Bundle Name base. This is the base name for calculating MacOSX Bundle Names. @<:@not specified@:>@])]) - if test "x$with_macosx_bundle_name_base" = xyes; then + if test "x$with_macosx_bundle_name_base" = xyes || test "x$with_macosx_bundle_name_base" = xno; then AC_MSG_ERROR([--with-macosx-bundle-name-base must have a value]) elif [ ! [[ $with_macosx_bundle_name_base =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-macosx-bundle-name-base contains non-printing characters: $with_macosx_bundle_name_base]) @@ -521,7 +526,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], AC_ARG_WITH(macosx-bundle-id-base, [AS_HELP_STRING([--with-macosx-bundle-id-base], [Set the MacOSX Bundle ID base. This is the base ID for calculating MacOSX Bundle IDs. @<:@not specified@:>@])]) - if test "x$with_macosx_bundle_id_base" = xyes; then + if test "x$with_macosx_bundle_id_base" = xyes || test "x$with_macosx_bundle_id_base" = xno; then AC_MSG_ERROR([--with-macosx-bundle-id-base must have a value]) elif [ ! [[ $with_macosx_bundle_id_base =~ ^[[:print:]]*$ ]] ]; then AC_MSG_ERROR([--with-macosx-bundle-id-base contains non-printing characters: $with_macosx_bundle_id_base]) @@ -542,7 +547,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], [Set the MacOSX Bundle CFBundleVersion field. This key is a machine-readable string composed of one to three period-separated integers and should represent the build version. Defaults to the build number.])]) - if test "x$with_macosx_bundle_build_version" = xyes; then + if test "x$with_macosx_bundle_build_version" = xyes || test "x$with_macosx_bundle_build_version" = xno; then AC_MSG_ERROR([--with-macosx-bundle-build-version must have a value]) elif [ ! [[ $with_macosx_bundle_build_version =~ ^[0-9\.]*$ ]] ]; then AC_MSG_ERROR([--with-macosx-bundle-build-version contains non numbers and periods: $with_macosx_bundle_build_version]) -- GitLab From f99193ae3fe8b7bcba34a451890da37cab5ebffb Mon Sep 17 00:00:00 2001 From: Christian Stein Date: Fri, 11 Mar 2022 09:58:22 +0000 Subject: [PATCH 022/237] 8282811: Typo in IAE details message of `RecordedObject.getValueDescriptor` Reviewed-by: egahlin --- src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java index 9b24844734e..14d5ce4985f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedObject.java @@ -329,7 +329,7 @@ public class RecordedObject { return v; } } - throw new IllegalArgumentException("\"Attempt to get unknown field \"" + name + "\""); + throw new IllegalArgumentException("Attempt to get unknown field \"" + name + "\""); } // Gets a value, but checks that type and name is correct first -- GitLab From 95ca94436d12974d98b1b999f9cc8408d64cbe3c Mon Sep 17 00:00:00 2001 From: Mahendra Chhipa Date: Fri, 11 Mar 2022 10:48:57 +0000 Subject: [PATCH 023/237] 8282354: Remove dependancy of TestHttpServer, HttpTransaction, HttpCallback from open/test/jdk/ tests Reviewed-by: dfuchs --- .../net/ProxySelector/LoopbackAddresses.java | 62 +- .../jdk/java/net/ProxySelector/ProxyTest.java | 61 +- test/jdk/java/net/URL/PerConnectionProxy.java | 68 +- test/jdk/java/net/URLConnection/B5052093.java | 67 +- test/jdk/sun/net/www/AuthHeaderTest.java | 134 +-- .../net/www/http/KeepAliveCache/B5045306.java | 80 +- .../net/www/httptest/AbstractCallback.java | 82 -- .../net/www/httptest/ClosedChannelList.java | 77 -- .../sun/net/www/httptest/HttpCallback.java | 39 - .../sun/net/www/httptest/HttpTransaction.java | 330 -------- .../sun/net/www/httptest/TestHttpServer.java | 797 ------------------ .../ssl/InputRecord/ClientHelloRead.java | 20 +- 12 files changed, 306 insertions(+), 1511 deletions(-) delete mode 100644 test/jdk/sun/net/www/httptest/AbstractCallback.java delete mode 100644 test/jdk/sun/net/www/httptest/ClosedChannelList.java delete mode 100644 test/jdk/sun/net/www/httptest/HttpCallback.java delete mode 100644 test/jdk/sun/net/www/httptest/HttpTransaction.java delete mode 100644 test/jdk/sun/net/www/httptest/TestHttpServer.java diff --git a/test/jdk/java/net/ProxySelector/LoopbackAddresses.java b/test/jdk/java/net/ProxySelector/LoopbackAddresses.java index cd5eb919b97..8e27185d518 100644 --- a/test/jdk/java/net/ProxySelector/LoopbackAddresses.java +++ b/test/jdk/java/net/ProxySelector/LoopbackAddresses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -27,15 +27,25 @@ * @summary PIT: Can no launch jnlp application via 127.0.0.1 address on the web server. * This test might fail intermittently as it needs a server that * binds to the wildcard address. - * @modules java.base/sun.net.www - * @library ../../../sun/net/www/httptest/ /test/lib - * @build ClosedChannelList TestHttpServer HttpTransaction HttpCallback + * @library /test/lib * @compile LoopbackAddresses.java * @run main/othervm LoopbackAddresses */ -import java.net.*; -import java.io.*; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; /** @@ -43,17 +53,8 @@ import jdk.test.lib.net.URIBuilder; * addresses when selecting proxies. This is the existing behaviour. */ -public class LoopbackAddresses implements HttpCallback { - static TestHttpServer server; - - public void request (HttpTransaction req) { - req.setResponseEntityBody ("Hello ."); - try { - req.sendResponse (200, "Ok"); - req.orderlyClose(); - } catch (IOException e) { - } - } +public class LoopbackAddresses { + static HttpServer server; public static void main(String[] args) { try { @@ -63,15 +64,17 @@ public class LoopbackAddresses implements HttpCallback { // to answer both for the loopback and "localhost". // Though "localhost" usually point to the loopback there is no // hard guarantee. - server = new TestHttpServer (new LoopbackAddresses(), 1, 10, 0); - ProxyServer pserver = new ProxyServer(InetAddress.getByName("localhost"), server.getLocalPort()); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10, "/", new LoopbackAddressesHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + ProxyServer pserver = new ProxyServer(InetAddress.getByName("localhost"), server.getAddress().getPort()); // start proxy server new Thread(pserver).start(); System.setProperty("http.proxyHost", loopback.getHostAddress()); System.setProperty("http.proxyPort", pserver.getPort()+""); - URL url = new URL("http://localhost:"+server.getLocalPort()); + URL url = new URL("http://localhost:"+server.getAddress().getPort()); try { HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); @@ -85,7 +88,7 @@ public class LoopbackAddresses implements HttpCallback { url = URIBuilder.newBuilder() .scheme("http") .host(loopback.getHostAddress()) - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .toURL(); HttpURLConnection urlc = (HttpURLConnection)url.openConnection (); int respCode = urlc.getResponseCode(); @@ -97,7 +100,7 @@ public class LoopbackAddresses implements HttpCallback { throw new RuntimeException(e); } finally { if (server != null) { - server.terminate(); + server.stop(1); } } @@ -151,3 +154,18 @@ public class LoopbackAddresses implements HttpCallback { } } } + +class LoopbackAddressesHandler implements HttpHandler { + + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + exchange.sendResponseHeaders(200, 0); + } catch (IOException e) { + e.printStackTrace(); + } + try(PrintWriter pw = new PrintWriter(exchange.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print("Hello ."); + } + } +} diff --git a/test/jdk/java/net/ProxySelector/ProxyTest.java b/test/jdk/java/net/ProxySelector/ProxyTest.java index 8debe931469..179cc886c00 100644 --- a/test/jdk/java/net/ProxySelector/ProxyTest.java +++ b/test/jdk/java/net/ProxySelector/ProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -25,33 +25,37 @@ * @test * @bug 4696512 * @summary HTTP client: Improve proxy server configuration and selection - * @modules java.base/sun.net.www - * @library ../../../sun/net/www/httptest/ /test/lib - * @build ClosedChannelList TestHttpServer HttpTransaction HttpCallback + * @library /test/lib * @compile ProxyTest.java * @run main/othervm -Dhttp.proxyHost=inexistant -Dhttp.proxyPort=8080 ProxyTest */ -import java.net.*; -import java.io.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.URL; +import java.nio.charset.Charset; import java.util.List; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -public class ProxyTest implements HttpCallback { - static TestHttpServer server; +public class ProxyTest { + static HttpServer server; public ProxyTest() { } - public void request(HttpTransaction req) { - req.setResponseEntityBody("Hello ."); - try { - req.sendResponse(200, "Ok"); - req.orderlyClose(); - } catch (IOException e) { - } - } - static public class MyProxySelector extends ProxySelector { private static volatile URI lastURI; private final static List NO_PROXY = List.of(Proxy.NO_PROXY); @@ -75,11 +79,13 @@ public class ProxyTest implements HttpCallback { ProxySelector.setDefault(new MyProxySelector()); try { InetAddress loopback = InetAddress.getLoopbackAddress(); - server = new TestHttpServer(new ProxyTest(), 1, 10, loopback, 0); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10, "/", new ProxyTestHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); URL url = URIBuilder.newBuilder() .scheme("http") .loopback() - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .toURL(); System.out.println("client opening connection to: " + url); HttpURLConnection urlc = (HttpURLConnection)url.openConnection(); @@ -93,8 +99,23 @@ public class ProxyTest implements HttpCallback { throw new RuntimeException(e); } finally { if (server != null) { - server.terminate(); + server.stop(1); } } } } + +class ProxyTestHandler implements HttpHandler { + + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + exchange.sendResponseHeaders(200, 0); + } catch (IOException e) { + e.printStackTrace(); + } + try(PrintWriter pw = new PrintWriter(exchange.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print("Hello ."); + } + } +} diff --git a/test/jdk/java/net/URL/PerConnectionProxy.java b/test/jdk/java/net/URL/PerConnectionProxy.java index 6ce25b9a50e..1877e7cef28 100644 --- a/test/jdk/java/net/URL/PerConnectionProxy.java +++ b/test/jdk/java/net/URL/PerConnectionProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -24,42 +24,47 @@ /* @test * @bug 4920526 * @summary Needs per connection proxy support for URLs - * @modules java.base/sun.net.www - * @library ../../../sun/net/www/httptest/ /test/lib - * @build ClosedChannelList TestHttpServer HttpTransaction HttpCallback + * @library /test/lib * @compile PerConnectionProxy.java * @run main/othervm -Dhttp.proxyHost=inexistant -Dhttp.proxyPort=8080 PerConnectionProxy */ -import java.net.*; -import java.io.*; - +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.nio.charset.Charset; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.net.URIBuilder; -public class PerConnectionProxy implements HttpCallback { - static TestHttpServer server; - - public void request (HttpTransaction req) { - req.setResponseEntityBody ("Hello ."); - try { - req.sendResponse (200, "Ok"); - req.orderlyClose(); - } catch (IOException e) { - } - } +public class PerConnectionProxy { + static HttpServer server; public static void main(String[] args) { try { InetAddress loopbackAddress = InetAddress.getLoopbackAddress(); - server = new TestHttpServer(new PerConnectionProxy(), 1, 10, loopbackAddress, 0); - ProxyServer pserver = new ProxyServer(loopbackAddress, server.getLocalPort()); + server = HttpServer.create(new InetSocketAddress(loopbackAddress, 0), 10, "/", new PerConnectionProxyHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + ProxyServer pserver = new ProxyServer(loopbackAddress, server.getAddress().getPort()); // start proxy server new Thread(pserver).start(); URL url = URIBuilder.newBuilder() .scheme("http") .loopback() - .port(server.getLocalPort()) + .port(server.getAddress().getPort()) .toURLUnchecked(); // for non existing proxy expect an IOException @@ -73,7 +78,6 @@ public class PerConnectionProxy implements HttpCallback { } catch (IOException ioex) { // expected } - // for NO_PROXY, expect direct connection try { HttpURLConnection urlc = (HttpURLConnection)url.openConnection (Proxy.NO_PROXY); @@ -82,7 +86,6 @@ public class PerConnectionProxy implements HttpCallback { } catch (IOException ioex) { throw new RuntimeException("direct connection should succeed :"+ioex.getMessage()); } - // for a normal proxy setting expect to see connection // goes through that proxy try { @@ -101,10 +104,9 @@ public class PerConnectionProxy implements HttpCallback { throw new RuntimeException(e); } finally { if (server != null) { - server.terminate(); + server.stop(1); } } - } static class ProxyServer extends Thread { @@ -145,7 +147,6 @@ public class PerConnectionProxy implements HttpCallback { private void processRequests() throws Exception { // connection set to the tunneling mode - Socket serverSocket = new Socket(serverInetAddr, serverPort); ProxyTunnel clientToServer = new ProxyTunnel( clientSocket, serverSocket); @@ -161,7 +162,6 @@ public class PerConnectionProxy implements HttpCallback { clientToServer.close(); serverToClient.close(); - } /** @@ -221,6 +221,20 @@ public class PerConnectionProxy implements HttpCallback { } catch (IOException ignored) { } } } + } +} +class PerConnectionProxyHandler implements HttpHandler { + + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + exchange.sendResponseHeaders(200, 0); + } catch (IOException e) { + } + try(PrintWriter pw = new PrintWriter(exchange.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print("Hello ."); + } } } + diff --git a/test/jdk/java/net/URLConnection/B5052093.java b/test/jdk/java/net/URLConnection/B5052093.java index f5434f9528b..c93098f2de8 100644 --- a/test/jdk/java/net/URLConnection/B5052093.java +++ b/test/jdk/java/net/URLConnection/B5052093.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, 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,21 +23,31 @@ /* * @test + * @modules java.base/sun.net.www.protocol.file * @bug 5052093 - * @modules java.base/sun.net.www java.base/sun.net.www.protocol.file - * @library ../../../sun/net/www/httptest/ - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction - * @run main B5052093 + * @library /test/lib + * @run main/othervm B5052093 * @summary URLConnection doesn't support large files */ -import java.net.*; -import java.io.*; -import sun.net.www.protocol.file.FileURLConnection; + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URL; +import java.net.URLConnection; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; import static java.net.Proxy.NO_PROXY; +import jdk.test.lib.net.URIBuilder; +import sun.net.www.protocol.file.FileURLConnection; -public class B5052093 implements HttpCallback { - private static TestHttpServer server; - private static long testSize = ((long) (Integer.MAX_VALUE)) + 2; +public class B5052093 { + private static HttpServer server; + static long testSize = ((long) (Integer.MAX_VALUE)) + 2; public static class LargeFile extends File { public LargeFile() { @@ -55,20 +65,18 @@ public class B5052093 implements HttpCallback { } } - public void request(HttpTransaction req) { - try { - req.setResponseHeader("content-length", Long.toString(testSize)); - req.sendResponse(200, "OK"); - } catch (IOException e) { - e.printStackTrace(); - } - } - public static void main(String[] args) throws Exception { InetAddress loopback = InetAddress.getLoopbackAddress(); - server = new TestHttpServer(new B5052093(), 1, 10, loopback, 0); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10, "/", new B5052093Handler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); try { - URL url = new URL("http://" + server.getAuthority() + "/foo"); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getAddress().getPort()) + .path("/foo") + .build().toURL(); URLConnection conn = url.openConnection(NO_PROXY); int i = conn.getContentLength(); long l = conn.getContentLengthLong(); @@ -89,7 +97,20 @@ public class B5052093 implements HttpCallback { throw new RuntimeException("Wrong content-length from file"); } } finally { - server.terminate(); + server.stop(1); + } + } +} + +class B5052093Handler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + exchange.getResponseHeaders().set("content-length", Long.toString(B5052093.testSize)); + exchange.sendResponseHeaders(200, 0); + exchange.close(); + } catch (IOException e) { + e.printStackTrace(); } } } diff --git a/test/jdk/sun/net/www/AuthHeaderTest.java b/test/jdk/sun/net/www/AuthHeaderTest.java index 53852aab8f1..ba1729cb7e6 100644 --- a/test/jdk/sun/net/www/AuthHeaderTest.java +++ b/test/jdk/sun/net/www/AuthHeaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -24,53 +24,31 @@ /** * @test * @bug 4804309 - * @modules java.base/sun.net.www - * @library ../../../sun/net/www/httptest/ - * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction - * @run main AuthHeaderTest + * @library /test/lib + * @run main/othervm AuthHeaderTest * @summary AuthHeaderTest bug */ -import java.io.*; -import java.net.*; - -public class AuthHeaderTest implements HttpCallback { - - static int count = 0; - static String authstring; - - void errorReply (HttpTransaction req, String reply) throws IOException { - req.addResponseHeader ("Connection", "close"); - req.addResponseHeader ("Www-authenticate", reply); - req.sendResponse (401, "Unauthorized"); - req.orderlyClose(); - } - - void okReply (HttpTransaction req) throws IOException { - req.setResponseEntityBody ("Hello ."); - req.sendResponse (200, "Ok"); - req.orderlyClose(); - } - - public void request (HttpTransaction req) { - try { - authstring = req.getRequestHeader ("Authorization"); - System.out.println (authstring); - switch (count) { - case 0: - errorReply (req, "Basic realm=\"wallyworld\""); - break; - case 1: - /* client stores a username/pw for wallyworld - */ - okReply (req); - break; - } - count ++; - } catch (IOException e) { - e.printStackTrace(); - } - } +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.Authenticator; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import jdk.test.lib.net.URIBuilder; + +public class AuthHeaderTest { + static HttpServer server; static void read (InputStream is) throws IOException { int c; @@ -91,19 +69,27 @@ public class AuthHeaderTest implements HttpCallback { is.close(); } - static TestHttpServer server; - public static void main (String[] args) throws Exception { MyAuthenticator auth = new MyAuthenticator (); Authenticator.setDefault (auth); InetAddress loopback = InetAddress.getLoopbackAddress(); try { - server = new TestHttpServer (new AuthHeaderTest(), 1, 10, loopback, 0); - System.out.println ("Server: listening on port: " + server.getAuthority()); - client ("http://" + server.getAuthority() + "/d1/foo.html"); + server = HttpServer.create(new InetSocketAddress(loopback, 0), 10, "/", new AuthHeaderTestHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); + System.out.println ("Server: listening on port: " + server.getAddress().getPort()); + + String serverURL = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(server.getAddress().getPort()) + .path("/") + .build() + .toString(); + client (serverURL + "d1/foo.html"); } catch (Exception e) { if (server != null) { - server.terminate(); + server.stop(1); } throw e; } @@ -111,11 +97,11 @@ public class AuthHeaderTest implements HttpCallback { if (f != 1) { except ("Authenticator was called "+f+" times. Should be 1"); } - server.terminate(); + server.stop(1); } public static void except (String s) { - server.terminate(); + server.stop(1); throw new RuntimeException (s); } @@ -138,3 +124,45 @@ public class AuthHeaderTest implements HttpCallback { } } } + +class AuthHeaderTestHandler implements HttpHandler { + static int count = 0; + static String authstring; + + void errorReply (HttpExchange req, String reply) throws IOException { + req.getResponseHeaders().set("Connection", "close"); + req.getResponseHeaders().set("Www-authenticate", reply); + req.sendResponseHeaders(401, -1); + } + + void okReply (HttpExchange req) throws IOException { + req.sendResponseHeaders (200, 0); + try(PrintWriter pw = new PrintWriter(req.getResponseBody(), false, Charset.forName("UTF-8"))) { + pw.print("Hello ."); + } + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + try { + if(exchange.getRequestHeaders().get("Authorization") != null) { + authstring = exchange.getRequestHeaders().get("Authorization").get(0); + System.out.println (authstring); + } + + switch (count) { + case 0: + errorReply (exchange, "Basic realm=\"wallyworld\""); + break; + case 1: + /* client stores a username/pw for wallyworld + */ + okReply (exchange); + break; + } + count ++; + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java b/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java index d624741bc2c..ebfb550b826 100644 --- a/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java +++ b/test/jdk/sun/net/www/http/KeepAliveCache/B5045306.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -24,19 +24,30 @@ /* * @test * @bug 5045306 6356004 6993490 8255124 - * @modules java.base/sun.net.www - * java.management - * @library ../../httptest/ - * @build HttpCallback TestHttpServer HttpTransaction + * @library /test/lib * @run main/othervm B5045306 * @summary Http keep-alive implementation is not efficient */ -import java.net.*; -import java.io.*; -import java.lang.management.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Executors; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; /* Part 1: * The http client makes a connection to a URL whos content contains a lot of @@ -51,20 +62,19 @@ import java.util.List; * Content-length header. */ -public class B5045306 -{ - static SimpleHttpTransaction httpTrans; - static TestHttpServer server; +public class B5045306 { + static HttpServer server; - public static void main(String[] args) throws Exception { + public static void main(String[] args) { startHttpServer(); clientHttpCalls(); } public static void startHttpServer() { try { - httpTrans = new SimpleHttpTransaction(); - server = new TestHttpServer(httpTrans, 1, 10, InetAddress.getLocalHost(), 0); + server = HttpServer.create(new InetSocketAddress(InetAddress.getLocalHost(), 0), 10, "/", new SimpleHttpTransactionHandler()); + server.setExecutor(Executors.newSingleThreadExecutor()); + server.start(); } catch (IOException e) { e.printStackTrace(); } @@ -76,10 +86,10 @@ public class B5045306 uncaught.add(ex); }); try { - System.out.println("http server listen on: " + server.getLocalPort()); + System.out.println("http server listen on: " + server.getAddress().getPort()); String hostAddr = InetAddress.getLocalHost().getHostAddress(); if (hostAddr.indexOf(':') > -1) hostAddr = "[" + hostAddr + "]"; - String baseURLStr = "http://" + hostAddr + ":" + server.getLocalPort() + "/"; + String baseURLStr = "http://" + hostAddr + ":" + server.getAddress().getPort() + "/"; URL bigDataURL = new URL (baseURLStr + "firstCall"); URL smallDataURL = new URL (baseURLStr + "secondCall"); @@ -98,7 +108,7 @@ public class B5045306 uc = (HttpURLConnection)smallDataURL.openConnection(Proxy.NO_PROXY); uc.getResponseCode(); - if (SimpleHttpTransaction.failed) + if (SimpleHttpTransactionHandler.failed) throw new RuntimeException("Failed: Initial Keep Alive Connection is not being reused"); // Part 2 @@ -137,7 +147,7 @@ public class B5045306 } catch (IOException e) { e.printStackTrace(); } finally { - server.terminate(); + server.stop(1); } if (!uncaught.isEmpty()) { throw new RuntimeException("Unhandled exception:", uncaught.get(0)); @@ -145,9 +155,9 @@ public class B5045306 } } -class SimpleHttpTransaction implements HttpCallback +class SimpleHttpTransactionHandler implements HttpHandler { - static boolean failed = false; + static volatile boolean failed = false; // Need to have enough data here that is too large for the socket buffer to hold. // Also http.KeepAlive.remainingData must be greater than this value, default is 256K. @@ -155,48 +165,46 @@ class SimpleHttpTransaction implements HttpCallback int port1; - public void request(HttpTransaction trans) { + public void handle(HttpExchange trans) { try { String path = trans.getRequestURI().getPath(); if (path.equals("/firstCall")) { - port1 = trans.channel().socket().getPort(); + port1 = trans.getLocalAddress().getPort(); System.out.println("First connection on client port = " + port1); byte[] responseBody = new byte[RESPONSE_DATA_LENGTH]; for (int i=0; i - * The incoming request fields can be examined via the {@link HttpTransaction} - * object, and a response can also be generated and sent via the request object. - */ -public interface HttpCallback { - /** - * handle the given request and generate an appropriate response. - * @param msg the transaction containing the request from the - * client and used to send the response - */ - void request (HttpTransaction msg); -} diff --git a/test/jdk/sun/net/www/httptest/HttpTransaction.java b/test/jdk/sun/net/www/httptest/HttpTransaction.java deleted file mode 100644 index 781aacaff5b..00000000000 --- a/test/jdk/sun/net/www/httptest/HttpTransaction.java +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Copyright (c) 2002, 2012, 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. - */ - -import java.io.*; -import java.nio.*; -import java.nio.channels.*; -import java.net.*; -import sun.net.www.MessageHeader; - -/** - * This class encapsulates a HTTP request received and a response to be - * generated in one transaction. It provides methods for examaining the - * request from the client, and for building and sending a reply. - */ - -public class HttpTransaction { - - String command; - URI requesturi; - TestHttpServer.Server server; - MessageHeader reqheaders, reqtrailers; - String reqbody; - byte[] rspbody; - MessageHeader rspheaders, rsptrailers; - SelectionKey key; - int rspbodylen; - boolean rspchunked; - - HttpTransaction (TestHttpServer.Server server, String command, - URI requesturi, MessageHeader headers, - String body, MessageHeader trailers, SelectionKey key) { - this.command = command; - this.requesturi = requesturi; - this.reqheaders = headers; - this.reqbody = body; - this.reqtrailers = trailers; - this.key = key; - this.server = server; - } - - /** - * Get the value of a request header whose name is specified by the - * String argument. - * - * @param key the name of the request header - * @return the value of the header or null if it does not exist - */ - public String getRequestHeader (String key) { - return reqheaders.findValue (key); - } - - /** - * Get the value of a response header whose name is specified by the - * String argument. - * - * @param key the name of the response header - * @return the value of the header or null if it does not exist - */ - public String getResponseHeader (String key) { - return rspheaders.findValue (key); - } - - /** - * Get the request URI - * - * @return the request URI - */ - public URI getRequestURI () { - return requesturi; - } - - public String toString () { - StringBuffer buf = new StringBuffer(); - buf.append ("Request from: ").append (key.channel().toString()).append("\r\n"); - buf.append ("Command: ").append (command).append("\r\n"); - buf.append ("Request URI: ").append (requesturi).append("\r\n"); - buf.append ("Headers: ").append("\r\n"); - buf.append (reqheaders.toString()).append("\r\n"); - buf.append ("Body: ").append (reqbody).append("\r\n"); - buf.append ("---------Response-------\r\n"); - buf.append ("Headers: ").append("\r\n"); - if (rspheaders != null) { - buf.append (rspheaders.toString()).append("\r\n"); - } - String rbody = rspbody == null? "": new String (rspbody); - buf.append ("Body: ").append (rbody).append("\r\n"); - return new String (buf); - } - - /** - * Get the value of a request trailer whose name is specified by - * the String argument. - * - * @param key the name of the request trailer - * @return the value of the trailer or null if it does not exist - */ - public String getRequestTrailer (String key) { - return reqtrailers.findValue (key); - } - - /** - * Add a response header to the response. Multiple calls with the same - * key value result in multiple header lines with the same key identifier - * @param key the name of the request header to add - * @param val the value of the header - */ - public void addResponseHeader (String key, String val) { - if (rspheaders == null) - rspheaders = new MessageHeader (); - rspheaders.add (key, val); - } - - /** - * Set a response header. Searches for first header with named key - * and replaces its value with val - * @param key the name of the request header to add - * @param val the value of the header - */ - public void setResponseHeader (String key, String val) { - if (rspheaders == null) - rspheaders = new MessageHeader (); - rspheaders.set (key, val); - } - - /** - * Add a response trailer to the response. Multiple calls with the same - * key value result in multiple trailer lines with the same key identifier - * @param key the name of the request trailer to add - * @param val the value of the trailer - */ - public void addResponseTrailer (String key, String val) { - if (rsptrailers == null) - rsptrailers = new MessageHeader (); - rsptrailers.add (key, val); - } - - /** - * Get the request method - * - * @return the request method - */ - public String getRequestMethod (){ - return command; - } - - /** - * Perform an orderly close of the TCP connection associated with this - * request. This method guarantees that any response already sent will - * not be reset (by this end). The implementation does a shutdownOutput() - * of the TCP connection and for a period of time consumes and discards - * data received on the reading side of the connection. This happens - * in the background. After the period has expired the - * connection is completely closed. - */ - - public void orderlyClose () { - try { - server.orderlyCloseChannel (key); - } catch (IOException e) { - System.out.println (e); - } - } - - /** - * Do an immediate abortive close of the TCP connection associated - * with this request. - */ - public void abortiveClose () { - try { - server.abortiveCloseChannel(key); - } catch (IOException e) { - System.out.println (e); - } - } - - /** - * Get the SocketChannel associated with this request - * - * @return the socket channel - */ - public SocketChannel channel() { - return (SocketChannel) key.channel(); - } - - /** - * Get the request entity body associated with this request - * as a single String. - * - * @return the entity body in one String - */ - public String getRequestEntityBody (){ - return reqbody; - } - - /** - * Set the entity response body with the given string - * The content length is set to the length of the string - * @param body the string to send in the response - */ - public void setResponseEntityBody (String body){ - rspbody = body.getBytes(); - rspbodylen = body.length(); - rspchunked = false; - addResponseHeader ("Content-length", Integer.toString (rspbodylen)); - } - /** - * Set the entity response body with the given byte[] - * The content length is set to the gven length - * @param body the string to send in the response - */ - public void setResponseEntityBody (byte[] body, int len){ - rspbody = body; - rspbodylen = len; - rspchunked = false; - addResponseHeader ("Content-length", Integer.toString (rspbodylen)); - } - - - /** - * Set the entity response body by reading the given inputstream - * - * @param is the inputstream from which to read the body - */ - public void setResponseEntityBody (InputStream is) throws IOException { - byte[] buf = new byte [2048]; - byte[] total = new byte [2048]; - int total_len = 2048; - int c, len=0; - while ((c=is.read (buf)) != -1) { - if (len+c > total_len) { - byte[] total1 = new byte [total_len * 2]; - System.arraycopy (total, 0, total1, 0, len); - total = total1; - total_len = total_len * 2; - } - System.arraycopy (buf, 0, total, len, c); - len += c; - } - setResponseEntityBody (total, len); - } - - /* chunked */ - - /** - * Set the entity response body with the given array of strings - * The content encoding is set to "chunked" and each array element - * is sent as one chunk. - * @param body the array of string chunks to send in the response - */ - public void setResponseEntityBody (String[] body) { - StringBuffer buf = new StringBuffer (); - int len = 0; - for (int i=0; i - * It must be instantiated with a {@link HttpCallback} object to which - * requests are given and must be handled. - *

- * Simple synchronization between the client(s) and server can be done - * using the {@link #waitForCondition(String)}, {@link #setCondition(String)} and - * {@link #rendezvous(String,int)} methods. - * - * NOTE NOTE NOTE NOTE NOTE NOTE NOTE - * - * If changes are made here, please sure they are propagated to - * the HTTPS equivalent in the JSSE regression test suite. - * - * NOTE NOTE NOTE NOTE NOTE NOTE NOTE - */ - -public class TestHttpServer { - - ServerSocketChannel schan; - int threads; - int cperthread; - HttpCallback cb; - Server[] servers; - - /** - * Create a TestHttpServer instance with the specified callback object - * for handling requests. One thread is created to handle requests, - * and up to ten TCP connections will be handled simultaneously. - * @param cb the callback object which is invoked to handle each - * incoming request - */ - - public TestHttpServer (HttpCallback cb) throws IOException { - this (cb, 1, 10, 0); - } - - /** - * Create a TestHttpServer instance with the specified callback object - * for handling requests. One thread is created to handle requests, - * and up to ten TCP connections will be handled simultaneously. - * @param cb the callback object which is invoked to handle each - * incoming request - * @param address the address to bind the server to. Null - * means bind to the wildcard address. - * @param port the port number to bind the server to. Zero - * means choose any free port. - */ - - public TestHttpServer (HttpCallback cb, InetAddress address, int port) throws IOException { - this (cb, 1, 10, address, 0); - } - - /** - * Create a TestHttpServer instance with the specified number of - * threads and maximum number of connections per thread. This functions - * the same as the 4 arg constructor, where the port argument is set to zero. - * @param cb the callback object which is invoked to handle each - * incoming request - * @param threads the number of threads to create to handle requests - * in parallel - * @param cperthread the number of simultaneous TCP connections to - * handle per thread - */ - - public TestHttpServer (HttpCallback cb, int threads, int cperthread) - throws IOException { - this (cb, threads, cperthread, 0); - } - - /** - * Create a TestHttpServer instance with the specified number - * of threads and maximum number of connections per thread and running on - * the specified port. The specified number of threads are created to - * handle incoming requests, and each thread is allowed - * to handle a number of simultaneous TCP connections. - * @param cb the callback object which is invoked to handle - * each incoming request - * @param threads the number of threads to create to handle - * requests in parallel - * @param cperthread the number of simultaneous TCP connections - * to handle per thread - * @param port the port number to bind the server to. Zero - * means choose any free port. - */ - - public TestHttpServer (HttpCallback cb, int threads, int cperthread, int port) - throws IOException { - this(cb, threads, cperthread, null, port); - } - - /** - * Create a TestHttpServer instance with the specified number - * of threads and maximum number of connections per thread and running on - * the specified port. The specified number of threads are created to - * handle incoming requests, and each thread is allowed - * to handle a number of simultaneous TCP connections. - * @param cb the callback object which is invoked to handle - * each incoming request - * @param threads the number of threads to create to handle - * requests in parallel - * @param cperthread the number of simultaneous TCP connections - * to handle per thread - * @param address the address to bind the server to. Null - * means bind to the wildcard address. - * @param port the port number to bind the server to. Zero - * means choose any free port. - */ - - public TestHttpServer (HttpCallback cb, int threads, int cperthread, - InetAddress address, int port) - throws IOException { - schan = ServerSocketChannel.open (); - InetSocketAddress addr = new InetSocketAddress (address, port); - schan.socket().bind (addr); - this.threads = threads; - this.cb = cb; - this.cperthread = cperthread; - servers = new Server [threads]; - for (int i=0; i -1) hostaddr = "[" + hostaddr + "]"; - return hostaddr + ":" + getLocalPort(); - } - - static class Server extends Thread { - - ServerSocketChannel schan; - Selector selector; - SelectionKey listenerKey; - SelectionKey key; /* the current key being processed */ - HttpCallback cb; - ByteBuffer consumeBuffer; - int maxconn; - int nconn; - ClosedChannelList clist; - volatile boolean shutdown; - - Server (HttpCallback cb, ServerSocketChannel schan, int maxconn) { - this.schan = schan; - this.maxconn = maxconn; - this.cb = cb; - nconn = 0; - consumeBuffer = ByteBuffer.allocate (512); - clist = new ClosedChannelList (); - try { - selector = Selector.open (); - schan.configureBlocking (false); - listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT); - } catch (IOException e) { - System.err.println ("Server could not start: " + e); - throw new RuntimeException("Server could not start: " + e, e); - } - } - - /* Stop the thread as soon as possible */ - public void terminate () { - shutdown = true; - } - - public void run () { - try { - while (true) { - selector.select(1000); - Set selected = selector.selectedKeys(); - Iterator iter = selected.iterator(); - while (iter.hasNext()) { - key = iter.next(); - if (key.equals (listenerKey)) { - SocketChannel sock = schan.accept (); - if (sock == null) { - /* false notification */ - iter.remove(); - continue; - } - sock.configureBlocking (false); - sock.register (selector, SelectionKey.OP_READ); - nconn ++; - System.out.println("SERVER: new connection. chan[" + sock + "]"); - if (nconn == maxconn) { - /* deregister */ - listenerKey.cancel (); - listenerKey = null; - } - } else { - if (key.isReadable()) { - boolean closed; - SocketChannel chan = (SocketChannel) key.channel(); - System.out.println("SERVER: connection readable. chan[" + chan + "]"); - if (key.attachment() != null) { - System.out.println("Server: consume"); - closed = consume (chan); - } else { - closed = read (chan, key); - } - if (closed) { - chan.close (); - key.cancel (); - if (nconn == maxconn) { - listenerKey = schan.register (selector, SelectionKey.OP_ACCEPT); - } - nconn --; - } - } - } - iter.remove(); - } - clist.check(); - if (shutdown) { - System.out.println("Force to Shutdown"); - SelectionKey sKey = schan.keyFor(selector); - if (sKey != null) { - sKey.cancel(); - } - - clist.terminate (); - selector.close(); - schan.socket().close(); - schan.close(); - return; - } - } - } catch (IOException e) { - System.out.println ("Server exception: " + e); - // TODO finish - } - } - - /* read all the data off the channel without looking at it - * return true if connection closed - */ - boolean consume (SocketChannel chan) { - try { - consumeBuffer.clear (); - int c = chan.read (consumeBuffer); - if (c == -1) - return true; - } catch (IOException e) { - return true; - } - return false; - } - - /* return true if the connection is closed, false otherwise */ - - private boolean read (SocketChannel chan, SelectionKey key) { - HttpTransaction msg; - boolean res; - try { - InputStream is = new BufferedInputStream (new NioInputStream (chan)); - String requestline = readLine (is); - MessageHeader mhead = new MessageHeader (is); - String clen = mhead.findValue ("Content-Length"); - String trferenc = mhead.findValue ("Transfer-Encoding"); - String data = null; - if (trferenc != null && trferenc.equals ("chunked")) - data = new String (readChunkedData (is)); - else if (clen != null) - data = new String (readNormalData (is, Integer.parseInt (clen))); - String[] req = requestline.split (" "); - if (req.length < 2) { - /* invalid request line */ - return false; - } - String cmd = req[0]; - URI uri = null; - try { - uri = new URI (req[1]); - msg = new HttpTransaction (this, cmd, uri, mhead, data, null, key); - cb.request (msg); - } catch (URISyntaxException e) { - System.err.println ("Invalid URI: " + e); - msg = new HttpTransaction (this, cmd, null, null, null, null, key); - msg.sendResponse (501, "Whatever"); - } - res = false; - } catch (IOException e) { - res = true; - } - return res; - } - - byte[] readNormalData (InputStream is, int len) throws IOException { - byte [] buf = new byte [len]; - int c, off=0, remain=len; - while (remain > 0 && ((c=is.read (buf, off, remain))>0)) { - remain -= c; - off += c; - } - return buf; - } - - private void readCRLF(InputStream is) throws IOException { - int cr = is.read(); - int lf = is.read(); - - if (((cr & 0xff) != 0x0d) || - ((lf & 0xff) != 0x0a)) { - throw new IOException( - "Expected : got '" + cr + "/" + lf + "'"); - } - } - - byte[] readChunkedData (InputStream is) throws IOException { - LinkedList l = new LinkedList (); - int total = 0; - for (int len=readChunkLen(is); len!=0; len=readChunkLen(is)) { - l.add (readNormalData(is, len)); - total += len; - readCRLF(is); // CRLF at end of chunk - } - readCRLF(is); // CRLF at end of Chunked Stream. - byte[] buf = new byte [total]; - Iterator i = l.iterator(); - int x = 0; - while (i.hasNext()) { - byte[] b = (byte[])i.next(); - System.arraycopy (b, 0, buf, x, b.length); - x += b.length; - } - return buf; - } - - private int readChunkLen (InputStream is) throws IOException { - int c, len=0; - boolean done=false, readCR=false; - while (!done) { - c = is.read (); - if (c == '\n' && readCR) { - done = true; - } else { - if (c == '\r' && !readCR) { - readCR = true; - } else { - int x=0; - if (c >= 'a' && c <= 'f') { - x = c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - x = c - 'A' + 10; - } else if (c >= '0' && c <= '9') { - x = c - '0'; - } - len = len * 16 + x; - } - } - } - return len; - } - - private String readLine (InputStream is) throws IOException { - boolean done=false, readCR=false; - byte[] b = new byte [512]; - int c, l = 0; - - while (!done) { - c = is.read (); - if (c == '\n' && readCR) { - done = true; - } else { - if (c == '\r' && !readCR) { - readCR = true; - } else { - b[l++] = (byte)c; - } - } - } - return new String (b); - } - - /** close the channel associated with the current key by: - * 1. shutdownOutput (send a FIN) - * 2. mark the key so that incoming data is to be consumed and discarded - * 3. After a period, close the socket - */ - - synchronized void orderlyCloseChannel (SelectionKey key) throws IOException { - SocketChannel ch = (SocketChannel)key.channel (); - System.out.println("SERVER: orderlyCloseChannel chan[" + ch + "]"); - ch.socket().shutdownOutput(); - key.attach (this); - clist.add (key); - } - - synchronized void abortiveCloseChannel (SelectionKey key) throws IOException { - SocketChannel ch = (SocketChannel)key.channel (); - System.out.println("SERVER: abortiveCloseChannel chan[" + ch + "]"); - - Socket s = ch.socket (); - s.setSoLinger (true, 0); - ch.close(); - } - } - - - /** - * Implements blocking reading semantics on top of a non-blocking channel - */ - - static class NioInputStream extends InputStream { - SocketChannel channel; - Selector selector; - ByteBuffer chanbuf; - SelectionKey key; - int available; - byte[] one; - boolean closed; - ByteBuffer markBuf; /* reads may be satisifed from this buffer */ - boolean marked; - boolean reset; - int readlimit; - - public NioInputStream (SocketChannel chan) throws IOException { - this.channel = chan; - selector = Selector.open(); - chanbuf = ByteBuffer.allocate (1024); - key = chan.register (selector, SelectionKey.OP_READ); - available = 0; - one = new byte[1]; - closed = marked = reset = false; - } - - public synchronized int read (byte[] b) throws IOException { - return read (b, 0, b.length); - } - - public synchronized int read () throws IOException { - return read (one, 0, 1); - } - - public synchronized int read (byte[] b, int off, int srclen) throws IOException { - - int canreturn, willreturn; - - if (closed) - return -1; - - if (reset) { /* satisfy from markBuf */ - canreturn = markBuf.remaining (); - willreturn = canreturn>srclen ? srclen : canreturn; - markBuf.get(b, off, willreturn); - if (canreturn == willreturn) { - reset = false; - } - } else { /* satisfy from channel */ - canreturn = available(); - if (canreturn == 0) { - block (); - canreturn = available(); - } - willreturn = canreturn>srclen ? srclen : canreturn; - chanbuf.get(b, off, willreturn); - available -= willreturn; - - if (marked) { /* copy into markBuf */ - try { - markBuf.put (b, off, willreturn); - } catch (BufferOverflowException e) { - marked = false; - } - } - } - return willreturn; - } - - public synchronized int available () throws IOException { - if (closed) - throw new IOException ("Stream is closed"); - - if (reset) - return markBuf.remaining(); - - if (available > 0) - return available; - - chanbuf.clear (); - available = channel.read (chanbuf); - if (available > 0) - chanbuf.flip(); - else if (available == -1) - throw new IOException ("Stream is closed"); - return available; - } - - /** - * block() only called when available==0 and buf is empty - */ - private synchronized void block () throws IOException { - //assert available == 0; - int n = selector.select (); - //assert n == 1; - selector.selectedKeys().clear(); - available (); - } - - public void close () throws IOException { - if (closed) - return; - channel.close (); - closed = true; - } - - public synchronized void mark (int readlimit) { - if (closed) - return; - this.readlimit = readlimit; - markBuf = ByteBuffer.allocate (readlimit); - marked = true; - reset = false; - } - - public synchronized void reset () throws IOException { - if (closed ) - return; - if (!marked) - throw new IOException ("Stream not marked"); - marked = false; - reset = true; - markBuf.flip (); - } - } - - static class NioOutputStream extends OutputStream { - SocketChannel channel; - ByteBuffer buf; - SelectionKey key; - Selector selector; - boolean closed; - byte[] one; - - public NioOutputStream (SocketChannel channel) throws IOException { - this.channel = channel; - selector = Selector.open (); - key = channel.register (selector, SelectionKey.OP_WRITE); - closed = false; - one = new byte [1]; - } - - public synchronized void write (int b) throws IOException { - one[0] = (byte)b; - write (one, 0, 1); - } - - public synchronized void write (byte[] b) throws IOException { - write (b, 0, b.length); - } - - public synchronized void write (byte[] b, int off, int len) throws IOException { - if (closed) - throw new IOException ("stream is closed"); - - buf = ByteBuffer.allocate (len); - buf.put (b, off, len); - buf.flip (); - int n; - while ((n = channel.write (buf)) < len) { - len -= n; - if (len == 0) - return; - selector.select (); - selector.selectedKeys().clear (); - } - } - - public void close () throws IOException { - if (closed) - return; - channel.close (); - closed = true; - } - } - - /** - * Utilities for synchronization. A condition is - * identified by a string name, and is initialized - * upon first use (ie. setCondition() or waitForCondition()). Threads - * are blocked until some thread calls (or has called) setCondition() for the same - * condition. - *

- * A rendezvous built on a condition is also provided for synchronizing - * N threads. - */ - - private static HashMap conditions = new HashMap(); - - /* - * Modifiable boolean object - */ - private static class BValue { - boolean v; - } - - /* - * Modifiable int object - */ - private static class IValue { - int v; - IValue (int i) { - v =i; - } - } - - - private static BValue getCond (String condition) { - synchronized (conditions) { - BValue cond = (BValue) conditions.get (condition); - if (cond == null) { - cond = new BValue(); - conditions.put (condition, cond); - } - return cond; - } - } - - /** - * Set the condition to true. Any threads that are currently blocked - * waiting on the condition, will be unblocked and allowed to continue. - * Threads that subsequently call waitForCondition() will not block. - * If the named condition did not exist prior to the call, then it is created - * first. - */ - - public static void setCondition (String condition) { - BValue cond = getCond (condition); - synchronized (cond) { - if (cond.v) { - return; - } - cond.v = true; - cond.notifyAll(); - } - } - - /** - * If the named condition does not exist, then it is created and initialized - * to false. If the condition exists or has just been created and its value - * is false, then the thread blocks until another thread sets the condition. - * If the condition exists and is already set to true, then this call returns - * immediately without blocking. - */ - - public static void waitForCondition (String condition) { - BValue cond = getCond (condition); - synchronized (cond) { - if (!cond.v) { - try { - cond.wait(); - } catch (InterruptedException e) {} - } - } - } - - /* conditions must be locked when accessing this */ - static HashMap rv = new HashMap(); - - /** - * Force N threads to rendezvous (ie. wait for each other) before proceeding. - * The first thread(s) to call are blocked until the last - * thread makes the call. Then all threads continue. - *

- * All threads that call with the same condition name, must use the same value - * for N (or the results may be not be as expected). - *

- * Obviously, if fewer than N threads make the rendezvous then the result - * will be a hang. - */ - - public static void rendezvous (String condition, int N) { - BValue cond; - IValue iv; - String name = "RV_"+condition; - - /* get the condition */ - - synchronized (conditions) { - cond = (BValue)conditions.get (name); - if (cond == null) { - /* we are first caller */ - if (N < 2) { - throw new RuntimeException ("rendezvous must be called with N >= 2"); - } - cond = new BValue (); - conditions.put (name, cond); - iv = new IValue (N-1); - rv.put (name, iv); - } else { - /* already initialised, just decrement the counter */ - iv = (IValue) rv.get (name); - iv.v --; - } - } - - if (iv.v > 0) { - waitForCondition (name); - } else { - setCondition (name); - synchronized (conditions) { - clearCondition (name); - rv.remove (name); - } - } - } - - /** - * If the named condition exists and is set then remove it, so it can - * be re-initialized and used again. If the condition does not exist, or - * exists but is not set, then the call returns without doing anything. - * Note, some higher level synchronization - * may be needed between clear and the other operations. - */ - - public static void clearCondition(String condition) { - BValue cond; - synchronized (conditions) { - cond = (BValue) conditions.get (condition); - if (cond == null) { - return; - } - synchronized (cond) { - if (cond.v) { - conditions.remove (condition); - } - } - } - } -} diff --git a/test/jdk/sun/security/ssl/InputRecord/ClientHelloRead.java b/test/jdk/sun/security/ssl/InputRecord/ClientHelloRead.java index e08230f325d..06cba109139 100644 --- a/test/jdk/sun/security/ssl/InputRecord/ClientHelloRead.java +++ b/test/jdk/sun/security/ssl/InputRecord/ClientHelloRead.java @@ -32,12 +32,22 @@ * system properties in samevm/agentvm mode. */ -import java.io.*; -import java.net.*; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.ServerSocket; +import java.net.URL; import java.security.KeyStore; -import javax.net.*; -import javax.net.ssl.*; -import java.security.cert.*; + +import javax.net.ServerSocketFactory; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; /* * ClientHelloRead.java -- includes a simple server that can serve -- GitLab From 0fd09d383b9921f26d2d609ab330630a4520325a Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Fri, 11 Mar 2022 13:25:09 +0000 Subject: [PATCH 024/237] 8282978: Wrong parameter passed to GetStringXXXChars in various places Reviewed-by: alanb, dfuchs --- src/java.base/unix/native/libnet/Inet4AddressImpl.c | 4 ++-- src/java.base/unix/native/libnet/Inet6AddressImpl.c | 4 ++-- src/java.base/windows/native/libnet/Inet4AddressImpl.c | 4 ++-- src/java.base/windows/native/libnet/Inet6AddressImpl.c | 4 ++-- src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c | 4 ++-- .../windows/native/libawt/windows/awt_Button.cpp | 6 +++--- .../windows/native/libawt/windows/awt_Checkbox.cpp | 6 +++--- .../windows/native/libawt/windows/awt_Desktop.cpp | 6 +++--- .../windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp | 6 +++--- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c index bc6c859b841..0edebdbb3ba 100644 --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -100,7 +100,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "host argument is null"); return NULL; } - hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); + hostname = JNU_GetStringPlatformChars(env, host, NULL); CHECK_NULL_RETURN(hostname, NULL); // try once, with our static buffer diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c index ed0ddbb562c..331151faeb5 100644 --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -220,7 +220,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "host argument is null"); return NULL; } - hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); + hostname = JNU_GetStringPlatformChars(env, host, NULL); CHECK_NULL_RETURN(hostname, NULL); // try once, with our static buffer diff --git a/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/src/java.base/windows/native/libnet/Inet4AddressImpl.c index 75dfb57eb2f..33f379024c0 100644 --- a/src/java.base/windows/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet4AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -76,7 +76,7 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "host argument is null"); return NULL; } - hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); + hostname = JNU_GetStringPlatformChars(env, host, NULL); CHECK_NULL_RETURN(hostname, NULL); // try once, with our static buffer diff --git a/src/java.base/windows/native/libnet/Inet6AddressImpl.c b/src/java.base/windows/native/libnet/Inet6AddressImpl.c index 87908775e99..a011b2fe5fa 100644 --- a/src/java.base/windows/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -71,7 +71,7 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, JNU_ThrowNullPointerException(env, "host argument is null"); return NULL; } - hostname = JNU_GetStringPlatformChars(env, host, JNI_FALSE); + hostname = JNU_GetStringPlatformChars(env, host, NULL); CHECK_NULL_RETURN(hostname, NULL); // try once, with our static buffer diff --git a/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c b/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c index 19173eb6052..851071db3e0 100644 --- a/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c +++ b/src/java.desktop/unix/native/libawt_xawt/xawt/XlibWrapper.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2022, 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 @@ -825,7 +825,7 @@ JNIEXPORT void JNICALL Java_sun_awt_X11_XlibWrapper_SetProperty */ if (!JNU_IsNull(env, jstr)) { #ifdef X_HAVE_UTF8_STRING - cname = (char *) (*env)->GetStringUTFChars(env, jstr, JNI_FALSE); + cname = (char *) (*env)->GetStringUTFChars(env, jstr, NULL); #else cname = (char *) JNU_GetStringPlatformChars(env, jstr, NULL); #endif diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp index 1a7a89fdef4..3f019b0c278 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Button.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -105,7 +105,7 @@ AwtButton* AwtButton::Create(jobject self, jobject parent) if (label == NULL) { labelStr = L""; } else { - labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE); + labelStr = JNU_GetStringPlatformChars(env, label, NULL); } style = 0; @@ -311,7 +311,7 @@ void AwtButton::_SetLabel(void *param) if (label == NULL) { labelStr = TEXT(""); } else { - labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE); + labelStr = JNU_GetStringPlatformChars(env, label, NULL); } if (labelStr == NULL) { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Checkbox.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Checkbox.cpp index d77ebb74a3e..5b004da95f2 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Checkbox.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Checkbox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -106,7 +106,7 @@ AwtCheckbox* AwtCheckbox::Create(jobject peer, jobject parent) label = (jstring)env->GetObjectField(target, AwtCheckbox::labelID); if (label != NULL) { - labelStr = JNU_GetStringPlatformChars(env, label, 0); + labelStr = JNU_GetStringPlatformChars(env, label, NULL); } if (labelStr != 0) { jint x = env->GetIntField(target, AwtComponent::xID); @@ -375,7 +375,7 @@ void AwtCheckbox::_SetLabel(void *param) } else { - labelStr = JNU_GetStringPlatformChars(env, label, JNI_FALSE); + labelStr = JNU_GetStringPlatformChars(env, label, NULL); } if (labelStr == NULL) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Desktop.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Desktop.cpp index 73b3c51c796..9cf2cea6fab 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Desktop.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Desktop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -75,9 +75,9 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WDesktopPeer_init JNIEXPORT jstring JNICALL Java_sun_awt_windows_WDesktopPeer_ShellExecute (JNIEnv *env, jclass cls, jstring fileOrUri_j, jstring verb_j) { - LPCWSTR fileOrUri_c = JNU_GetStringPlatformChars(env, fileOrUri_j, JNI_FALSE); + LPCWSTR fileOrUri_c = JNU_GetStringPlatformChars(env, fileOrUri_j, NULL); CHECK_NULL_RETURN(fileOrUri_c, NULL); - LPCWSTR verb_c = JNU_GetStringPlatformChars(env, verb_j, JNI_FALSE); + LPCWSTR verb_c = JNU_GetStringPlatformChars(env, verb_j, NULL); if (verb_c == NULL) { JNU_ReleaseStringPlatformChars(env, fileOrUri_j, fileOrUri_c); return NULL; diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp index 434050215a3..ab8ad1ddf9e 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsEnv.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, 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 @@ -183,7 +183,7 @@ Java_sun_awt_Win32FontManager_registerFontWithPlatform(JNIEnv *env, jclass cl, jstring fontName) { - LPTSTR file = (LPTSTR)JNU_GetStringPlatformChars(env, fontName, JNI_FALSE); + LPTSTR file = (LPTSTR)JNU_GetStringPlatformChars(env, fontName, NULL); if (file) { ::AddFontResourceEx(file, FR_PRIVATE, NULL); JNU_ReleaseStringPlatformChars(env, fontName, file); @@ -203,7 +203,7 @@ Java_sun_awt_Win32FontManager_deRegisterFontWithPlatform(JNIEnv *env, jclass cl, jstring fontName) { - LPTSTR file = (LPTSTR)JNU_GetStringPlatformChars(env, fontName, JNI_FALSE); + LPTSTR file = (LPTSTR)JNU_GetStringPlatformChars(env, fontName, NULL); if (file) { ::RemoveFontResourceEx(file, FR_PRIVATE, NULL); JNU_ReleaseStringPlatformChars(env, fontName, file); -- GitLab From 374193b6d2465a356941f9588a0ccf6d97cb76f6 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Fri, 11 Mar 2022 22:41:47 +0000 Subject: [PATCH 025/237] 8283041: [javadoc] Crashes using {@return} with @param Reviewed-by: jjg --- .../jdk/javadoc/internal/doclint/Checker.java | 6 +++--- .../doclet/testReturnTag/TestReturnTag.java | 20 ++++++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java index 446757513a1..6b167aa3933 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclint/Checker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -985,8 +985,8 @@ public class Checker extends DocTreePathScanner { } if (tree.isInline()) { DocCommentTree dct = getCurrentPath().getDocComment(); - if (tree != dct.getFirstSentence().get(0)) { - env.messages.warning(REFERENCE, tree, "dc.return.not.first"); + if (dct.getFirstSentence().isEmpty() || tree != dct.getFirstSentence().get(0)) { + env.messages.warning(SYNTAX, tree, "dc.return.not.first"); } } diff --git a/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java b/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java index 00d5c92c630..4974f4e586e 100644 --- a/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java +++ b/test/langtools/jdk/javadoc/doclet/testReturnTag/TestReturnTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 4490068 8075778 + * @bug 4490068 8075778 8283041 * @summary General tests for inline or block at-return tag * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -265,16 +265,30 @@ public class TestReturnTag extends JavadocTester { */ public int m() { return 0; } } + """, + """ + /** Comment. */ + public class X { + /** + * @author Jim + * {@return the result} + */ + public int m() { return 0; } + } """); javadoc("-d", base.resolve("out").toString(), "-sourcepath", src.toString(), - src.resolve("C.java").toString()); + src.resolve("C.java").toString(), + src.resolve("X.java").toString()); checkExit(Exit.OK); checkOutput(Output.OUT, true, "C.java:4: warning: {@return} not at beginning of description"); + checkOutput(Output.OUT, true, + "X.java:5: warning: {@return} not at beginning of description"); + checkOutput("C.html", true, """

Some text. Returns the result. More text.
-- GitLab From 5c408c1410e15087f735a815b7edc716d514b1b3 Mon Sep 17 00:00:00 2001 From: Joshua Zhu Date: Sat, 12 Mar 2022 04:04:28 +0000 Subject: [PATCH 026/237] 8282874: Bad performance on gather/scatter API caused by different IntSpecies of indexMap Reviewed-by: psandoz --- .../classes/jdk/incubator/vector/ByteVector.java | 12 ++++++------ .../classes/jdk/incubator/vector/DoubleVector.java | 12 ++++++------ .../classes/jdk/incubator/vector/FloatVector.java | 12 ++++++------ .../classes/jdk/incubator/vector/IntVector.java | 12 ++++++------ .../classes/jdk/incubator/vector/LongVector.java | 12 ++++++------ .../classes/jdk/incubator/vector/ShortVector.java | 12 ++++++------ .../jdk/incubator/vector/X-Vector.java.template | 12 ++++++------ 7 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index 5bd14c97601..c21fde386b9 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -4336,12 +4336,12 @@ public abstract class ByteVector extends AbstractVector { */ static ByteSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (ByteSpecies) SPECIES_64; - case S_128_BIT: return (ByteSpecies) SPECIES_128; - case S_256_BIT: return (ByteSpecies) SPECIES_256; - case S_512_BIT: return (ByteSpecies) SPECIES_512; - case S_Max_BIT: return (ByteSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (ByteSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (ByteSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (ByteSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (ByteSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (ByteSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index aec717394ed..4d62284bb6e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -3963,12 +3963,12 @@ public abstract class DoubleVector extends AbstractVector { */ static DoubleSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (DoubleSpecies) SPECIES_64; - case S_128_BIT: return (DoubleSpecies) SPECIES_128; - case S_256_BIT: return (DoubleSpecies) SPECIES_256; - case S_512_BIT: return (DoubleSpecies) SPECIES_512; - case S_Max_BIT: return (DoubleSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (DoubleSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (DoubleSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (DoubleSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (DoubleSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (DoubleSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index c55df4b72bd..60da7eb57fc 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -3913,12 +3913,12 @@ public abstract class FloatVector extends AbstractVector { */ static FloatSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (FloatSpecies) SPECIES_64; - case S_128_BIT: return (FloatSpecies) SPECIES_128; - case S_256_BIT: return (FloatSpecies) SPECIES_256; - case S_512_BIT: return (FloatSpecies) SPECIES_512; - case S_Max_BIT: return (FloatSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (FloatSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (FloatSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (FloatSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (FloatSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (FloatSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index 312e1ad725a..e5033ac5366 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -4061,12 +4061,12 @@ public abstract class IntVector extends AbstractVector { */ static IntSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (IntSpecies) SPECIES_64; - case S_128_BIT: return (IntSpecies) SPECIES_128; - case S_256_BIT: return (IntSpecies) SPECIES_256; - case S_512_BIT: return (IntSpecies) SPECIES_512; - case S_Max_BIT: return (IntSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (IntSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (IntSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (IntSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (IntSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (IntSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 513178181f4..37ba7189679 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -3987,12 +3987,12 @@ public abstract class LongVector extends AbstractVector { */ static LongSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (LongSpecies) SPECIES_64; - case S_128_BIT: return (LongSpecies) SPECIES_128; - case S_256_BIT: return (LongSpecies) SPECIES_256; - case S_512_BIT: return (LongSpecies) SPECIES_512; - case S_Max_BIT: return (LongSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (LongSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (LongSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (LongSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (LongSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (LongSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index 511e10a6563..8c6dd4718f7 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -4330,12 +4330,12 @@ public abstract class ShortVector extends AbstractVector { */ static ShortSpecies species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return (ShortSpecies) SPECIES_64; - case S_128_BIT: return (ShortSpecies) SPECIES_128; - case S_256_BIT: return (ShortSpecies) SPECIES_256; - case S_512_BIT: return (ShortSpecies) SPECIES_512; - case S_Max_BIT: return (ShortSpecies) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return (ShortSpecies) SPECIES_64; + case VectorShape.SK_128_BIT: return (ShortSpecies) SPECIES_128; + case VectorShape.SK_256_BIT: return (ShortSpecies) SPECIES_256; + case VectorShape.SK_512_BIT: return (ShortSpecies) SPECIES_512; + case VectorShape.SK_Max_BIT: return (ShortSpecies) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index 16d2dbea06e..6c5ed6b9c13 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -5543,12 +5543,12 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { */ static $Type$Species species(VectorShape s) { Objects.requireNonNull(s); - switch (s) { - case S_64_BIT: return ($Type$Species) SPECIES_64; - case S_128_BIT: return ($Type$Species) SPECIES_128; - case S_256_BIT: return ($Type$Species) SPECIES_256; - case S_512_BIT: return ($Type$Species) SPECIES_512; - case S_Max_BIT: return ($Type$Species) SPECIES_MAX; + switch (s.switchKey) { + case VectorShape.SK_64_BIT: return ($Type$Species) SPECIES_64; + case VectorShape.SK_128_BIT: return ($Type$Species) SPECIES_128; + case VectorShape.SK_256_BIT: return ($Type$Species) SPECIES_256; + case VectorShape.SK_512_BIT: return ($Type$Species) SPECIES_512; + case VectorShape.SK_Max_BIT: return ($Type$Species) SPECIES_MAX; default: throw new IllegalArgumentException("Bad shape: " + s); } } -- GitLab From 3cf83a671eaedd78d87197dffa76dcc3fededb78 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Mon, 14 Mar 2022 03:17:57 +0000 Subject: [PATCH 027/237] 8282572: EnumSet should be a sealed class Reviewed-by: sundar --- src/java.base/share/classes/java/util/EnumSet.java | 6 +++--- src/java.base/share/classes/java/util/JumboEnumSet.java | 4 ++-- src/java.base/share/classes/java/util/RegularEnumSet.java | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/util/EnumSet.java b/src/java.base/share/classes/java/util/EnumSet.java index ee475ba338a..3776cedd5bb 100644 --- a/src/java.base/share/classes/java/util/EnumSet.java +++ b/src/java.base/share/classes/java/util/EnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -76,8 +76,8 @@ import jdk.internal.access.SharedSecrets; * @since 1.5 * @see EnumMap */ -public abstract class EnumSet> extends AbstractSet - implements Cloneable, java.io.Serializable +public abstract sealed class EnumSet> extends AbstractSet + implements Cloneable, java.io.Serializable permits JumboEnumSet, RegularEnumSet { // declare EnumSet.class serialization compatibility with JDK 8 @java.io.Serial diff --git a/src/java.base/share/classes/java/util/JumboEnumSet.java b/src/java.base/share/classes/java/util/JumboEnumSet.java index f80e5056803..126fc077b6c 100644 --- a/src/java.base/share/classes/java/util/JumboEnumSet.java +++ b/src/java.base/share/classes/java/util/JumboEnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -33,7 +33,7 @@ package java.util; * @since 1.5 * @serial exclude */ -class JumboEnumSet> extends EnumSet { +final class JumboEnumSet> extends EnumSet { @java.io.Serial private static final long serialVersionUID = 334349849919042784L; diff --git a/src/java.base/share/classes/java/util/RegularEnumSet.java b/src/java.base/share/classes/java/util/RegularEnumSet.java index 1deda8a2935..f06adcbf692 100644 --- a/src/java.base/share/classes/java/util/RegularEnumSet.java +++ b/src/java.base/share/classes/java/util/RegularEnumSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -33,7 +33,7 @@ package java.util; * @since 1.5 * @serial exclude */ -class RegularEnumSet> extends EnumSet { +final class RegularEnumSet> extends EnumSet { @java.io.Serial private static final long serialVersionUID = 3411599620347842686L; /** -- GitLab From fde31498963d76630ada31bd0e0cf3035f87445b Mon Sep 17 00:00:00 2001 From: Jatin Bhateja Date: Mon, 14 Mar 2022 07:11:23 +0000 Subject: [PATCH 028/237] 8281375: Accelerate bitCount operation for AVX2 and AVX512 target. Reviewed-by: sviswanathan, thartmann --- src/hotspot/cpu/aarch64/matcher_aarch64.hpp | 6 ++ src/hotspot/cpu/arm/matcher_arm.hpp | 5 ++ src/hotspot/cpu/ppc/matcher_ppc.hpp | 6 ++ src/hotspot/cpu/s390/matcher_s390.hpp | 5 ++ src/hotspot/cpu/x86/assembler_x86.cpp | 22 ++++- src/hotspot/cpu/x86/assembler_x86.hpp | 7 ++ src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 88 +++++++++++++++++++ src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 8 ++ src/hotspot/cpu/x86/matcher_x86.hpp | 9 ++ src/hotspot/cpu/x86/stubGenerator_x86_32.cpp | 29 ++++++ src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 20 +++++ src/hotspot/cpu/x86/stubRoutines_x86.cpp | 1 + src/hotspot/cpu/x86/stubRoutines_x86.hpp | 4 + src/hotspot/cpu/x86/x86.ad | 60 +++++++++++-- src/hotspot/share/opto/loopTransform.cpp | 7 ++ .../vectorization/TestPopCountVectorLong.java | 3 +- 16 files changed, 268 insertions(+), 12 deletions(-) diff --git a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp index aca82240a57..c2f801f408a 100644 --- a/src/hotspot/cpu/aarch64/matcher_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/matcher_aarch64.hpp @@ -163,4 +163,10 @@ // Implements a variant of EncodeISOArrayNode that encode ASCII only static const bool supports_encode_ascii_array = true; + // Returns pre-selection estimated size of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } + + #endif // CPU_AARCH64_MATCHER_AARCH64_HPP diff --git a/src/hotspot/cpu/arm/matcher_arm.hpp b/src/hotspot/cpu/arm/matcher_arm.hpp index 7552b014c06..496ea27c086 100644 --- a/src/hotspot/cpu/arm/matcher_arm.hpp +++ b/src/hotspot/cpu/arm/matcher_arm.hpp @@ -155,4 +155,9 @@ // Implements a variant of EncodeISOArrayNode that encode ASCII only static const bool supports_encode_ascii_array = false; + // Returns pre-selection estimated cost of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } + #endif // CPU_ARM_MATCHER_ARM_HPP diff --git a/src/hotspot/cpu/ppc/matcher_ppc.hpp b/src/hotspot/cpu/ppc/matcher_ppc.hpp index df2074dee24..069c40485fe 100644 --- a/src/hotspot/cpu/ppc/matcher_ppc.hpp +++ b/src/hotspot/cpu/ppc/matcher_ppc.hpp @@ -164,4 +164,10 @@ // Implements a variant of EncodeISOArrayNode that encode ASCII only static const bool supports_encode_ascii_array = true; + // Returns pre-selection estimated cost of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } + + #endif // CPU_PPC_MATCHER_PPC_HPP diff --git a/src/hotspot/cpu/s390/matcher_s390.hpp b/src/hotspot/cpu/s390/matcher_s390.hpp index ac55bd84dff..5c56ec5373b 100644 --- a/src/hotspot/cpu/s390/matcher_s390.hpp +++ b/src/hotspot/cpu/s390/matcher_s390.hpp @@ -153,4 +153,9 @@ // Implements a variant of EncodeISOArrayNode that encode ASCII only static const bool supports_encode_ascii_array = true; + // Returns pre-selection estimated cost of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } + #endif // CPU_S390_MATCHER_S390_HPP diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index be8c18b0710..03229421305 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -8317,8 +8317,28 @@ void Assembler::vpbroadcastw(XMMRegister dst, Address src, int vector_len) { emit_operand(dst, src); } -// xmm/mem sourced byte/word/dword/qword replicate +void Assembler::vpsadbw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16((unsigned char)0xF6, (0xC0 | encode)); +} + +void Assembler::vpunpckhdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x6A, (0xC0 | encode)); +} +void Assembler::vpunpckldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len) { + assert(UseAVX > 0, "requires some form of AVX"); + InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ true); + int encode = vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x62, (0xC0 | encode)); +} + +// xmm/mem sourced byte/word/dword/qword replicate void Assembler::evpaddb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len) { assert(VM_Version::supports_avx512bw() && (vector_len == AVX_512bit || VM_Version::supports_avx512vl()), ""); InstructionAttr attributes(vector_len, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false,/* uses_vl */ true); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index f21dd901c5d..3256b990cf7 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1933,10 +1933,17 @@ private: // Interleave Low Doublewords void punpckldq(XMMRegister dst, XMMRegister src); void punpckldq(XMMRegister dst, Address src); + void vpunpckldq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + + // Interleave High Doublewords + void vpunpckhdq(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); // Interleave Low Quadwords void punpcklqdq(XMMRegister dst, XMMRegister src); + // Vector sum of absolute difference. + void vpsadbw(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + #ifndef _LP64 // no 32bit push/pop on amd64 void pushl(Address src); #endif diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 400bcec45e2..f3f684b1b25 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -4321,6 +4321,94 @@ void C2_MacroAssembler::vector_maskall_operation(KRegister dst, Register src, in } } + +// +// Following is lookup table based popcount computation algorithm:- +// Index Bit set count +// [ 0000 -> 0, +// 0001 -> 1, +// 0010 -> 1, +// 0011 -> 2, +// 0100 -> 1, +// 0101 -> 2, +// 0110 -> 2, +// 0111 -> 3, +// 1000 -> 1, +// 1001 -> 2, +// 1010 -> 3, +// 1011 -> 3, +// 1100 -> 2, +// 1101 -> 3, +// 1111 -> 4 ] +// a. Count the number of 1s in 4 LSB bits of each byte. These bits are used as +// shuffle indices for lookup table access. +// b. Right shift each byte of vector lane by 4 positions. +// c. Count the number of 1s in 4 MSB bits each byte. These bits are used as +// shuffle indices for lookup table access. +// d. Add the bitset count of upper and lower 4 bits of each byte. +// e. Unpack double words to quad words and compute sum of absolute difference of bitset +// count of all the bytes of a quadword. +// f. Perform step e. for upper 128bit vector lane. +// g. Pack the bitset count of quadwords back to double word. +// h. Unpacking and packing operations are not needed for 64bit vector lane. +void C2_MacroAssembler::vector_popcount_int(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, + int vec_enc) { + if (VM_Version::supports_avx512_vpopcntdq()) { + vpopcntd(dst, src, vec_enc); + } else { + assert((vec_enc == Assembler::AVX_512bit && VM_Version::supports_avx512bw()) || VM_Version::supports_avx2(), ""); + movl(rtmp, 0x0F0F0F0F); + movdl(xtmp1, rtmp); + vpbroadcastd(xtmp1, xtmp1, vec_enc); + if (Assembler::AVX_512bit == vec_enc) { + evmovdqul(xtmp2, k0, ExternalAddress(StubRoutines::x86::vector_popcount_lut()), false, vec_enc, rtmp); + } else { + vmovdqu(xtmp2, ExternalAddress(StubRoutines::x86::vector_popcount_lut()), rtmp); + } + vpand(xtmp3, src, xtmp1, vec_enc); + vpshufb(xtmp3, xtmp2, xtmp3, vec_enc); + vpsrlw(dst, src, 4, vec_enc); + vpand(dst, dst, xtmp1, vec_enc); + vpshufb(dst, xtmp2, dst, vec_enc); + vpaddb(xtmp3, dst, xtmp3, vec_enc); + vpxor(xtmp1, xtmp1, xtmp1, vec_enc); + vpunpckhdq(dst, xtmp3, xtmp1, vec_enc); + vpsadbw(dst, dst, xtmp1, vec_enc); + vpunpckldq(xtmp2, xtmp3, xtmp1, vec_enc); + vpsadbw(xtmp2, xtmp2, xtmp1, vec_enc); + vpackuswb(dst, xtmp2, dst, vec_enc); + } +} + +void C2_MacroAssembler::vector_popcount_long(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, + int vec_enc) { + if (VM_Version::supports_avx512_vpopcntdq()) { + vpopcntq(dst, src, vec_enc); + } else if (vec_enc == Assembler::AVX_512bit) { + assert(VM_Version::supports_avx512bw(), ""); + movl(rtmp, 0x0F0F0F0F); + movdl(xtmp1, rtmp); + vpbroadcastd(xtmp1, xtmp1, vec_enc); + evmovdqul(xtmp2, k0, ExternalAddress(StubRoutines::x86::vector_popcount_lut()), true, vec_enc, rtmp); + vpandq(xtmp3, src, xtmp1, vec_enc); + vpshufb(xtmp3, xtmp2, xtmp3, vec_enc); + vpsrlw(dst, src, 4, vec_enc); + vpandq(dst, dst, xtmp1, vec_enc); + vpshufb(dst, xtmp2, dst, vec_enc); + vpaddb(xtmp3, dst, xtmp3, vec_enc); + vpxorq(xtmp1, xtmp1, xtmp1, vec_enc); + vpsadbw(dst, xtmp3, xtmp1, vec_enc); + } else { + // We do not see any performance benefit of running + // above instruction sequence on 256 bit vector which + // can operate over maximum 4 long elements. + ShouldNotReachHere(); + } + evpmovqd(dst, dst, vec_enc); +} + #ifndef _LP64 void C2_MacroAssembler::vector_maskall_operation32(KRegister dst, Register src, KRegister tmp, int mask_len) { assert(VM_Version::supports_avx512bw(), ""); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 0e6a381430f..0464d755ed4 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -317,4 +317,12 @@ public: void evpternlog(XMMRegister dst, int func, KRegister mask, XMMRegister src2, Address src3, bool merge, BasicType bt, int vlen_enc); + void vector_popcount_int(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, + int vec_enc); + + void vector_popcount_long(XMMRegister dst, XMMRegister src, XMMRegister xtmp1, + XMMRegister xtmp2, XMMRegister xtmp3, Register rtmp, + int vec_enc); + #endif // CPU_X86_C2_MACROASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/matcher_x86.hpp b/src/hotspot/cpu/x86/matcher_x86.hpp index 61af24cf31c..9711bc8c2c4 100644 --- a/src/hotspot/cpu/x86/matcher_x86.hpp +++ b/src/hotspot/cpu/x86/matcher_x86.hpp @@ -183,4 +183,13 @@ // Implements a variant of EncodeISOArrayNode that encode ASCII only static const bool supports_encode_ascii_array = true; + // Returns pre-selection estimated cost of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + switch(vopc) { + default: return 0; + case Op_PopCountVI: return VM_Version::supports_avx512_vpopcntdq() ? 0 : 50; + case Op_PopCountVL: return VM_Version::supports_avx512_vpopcntdq() ? 0 : 40; + } + } + #endif // CPU_X86_MATCHER_X86_HPP diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp index 1525d10e5b5..24cfc237b23 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp @@ -588,6 +588,30 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_popcount_avx_lut(const char *stub_name) { + __ align64(); + StubCodeMark mark(this, "StubRoutines", stub_name); + address start = __ pc(); + __ emit_data(0x02010100, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x04030302, relocInfo::none, 0); + __ emit_data(0x02010100, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x04030302, relocInfo::none, 0); + __ emit_data(0x02010100, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x04030302, relocInfo::none, 0); + __ emit_data(0x02010100, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x03020201, relocInfo::none, 0); + __ emit_data(0x04030302, relocInfo::none, 0); + return start; + } + + address generate_iota_indices(const char *stub_name) { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", stub_name); @@ -4004,6 +4028,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::x86::_vector_int_mask_cmp_bits = generate_vector_mask("vector_int_mask_cmp_bits", 0x00000001); StubRoutines::x86::_vector_iota_indices = generate_iota_indices("iota_indices"); + if (UsePopCountInstruction && VM_Version::supports_avx2() && !VM_Version::supports_avx512_vpopcntdq()) { + // lut implementation influenced by counting 1s algorithm from section 5-1 of Hackers' Delight. + StubRoutines::x86::_vector_popcount_lut = generate_popcount_avx_lut("popcount_lut"); + } + // support for verify_oop (must happen after universe_init) StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 8b7188ca42c..6bdff24bddd 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -795,6 +795,21 @@ class StubGenerator: public StubCodeGenerator { return start; } + address generate_popcount_avx_lut(const char *stub_name) { + __ align64(); + StubCodeMark mark(this, "StubRoutines", stub_name); + address start = __ pc(); + __ emit_data64(0x0302020102010100, relocInfo::none); + __ emit_data64(0x0403030203020201, relocInfo::none); + __ emit_data64(0x0302020102010100, relocInfo::none); + __ emit_data64(0x0403030203020201, relocInfo::none); + __ emit_data64(0x0302020102010100, relocInfo::none); + __ emit_data64(0x0403030203020201, relocInfo::none); + __ emit_data64(0x0302020102010100, relocInfo::none); + __ emit_data64(0x0403030203020201, relocInfo::none); + return start; + } + address generate_iota_indices(const char *stub_name) { __ align(CodeEntryAlignment); StubCodeMark mark(this, "StubRoutines", stub_name); @@ -7713,6 +7728,11 @@ address generate_avx_ghash_processBlocks() { StubRoutines::x86::_vector_long_sign_mask = generate_vector_mask("vector_long_sign_mask", 0x8000000000000000); StubRoutines::x86::_vector_iota_indices = generate_iota_indices("iota_indices"); + if (UsePopCountInstruction && VM_Version::supports_avx2() && !VM_Version::supports_avx512_vpopcntdq()) { + // lut implementation influenced by counting 1s algorithm from section 5-1 of Hackers' Delight. + StubRoutines::x86::_vector_popcount_lut = generate_popcount_avx_lut("popcount_lut"); + } + // support for verify_oop (must happen after universe_init) if (VerifyOops) { StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.cpp b/src/hotspot/cpu/x86/stubRoutines_x86.cpp index 81362c76bd6..f5a0eb623d0 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.cpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.cpp @@ -59,6 +59,7 @@ address StubRoutines::x86::_vector_double_sign_flip = NULL; address StubRoutines::x86::_vector_byte_perm_mask = NULL; address StubRoutines::x86::_vector_long_sign_mask = NULL; address StubRoutines::x86::_vector_iota_indices = NULL; +address StubRoutines::x86::_vector_popcount_lut = NULL; address StubRoutines::x86::_vector_32_bit_mask = NULL; address StubRoutines::x86::_vector_64_bit_mask = NULL; #ifdef _LP64 diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index e4dd9550ce2..5119dde4fd5 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -177,6 +177,7 @@ class x86 { static address _vector_short_shuffle_mask; static address _vector_long_shuffle_mask; static address _vector_iota_indices; + static address _vector_popcount_lut; #ifdef _LP64 static juint _k256_W[]; static address _k256_W_adr; @@ -340,6 +341,9 @@ class x86 { return _vector_iota_indices; } + static address vector_popcount_lut() { + return _vector_popcount_lut; + } #ifdef _LP64 static address k256_W_addr() { return _k256_W_adr; } static address k512_W_addr() { return _k512_W_addr; } diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 7ff67e9a085..ab28ebd5ca5 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1405,8 +1405,12 @@ const bool Matcher::match_rule_supported(int opcode) { } break; case Op_PopCountVI: + if (!UsePopCountInstruction || (UseAVX < 2)) { + return false; + } + break; case Op_PopCountVL: - if (!UsePopCountInstruction || !VM_Version::supports_avx512_vpopcntdq()) { + if (!UsePopCountInstruction || (UseAVX <= 2)) { return false; } break; @@ -1861,6 +1865,18 @@ const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType return false; } break; + case Op_PopCountVI: + if (!VM_Version::supports_avx512_vpopcntdq() && + (vlen == 16) && !VM_Version::supports_avx512bw()) { + return false; + } + break; + case Op_PopCountVL: + if (!VM_Version::supports_avx512_vpopcntdq() && + ((vlen <= 4) || ((vlen == 8) && !VM_Version::supports_avx512bw()))) { + return false; + } + break; } return true; // Per default match rules are supported. } @@ -8571,28 +8587,54 @@ instruct vmuladdaddS2I_reg(vec dst, vec src1, vec src2) %{ // --------------------------------- PopCount -------------------------------------- -instruct vpopcountI(vec dst, vec src) %{ +instruct vpopcountI_popcntd(vec dst, vec src) %{ + predicate(VM_Version::supports_avx512_vpopcntdq()); match(Set dst (PopCountVI src)); - format %{ "vpopcntd $dst,$src\t! vector popcount packedI" %} + format %{ "vector_popcount_int $dst, $src\t! vector popcount packedI" %} ins_encode %{ assert(UsePopCountInstruction, "not enabled"); + int vlen_enc = vector_length_encoding(this); + __ vector_popcount_int($dst$$XMMRegister, $src$$XMMRegister, xnoreg, xnoreg, xnoreg, noreg, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} +instruct vpopcountI(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, rRegP rtmp, rFlagsReg cc) %{ + predicate(!VM_Version::supports_avx512_vpopcntdq()); + match(Set dst (PopCountVI src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, KILL cc); + format %{ "vector_popcount_int $dst, $src\t! using $xtmp1, $xtmp2, $xtmp3, and $rtmp as TEMP" %} + ins_encode %{ + assert(UsePopCountInstruction, "not enabled"); int vlen_enc = vector_length_encoding(this); - __ vpopcntd($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); + __ vector_popcount_int($dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, + $xtmp3$$XMMRegister, $rtmp$$Register, vlen_enc); %} ins_pipe( pipe_slow ); %} -instruct vpopcountL(vec dst, vec src) %{ +instruct vpopcountL_popcntd(vec dst, vec src) %{ + predicate(VM_Version::supports_avx512_vpopcntdq()); match(Set dst (PopCountVL src)); - format %{ "vpopcntq $dst,$src\t! vector popcount packedL" %} + format %{ "vector_popcount_long $dst, $src\t! vector popcount packedL" %} ins_encode %{ assert(UsePopCountInstruction, "not enabled"); - int vlen_enc = vector_length_encoding(this, $src); - __ vpopcntq($dst$$XMMRegister, $src$$XMMRegister, vlen_enc); - __ evpmovqd($dst$$XMMRegister, $dst$$XMMRegister, vlen_enc); + __ vector_popcount_long($dst$$XMMRegister, $src$$XMMRegister, xnoreg, xnoreg, xnoreg, noreg, vlen_enc); + %} + ins_pipe( pipe_slow ); +%} +instruct vpopcountL(vec dst, vec src, vec xtmp1, vec xtmp2, vec xtmp3, rRegP rtmp, rFlagsReg cc) %{ + predicate(!VM_Version::supports_avx512_vpopcntdq()); + match(Set dst (PopCountVL src)); + effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP xtmp3, TEMP rtmp, KILL cc); + format %{ "vector_popcount_long $dst, $src\t! using $xtmp1, $xtmp2, $xtmp3, and $rtmp as TEMP" %} + ins_encode %{ + assert(UsePopCountInstruction, "not enabled"); + int vlen_enc = vector_length_encoding(this, $src); + __ vector_popcount_long($dst$$XMMRegister, $src$$XMMRegister, $xtmp1$$XMMRegister, $xtmp2$$XMMRegister, + $xtmp3$$XMMRegister, $rtmp$$Register, vlen_enc); %} ins_pipe( pipe_slow ); %} diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index a997439f43f..dccf75c0022 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -956,6 +956,8 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) { (stride_con < 0 && ((max_jint + stride_con) < limit_type->_lo))) return false; // overflow + // Rudimentary cost model to estimate loop unrolling + // factor. // Adjust body_size to determine if we unroll or not uint body_size = _body.size(); // Key test to unroll loop in CRC32 java code @@ -968,6 +970,11 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) { case Op_ModL: body_size += 30; break; case Op_DivL: body_size += 30; break; case Op_MulL: body_size += 10; break; + case Op_PopCountVI: + case Op_PopCountVL: { + const TypeVect* vt = n->bottom_type()->is_vect(); + body_size += Matcher::vector_op_pre_select_sz_estimate(n->Opcode(), vt->element_basic_type(), vt->length()); + } break; case Op_StrComp: case Op_StrEquals: case Op_StrIndexOf: diff --git a/test/hotspot/jtreg/compiler/vectorization/TestPopCountVectorLong.java b/test/hotspot/jtreg/compiler/vectorization/TestPopCountVectorLong.java index e80c7cfac95..49e3a428c30 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestPopCountVectorLong.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestPopCountVectorLong.java @@ -24,9 +24,8 @@ /** * @test * @summary Test vectorization of popcount for Long -* @requires vm.cpu.features ~= ".*avx512dq.*" -* @requires vm.cpu.features ~= ".*vpopcntdq.*" * @requires vm.compiler2.enabled +* @requires vm.cpu.features ~= ".*avx512bw.*" * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" * @library /test/lib / * @run driver compiler.vectorization.TestPopCountVectorLong -- GitLab From c0e3d107f67a1a333dbe58ae745200d85764c74e Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 14 Mar 2022 09:02:12 +0000 Subject: [PATCH 029/237] 8283008: KRegister documentation out of date Reviewed-by: dlong, sviswanathan, jiefu, jbhateja --- src/hotspot/cpu/x86/register_x86.hpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/x86/register_x86.hpp b/src/hotspot/cpu/x86/register_x86.hpp index b9ac2890240..38ca95c0126 100644 --- a/src/hotspot/cpu/x86/register_x86.hpp +++ b/src/hotspot/cpu/x86/register_x86.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -135,7 +135,7 @@ inline XMMRegister as_XMMRegister(int encoding) { } -// The implementation of XMM registers for the IA32 architecture +// The implementation of XMM registers. class XMMRegisterImpl: public AbstractRegisterImpl { public: enum { @@ -201,11 +201,7 @@ CONSTANT_REGISTER_DECLARATION(XMMRegister, xmm30, (30)); CONSTANT_REGISTER_DECLARATION(XMMRegister, xmm31, (31)); #endif // AMD64 -// Only used by the 32bit stubGenerator. These can't be described by vmreg and hence -// can't be described in oopMaps and therefore can't be used by the compilers (at least -// were deopt might wan't to see them). - -// Use XMMRegister as shortcut +// Use KRegister as shortcut class KRegisterImpl; typedef KRegisterImpl* KRegister; @@ -213,7 +209,7 @@ inline KRegister as_KRegister(int encoding) { return (KRegister)(intptr_t)encoding; } -// The implementation of XMM registers for the IA32 architecture +// The implementation of AVX-3 (AVX-512) opmask registers. class KRegisterImpl : public AbstractRegisterImpl { public: enum { -- GitLab From 01570ca92d234481df2d540027e320b91af415a0 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Mon, 14 Mar 2022 09:03:05 +0000 Subject: [PATCH 030/237] 8283017: GHA: Workflows break with update release versions Reviewed-by: erikj, ihse --- .github/workflows/submit.yml | 40 ++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/.github/workflows/submit.yml b/.github/workflows/submit.yml index b7018a5fc95..93dd4e4b9f0 100644 --- a/.github/workflows/submit.yml +++ b/.github/workflows/submit.yml @@ -23,6 +23,7 @@ jobs: outputs: should_run: ${{ steps.check_submit.outputs.should_run }} bundle_id: ${{ steps.check_bundle_id.outputs.bundle_id }} + jdk_version: ${{ steps.check_jdk_versions.outputs.jdk_version }} platform_linux_additional: ${{ steps.check_platforms.outputs.platform_linux_additional }} platform_linux_x64: ${{ steps.check_platforms.outputs.platform_linux_x64 }} platform_linux_x86: ${{ steps.check_platforms.outputs.platform_linux_x86 }} @@ -70,6 +71,23 @@ jobs: run: "echo '${{ steps.check_deps.outputs.dependencies }}'" if: steps.check_submit.outputs.should_run != 'false' + - name: Determine full JDK versions + id: check_jdk_versions + shell: bash + run: | + FEATURE=${{ fromJson(steps.check_deps.outputs.dependencies).DEFAULT_VERSION_FEATURE }} + INTERIM=${{ fromJson(steps.check_deps.outputs.dependencies).DEFAULT_VERSION_INTERIM }} + UPDATE=${{ fromJson(steps.check_deps.outputs.dependencies).DEFAULT_VERSION_UPDATE }} + if [ "x${UPDATE}" != "x0" ]; then + V=${FEATURE}.${INTERIM}.${UPDATE} + elif [ "x${INTERIM}" != "x0" ]; then + V={FEATURE}.${INTERIM} + else + V=${FEATURE} + fi + echo "::set-output name=jdk_version::${V}" + if: steps.check_submit.outputs.should_run != 'false' + - name: Determine the jtreg ref to checkout run: "echo JTREG_REF=jtreg-${{ fromJson(steps.check_deps.outputs.dependencies).JTREG_VERSION }}+${{ fromJson(steps.check_deps.outputs.dependencies).JTREG_BUILD }} >> $GITHUB_ENV" if: steps.check_submit.outputs.should_run != 'false' @@ -125,7 +143,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -253,7 +271,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -435,7 +453,7 @@ jobs: gnu-arch: powerpc64le env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -582,7 +600,7 @@ jobs: # Reduced 32-bit build uses the same boot JDK as 64-bit build env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -718,7 +736,7 @@ jobs: # Reduced 32-bit build uses the same boot JDK as 64-bit build env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" @@ -869,7 +887,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_URL }}" @@ -957,7 +975,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_URL }}" @@ -1108,7 +1126,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).WINDOWS_X64_BOOT_JDK_URL }}" @@ -1283,7 +1301,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_URL }}" @@ -1384,7 +1402,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_URL }}" @@ -1514,7 +1532,7 @@ jobs: artifact: -debug env: - JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + JDK_VERSION: "${{ needs.prerequisites.outputs.jdk_version }}" BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_FILENAME }}" BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).MACOS_X64_BOOT_JDK_URL }}" -- GitLab From 5f3d4032f3a8854f7afde28698e66a7b6684aed7 Mon Sep 17 00:00:00 2001 From: Ahmed Muhsin Date: Mon, 14 Mar 2022 09:05:53 +0000 Subject: [PATCH 031/237] 8272735: Add missing SubL node transformations Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/subnode.cpp | 6 +- .../c2/irTests/SubINodeIdealizationTests.java | 8 +- .../c2/irTests/SubLNodeIdealizationTests.java | 85 ++++++++++++------- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 67b60f74c60..7897a2e99d3 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -61,7 +61,7 @@ Node* SubNode::Identity(PhaseGVN* phase) { } // Convert "(X+Y) - Y" into X and "(X+Y) - X" into Y - if (in(1)->Opcode() == Op_AddI) { + if (in(1)->Opcode() == Op_AddI || in(1)->Opcode() == Op_AddL) { if (in(1)->in(2) == in(2)) { return in(1)->in(1); } @@ -417,6 +417,10 @@ Node *SubLNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (op2 == Op_AddL && in1 == in2->in(1)) { return new SubLNode(phase->makecon(TypeLong::ZERO), in2->in(2)); } + // Convert "(x-y) - x" into "-y" + if (op1 == Op_SubL && in1->in(1) == in2) { + return new SubLNode(phase->makecon(TypeLong::ZERO), in1->in(2)); + } // Convert "x - (y+x)" into "-y" if (op2 == Op_AddL && in1 == in2->in(2)) { return new SubLNode(phase->makecon(TypeLong::ZERO), in2->in(1)); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/SubINodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/SubINodeIdealizationTests.java index a71710a9664..04a122000e5 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/SubINodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/SubINodeIdealizationTests.java @@ -112,14 +112,14 @@ public class SubINodeIdealizationTests { @Test @IR(failOn = {IRNode.ADD}) @IR(counts = {IRNode.SUB, "1"}) - // Checks x - (x + y) => -y + // Checks x - (x + y) => 0 - y public int test4(int x, int y) { return x - (x + y); } @Test @IR(counts = {IRNode.SUB, "1"}) - // Checks (x - y) - x => -y + // Checks (x - y) - x => 0 - y public int test5(int x, int y) { return (x - y) - x; } @@ -127,7 +127,7 @@ public class SubINodeIdealizationTests { @Test @IR(failOn = {IRNode.ADD}) @IR(counts = {IRNode.SUB, "1"}) - // Checks x - (y + x) => -y + // Checks x - (y + x) => 0 - y public int test6(int x, int y) { return x - (y + x); } @@ -206,7 +206,7 @@ public class SubINodeIdealizationTests { @Test @IR(failOn = {IRNode.SUB, IRNode.ADD}) - // Checks (x + y) - y => y + // Checks (x + y) - y => x public int test16(int x, int y) { return (x + y) - y; } diff --git a/test/hotspot/jtreg/compiler/c2/irTests/SubLNodeIdealizationTests.java b/test/hotspot/jtreg/compiler/c2/irTests/SubLNodeIdealizationTests.java index bf60147e142..f03a07d84d0 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/SubLNodeIdealizationTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/SubLNodeIdealizationTests.java @@ -27,7 +27,7 @@ import compiler.lib.ir_framework.*; /* * @test - * @bug 8267265 + * @bug 8267265 8272735 * @summary Test that Ideal transformations of SubLNode* are being performed as expected. * @library /test/lib / * @run driver compiler.c2.irTests.SubLNodeIdealizationTests @@ -42,7 +42,8 @@ public class SubLNodeIdealizationTests { "test7", "test8", "test9", "test10", "test11", "test12", "test13", "test14", "test15", - "test16", "test17", "test18"}) + "test16", "test17", "test18", + "test19", "test20", "test21"}) public void runMethod() { long a = RunInfo.getRandom().nextLong(); long b = RunInfo.getRandom().nextLong(); @@ -63,20 +64,23 @@ public class SubLNodeIdealizationTests { Asserts.assertEQ((a + 1) - b , test2(a, b)); Asserts.assertEQ(a - (b + 2021) , test3(a, b)); Asserts.assertEQ(a - (a + b) , test4(a, b)); - Asserts.assertEQ(a - (b + a) , test5(a, b)); - Asserts.assertEQ(0 - (a - b) , test6(a, b)); - Asserts.assertEQ(0 - (a + 2021) , test7(a, b)); - Asserts.assertEQ((a + b) - (a + c), test8(a, b, c)); - Asserts.assertEQ((b + a) - (c + a), test9(a, b, c)); - Asserts.assertEQ((b + a) - (a + c), test10(a, b, c)); - Asserts.assertEQ((a + b) - (c + a), test11(a, b, c)); - Asserts.assertEQ(a - (b - c) , test12(a, b, c)); - Asserts.assertEQ(0 - (a >> 63) , test13(a)); - Asserts.assertEQ(0 - (0 - a) , test14(a)); - Asserts.assertEQ(a*b - a*c , test15(a, b, c)); - Asserts.assertEQ(a*b - b*c , test16(a, b, c)); - Asserts.assertEQ(a*c - b*c , test17(a, b, c)); - Asserts.assertEQ(a*b - c*a , test18(a, b, c)); + Asserts.assertEQ((a - b) - a , test5(a, b)); + Asserts.assertEQ(a - (b + a) , test6(a, b)); + Asserts.assertEQ(0 - (a - b) , test7(a, b)); + Asserts.assertEQ(0 - (a + 2021) , test8(a, b)); + Asserts.assertEQ((a + b) - (a + c), test9(a, b, c)); + Asserts.assertEQ((b + a) - (c + a), test10(a, b, c)); + Asserts.assertEQ((b + a) - (a + c), test11(a, b, c)); + Asserts.assertEQ((a + b) - (c + a), test12(a, b, c)); + Asserts.assertEQ(a - (b - c) , test13(a, b, c)); + Asserts.assertEQ(0 - (a >> 63) , test14(a)); + Asserts.assertEQ(0 - (0 - a) , test15(a)); + Asserts.assertEQ((a + b) - b , test16(a, b)); + Asserts.assertEQ((a + b) - a , test17(a, b)); + Asserts.assertEQ(a*b - a*c , test18(a, b, c)); + Asserts.assertEQ(a*b - b*c , test19(a, b, c)); + Asserts.assertEQ(a*c - b*c , test20(a, b, c)); + Asserts.assertEQ(a*b - c*a , test21(a, b, c)); } @Test @@ -113,18 +117,25 @@ public class SubLNodeIdealizationTests { return x - (x + y); } + @Test + @IR(counts = {IRNode.SUB, "1"}) + // Checks (x - y) - x => 0 - y + public long test5(long x, long y) { + return (x - y) - x; + } + @Test @IR(failOn = {IRNode.ADD}) @IR(counts = {IRNode.SUB, "1"}) // Checks x - (y + x) => 0 - y - public long test5(long x, long y) { + public long test6(long x, long y) { return x - (y + x); } @Test @IR(counts = {IRNode.SUB, "1"}) // Checks 0 - (x - y) => y - x - public long test6(long x, long y) { + public long test7(long x, long y) { return 0 - (x - y); } @@ -132,7 +143,7 @@ public class SubLNodeIdealizationTests { @IR(failOn = {IRNode.ADD}) @IR(counts = {IRNode.SUB, "1"}) // Checks 0 - (x + 2021) => -2021 - x - public long test7(long x, long y) { + public long test8(long x, long y) { return 0 - (x + 2021); } @@ -140,7 +151,7 @@ public class SubLNodeIdealizationTests { @IR(failOn = {IRNode.ADD}) @IR(counts = {IRNode.SUB, "1"}) // Checks (x + a) - (x + b) => a - b; - public long test8(long x, long a, long b) { + public long test9(long x, long a, long b) { return (x + a) - (x + b); } @@ -148,7 +159,7 @@ public class SubLNodeIdealizationTests { @IR(failOn = {IRNode.ADD}) @IR(counts = {IRNode.SUB, "1"}) // Checks (a + x) - (b + x) => a - b - public long test9(long x, long a, long b) { + public long test10(long x, long a, long b) { return (a + x) - (b + x); } @@ -156,7 +167,7 @@ public class SubLNodeIdealizationTests { @IR(failOn = {IRNode.ADD}) @IR(counts = {IRNode.SUB, "1"}) // Checks (a + x) - (x + b) => a - b - public long test10(long x, long a, long b) { + public long test11(long x, long a, long b) { return (a + x) - (x + b); } @@ -164,7 +175,7 @@ public class SubLNodeIdealizationTests { @IR(failOn = {IRNode.ADD}) @IR(counts = {IRNode.SUB, "1"}) // Checks (x + a) - (b + x) => a - b - public long test11(long x, long a, long b) { + public long test12(long x, long a, long b) { return (x + a) - (b + x); } @@ -173,7 +184,7 @@ public class SubLNodeIdealizationTests { IRNode.ADD, "1" }) // Checks a - (b - c) => (a + c) - b - public long test12(long a, long b, long c) { + public long test13(long a, long b, long c) { return a - (b - c); } @@ -182,22 +193,36 @@ public class SubLNodeIdealizationTests { @IR(counts = {IRNode.URSHIFT_L, "1"}) // Checks 0 - (a >> 63) => a >>> 63 // signed ^^ ^^^ unsigned - public long test13(long a) { + public long test14(long a) { return 0 - (a >> 63); } @Test @IR(failOn = {IRNode.SUB}) // Checks 0 - (0 - x) => x - public long test14(long x) { + public long test15(long x) { return 0 - (0 - x); } + @Test + @IR(failOn = {IRNode.SUB, IRNode.ADD}) + // Checks (x + y) - y => x + public long test16(long x, long y) { + return (x + y) - y; + } + + @Test + @IR(failOn = {IRNode.SUB, IRNode.ADD}) + // Checks (x + y) - x => y + public long test17(long x, long y) { + return (x + y) - x; + } + @Test @IR(counts = {IRNode.MUL, "1", IRNode.SUB, "1"}) // Checks "a*b-a*c => a*(b-c) - public long test15(long a, long b, long c) { + public long test18(long a, long b, long c) { return a*b - a*c; } @@ -205,7 +230,7 @@ public class SubLNodeIdealizationTests { @IR(counts = {IRNode.MUL, "1", IRNode.SUB, "1"}) // Checks a*b-b*c => b*(a-c) - public long test16(long a, long b, long c) { + public long test19(long a, long b, long c) { return a*b - b*c; } @@ -213,7 +238,7 @@ public class SubLNodeIdealizationTests { @IR(counts = {IRNode.MUL, "1", IRNode.SUB, "1"}) // Checks a*c-b*c => (a-b)*c - public long test17(long a, long b, long c) { + public long test20(long a, long b, long c) { return a*c - b*c; } @@ -221,7 +246,7 @@ public class SubLNodeIdealizationTests { @IR(counts = {IRNode.MUL, "1", IRNode.SUB, "1"}) // Checks a*b-c*a => a*(b-c) - public long test18(long a, long b, long c) { + public long test21(long a, long b, long c) { return a*b - c*a; } } -- GitLab From ea9eeea8ffea6ed32a270051c6986f4f059943c0 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Mon, 14 Mar 2022 13:59:13 +0000 Subject: [PATCH 032/237] 8281322: C2: always construct strip mined loop initially (even if strip mining is disabled) Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/loopnode.cpp | 406 ++++++++++-------- src/hotspot/share/opto/loopnode.hpp | 15 +- .../c2/irTests/TestCountedLoopSafepoint.java | 61 +++ .../c2/irTests/TestLongRangeChecks.java | 4 +- 4 files changed, 296 insertions(+), 190 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/TestCountedLoopSafepoint.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 6732c6dee01..39c6ad49563 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -852,7 +852,10 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { SafePointNode* safepoint; if (bt == T_INT && head->as_CountedLoop()->is_strip_mined()) { // Loop is strip mined: use the safepoint of the outer strip mined loop - strip_mined_nest_back_to_counted_loop(loop, head, back_control, exit_test, safepoint); + OuterStripMinedLoopNode* outer_loop = head->as_CountedLoop()->outer_loop(); + safepoint = outer_loop->outer_safepoint(); + outer_loop->transform_to_counted_loop(&_igvn, this); + exit_test = head->loopexit(); } else { safepoint = find_safepoint(back_control, x, loop); } @@ -1058,68 +1061,6 @@ bool PhaseIdealLoop::create_loop_nest(IdealLoopTree* loop, Node_List &old_new) { return true; } -// Convert the strip mined loop nest back to a single loop with the safepoint right before the loop exit test -void PhaseIdealLoop::strip_mined_nest_back_to_counted_loop(IdealLoopTree* loop, const BaseCountedLoopNode* head, - Node* back_control, IfNode*& exit_test, - SafePointNode*& safepoint) { - CountedLoopNode* cl = head->as_CountedLoop(); - cl->verify_strip_mined(1); - safepoint = cl->outer_safepoint(); - CountedLoopEndNode* cle = cl->loopexit(); - OuterStripMinedLoopNode* outer_head = cl->outer_loop(); - OuterStripMinedLoopEndNode* outer_end = cl->outer_loop_end(); - - cl->clear_strip_mined(); - - _igvn.replace_input_of(cl, LoopNode::EntryControl, outer_head->in(LoopNode::EntryControl)); - _igvn.replace_input_of(outer_head, LoopNode::EntryControl, C->top()); - set_idom(cl, cl->in(LoopNode::EntryControl), dom_depth(cl)); - - Node* exit_bol = cle->in(1); - Node *zero = _igvn.intcon(0); - set_ctrl(zero, C->root()); - _igvn.replace_input_of(cle, 1, zero); - - _igvn.replace_input_of(outer_end, 1, exit_bol); - - assert(outer_head->in(LoopNode::LoopBackControl)->in(0) == outer_end, ""); - _igvn.replace_input_of(outer_head->in(LoopNode::LoopBackControl), 0, C->top()); - _igvn.replace_input_of(back_control, 0, outer_end); - set_idom(back_control, outer_end, dom_depth(outer_end) + 1); - - Unique_Node_List wq; - wq.push(safepoint); - - IdealLoopTree* outer_loop_ilt = get_loop(outer_head); - - for (uint i = 0; i < wq.size(); i++) { - Node* n = wq.at(i); - for (uint j = 0; j < n->req(); ++j) { - Node* in = n->in(j); - if (in == NULL || in->is_CFG()) { - continue; - } - if (get_loop(get_ctrl(in)) != outer_loop_ilt) { - continue; - } - assert(!loop->_body.contains(in), ""); - loop->_body.push(in); - wq.push(in); - } - } - - set_loop(outer_end, loop); - loop->_body.push(outer_end); - set_loop(safepoint, loop); - loop->_body.push(safepoint); - set_loop(safepoint->in(0), loop); - loop->_body.push(safepoint->in(0)); - - exit_test = outer_end; - - outer_loop_ilt->_tail = C->top(); -} - int PhaseIdealLoop::extract_long_range_checks(const IdealLoopTree* loop, jlong stride_con, int iters_limit, PhiNode* phi, Node_List& range_checks) { const jlong min_iters = 2; @@ -2054,7 +1995,6 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ Node* entry_control = init_control; bool strip_mine_loop = iv_bt == T_INT && - LoopStripMiningIter > 1 && loop->_child == NULL && sfpt != NULL && !loop->_has_call; @@ -2082,7 +2022,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ if (iv_bt == T_INT && (LoopStripMiningIter == 0 || strip_mine_loop)) { // Check for immediately preceding SafePoint and remove - if (sfpt != NULL && (LoopStripMiningIter != 0 || is_deleteable_safept(sfpt))) { + if (sfpt != NULL && (strip_mine_loop || is_deleteable_safept(sfpt))) { if (strip_mine_loop) { Node* outer_le = outer_ilt->_tail->in(0); Node* sfpt_clone = sfpt->clone(); @@ -2624,6 +2564,123 @@ BaseCountedLoopNode* BaseCountedLoopNode::make(Node* entry, Node* backedge, Basi return new LongCountedLoopNode(entry, backedge); } +void OuterStripMinedLoopNode::fix_sunk_stores(CountedLoopEndNode* inner_cle, LoopNode* inner_cl, PhaseIterGVN* igvn, + PhaseIdealLoop* iloop) { + Node* cle_out = inner_cle->proj_out(false); + Node* cle_tail = inner_cle->proj_out(true); + if (cle_out->outcnt() > 1) { + // Look for chains of stores that were sunk + // out of the inner loop and are in the outer loop + for (DUIterator_Fast imax, i = cle_out->fast_outs(imax); i < imax; i++) { + Node* u = cle_out->fast_out(i); + if (u->is_Store()) { + int alias_idx = igvn->C->get_alias_index(u->adr_type()); + Node* first = u; + for (;;) { + Node* next = first->in(MemNode::Memory); + if (!next->is_Store() || next->in(0) != cle_out) { + break; + } + assert(igvn->C->get_alias_index(next->adr_type()) == alias_idx, ""); + first = next; + } + Node* last = u; + for (;;) { + Node* next = NULL; + for (DUIterator_Fast jmax, j = last->fast_outs(jmax); j < jmax; j++) { + Node* uu = last->fast_out(j); + if (uu->is_Store() && uu->in(0) == cle_out) { + assert(next == NULL, "only one in the outer loop"); + next = uu; + assert(igvn->C->get_alias_index(next->adr_type()) == alias_idx, ""); + } + } + if (next == NULL) { + break; + } + last = next; + } + Node* phi = NULL; + for (DUIterator_Fast jmax, j = inner_cl->fast_outs(jmax); j < jmax; j++) { + Node* uu = inner_cl->fast_out(j); + if (uu->is_Phi()) { + Node* be = uu->in(LoopNode::LoopBackControl); + if (be->is_Store() && be->in(0) == inner_cl->in(LoopNode::LoopBackControl)) { + assert(igvn->C->get_alias_index(uu->adr_type()) != alias_idx && igvn->C->get_alias_index(uu->adr_type()) != Compile::AliasIdxBot, "unexpected store"); + } + if (be == last || be == first->in(MemNode::Memory)) { + assert(igvn->C->get_alias_index(uu->adr_type()) == alias_idx || igvn->C->get_alias_index(uu->adr_type()) == Compile::AliasIdxBot, "unexpected alias"); + assert(phi == NULL, "only one phi"); + phi = uu; + } + } + } +#ifdef ASSERT + for (DUIterator_Fast jmax, j = inner_cl->fast_outs(jmax); j < jmax; j++) { + Node* uu = inner_cl->fast_out(j); + if (uu->is_Phi() && uu->bottom_type() == Type::MEMORY) { + if (uu->adr_type() == igvn->C->get_adr_type(igvn->C->get_alias_index(u->adr_type()))) { + assert(phi == uu, "what's that phi?"); + } else if (uu->adr_type() == TypePtr::BOTTOM) { + Node* n = uu->in(LoopNode::LoopBackControl); + uint limit = igvn->C->live_nodes(); + uint i = 0; + while (n != uu) { + i++; + assert(i < limit, "infinite loop"); + if (n->is_Proj()) { + n = n->in(0); + } else if (n->is_SafePoint() || n->is_MemBar()) { + n = n->in(TypeFunc::Memory); + } else if (n->is_Phi()) { + n = n->in(1); + } else if (n->is_MergeMem()) { + n = n->as_MergeMem()->memory_at(igvn->C->get_alias_index(u->adr_type())); + } else if (n->is_Store() || n->is_LoadStore() || n->is_ClearArray()) { + n = n->in(MemNode::Memory); + } else { + n->dump(); + ShouldNotReachHere(); + } + } + } + } + } +#endif + if (phi == NULL) { + // If an entire chains was sunk, the + // inner loop has no phi for that memory + // slice, create one for the outer loop + phi = PhiNode::make(inner_cl, first->in(MemNode::Memory), Type::MEMORY, + igvn->C->get_adr_type(igvn->C->get_alias_index(u->adr_type()))); + phi->set_req(LoopNode::LoopBackControl, last); + phi = register_new_node(phi, inner_cl, igvn, iloop); + igvn->replace_input_of(first, MemNode::Memory, phi); + } else { + // Or fix the outer loop fix to include + // that chain of stores. + Node* be = phi->in(LoopNode::LoopBackControl); + assert(!(be->is_Store() && be->in(0) == inner_cl->in(LoopNode::LoopBackControl)), "store on the backedge + sunk stores: unsupported"); + if (be == first->in(MemNode::Memory)) { + if (be == phi->in(LoopNode::LoopBackControl)) { + igvn->replace_input_of(phi, LoopNode::LoopBackControl, last); + } else { + igvn->replace_input_of(be, MemNode::Memory, last); + } + } else { +#ifdef ASSERT + if (be == phi->in(LoopNode::LoopBackControl)) { + assert(phi->in(LoopNode::LoopBackControl) == last, ""); + } else { + assert(be->in(MemNode::Memory) == last, ""); + } +#endif + } + } + } + } + } +} void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { // Look for the outer & inner strip mined loop, reduce number of @@ -2631,6 +2688,14 @@ void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { // construct required phi nodes for outer loop. CountedLoopNode* inner_cl = unique_ctrl_out()->as_CountedLoop(); assert(inner_cl->is_strip_mined(), "inner loop should be strip mined"); + if (LoopStripMiningIter == 0) { + remove_outer_loop_and_safepoint(igvn); + return; + } + if (LoopStripMiningIter == 1) { + transform_to_counted_loop(igvn, NULL); + return; + } Node* inner_iv_phi = inner_cl->phi(); if (inner_iv_phi == NULL) { IfNode* outer_le = outer_loop_end(); @@ -2650,11 +2715,7 @@ void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { assert(iter_estimate > 0, "broken"); if ((jlong)scaled_iters != scaled_iters_long || iter_estimate <= short_scaled_iters) { // Remove outer loop and safepoint (too few iterations) - Node* outer_sfpt = outer_safepoint(); - Node* outer_out = outer_loop_exit(); - igvn->replace_node(outer_out, outer_sfpt->in(0)); - igvn->replace_input_of(outer_sfpt, 0, igvn->C->top()); - inner_cl->clear_strip_mined(); + remove_outer_loop_and_safepoint(igvn); return; } if (iter_estimate <= scaled_iters_long) { @@ -2735,121 +2796,6 @@ void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { } } } - Node* cle_out = inner_cle->proj_out(false); - if (cle_out->outcnt() > 1) { - // Look for chains of stores that were sunk - // out of the inner loop and are in the outer loop - for (DUIterator_Fast imax, i = cle_out->fast_outs(imax); i < imax; i++) { - Node* u = cle_out->fast_out(i); - if (u->is_Store()) { - Node* first = u; - for(;;) { - Node* next = first->in(MemNode::Memory); - if (!next->is_Store() || next->in(0) != cle_out) { - break; - } - first = next; - } - Node* last = u; - for(;;) { - Node* next = NULL; - for (DUIterator_Fast jmax, j = last->fast_outs(jmax); j < jmax; j++) { - Node* uu = last->fast_out(j); - if (uu->is_Store() && uu->in(0) == cle_out) { - assert(next == NULL, "only one in the outer loop"); - next = uu; - } - } - if (next == NULL) { - break; - } - last = next; - } - Node* phi = NULL; - for (DUIterator_Fast jmax, j = fast_outs(jmax); j < jmax; j++) { - Node* uu = fast_out(j); - if (uu->is_Phi()) { - Node* be = uu->in(LoopNode::LoopBackControl); - if (be->is_Store() && old_new[be->_idx] != NULL) { - assert(false, "store on the backedge + sunk stores: unsupported"); - // drop outer loop - IfNode* outer_le = outer_loop_end(); - Node* iff = igvn->transform(new IfNode(outer_le->in(0), outer_le->in(1), outer_le->_prob, outer_le->_fcnt)); - igvn->replace_node(outer_le, iff); - inner_cl->clear_strip_mined(); - return; - } - if (be == last || be == first->in(MemNode::Memory)) { - assert(phi == NULL, "only one phi"); - phi = uu; - } - } - } -#ifdef ASSERT - for (DUIterator_Fast jmax, j = fast_outs(jmax); j < jmax; j++) { - Node* uu = fast_out(j); - if (uu->is_Phi() && uu->bottom_type() == Type::MEMORY) { - if (uu->adr_type() == igvn->C->get_adr_type(igvn->C->get_alias_index(u->adr_type()))) { - assert(phi == uu, "what's that phi?"); - } else if (uu->adr_type() == TypePtr::BOTTOM) { - Node* n = uu->in(LoopNode::LoopBackControl); - uint limit = igvn->C->live_nodes(); - uint i = 0; - while (n != uu) { - i++; - assert(i < limit, "infinite loop"); - if (n->is_Proj()) { - n = n->in(0); - } else if (n->is_SafePoint() || n->is_MemBar()) { - n = n->in(TypeFunc::Memory); - } else if (n->is_Phi()) { - n = n->in(1); - } else if (n->is_MergeMem()) { - n = n->as_MergeMem()->memory_at(igvn->C->get_alias_index(u->adr_type())); - } else if (n->is_Store() || n->is_LoadStore() || n->is_ClearArray()) { - n = n->in(MemNode::Memory); - } else { - n->dump(); - ShouldNotReachHere(); - } - } - } - } - } -#endif - if (phi == NULL) { - // If the an entire chains was sunk, the - // inner loop has no phi for that memory - // slice, create one for the outer loop - phi = PhiNode::make(this, first->in(MemNode::Memory), Type::MEMORY, - igvn->C->get_adr_type(igvn->C->get_alias_index(u->adr_type()))); - phi->set_req(LoopNode::LoopBackControl, last); - phi = igvn->transform(phi); - igvn->replace_input_of(first, MemNode::Memory, phi); - } else { - // Or fix the outer loop fix to include - // that chain of stores. - Node* be = phi->in(LoopNode::LoopBackControl); - assert(!(be->is_Store() && old_new[be->_idx] != NULL), "store on the backedge + sunk stores: unsupported"); - if (be == first->in(MemNode::Memory)) { - if (be == phi->in(LoopNode::LoopBackControl)) { - igvn->replace_input_of(phi, LoopNode::LoopBackControl, last); - } else { - igvn->replace_input_of(be, MemNode::Memory, last); - } - } else { -#ifdef ASSERT - if (be == phi->in(LoopNode::LoopBackControl)) { - assert(phi->in(LoopNode::LoopBackControl) == last, ""); - } else { - assert(be->in(MemNode::Memory) == last, ""); - } -#endif - } - } - } - } - } if (iv_phi != NULL) { // Now adjust the inner loop's exit condition @@ -2898,6 +2844,96 @@ void OuterStripMinedLoopNode::adjust_strip_mined_loop(PhaseIterGVN* igvn) { } } +void OuterStripMinedLoopNode::transform_to_counted_loop(PhaseIterGVN* igvn, PhaseIdealLoop* iloop) { + CountedLoopNode* inner_cl = unique_ctrl_out()->as_CountedLoop(); + CountedLoopEndNode* cle = inner_cl->loopexit(); + Node* inner_test = cle->in(1); + IfNode* outer_le = outer_loop_end(); + CountedLoopEndNode* inner_cle = inner_cl->loopexit(); + Node* safepoint = outer_safepoint(); + + fix_sunk_stores(inner_cle, inner_cl, igvn, iloop); + + // make counted loop exit test always fail + ConINode* zero = igvn->intcon(0); + if (iloop != NULL) { + iloop->set_ctrl(zero, igvn->C->root()); + } + igvn->replace_input_of(cle, 1, zero); + // replace outer loop end with CountedLoopEndNode with formers' CLE's exit test + Node* new_end = new CountedLoopEndNode(outer_le->in(0), inner_test, cle->_prob, cle->_fcnt); + register_control(new_end, inner_cl, outer_le->in(0), igvn, iloop); + if (iloop == NULL) { + igvn->replace_node(outer_le, new_end); + } else { + iloop->lazy_replace(outer_le, new_end); + } + // the backedge of the inner loop must be rewired to the new loop end + Node* backedge = cle->proj_out(true); + igvn->replace_input_of(backedge, 0, new_end); + if (iloop != NULL) { + iloop->set_idom(backedge, new_end, iloop->dom_depth(new_end) + 1); + } + // make the outer loop go away + igvn->replace_input_of(in(LoopBackControl), 0, igvn->C->top()); + igvn->replace_input_of(this, LoopBackControl, igvn->C->top()); + inner_cl->clear_strip_mined(); + if (iloop != NULL) { + Unique_Node_List wq; + wq.push(safepoint); + + IdealLoopTree* outer_loop_ilt = iloop->get_loop(this); + IdealLoopTree* loop = iloop->get_loop(inner_cl); + + for (uint i = 0; i < wq.size(); i++) { + Node* n = wq.at(i); + for (uint j = 0; j < n->req(); ++j) { + Node* in = n->in(j); + if (in == NULL || in->is_CFG()) { + continue; + } + if (iloop->get_loop(iloop->get_ctrl(in)) != outer_loop_ilt) { + continue; + } + assert(!loop->_body.contains(in), ""); + loop->_body.push(in); + wq.push(in); + } + } + iloop->set_loop(safepoint, loop); + loop->_body.push(safepoint); + iloop->set_loop(safepoint->in(0), loop); + loop->_body.push(safepoint->in(0)); + outer_loop_ilt->_tail = igvn->C->top(); + } +} + +void OuterStripMinedLoopNode::remove_outer_loop_and_safepoint(PhaseIterGVN* igvn) const { + CountedLoopNode* inner_cl = unique_ctrl_out()->as_CountedLoop(); + Node* outer_sfpt = outer_safepoint(); + Node* outer_out = outer_loop_exit(); + igvn->replace_node(outer_out, outer_sfpt->in(0)); + igvn->replace_input_of(outer_sfpt, 0, igvn->C->top()); + inner_cl->clear_strip_mined(); +} + +Node* OuterStripMinedLoopNode::register_new_node(Node* node, LoopNode* ctrl, PhaseIterGVN* igvn, PhaseIdealLoop* iloop) { + if (iloop == NULL) { + return igvn->transform(node); + } + iloop->register_new_node(node, ctrl); + return node; +} + +Node* OuterStripMinedLoopNode::register_control(Node* node, Node* loop, Node* idom, PhaseIterGVN* igvn, + PhaseIdealLoop* iloop) { + if (iloop == NULL) { + return igvn->transform(node); + } + iloop->register_control(node, iloop->get_loop(loop), idom); + return node; +} + const Type* OuterStripMinedLoopEndNode::Value(PhaseGVN* phase) const { if (!in(0)) return Type::TOP; if (phase->type(in(0)) == Type::TOP) diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 606d9c46331..c81180fa7b8 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -546,7 +546,8 @@ class LoopLimitNode : public Node { // Support for strip mining class OuterStripMinedLoopNode : public LoopNode { private: - CountedLoopNode* inner_loop() const; + static void fix_sunk_stores(CountedLoopEndNode* inner_cle, LoopNode* inner_cl, PhaseIterGVN* igvn, PhaseIdealLoop* iloop); + public: OuterStripMinedLoopNode(Compile* C, Node *entry, Node *backedge) : LoopNode(entry, backedge) { @@ -562,6 +563,15 @@ public: virtual IfFalseNode* outer_loop_exit() const; virtual SafePointNode* outer_safepoint() const; void adjust_strip_mined_loop(PhaseIterGVN* igvn); + + void remove_outer_loop_and_safepoint(PhaseIterGVN* igvn) const; + + void transform_to_counted_loop(PhaseIterGVN* igvn, PhaseIdealLoop* iloop); + + static Node* register_new_node(Node* node, LoopNode* ctrl, PhaseIterGVN* igvn, PhaseIdealLoop* iloop); + + Node* register_control(Node* node, Node* loop, Node* idom, PhaseIterGVN* igvn, + PhaseIdealLoop* iloop); }; class OuterStripMinedLoopEndNode : public IfNode { @@ -1662,9 +1672,6 @@ public: bool safe_for_if_replacement(const Node* dom) const; - void strip_mined_nest_back_to_counted_loop(IdealLoopTree* loop, const BaseCountedLoopNode* head, Node* back_control, - IfNode*&exit_test, SafePointNode*&safepoint); - void push_pinned_nodes_thru_region(IfNode* dom_if, Node* region); bool try_merge_identical_ifs(Node* n); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestCountedLoopSafepoint.java b/test/hotspot/jtreg/compiler/c2/irTests/TestCountedLoopSafepoint.java new file mode 100644 index 00000000000..a56fd1592fd --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestCountedLoopSafepoint.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * bug 8281322 + * @summary check counted loop is properly constructed with/without safepoint + * @library /test/lib / + * @run driver compiler.c2.irTests.TestCountedLoopSafepoint + */ + +public class TestCountedLoopSafepoint { + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:LoopMaxUnroll=1", "-XX:-UseCountedLoopSafepoints"); + TestFramework.runWithFlags("-XX:LoopMaxUnroll=1", "-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1"); + TestFramework.runWithFlags("-XX:LoopMaxUnroll=1", "-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000"); + } + + @Test + @IR(counts = { IRNode.COUNTEDLOOP, "1" }) + @IR(applyIf = { "LoopStripMiningIter", "0" }, failOn = { IRNode.SAFEPOINT, IRNode.OUTERSTRIPMINEDLOOP }) + @IR(applyIf = { "LoopStripMiningIter", "1" }, counts = { IRNode.SAFEPOINT, "1" }, failOn = { IRNode.OUTERSTRIPMINEDLOOP }) + @IR(applyIf = { "LoopStripMiningIter", "> 1" }, counts = { IRNode.SAFEPOINT, "1", IRNode.OUTERSTRIPMINEDLOOP, "1" }) + public static float test(int start, int stop) { + float v = 1; + for (int i = start; i < stop; i++) { + v *= 2; + } + return v; + } + + @Run(test = "test") + private void testRunner() { + test(0, 100); + } + +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java b/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java index e84f3062f14..87bfd943888 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestLongRangeChecks.java @@ -36,7 +36,9 @@ import java.util.Objects; public class TestLongRangeChecks { public static void main(String[] args) { - TestFramework.run(); + TestFramework.runWithFlags("-XX:-UseCountedLoopSafepoints"); + TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1"); + TestFramework.runWithFlags("-XX:+UseCountedLoopSafepoints", "-XX:LoopStripMiningIter=1000"); } -- GitLab From 08573cc3b2370a697a7bd4ad0665ee20ae148d39 Mon Sep 17 00:00:00 2001 From: Zdenek Zambersky Date: Mon, 14 Mar 2022 14:21:58 +0000 Subject: [PATCH 033/237] 8282529: Fix API Note in javadoc for javax.net.ssl.SSLSocket Reviewed-by: wetmore, xuelei --- .../classes/javax/net/ssl/SSLSocket.java | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/javax/net/ssl/SSLSocket.java b/src/java.base/share/classes/javax/net/ssl/SSLSocket.java index b2c912c3b65..e5cdd3741b9 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLSocket.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLSocket.java @@ -174,17 +174,19 @@ import java.util.function.BiFunction; * @apiNote * When the connection is no longer needed, the client and server * applications should each close both sides of their respective connection. - * For {@code SSLSocket} objects, for example, an application can call - * {@link Socket#shutdownOutput()} or {@link java.io.OutputStream#close()} - * for output stream close and call {@link Socket#shutdownInput()} or - * {@link java.io.InputStream#close()} for input stream close. Note that - * in some cases, closing the input stream may depend on the peer's output - * stream being closed first. If the connection is not closed in an orderly - * manner (for example {@link Socket#shutdownInput()} is called before the - * peer's write closure notification has been received), exceptions may - * be raised to indicate that an error has occurred. Once an - * {@code SSLSocket} is closed, it is not reusable: a new {@code SSLSocket} - * must be created. + * This can be done either in one shot by calling {@link Socket#close()}, + * or by closing each side individually using + * {@link Socket#shutdownOutput()} / {@link Socket#shutdownInput()} which is + * useful for protocol versions that can support half-closed connections. + * + *

Note that in some cases, closing the input stream may depend on the + * peer's output stream being closed first. If the connection is not closed + * in an orderly manner (for example {@link Socket#shutdownInput()} is called + * before the peer's write closure notification has been received), exceptions + * may be raised to indicate that an error has occurred. + * + *

Once an {@code SSLSocket} is closed, it is not reusable: a new + * {@code SSLSocket} must be created. * * @see java.net.Socket * @see SSLServerSocket -- GitLab From 13cebffe618255ae29310c95fd1b91576e576751 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 14 Mar 2022 16:10:15 +0000 Subject: [PATCH 034/237] 8058924: FileReader(String) documentation is insufficient Reviewed-by: naoto, lancea --- src/java.base/share/classes/java/io/package-info.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/io/package-info.java b/src/java.base/share/classes/java/io/package-info.java index 1c41f9835e6..81f61412eed 100644 --- a/src/java.base/share/classes/java/io/package-info.java +++ b/src/java.base/share/classes/java/io/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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 @@ -27,10 +27,14 @@ * Provides for system input and output through data streams, * serialization and the file system. * - * Unless otherwise noted, passing a null argument to a constructor or + * Unless otherwise noted, passing a {@code null} argument to a constructor or * method in any class or interface in this package will cause a * {@code NullPointerException} to be thrown. * + * A pathname string passed as a {@code String} argument to a + * constructor or method in any class or interface in this package will be + * interpreted as described in the class specification of {@link File}. + * *

Object Serialization

*

Warning: Deserialization of untrusted data is inherently dangerous * and should be avoided. Untrusted data should be carefully validated according to the -- GitLab From c96085eaab1f6b21e084b94fcc619d090f0afc97 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 14 Mar 2022 16:28:15 +0000 Subject: [PATCH 035/237] 8282929: Localized monetary symbols are not reflected in `toLocalizedPattern` return value Reviewed-by: joehw, lancea --- .../classes/java/text/DecimalFormat.java | 12 ++-- .../DecimalFormat/ToLocalizedPatternTest.java | 61 +++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index ea125b7d14b..094a5258b09 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -3210,16 +3210,18 @@ public class DecimalFormat extends NumberFormat { for (i = digitCount; i > 0; --i) { if (i != digitCount && isGroupingUsed() && groupingSize != 0 && i % groupingSize == 0) { - result.append(localized ? symbols.getGroupingSeparator() : - PATTERN_GROUPING_SEPARATOR); + result.append(localized ? + (isCurrencyFormat ? symbols.getMonetaryGroupingSeparator() : symbols.getGroupingSeparator()) : + PATTERN_GROUPING_SEPARATOR); } result.append(i <= getMinimumIntegerDigits() ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT) : (localized ? symbols.getDigit() : PATTERN_DIGIT)); } if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) - result.append(localized ? symbols.getDecimalSeparator() : - PATTERN_DECIMAL_SEPARATOR); + result.append(localized ? + (isCurrencyFormat ? symbols.getMonetaryDecimalSeparator() : symbols.getDecimalSeparator()) : + PATTERN_DECIMAL_SEPARATOR); for (i = 0; i < getMaximumFractionDigits(); ++i) { if (i < getMinimumFractionDigits()) { result.append(localized ? symbols.getZeroDigit() : diff --git a/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java b/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java new file mode 100644 index 00000000000..6d8ab9c9a0c --- /dev/null +++ b/test/jdk/java/text/Format/DecimalFormat/ToLocalizedPatternTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022, 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 8282929 + * @summary Verifies that toLocalizedPattern() method correctly returns + * monetary symbols in a currency formatter + * @run testng ToLocalizedPatternTest + */ + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.Test; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +@Test +public class ToLocalizedPatternTest { + private static final char MONETARY_GROUPING = 'g'; + private static final char MONETARY_DECIMAL = 'd'; + + public void testToLocalizedPattern() { + var dfs = new DecimalFormatSymbols(Locale.US); + + // Customize the decimal format symbols + dfs.setMonetaryGroupingSeparator(MONETARY_GROUPING); + dfs.setMonetaryDecimalSeparator(MONETARY_DECIMAL); + + // create a currency formatter + var cf = (DecimalFormat)DecimalFormat.getCurrencyInstance(Locale.US); + cf.setDecimalFormatSymbols(dfs); + + // check + assertEquals(cf.toLocalizedPattern(), + cf.toPattern() + .replace(',', MONETARY_GROUPING) + .replace('.', MONETARY_DECIMAL)); + } +} -- GitLab From 7833667f0e2151fc56c7c1533015f004f02f7ab2 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Mon, 14 Mar 2022 17:35:09 +0000 Subject: [PATCH 036/237] 8282881: Print exception message in VM crash with -XX:AbortVMOnException Reviewed-by: dholmes, hseigel --- src/hotspot/share/utilities/exceptions.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/utilities/exceptions.cpp b/src/hotspot/share/utilities/exceptions.cpp index 4ddc8e18ae6..1b56009a27d 100644 --- a/src/hotspot/share/utilities/exceptions.cpp +++ b/src/hotspot/share/utilities/exceptions.cpp @@ -538,7 +538,11 @@ void Exceptions::debug_check_abort(const char *value_string, const char* message strstr(value_string, AbortVMOnException)) { if (AbortVMOnExceptionMessage == NULL || (message != NULL && strstr(message, AbortVMOnExceptionMessage))) { - fatal("Saw %s, aborting", value_string); + if (message == NULL) { + fatal("Saw %s, aborting", value_string); + } else { + fatal("Saw %s: %s, aborting", value_string, message); + } } } } -- GitLab From 70bd57ed3544cdb41029d425507ba4b9b35c8cdb Mon Sep 17 00:00:00 2001 From: Carter Kozak Date: Mon, 14 Mar 2022 17:54:19 +0000 Subject: [PATCH 037/237] 8283049: Fix non-singleton LoggerFinder error message: s/on/one Reviewed-by: dfuchs --- .../classes/jdk/internal/logger/LoggerFinderLoader.java | 4 ++-- .../LoggerFinderLoaderTest/LoggerFinderLoaderTest.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java b/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java index dbf4ccca128..4f009973e27 100644 --- a/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java +++ b/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -129,7 +129,7 @@ public final class LoggerFinderLoader { result = iterator.next(); if (iterator.hasNext() && ensureSingletonProvider()) { throw new ServiceConfigurationError( - "More than on LoggerFinder implementation"); + "More than one LoggerFinder implementation"); } } else { result = loadDefaultImplementation(); diff --git a/test/jdk/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java b/test/jdk/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java index 8f1ce47fb07..d7ac2286678 100644 --- a/test/jdk/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java +++ b/test/jdk/java/lang/System/LoggerFinder/internal/LoggerFinderLoaderTest/LoggerFinderLoaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -53,7 +53,7 @@ import java.util.concurrent.atomic.AtomicReference; /** * @test - * @bug 8140364 8189291 + * @bug 8140364 8189291 8283049 * @summary JDK implementation specific unit test for LoggerFinderLoader. * Tests the behavior of LoggerFinderLoader with respect to the * value of the internal diagnosability switches. Also test the @@ -230,7 +230,7 @@ public class LoggerFinderLoaderTest { throw new RuntimeException("Expected message not found. Error stream contained: " + warning); } } else if (singleton) { - if (!warning.contains("java.util.ServiceConfigurationError: More than on LoggerFinder implementation")) { + if (!warning.contains("java.util.ServiceConfigurationError: More than one LoggerFinder implementation")) { throw new RuntimeException("Expected message not found. Error stream contained: " + warning); } } -- GitLab From f66070b00d4311c6e3a6fbf38956fa2d5da5fada Mon Sep 17 00:00:00 2001 From: Phil Race Date: Mon, 14 Mar 2022 18:05:38 +0000 Subject: [PATCH 038/237] 8282577: ICC_Profile.setData(int, byte[]) invalidates the profile Reviewed-by: serb --- src/java.desktop/share/native/liblcms/LCMS.c | 27 ++++--- .../ICC_ColorSpace/SetTagDataValidation.java | 75 +++++++++++++++++++ .../java/awt/color/ICC_Profile/MTGetData.java | 2 + 3 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 test/jdk/java/awt/color/ICC_ColorSpace/SetTagDataValidation.java diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c index 27c23c6d92f..06a7eb26140 100644 --- a/src/java.desktop/share/native/liblcms/LCMS.c +++ b/src/java.desktop/share/native/liblcms/LCMS.c @@ -734,34 +734,43 @@ static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget, // now we have all tags moved to the new profile. // do some sanity checks: write it to a memory buffer and read again. + void* buf = NULL; if (cmsSaveProfileToMem(p, NULL, &pfSize)) { - void* buf = malloc(pfSize); + buf = malloc(pfSize); if (buf != NULL) { // load raw profile data into the buffer if (cmsSaveProfileToMem(p, buf, &pfSize)) { pfSanity = cmsOpenProfileFromMem(buf, pfSize); } - free(buf); } } + cmsCloseProfile(p); // No longer needed. + if (pfSanity == NULL) { // for some reason, we failed to save and read the updated profile // It likely indicates that the profile is not correct, so we report // a failure here. - cmsCloseProfile(p); - p = NULL; + free(buf); + return NULL; } else { // do final check whether we can read and handle the target tag. const void* pTag = cmsReadTag(pfSanity, sig); if (pTag == NULL) { // the tag can not be cooked - cmsCloseProfile(p); - p = NULL; + free(buf); + cmsCloseProfile(pfSanity); + return NULL; } + // The profile we used for sanity checking needs to be returned + // since the one we updated is raw - not cooked. + // Except we want to re-open it since the call to cmsReadTag() + // means we may not get back the same bytes as we set. + // Whilst this may change later anyway, we can at least prevent + // it from happening immediately. cmsCloseProfile(pfSanity); - pfSanity = NULL; + pfSanity = cmsOpenProfileFromMem(buf, pfSize); + free(buf); + return pfSanity; } - - return p; } diff --git a/test/jdk/java/awt/color/ICC_ColorSpace/SetTagDataValidation.java b/test/jdk/java/awt/color/ICC_ColorSpace/SetTagDataValidation.java new file mode 100644 index 00000000000..92faced75ba --- /dev/null +++ b/test/jdk/java/awt/color/ICC_ColorSpace/SetTagDataValidation.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2022, 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 8282577 + * @summary Verify setting data for a tag doesn't invalidate the profile. + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; + +public final class SetTagDataValidation { + + public static void main(String[] args) throws Exception { + + ICC_Profile srgb = ICC_Profile.getInstance(ColorSpace.CS_sRGB); + // Create a new profile, using the srgb data but private to us. + ICC_Profile icc = ICC_Profile.getInstance(srgb.getData()); + + // Get data for some tag, which one isn't important so long as it exists + int tag = ICC_Profile.icSigBlueColorantTag; + byte[] tagData = icc.getData(tag); + if (tagData == null) { + throw new RuntimeException("No data for tag"); + } + // Set the data to be the SAME data which ought to be a harmless no-op + icc.setData(tag, tagData); + + // Perform a color conversion - from rgb to rgb but it doesn't matter + // we just need to verify the op is applied and results are sane. + + ColorSpace cs = new ICC_ColorSpace(icc); + float[] in = new float[3]; + in[0] = 0.4f; + in[1] = 0.5f; + in[2] = 0.6f; + + // the toRGB op previously threw an exception - or crashed + float[] out = cs.toRGB(in); + // If we get this far let's validate the results. + if (out == null || out.length !=3) { + throw new RuntimeException("out array invalid"); + } + for (int i=0;i 0.01)) { + throw new RuntimeException("Inaccurate no-op conversion"); + } + } + } +} diff --git a/test/jdk/java/awt/color/ICC_Profile/MTGetData.java b/test/jdk/java/awt/color/ICC_Profile/MTGetData.java index 5b2572e14f1..7d634cb0f4a 100644 --- a/test/jdk/java/awt/color/ICC_Profile/MTGetData.java +++ b/test/jdk/java/awt/color/ICC_Profile/MTGetData.java @@ -23,6 +23,7 @@ import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; +import java.awt.color.CMMException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -103,6 +104,7 @@ public final class MTGetData { icc.setData(tag, data2); } } catch (IllegalArgumentException ignored) { + System.err.println("Ignoring " + ignored); } catch (Throwable throwable) { throwable.printStackTrace(); failed = true; -- GitLab From 5bf6a7f7d78506118ded0f0bf6383b0825366619 Mon Sep 17 00:00:00 2001 From: Chris Plummer Date: Mon, 14 Mar 2022 18:15:40 +0000 Subject: [PATCH 039/237] 8282691: add jdb "-R" option for passing any argument to the launched debuggee process Reviewed-by: alanb, kevinw --- .../com/sun/tools/example/debug/tty/TTY.java | 4 +++- .../tools/example/debug/tty/TTYResources.java | 3 ++- src/jdk.jdi/share/man/jdb.1 | 16 +++++++++++++--- test/jdk/com/sun/jdi/JdbOptions.java | 18 +++++++++++++++++- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java index 6e1ddcb1b84..9373bc9e0e0 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTY.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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 @@ -993,6 +993,8 @@ public class TTY implements EventNotifier { token.startsWith("-ss") || token.startsWith("-oss") ) { javaArgs = addArgument(javaArgs, token); + } else if (token.startsWith("-R")) { + javaArgs = addArgument(javaArgs, token.substring(2)); } else if (token.equals("-tclassic")) { usageError("Classic VM no longer supported."); return; diff --git a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java index adec7aa98cf..e7090c8c8c8 100644 --- a/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java +++ b/src/jdk.jdi/share/classes/com/sun/tools/example/debug/tty/TTYResources.java @@ -477,8 +477,9 @@ public class TTYResources extends java.util.ListResourceBundle { " -dbgtrace [flags] print info for debugging {0}\n" + " -tclient run the application in the HotSpot(TM) Client Compiler\n" + " -tserver run the application in the HotSpot(TM) Server Compiler\n" + + " -R

",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):("number"==typeof f.top&&(f.top+="px"),"number"==typeof f.left&&(f.left+="px"),c.css(f))}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=$e(y.pixelPosition,function(e,t){if(t)return t=Be(e,n),Me.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }; + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + // Support: QtWeb <=3.8.5, WebKit <=534.34, wkhtmltopdf tool <=0.12.5 + // Plus for old WebKit, typeof returns "function" for HTML collections + // (e.g., `typeof document.getElementsByTagName("div") === "function"`). (gh-4756) + return typeof obj === "function" && typeof obj.nodeType !== "number" && + typeof obj.item !== "function"; + }; var isWindow = function isWindow( obj ) { @@ -147,7 +151,7 @@ function toType( obj ) { var - version = "3.5.1", + version = "3.6.0", // Define a local copy of jQuery jQuery = function( selector, context ) { @@ -401,7 +405,7 @@ jQuery.extend( { if ( isArrayLike( Object( arr ) ) ) { jQuery.merge( ret, typeof arr === "string" ? - [ arr ] : arr + [ arr ] : arr ); } else { push.call( ret, arr ); @@ -496,9 +500,9 @@ if ( typeof Symbol === "function" ) { // Populate the class2type map jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); function isArrayLike( obj ) { @@ -518,14 +522,14 @@ function isArrayLike( obj ) { } var Sizzle = /*! - * Sizzle CSS Selector Engine v2.3.5 + * Sizzle CSS Selector Engine v2.3.6 * https://sizzlejs.com/ * * Copyright JS Foundation and other contributors * Released under the MIT license * https://js.foundation/ * - * Date: 2020-03-14 + * Date: 2021-02-16 */ ( function( window ) { var i, @@ -1108,8 +1112,8 @@ support = Sizzle.support = {}; * @returns {Boolean} True iff elem is a non-HTML XML node */ isXML = Sizzle.isXML = function( elem ) { - var namespace = elem.namespaceURI, - docElem = ( elem.ownerDocument || elem ).documentElement; + var namespace = elem && elem.namespaceURI, + docElem = elem && ( elem.ownerDocument || elem ).documentElement; // Support: IE <=8 // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes @@ -3024,9 +3028,9 @@ var rneedsContext = jQuery.expr.match.needsContext; function nodeName( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); -}; +} var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); @@ -3997,8 +4001,8 @@ jQuery.extend( { resolveContexts = Array( i ), resolveValues = slice.call( arguments ), - // the master Deferred - master = jQuery.Deferred(), + // the primary Deferred + primary = jQuery.Deferred(), // subordinate callback factory updateFunc = function( i ) { @@ -4006,30 +4010,30 @@ jQuery.extend( { resolveContexts[ i ] = this; resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); + primary.resolveWith( resolveContexts, resolveValues ); } }; }; // Single- and empty arguments are adopted like Promise.resolve if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + adoptValue( singleValue, primary.done( updateFunc( i ) ).resolve, primary.reject, !remaining ); // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || + if ( primary.state() === "pending" || isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - return master.then(); + return primary.then(); } } // Multiple arguments are aggregated like Promise.all array elements while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + adoptValue( resolveValues[ i ], updateFunc( i ), primary.reject ); } - return master.promise(); + return primary.promise(); } } ); @@ -4180,8 +4184,8 @@ var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { for ( ; i < len; i++ ) { fn( elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) ); } } @@ -5089,10 +5093,7 @@ function buildFragment( elems, context, scripts, selection, ignored ) { } -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; +var rtypenamespace = /^([^.]*)(?:\.(.+)|)/; function returnTrue() { return true; @@ -5387,8 +5388,8 @@ jQuery.event = { event = jQuery.event.fix( nativeEvent ), handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ event.type ] || [], + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event @@ -5512,12 +5513,12 @@ jQuery.event = { get: isFunction( hook ) ? function() { if ( this.originalEvent ) { - return hook( this.originalEvent ); + return hook( this.originalEvent ); } } : function() { if ( this.originalEvent ) { - return this.originalEvent[ name ]; + return this.originalEvent[ name ]; } }, @@ -5656,7 +5657,13 @@ function leverageNative( el, type, expectSync ) { // Cancel the outer synthetic event event.stopImmediatePropagation(); event.preventDefault(); - return result.value; + + // Support: Chrome 86+ + // In Chrome, if an element having a focusout handler is blurred by + // clicking outside of it, it invokes the handler synchronously. If + // that handler calls `.remove()` on the element, the data is cleared, + // leaving `result` undefined. We need to guard against this. + return result && result.value; } // If this is an inner synthetic event for an event with a bubbling surrogate @@ -5821,34 +5828,7 @@ jQuery.each( { targetTouches: true, toElement: true, touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } + which: true }, jQuery.event.addProp ); jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { @@ -5874,6 +5854,12 @@ jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateTyp return true; }, + // Suppress native focus or blur as it's already being fired + // in leverageNative. + _default: function() { + return true; + }, + delegateType: delegateType }; } ); @@ -6541,6 +6527,10 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); // set in CSS while `offset*` properties report correct values. // Behavior in IE 9 is more subtle than in newer versions & it passes // some versions of this test; make sure not to make it pass there! + // + // Support: Firefox 70+ + // Only Firefox includes border widths + // in computed dimensions. (gh-4529) reliableTrDimensions: function() { var table, tr, trChild, trStyle; if ( reliableTrDimensionsVal == null ) { @@ -6548,17 +6538,32 @@ var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); tr = document.createElement( "tr" ); trChild = document.createElement( "div" ); - table.style.cssText = "position:absolute;left:-11111px"; + table.style.cssText = "position:absolute;left:-11111px;border-collapse:separate"; + tr.style.cssText = "border:1px solid"; + + // Support: Chrome 86+ + // Height set through cssText does not get applied. + // Computed height then comes back as 0. tr.style.height = "1px"; trChild.style.height = "9px"; + // Support: Android 8 Chrome 86+ + // In our bodyBackground.html iframe, + // display for all div elements is set to "inline", + // which causes a problem only in Android 8 Chrome 86. + // Ensuring the div is display: block + // gets around this issue. + trChild.style.display = "block"; + documentElement .appendChild( table ) .appendChild( tr ) .appendChild( trChild ); trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + reliableTrDimensionsVal = ( parseInt( trStyle.height, 10 ) + + parseInt( trStyle.borderTopWidth, 10 ) + + parseInt( trStyle.borderBottomWidth, 10 ) ) === tr.offsetHeight; documentElement.removeChild( table ); } @@ -7022,10 +7027,10 @@ jQuery.each( [ "height", "width" ], function( _i, dimension ) { // Running getBoundingClientRect on a disconnected node // in IE throws an error. ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); } }, @@ -7084,7 +7089,7 @@ jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, swap( elem, { marginLeft: 0 }, function() { return elem.getBoundingClientRect().left; } ) - ) + "px"; + ) + "px"; } } ); @@ -7223,7 +7228,7 @@ Tween.propHooks = { if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || + jQuery.cssHooks[ tween.prop ] || tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); } else { @@ -7468,7 +7473,7 @@ function defaultPrefilter( elem, props, opts ) { anim.done( function() { - /* eslint-enable no-loop-func */ + /* eslint-enable no-loop-func */ // The final step of a "hide" animation is actually hiding the element if ( !hidden ) { @@ -7588,7 +7593,7 @@ function Animation( elem, properties, options ) { tweens: [], createTween: function( prop, end ) { var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.opts.specialEasing[ prop ] || animation.opts.easing ); animation.tweens.push( tween ); return tween; }, @@ -7761,7 +7766,8 @@ jQuery.fn.extend( { anim.stop( true ); } }; - doAnimation.finish = doAnimation; + + doAnimation.finish = doAnimation; return empty || optall.queue === false ? this.each( doAnimation ) : @@ -8401,8 +8407,8 @@ jQuery.fn.extend( { if ( this.setAttribute ) { this.setAttribute( "class", className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" + "" : + dataPriv.get( this, "__className__" ) || "" ); } } @@ -8417,7 +8423,7 @@ jQuery.fn.extend( { while ( ( elem = this[ i++ ] ) ) { if ( elem.nodeType === 1 && ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; + return true; } } @@ -8707,9 +8713,7 @@ jQuery.extend( jQuery.event, { special.bindType || type; // jQuery handler - handle = ( - dataPriv.get( cur, "events" ) || Object.create( null ) - )[ event.type ] && + handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && dataPriv.get( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); @@ -8856,7 +8860,7 @@ var rquery = ( /\?/ ); // Cross-browser xml parsing jQuery.parseXML = function( data ) { - var xml; + var xml, parserErrorElem; if ( !data || typeof data !== "string" ) { return null; } @@ -8865,12 +8869,17 @@ jQuery.parseXML = function( data ) { // IE throws on parseFromString with invalid input. try { xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } + } catch ( e ) {} - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); + parserErrorElem = xml && xml.getElementsByTagName( "parsererror" )[ 0 ]; + if ( !xml || parserErrorElem ) { + jQuery.error( "Invalid XML: " + ( + parserErrorElem ? + jQuery.map( parserErrorElem.childNodes, function( el ) { + return el.textContent; + } ).join( "\n" ) : + data + ) ); } return xml; }; @@ -8971,16 +8980,14 @@ jQuery.fn.extend( { // Can add propHook for "elements" to filter or add form elements var elements = jQuery.prop( this, "elements" ); return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { + } ).filter( function() { var type = this.type; // Use .is( ":disabled" ) so that fieldset[disabled] works return this.name && !jQuery( this ).is( ":disabled" ) && rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( _i, elem ) { + } ).map( function( _i, elem ) { var val = jQuery( this ).val(); if ( val == null ) { @@ -9033,7 +9040,8 @@ var // Anchor tag for parsing the document origin originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; + +originAnchor.href = location.href; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { @@ -9414,8 +9422,8 @@ jQuery.extend( { // Context for global events is callbackContext if it is a DOM node or jQuery collection globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, + jQuery( callbackContext ) : + jQuery.event, // Deferreds deferred = jQuery.Deferred(), @@ -9727,8 +9735,10 @@ jQuery.extend( { response = ajaxHandleResponses( s, jqXHR, responses ); } - // Use a noop converter for missing script - if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + // Use a noop converter for missing script but not if jsonp + if ( !isSuccess && + jQuery.inArray( "script", s.dataTypes ) > -1 && + jQuery.inArray( "json", s.dataTypes ) < 0 ) { s.converters[ "text script" ] = function() {}; } @@ -10466,12 +10476,6 @@ jQuery.offset = { options.using.call( elem, props ); } else { - if ( typeof props.top === "number" ) { - props.top += "px"; - } - if ( typeof props.left === "number" ) { - props.left += "px"; - } curElem.css( props ); } } @@ -10640,8 +10644,11 @@ jQuery.each( [ "top", "left" ], function( _i, prop ) { // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { - jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, - function( defaultExtra, funcName ) { + jQuery.each( { + padding: "inner" + name, + content: type, + "": "outer" + name + }, function( defaultExtra, funcName ) { // Margin is only for outerHeight, outerWidth jQuery.fn[ funcName ] = function( margin, value ) { @@ -10726,7 +10733,8 @@ jQuery.fn.extend( { } } ); -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + +jQuery.each( + ( "blur focus focusin focusout resize scroll click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup contextmenu" ).split( " " ), function( _i, name ) { @@ -10737,7 +10745,8 @@ jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + this.on( name, null, data, fn ) : this.trigger( name ); }; - } ); + } +); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.0.min.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.0.min.js new file mode 100644 index 00000000000..c4c6022f298 --- /dev/null +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script-dir/jquery-3.6.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 """, """ - + """, """ """, @@ -684,7 +684,7 @@ public class TestSearch extends JavadocTester { checkFiles(expectedOutput, "search.js", "jquery-ui.overrides.css", - "script-dir/jquery-3.5.1.min.js", + "script-dir/jquery-3.6.0.min.js", "script-dir/jquery-ui.min.js", "script-dir/jquery-ui.min.css", "script-dir/jquery-ui.structure.min.css", diff --git a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java index a0d68d85403..3a5ddda8261 100644 --- a/test/langtools/jdk/javadoc/tool/api/basic/APITest.java +++ b/test/langtools/jdk/javadoc/tool/api/basic/APITest.java @@ -201,7 +201,7 @@ class APITest { "help-doc.html", "index-all.html", "index.html", - "script-dir/jquery-3.5.1.min.js", + "script-dir/jquery-3.6.0.min.js", "script-dir/jquery-ui.min.js", "script-dir/jquery-ui.min.css", "script-dir/jquery-ui.structure.min.css", -- GitLab From 6013d09e82693a1c07cf0bf6daffd95114b3cbfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hannes=20Walln=C3=B6fer?= Date: Mon, 14 Mar 2022 20:29:15 +0000 Subject: [PATCH 042/237] 8268866: Javascript when used in an iframe cannot display search results Reviewed-by: jjg --- .../doclets/formats/html/resources/search.js.template | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template index b5c92aefeb3..27ad08ad580 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/search.js.template @@ -359,11 +359,7 @@ $(function() { } else if (ui.item.category === catSearchTags) { url += ui.item.u; } - if (top !== window) { - parent.classFrame.location = pathtoroot + url; - } else { - window.location.href = pathtoroot + url; - } + window.location.href = pathtoroot + url; $("#search-input").focus(); } } -- GitLab From 34d4ffcea5d71560c549655967de863342b48984 Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 15 Mar 2022 07:24:50 +0000 Subject: [PATCH 043/237] 8279317: compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java assumes immutable code Reviewed-by: dnsimon, iveresov --- .../compilerToVM/DisassembleCodeBlobTest.java | 43 +++++++++++++------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java index 9d26ed16eb6..ec5b9337b49 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/DisassembleCodeBlobTest.java @@ -83,6 +83,11 @@ public class DisassembleCodeBlobTest { + " : non-null return value for invalid installCode"); } + private void checkLineStart(CompileCodeTestCase testCase, String line, String match) { + Asserts.assertTrue(line.startsWith(match), + testCase + " : line \"" + line + "\" does not start with: \"" + match +"\""); + } + private void check(CompileCodeTestCase testCase) { System.out.println(testCase); // to have a clean state @@ -98,19 +103,33 @@ public class DisassembleCodeBlobTest { } // The very first call to the disassembler contains a string specifying the // architecture: [Disassembling for mach='i386:x86-64'] - // Therefore compare strings 2 and 3. + // so discard it and try again. String str2 = CompilerToVMHelper.disassembleCodeBlob(installedCode); - String str3 = CompilerToVMHelper.disassembleCodeBlob(installedCode); - String[] str2Lines = str2.split(System.lineSeparator()); - String[] str3Lines = str3.split(System.lineSeparator()); - // skip the first two lines since it contains a timestamp that may vary from different invocations - // - // Compiled method (c2) 309 463 4 compiler.jvmci.compilerToVM.CompileCodeTestCase$Dummy::staticMethod (1 bytes) - // - // Compiled method (c2) 310 463 4 compiler.jvmci.compilerToVM.CompileCodeTestCase$Dummy::staticMethod (1 bytes) - for (int i = 2; i < str2Lines.length; i++) { - Asserts.assertEQ(str2Lines[i], str3Lines[i], - testCase + " : 3nd invocation returned different value from 2nd"); + String[] strLines = str2.split("\\R"); + // Check some basic layout + int MIN_LINES = 5; + Asserts.assertTrue(strLines.length > 2, + testCase + " : read " + strLines.length + " lines, " + MIN_LINES + " expected"); + int l = 1; + checkLineStart(testCase, strLines[l++], "Compiled method "); // 2 + checkLineStart(testCase, strLines[l++], " total in heap "); // 3 + int foundDisassemblyLine = -1; + int foundEntryPointLine = -1; + for (; l < strLines.length; ++l) { + String line = strLines[l]; + if (line.equals("[Disassembly]") || line.equals("[MachCode]")) { + Asserts.assertTrue(foundDisassemblyLine == -1, + testCase + " : Duplicate disassembly section markers found at lines " + foundDisassemblyLine + " and " + l); + foundDisassemblyLine = l; + } + if (line.equals("[Entry Point]") || line.equals("[Verified Entry Point]")) { + Asserts.assertTrue(foundDisassemblyLine != -1, + testCase + " : entry point found but [Disassembly] section missing "); + foundEntryPointLine = l; + break; + } } + Asserts.assertTrue(foundDisassemblyLine != -1, testCase + " : no disassembly section found"); + Asserts.assertTrue(foundEntryPointLine != -1, testCase + " : no entry point found"); } } -- GitLab From 710653ce1856d13161ae1786d7c5f71997536e78 Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Tue, 15 Mar 2022 12:59:54 +0000 Subject: [PATCH 044/237] 8254786: java/net/httpclient/CancelRequestTest.java failing intermittently Reviewed-by: jpai, michaelm --- .../jdk/internal/net/http/Exchange.java | 53 ++++++++++++++----- .../internal/net/http/Http2ClientImpl.java | 12 +++-- .../internal/net/http/Http2Connection.java | 6 ++- .../net/httpclient/CancelRequestTest.java | 4 +- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java index 36af3005032..8c9282c0579 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -144,14 +144,45 @@ final class Exchange { private volatile boolean closeRequested; void connection(HttpConnection connection) { - this.connection = connection; - if (closeRequested) closeConnection(); + boolean closeRequested; + synchronized (this) { + // check whether this new connection should be + // closed + closeRequested = this.closeRequested; + if (!closeRequested) { + this.connection = connection; + } else { + // assert this.connection == null + this.closeRequested = false; + } + } + if (closeRequested) closeConnection(connection); } void closeConnection() { - closeRequested = true; - HttpConnection connection = this.connection; - this.connection = null; + HttpConnection connection; + synchronized (this) { + connection = this.connection; + if (connection == null) { + closeRequested = true; + } else { + this.connection = null; + } + } + closeConnection(connection); + } + + HttpConnection disable() { + HttpConnection connection; + synchronized (this) { + connection = this.connection; + this.connection = null; + this.closeRequested = false; + } + return connection; + } + + private static void closeConnection(HttpConnection connection) { if (connection != null) { try { connection.close(); @@ -160,11 +191,6 @@ final class Exchange { } } } - - void disable() { - connection = null; - closeRequested = false; - } } // Called for 204 response - when no body is permitted @@ -524,8 +550,11 @@ final class Exchange { client.client2(), this, e::drainLeftOverBytes) .thenCompose((Http2Connection c) -> { + HttpConnection connection = connectionAborter.disable(); boolean cached = c.offerConnection(); - if (cached) connectionAborter.disable(); + if (!cached && connection != null) { + connectionAborter.connection(connection); + } Stream s = c.getStream(1); if (s == null) { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java index 4101133a025..c3861b2ad9f 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -28,7 +28,6 @@ package jdk.internal.net.http; import java.io.EOFException; import java.io.IOException; import java.io.UncheckedIOException; -import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.URI; import java.util.Base64; @@ -101,7 +100,7 @@ class Http2ClientImpl { Http2Connection connection = connections.get(key); if (connection != null) { try { - if (connection.closed || !connection.reserveStream(true)) { + if (!connection.isOpen() || !connection.reserveStream(true)) { if (debug.on()) debug.log("removing found closed or closing connection: %s", connection); deleteConnection(connection); @@ -153,7 +152,7 @@ class Http2ClientImpl { */ boolean offerConnection(Http2Connection c) { if (debug.on()) debug.log("offering to the connection pool: %s", c); - if (c.closed || c.finalStream()) { + if (!c.isOpen() || c.finalStream()) { if (debug.on()) debug.log("skipping offered closed or closing connection: %s", c); return false; @@ -161,6 +160,11 @@ class Http2ClientImpl { String key = c.key(); synchronized(this) { + if (!c.isOpen()) { + if (debug.on()) + debug.log("skipping offered closed or closing connection: %s", c); + return false; + } Http2Connection c1 = connections.putIfAbsent(key, c); if (c1 != null) { c.setFinalStream(); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java index 6a07d755e69..8cd9db1210a 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -880,6 +880,10 @@ class Http2Connection { } } + boolean isOpen() { + return !closed && connection.channel().isOpen(); + } + void resetStream(int streamid, int code) { try { if (connection.channel().isOpen()) { diff --git a/test/jdk/java/net/httpclient/CancelRequestTest.java b/test/jdk/java/net/httpclient/CancelRequestTest.java index de48316a25b..95d56fdbcce 100644 --- a/test/jdk/java/net/httpclient/CancelRequestTest.java +++ b/test/jdk/java/net/httpclient/CancelRequestTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 8245462 8229822 + * @bug 8245462 8229822 8254786 * @summary Tests cancelling the request. * @library /test/lib http2/server * @key randomness -- GitLab From 2cddf3f5391518ea40796e6c4759047d51b7b312 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 15 Mar 2022 14:16:35 +0000 Subject: [PATCH 045/237] 8282887: Potential memory leak in sun.util.locale.provider.HostLocaleProviderAdapterImpl.getNumberPattern() on Windows Reviewed-by: naoto, alanb --- .../native/libjava/HostLocaleProviderAdapter_md.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c index 5d5f3ab476e..ebbad326146 100644 --- a/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c +++ b/src/java.base/windows/native/libjava/HostLocaleProviderAdapter_md.c @@ -359,18 +359,17 @@ JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderA JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getNumberPattern (JNIEnv *env, jclass cls, jint numberStyle, jstring jlangtag) { const jchar *langtag; - jstring ret; + jstring ret = NULL; WCHAR * pattern; langtag = (*env)->GetStringChars(env, jlangtag, NULL); CHECK_NULL_RETURN(langtag, NULL); pattern = getNumberPattern(langtag, numberStyle); - CHECK_NULL_RETURN(pattern, NULL); - + if (!IS_NULL(pattern)) { + ret = (*env)->NewString(env, pattern, (jsize)wcslen(pattern)); + free(pattern); + } (*env)->ReleaseStringChars(env, jlangtag, langtag); - ret = (*env)->NewString(env, pattern, (jsize)wcslen(pattern)); - free(pattern); - return ret; } -- GitLab From 4de72014d3a33469399fec6f428f35c47c4cfbe0 Mon Sep 17 00:00:00 2001 From: Tyler Steele Date: Tue, 15 Mar 2022 14:52:27 +0000 Subject: [PATCH 046/237] 8283122: [AIX, s390] UnsafeCopyMemory 'Mismatched' Tests Fail on Big Endian Systems Reviewed-by: thartmann, stuefe --- .../jtreg/compiler/unsafe/UnsafeCopyMemory.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java b/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java index 51cbb5e8c2f..eb6f065305e 100644 --- a/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java +++ b/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022 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 @@ -36,11 +36,14 @@ package compiler.unsafe; import jdk.internal.misc.Unsafe; +import java.nio.ByteOrder; import static jdk.test.lib.Asserts.assertEQ; public class UnsafeCopyMemory { static private Unsafe UNSAFE = Unsafe.getUnsafe(); + static final boolean IS_BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; + // On-heap arrays static int[] srcArr = new int[1]; static int[] dstArr = new int[1]; @@ -104,8 +107,12 @@ public class UnsafeCopyMemory { srcArr [readIdx] = v1; dstArrL[writeIdx] = v2; + // On LE systems, low-order bytes of long and int overlap, but + // on BE systems, they differ by the size of an int. + long mismatchedOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (IS_BIG_ENDIAN ? 4 : 0); + UNSAFE.copyMemory(srcArr, Unsafe.ARRAY_INT_BASE_OFFSET, - dstArrL, Unsafe.ARRAY_LONG_BASE_OFFSET, 4); // mismatched + dstArrL, mismatchedOffset, 4); // mismatched long r = resArrL[0]; // snapshot srcArr[readIdx] = v3; @@ -156,6 +163,7 @@ public class UnsafeCopyMemory { Object srcArrLocal = (flag ? srcArrIntLocal : srcArrLongLocal); long srcOffset = (flag ? Unsafe.ARRAY_INT_BASE_OFFSET : Unsafe.ARRAY_LONG_BASE_OFFSET); + srcOffset += (!flag && IS_BIG_ENDIAN ? 4 : 0); srcArrIntLocal[0] = v1; srcArrLongLocal[0] = v1; @@ -179,6 +187,7 @@ public class UnsafeCopyMemory { Object dstArrLocal = (flag ? dstArrIntLocal : dstArrLongLocal); long dstOffset = (flag ? Unsafe.ARRAY_INT_BASE_OFFSET : Unsafe.ARRAY_LONG_BASE_OFFSET); + dstOffset += (!flag && IS_BIG_ENDIAN ? 4 : 0); srcArr[readIdx] = v1; dstArrIntLocal[0] = v2; -- GitLab From f43ffe211f8ff287697092c39e4c25a16b40a383 Mon Sep 17 00:00:00 2001 From: Hai-May Chao Date: Tue, 15 Mar 2022 15:54:47 +0000 Subject: [PATCH 047/237] 8282633: jarsigner output does not explain why an EC key is disabled if its curve has been disabled Reviewed-by: weijun --- .../sun/security/tools/keytool/Main.java | 30 ++---- .../classes/sun/security/util/KeyUtil.java | 24 ++++- .../sun/security/tools/jarsigner/Main.java | 35 ++++-- .../security/tools/jarsigner/Resources.java | 2 + .../tools/jarsigner/DisableCurveTest.java | 100 ++++++++++++++++++ 5 files changed, 160 insertions(+), 31 deletions(-) create mode 100644 test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 032fcd768ea..462606c7f84 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -42,8 +42,6 @@ import java.security.cert.TrustAnchor; import java.security.cert.URICertStoreParameters; -import java.security.interfaces.ECKey; -import java.security.interfaces.EdECKey; import java.security.spec.ECParameterSpec; import java.text.Collator; import java.text.MessageFormat; @@ -2018,7 +2016,7 @@ public final class Main { ("Generating.keysize.bit.keyAlgName.key.pair.and.a.certificate.sigAlgName.issued.by.signerAlias.with.a.validity.of.validality.days.for")); Object[] source = { groupName == null ? keysize : KeyUtil.getKeySize(privKey), - fullDisplayAlgName(privKey), + KeyUtil.fullDisplayAlgName(privKey), newCert.getSigAlgName(), signerAlias, validity, @@ -2029,7 +2027,7 @@ public final class Main { ("Generating.keysize.bit.keyAlgName.key.pair.and.self.signed.certificate.sigAlgName.with.a.validity.of.validality.days.for")); Object[] source = { groupName == null ? keysize : KeyUtil.getKeySize(privKey), - fullDisplayAlgName(privKey), + KeyUtil.fullDisplayAlgName(privKey), newCert.getSigAlgName(), validity, x500Name}; @@ -3560,24 +3558,10 @@ public final class Main { } } - private String fullDisplayAlgName(Key key) { - String result = key.getAlgorithm(); - if (key instanceof ECKey) { - ECParameterSpec paramSpec = ((ECKey) key).getParams(); - if (paramSpec instanceof NamedCurve) { - NamedCurve nc = (NamedCurve)paramSpec; - result += " (" + nc.getNameAndAliases()[0] + ")"; - } - } else if (key instanceof EdECKey) { - result = ((EdECKey) key).getParams().getName(); - } - return result; - } - private String withWeakConstraint(Key key, CertPathConstraintsParameters cpcp) { int kLen = KeyUtil.getKeySize(key); - String displayAlg = fullDisplayAlgName(key); + String displayAlg = KeyUtil.fullDisplayAlgName(key); try { DISABLED_CHECK.permits(key.getAlgorithm(), cpcp, true); } catch (CertPathValidatorException e) { @@ -4946,13 +4930,13 @@ public final class Main { weakWarnings.add(String.format( rb.getString("whose.key.weak"), label, String.format(rb.getString("key.bit"), - KeyUtil.getKeySize(key), fullDisplayAlgName(key)))); + KeyUtil.getKeySize(key), KeyUtil.fullDisplayAlgName(key)))); } } catch (CertPathValidatorException e) { weakWarnings.add(String.format( rb.getString("whose.key.disabled"), label, String.format(rb.getString("key.bit"), - KeyUtil.getKeySize(key), fullDisplayAlgName(key)))); + KeyUtil.getKeySize(key), KeyUtil.fullDisplayAlgName(key)))); } } } @@ -4973,12 +4957,12 @@ public final class Main { weakWarnings.add(String.format( rb.getString("whose.key.disabled"), label, String.format(rb.getString("key.bit"), - KeyUtil.getKeySize(key), fullDisplayAlgName(key)))); + KeyUtil.getKeySize(key), KeyUtil.fullDisplayAlgName(key)))); } else if (!LEGACY_CHECK.permits(SIG_PRIMITIVE_SET, key)) { weakWarnings.add(String.format( rb.getString("whose.key.weak"), label, String.format(rb.getString("key.bit"), - KeyUtil.getKeySize(key), fullDisplayAlgName(key)))); + KeyUtil.getKeySize(key), KeyUtil.fullDisplayAlgName(key)))); } } } diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java index a20ebffa5ff..3648447e10e 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -190,6 +190,28 @@ public final class KeyUtil { return -1; } + /** + * Returns the algorithm name of the given key object. If an EC key is + * specified, returns the algorithm name and its named curve. + * + * @param key the key object, cannot be null + * @return the algorithm name of the given key object, or return in the + * form of "EC (named curve)" if the given key object is an EC key + */ + public static final String fullDisplayAlgName(Key key) { + String result = key.getAlgorithm(); + if (key instanceof ECKey) { + ECParameterSpec paramSpec = ((ECKey) key).getParams(); + if (paramSpec instanceof NamedCurve) { + NamedCurve nc = (NamedCurve)paramSpec; + result += " (" + nc.getNameAndAliases()[0] + ")"; + } + } else if (key instanceof EdECKey) { + result = ((EdECKey) key).getParams().getName(); + } + return result; + } + /** * Returns whether the key is valid or not. *

diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index 750b125f10d..1b9e23f0fde 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -30,6 +30,7 @@ import java.net.UnknownHostException; import java.net.URLClassLoader; import java.security.cert.CertPathValidatorException; import java.security.cert.PKIXBuilderParameters; +import java.security.interfaces.ECKey; import java.util.*; import java.util.stream.Collectors; import java.util.zip.*; @@ -1244,13 +1245,13 @@ public class Main { if ((legacyAlg & 8) == 8) { warnings.add(String.format( rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."), - privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey))); + KeyUtil.fullDisplayAlgName(privateKey), KeyUtil.getKeySize(privateKey))); } if ((disabledAlg & 8) == 8) { errors.add(String.format( rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk.and.is.disabled."), - privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey))); + KeyUtil.fullDisplayAlgName(privateKey), KeyUtil.getKeySize(privateKey))); } } else { if ((legacyAlg & 1) != 0) { @@ -1274,7 +1275,7 @@ public class Main { if ((legacyAlg & 8) == 8) { warnings.add(String.format( rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk..This.key.size.will.be.disabled.in.a.future.update."), - weakPublicKey.getAlgorithm(), KeyUtil.getKeySize(weakPublicKey))); + KeyUtil.fullDisplayAlgName(weakPublicKey), KeyUtil.getKeySize(weakPublicKey))); } } @@ -1451,7 +1452,12 @@ public class Main { JAR_DISABLED_CHECK.permits(key.getAlgorithm(), jcp, true); } catch (CertPathValidatorException e) { disabledAlgFound = true; - return String.format(rb.getString("key.bit.disabled"), kLen); + if (key instanceof ECKey) { + return String.format(rb.getString("key.bit.eccurve.disabled"), kLen, + KeyUtil.fullDisplayAlgName(key)); + } else { + return String.format(rb.getString("key.bit.disabled"), kLen); + } } try { LEGACY_CHECK.permits(key.getAlgorithm(), jcp, true); @@ -1463,7 +1469,12 @@ public class Main { } catch (CertPathValidatorException e) { weakPublicKey = key; legacyAlg |= 8; - return String.format(rb.getString("key.bit.weak"), kLen); + if (key instanceof ECKey) { + return String.format(rb.getString("key.bit.eccurve.weak"), kLen, + KeyUtil.fullDisplayAlgName(key)); + } else { + return String.format(rb.getString("key.bit.weak"), kLen); + } } } @@ -1516,7 +1527,12 @@ public class Main { try { CERTPATH_DISABLED_CHECK.permits(key.getAlgorithm(), cpcp, true); } catch (CertPathValidatorException e) { - return String.format(rb.getString("key.bit.disabled"), kLen); + if (key instanceof ECKey) { + return String.format(rb.getString("key.bit.eccurve.disabled"), kLen, + KeyUtil.fullDisplayAlgName(key)); + } else { + return String.format(rb.getString("key.bit.disabled"), kLen); + } } try { LEGACY_CHECK.permits(key.getAlgorithm(), cpcp, true); @@ -1526,7 +1542,12 @@ public class Main { return rb.getString("unknown.size"); } } catch (CertPathValidatorException e) { - return String.format(rb.getString("key.bit.weak"), kLen); + if (key instanceof ECKey) { + return String.format(rb.getString("key.bit.eccurve.weak"), kLen, + KeyUtil.fullDisplayAlgName(key)); + } else { + return String.format(rb.getString("key.bit.weak"), kLen); + } } } diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java index f5a1bb2e3cb..37a1f24f90d 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java @@ -181,7 +181,9 @@ public class Resources extends java.util.ListResourceBundle { {"with.algparams.disabled", "%1$s using %2$s (disabled)"}, {"key.bit", "%d-bit key"}, {"key.bit.weak", "%d-bit key (weak)"}, + {"key.bit.eccurve.weak", "%1$d-bit %2$s key (weak)"}, {"key.bit.disabled", "%d-bit key (disabled)"}, + {"key.bit.eccurve.disabled", "%1$d-bit %2$s key (disabled)"}, {"unknown.size", "unknown size"}, {"extra.attributes.detected", "POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature."}, diff --git a/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java b/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java new file mode 100644 index 00000000000..9270899182c --- /dev/null +++ b/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022, 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 8282633 + * @summary jarsigner should display the named curve to better explain why + * an EC key is disabled or will be disabled. + * @library /test/lib + */ + +import jdk.test.lib.SecurityTools; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.util.JarUtils; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class DisableCurveTest { + private static final String JAVA_SECURITY_FILE = "java.security"; + + public static void main(String[] args) throws Exception{ + SecurityTools.keytool("-keystore ks -storepass changeit " + + "-genkeypair -keyalg EC -alias ca -dname CN=CA " + + "-ext bc:c") + .shouldHaveExitValue(0); + + JarUtils.createJarFile(Path.of("a.jar"), Path.of("."), Path.of("ks")); + + Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), + "jdk.jar.disabledAlgorithms=secp256r1\n" + + "jdk.certpath.disabledAlgorithms=secp256r1\n"); + + SecurityTools.jarsigner("-keystore ks -storepass changeit " + + "-signedjar signeda.jar -verbose " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " a.jar ca") + .shouldContain(">>> Signer") + .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (disabled)") + .shouldContain("Warning:") + .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk and is disabled") + .shouldHaveExitValue(0); + + SecurityTools.jarsigner("-verify signeda.jar " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " -keystore ks -storepass changeit -verbose -debug") + .shouldContain("- Signed by") + .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (disabled)") + .shouldContain("WARNING: The jar will be treated as unsigned") + .shouldHaveExitValue(0); + + Files.deleteIfExists(Paths.get(JAVA_SECURITY_FILE)); + Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), + "jdk.security.legacyAlgorithms=secp256r1\n"); + + SecurityTools.jarsigner("-keystore ks -storepass changeit " + + "-signedjar signeda.jar -verbose " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " a.jar ca") + .shouldContain(">>> Signer") + .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (weak)") + .shouldContain("Warning:") + .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk. This key size will be disabled in a future update") + .shouldHaveExitValue(0); + + SecurityTools.jarsigner("-verify signeda.jar " + + "-J-Djava.security.properties=" + + JAVA_SECURITY_FILE + + " -keystore ks -storepass changeit -verbose -debug") + .shouldContain("- Signed by") + .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (weak)") + .shouldContain("jar verified") + .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk. This key size will be disabled in a future update") + .shouldHaveExitValue(0); + } +} -- GitLab From 671b6efd6126384c0630d1cd84f53f52995e68d8 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 15 Mar 2022 16:05:37 +0000 Subject: [PATCH 048/237] 8283143: Use minimal-length literals to initialize PI and E constants Reviewed-by: smarks --- src/java.base/share/classes/java/lang/Math.java | 6 +++--- src/java.base/share/classes/java/lang/StrictMath.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 7341aa56a6a..649a85cfc52 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2022, 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 @@ -131,14 +131,14 @@ public final class Math { * The {@code double} value that is closer than any other to * e, the base of the natural logarithms. */ - public static final double E = 2.7182818284590452354; + public static final double E = 2.718281828459045; /** * The {@code double} value that is closer than any other to * pi, the ratio of the circumference of a circle to its * diameter. */ - public static final double PI = 3.14159265358979323846; + public static final double PI = 3.141592653589793; /** * Constant by which to multiply an angular value in degrees to obtain an diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index 53b25fedebb..b212ab592cb 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -92,14 +92,14 @@ public final class StrictMath { * The {@code double} value that is closer than any other to * e, the base of the natural logarithms. */ - public static final double E = 2.7182818284590452354; + public static final double E = 2.718281828459045; /** * The {@code double} value that is closer than any other to * pi, the ratio of the circumference of a circle to its * diameter. */ - public static final double PI = 3.14159265358979323846; + public static final double PI = 3.141592653589793; /** * Returns the trigonometric sine of an angle. Special cases: -- GitLab From 05a83e03ca35b4885b48bb0e7d188baf8f7d9d7f Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 15 Mar 2022 16:22:11 +0000 Subject: [PATCH 049/237] 8283124: Add constant for tau to Math and StrictMath Reviewed-by: bpb, iris --- src/java.base/share/classes/java/lang/Math.java | 17 +++++++++++++++-- .../share/classes/java/lang/StrictMath.java | 15 ++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 649a85cfc52..6d8fa48c976 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -135,11 +135,24 @@ public final class Math { /** * The {@code double} value that is closer than any other to - * pi, the ratio of the circumference of a circle to its - * diameter. + * pi (π), the ratio of the circumference of a circle to + * its diameter. */ public static final double PI = 3.141592653589793; + /** + * The {@code double} value that is closer than any other to + * tau (τ), the ratio of the circumference of a circle + * to its radius. + * + * @apiNote + * The value of pi is one half that of tau; in other + * words, tau is double pi . + * + * @since 19 + */ + public static final double TAU = 2.0 * PI; + /** * Constant by which to multiply an angular value in degrees to obtain an * angular value in radians. diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index b212ab592cb..b551288a38f 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -96,11 +96,24 @@ public final class StrictMath { /** * The {@code double} value that is closer than any other to - * pi, the ratio of the circumference of a circle to its + * pi (π), the ratio of the circumference of a circle to its * diameter. */ public static final double PI = 3.141592653589793; + /** + * The {@code double} value that is closer than any other to + * tau (τ), the ratio of the circumference of a circle + * to its radius. + * + * @apiNote + * The value of pi is one half that of tau; in other + * words, tau is double pi . + * + * @since 19 + */ + public static final double TAU = 2.0 * PI; + /** * Returns the trigonometric sine of an angle. Special cases: *

  • If the argument is NaN or an infinity, then the -- GitLab From 12dca36c73583d0ed2e1f684b056100dc1f2ef55 Mon Sep 17 00:00:00 2001 From: Tobias Hartmann Date: Tue, 15 Mar 2022 16:28:54 +0000 Subject: [PATCH 050/237] 8283189: Bad copyright header in UnsafeCopyMemory.java Reviewed-by: chagedorn, dcubed --- test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java b/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java index eb6f065305e..950fef40ec0 100644 --- a/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java +++ b/test/hotspot/jtreg/compiler/unsafe/UnsafeCopyMemory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, 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 -- GitLab From 32f8437d85a003914d5ca35bdddebdc732ab222d Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 15 Mar 2022 17:33:45 +0000 Subject: [PATCH 051/237] 8283075: Bad IllegalArgumentException message for out of range rank from ClassDesc.arrayType(int) Reviewed-by: vromero, alanb --- .../classes/java/lang/constant/ClassDesc.java | 26 ++++++++++++++----- .../jdk/java/lang/constant/ClassDescTest.java | 16 +++++++++++- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index 14923594c0e..c992bfb4380 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -148,7 +148,8 @@ public sealed interface ClassDesc * is described by this {@linkplain ClassDesc}. * * @return a {@linkplain ClassDesc} describing the array type - * @throws IllegalStateException if the resulting {@linkplain ClassDesc} would have an array rank of greater than 255 + * @throws IllegalStateException if the resulting {@linkplain + * ClassDesc} would have an array rank of greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */ default ClassDesc arrayType() { @@ -167,14 +168,27 @@ public sealed interface ClassDesc * * @param rank the rank of the array * @return a {@linkplain ClassDesc} describing the array type - * @throws IllegalArgumentException if the rank is less than or equal to zero or if the rank of the resulting array type is + * @throws IllegalArgumentException if the rank is less than or + * equal to zero or if the rank of the resulting array type is * greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */ default ClassDesc arrayType(int rank) { - int currentDepth = ConstantUtils.arrayDepth(descriptorString()); - if (rank <= 0 || currentDepth + rank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) - throw new IllegalArgumentException("rank: " + currentDepth + rank); + int netRank; + if (rank <= 0) { + throw new IllegalArgumentException("rank " + rank + " is not a positive value"); + } + try { + int currentDepth = ConstantUtils.arrayDepth(descriptorString()); + netRank = Math.addExact(currentDepth, rank); + if (netRank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) { + throw new IllegalArgumentException("rank: " + netRank + + " exceeds maximum supported dimension of " + + ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS); + } + } catch (ArithmeticException ae) { + throw new IllegalArgumentException("Integer overflow in rank computation"); + } return ClassDesc.ofDescriptor("[".repeat(rank) + descriptorString()); } diff --git a/test/jdk/java/lang/constant/ClassDescTest.java b/test/jdk/java/lang/constant/ClassDescTest.java index 32cf19b4fb4..81104e92c49 100644 --- a/test/jdk/java/lang/constant/ClassDescTest.java +++ b/test/jdk/java/lang/constant/ClassDescTest.java @@ -42,7 +42,7 @@ import static org.testng.Assert.fail; /** * @test - * @bug 8215510 + * @bug 8215510 8283075 * @compile ClassDescTest.java * @run testng ClassDescTest * @summary unit tests for java.lang.constant.ClassDesc @@ -184,6 +184,19 @@ public class ClassDescTest extends SymbolicDescTest { } } + private void testArrayRankOverflow() { + ClassDesc TwoDArrayDesc = + String.class.describeConstable().get().arrayType().arrayType(); + + try { + TwoDArrayDesc.arrayType(Integer.MAX_VALUE); + fail(""); + } catch (IllegalArgumentException iae) { + // Expected + } + } + + public void testArrayClassDesc() throws ReflectiveOperationException { for (String d : basicDescs) { ClassDesc a0 = ClassDesc.ofDescriptor(d); @@ -218,6 +231,7 @@ public class ClassDescTest extends SymbolicDescTest { testBadArrayRank(ConstantDescs.CD_int); testBadArrayRank(ConstantDescs.CD_String); testBadArrayRank(ClassDesc.of("Bar")); + testArrayRankOverflow(); } } -- GitLab From ac06bdb1239a97b7ea2fee8280da8ebc9728dc30 Mon Sep 17 00:00:00 2001 From: Man Cao Date: Tue, 15 Mar 2022 20:05:33 +0000 Subject: [PATCH 052/237] 8282507: Add a separate license file for hsdis Reviewed-by: ihse --- src/utils/hsdis/hsdis-license.txt | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/utils/hsdis/hsdis-license.txt diff --git a/src/utils/hsdis/hsdis-license.txt b/src/utils/hsdis/hsdis-license.txt new file mode 100644 index 00000000000..3c0b0823265 --- /dev/null +++ b/src/utils/hsdis/hsdis-license.txt @@ -0,0 +1,35 @@ +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to +any person obtaining a copy of this software, associated documentation +and/or data (collectively the "Software"), free of charge and under any +and all copyright rights in the Software, and any and all patent rights +owned or freely licensable by each licensor hereunder covering either (i) +the unmodified Software as contributed to or provided by such licensor, +or (ii) the Larger Works (as defined below), to deal in both + +(a) the Software, and + +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file +if one is included with the Software (each a "Larger Work" to which the +Software is contributed by such licensors), + +without restriction, including without limitation the rights to copy, +create derivative works of, display, perform, and distribute the Software +and make, use, sell, offer for sale, import, export, have made, and have +sold the Software and the Larger Work(s), and to sublicense the foregoing +rights on either these or other terms. + +This license is subject to the following condition: + +The above copyright notice and either this complete permission notice or +at a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. -- GitLab From 1465ea98b7736b5960a8b546ccc366c3e3260bdd Mon Sep 17 00:00:00 2001 From: Dean Long Date: Tue, 15 Mar 2022 20:17:36 +0000 Subject: [PATCH 053/237] 8282355: compiler/arguments/TestCodeEntryAlignment.java failed "guarantee(sect->end() <= tend) failed: sanity" Reviewed-by: jiefu, thartmann, shade --- src/hotspot/share/runtime/stubRoutines.cpp | 12 +++++++++--- .../compiler/arguments/TestCodeEntryAlignment.java | 8 ++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index 591950fa213..c378ab09dc8 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -215,7 +215,10 @@ void StubRoutines::initialize1() { if (_code1 == NULL) { ResourceMark rm; TraceTime timer("StubRoutines generation 1", TRACETIME_LOG(Info, startuptime)); - _code1 = BufferBlob::create("StubRoutines (1)", code_size1); + // Add extra space for large CodeEntryAlignment + int max_aligned_stubs = 10; + int size = code_size1 + CodeEntryAlignment * max_aligned_stubs; + _code1 = BufferBlob::create("StubRoutines (1)", size); if (_code1 == NULL) { vm_exit_out_of_memory(code_size1, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (1)"); } @@ -269,7 +272,10 @@ void StubRoutines::initialize2() { if (_code2 == NULL) { ResourceMark rm; TraceTime timer("StubRoutines generation 2", TRACETIME_LOG(Info, startuptime)); - _code2 = BufferBlob::create("StubRoutines (2)", code_size2); + // Add extra space for large CodeEntryAlignment + int max_aligned_stubs = 100; + int size = code_size2 + CodeEntryAlignment * max_aligned_stubs; + _code2 = BufferBlob::create("StubRoutines (2)", size); if (_code2 == NULL) { vm_exit_out_of_memory(code_size2, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (2)"); } diff --git a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java index fd6c8ca50bf..15a60382245 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * Copyright (c) 2022, 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 @@ -72,6 +73,13 @@ public class TestCodeEntryAlignment { "-XX:CodeEntryAlignment=" + align ); } + for (int align = 256; align <= 1024; align *= 2) { + shouldPass( + "-XX:+UnlockExperimentalVMOptions", + "-XX:CodeCacheSegmentSize=" + align, + "-XX:CodeEntryAlignment=" + align + ); + } } } -- GitLab From bacfaa3ee16882563200ef3b3df4441b33664451 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Wed, 16 Mar 2022 01:10:22 +0000 Subject: [PATCH 054/237] 8282414: x86: Enhance the assembler to generate more compact instructions Reviewed-by: thartmann, sviswanathan --- src/hotspot/cpu/x86/assembler_x86.cpp | 96 ++++++++++++++++++++++----- src/hotspot/cpu/x86/assembler_x86.hpp | 6 +- src/hotspot/cpu/x86/x86_64.ad | 2 +- 3 files changed, 81 insertions(+), 23 deletions(-) diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 03229421305..e287512b93c 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -300,12 +300,24 @@ void Assembler::emit_arith_b(int op1, int op2, Register dst, int imm8) { void Assembler::emit_arith(int op1, int op2, Register dst, int32_t imm32) { assert(isByte(op1) && isByte(op2), "wrong opcode"); - assert((op1 & 0x01) == 1, "should be 32bit operation"); - assert((op1 & 0x02) == 0, "sign-extension bit should not be set"); + assert(op1 == 0x81, "Unexpected opcode"); if (is8bit(imm32)) { emit_int24(op1 | 0x02, // set sign bit op2 | encode(dst), imm32 & 0xFF); + } else if (dst == rax) { + switch (op2) { + case 0xD0: emit_int8(0x15); break; // adc + case 0xC0: emit_int8(0x05); break; // add + case 0xE0: emit_int8(0x25); break; // and + case 0xF8: emit_int8(0x3D); break; // cmp + case 0xC8: emit_int8(0x0D); break; // or + case 0xD8: emit_int8(0x1D); break; // sbb + case 0xE8: emit_int8(0x2D); break; // sub + case 0xF0: emit_int8(0x35); break; // xor + default: ShouldNotReachHere(); + } + emit_int32(imm32); } else { emit_int16(op1, (op2 | encode(dst))); emit_int32(imm32); @@ -929,6 +941,16 @@ address Assembler::locate_operand(address inst, WhichOperand which) { tail_size = 1; break; + case 0x15: // adc rax, #32 + case 0x05: // add rax, #32 + case 0x25: // and rax, #32 + case 0x3D: // cmp rax, #32 + case 0x0D: // or rax, #32 + case 0x1D: // sbb rax, #32 + case 0x2D: // sub rax, #32 + case 0x35: // xor rax, #32 + return which == end_pc_operand ? ip + 4 : ip; + case 0x9B: switch (0xFF & *ip++) { case 0xD9: // fnstcw a @@ -954,6 +976,11 @@ address Assembler::locate_operand(address inst, WhichOperand which) { debug_only(has_disp32 = true); // has both kinds of operands! break; + case 0xA8: // testb rax, #8 + return which == end_pc_operand ? ip + 1 : ip; + case 0xA9: // testl/testq rax, #32 + return which == end_pc_operand ? ip + 4 : ip; + case 0xC1: // sal a, #8; sar a, #8; shl a, #8; shr a, #8 case 0xC6: // movb a, #8 case 0x80: // cmpb a, #8 @@ -1683,12 +1710,6 @@ void Assembler::cmpl(Address dst, int32_t imm32) { emit_int32(imm32); } -void Assembler::cmp(Register dst, int32_t imm32) { - prefix(dst); - emit_int8((unsigned char)0x3D); - emit_int32(imm32); -} - void Assembler::cmpl(Register dst, int32_t imm32) { prefix(dst); emit_arith(0x81, 0xF8, dst, imm32); @@ -5775,8 +5796,13 @@ void Assembler::subss(XMMRegister dst, Address src) { void Assembler::testb(Register dst, int imm8) { NOT_LP64(assert(dst->has_byte_register(), "must have byte register")); - (void) prefix_and_encode(dst->encoding(), true); - emit_arith_b(0xF6, 0xC0, dst, imm8); + if (dst == rax) { + emit_int8((unsigned char)0xA8); + emit_int8(imm8); + } else { + (void) prefix_and_encode(dst->encoding(), true); + emit_arith_b(0xF6, 0xC0, dst, imm8); + } } void Assembler::testb(Address dst, int imm8) { @@ -5787,14 +5813,34 @@ void Assembler::testb(Address dst, int imm8) { emit_int8(imm8); } +void Assembler::testl(Address dst, int32_t imm32) { + if (imm32 >= 0 && is8bit(imm32)) { + testb(dst, imm32); + return; + } + InstructionMark im(this); + emit_int8((unsigned char)0xF7); + emit_operand(as_Register(0), dst); + emit_int32(imm32); +} + void Assembler::testl(Register dst, int32_t imm32) { + if (imm32 >= 0 && is8bit(imm32) && dst->has_byte_register()) { + testb(dst, imm32); + return; + } // not using emit_arith because test // doesn't support sign-extension of // 8bit operands - int encode = dst->encoding(); - encode = prefix_and_encode(encode); - emit_int16((unsigned char)0xF7, (0xC0 | encode)); - emit_int32(imm32); + if (dst == rax) { + emit_int8((unsigned char)0xA9); + emit_int32(imm32); + } else { + int encode = dst->encoding(); + encode = prefix_and_encode(encode); + emit_int16((unsigned char)0xF7, (0xC0 | encode)); + emit_int32(imm32); + } } void Assembler::testl(Register dst, Register src) { @@ -13013,6 +13059,10 @@ void Assembler::subq(Register dst, Register src) { } void Assembler::testq(Address dst, int32_t imm32) { + if (imm32 >= 0) { + testl(dst, imm32); + return; + } InstructionMark im(this); emit_int16(get_prefixq(dst), (unsigned char)0xF7); emit_operand(as_Register(0), dst); @@ -13020,13 +13070,23 @@ void Assembler::testq(Address dst, int32_t imm32) { } void Assembler::testq(Register dst, int32_t imm32) { + if (imm32 >= 0) { + testl(dst, imm32); + return; + } // not using emit_arith because test // doesn't support sign-extension of // 8bit operands - int encode = dst->encoding(); - encode = prefixq_and_encode(encode); - emit_int16((unsigned char)0xF7, (0xC0 | encode)); - emit_int32(imm32); + if (dst == rax) { + prefix(REX_W); + emit_int8((unsigned char)0xA9); + emit_int32(imm32); + } else { + int encode = dst->encoding(); + encode = prefixq_and_encode(encode); + emit_int16((unsigned char)0xF7, (0xC0 | encode)); + emit_int32(imm32); + } } void Assembler::testq(Register dst, Register src) { diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 3256b990cf7..7141e4b96c4 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -1081,15 +1081,12 @@ private: void cmpb(Address dst, int imm8); void cmpl(Address dst, int32_t imm32); - - void cmp(Register dst, int32_t imm32); void cmpl(Register dst, int32_t imm32); void cmpl(Register dst, Register src); void cmpl(Register dst, Address src); void cmpq(Address dst, int32_t imm32); void cmpq(Address dst, Register src); - void cmpq(Register dst, int32_t imm32); void cmpq(Register dst, Register src); void cmpq(Register dst, Address src); @@ -2099,9 +2096,10 @@ private: void subss(XMMRegister dst, Address src); void subss(XMMRegister dst, XMMRegister src); - void testb(Register dst, int imm8); void testb(Address dst, int imm8); + void testb(Register dst, int imm8); + void testl(Address dst, int32_t imm32); void testl(Register dst, int32_t imm32); void testl(Register dst, Register src); void testl(Register dst, Address src); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index fbf71300dcd..bc04106f3f2 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -1926,7 +1926,7 @@ encode %{ Label done; // cmp $0x80000000,%eax - __ cmp(as_Register(RAX_enc), 0x80000000); + __ cmpl(as_Register(RAX_enc), 0x80000000); // jne e __ jccb(Assembler::notEqual, normal); -- GitLab From 27fe3d7f8db4ede6441a7cc325d9f29eb4a1d10d Mon Sep 17 00:00:00 2001 From: Toshio Nakamura Date: Wed, 16 Mar 2022 01:11:40 +0000 Subject: [PATCH 055/237] 8240756: [macos] SwingSet2:TableDemo:Printed Japanese characters were garbled Reviewed-by: prr, serb --- .../classes/sun/lwawt/macosx/CTextPipe.java | 80 ++++++++++- .../font/GlyphVector/MultiSlotFontTest.java | 136 ++++++++++++++++++ 2 files changed, 212 insertions(+), 4 deletions(-) create mode 100644 test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java index f4dcc7ec675..6aa36453ac0 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTextPipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, 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 @@ -81,10 +81,57 @@ public class CTextPipe implements TextPipe { } } - public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { - final Font prevFont = sg2d.getFont(); - sg2d.setFont(gV.getFont()); + private boolean hasSlotData(GlyphVector gv) { + final int length = gv.getNumGlyphs(); + for (int i = 0; i < length; i++) { + if ((gv.getGlyphCode(i) & CompositeGlyphMapper.SLOTMASK) != 0) { + return true; + } + } + return false; + } + + private Font getSlotFont(Font font, int slot) { + Font2D f2d = FontUtilities.getFont2D(font); + if (f2d instanceof CFont) { + CompositeFont cf = ((CFont)f2d).getCompositeFont2D(); + PhysicalFont pf = cf.getSlotFont(slot); + Font f = new Font(pf.getFontName(null), + font.getStyle(), font.getSize()); + return f; + } + return null; + } + + private GlyphVector getGlyphVectorWithRange(final Font font, final GlyphVector gV, int start, int count) { + int[] glyphs = new int[count]; + for (int i = 0; i < count; i++) { + glyphs[i] = gV.getGlyphCode(start+i) & CompositeGlyphMapper.GLYPHMASK; + } + // Positions should be null to recalculate by native methods, + // if GV was segmented. + StandardGlyphVector sgv = new StandardGlyphVector(font, + gV.getFontRenderContext(), + glyphs, + null, // positions + null, // indices + gV.getLayoutFlags()); + return sgv; + } + + private int getLengthOfSameSlot(final GlyphVector gV, final int targetSlot, final int start, final int length) { + int count = 1; + for (; start + count < length; count++) { + int slot = (gV.getGlyphCode(start + count) & + CompositeGlyphMapper.SLOTMASK) >> 24; + if (targetSlot != slot) { + break; + } + } + return count; + } + private void drawGlyphVectorImpl(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { final long nativeStrikePtr = getNativeStrikePtr(sg2d); if (OSXSurfaceData.IsSimpleColor(sg2d.paint) && nativeStrikePtr != 0) { final OSXSurfaceData surfaceData = (OSXSurfaceData)sg2d.getSurfaceData(); @@ -92,6 +139,31 @@ public class CTextPipe implements TextPipe { } else { drawGlyphVectorAsShape(sg2d, gV, x, y); } + } + + public void drawGlyphVector(final SunGraphics2D sg2d, final GlyphVector gV, final float x, final float y) { + final Font prevFont = sg2d.getFont(); + sg2d.setFont(gV.getFont()); + + if (hasSlotData(gV)) { + final int length = gV.getNumGlyphs(); + float[] positions = gV.getGlyphPositions(0, length, null); + int start = 0; + while (start < length) { + int slot = (gV.getGlyphCode(start) & + CompositeGlyphMapper.SLOTMASK) >> 24; + sg2d.setFont(getSlotFont(gV.getFont(), slot)); + int count = getLengthOfSameSlot(gV, slot, start, length); + GlyphVector rangeGV = getGlyphVectorWithRange(sg2d.getFont(), + gV, start, count); + drawGlyphVectorImpl(sg2d, rangeGV, + x + positions[start * 2], + y + positions[start * 2 + 1]); + start += count; + } + } else { + drawGlyphVectorImpl(sg2d, gV, x, y); + } sg2d.setFont(prevFont); } diff --git a/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java b/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java new file mode 100644 index 00000000000..65acd420345 --- /dev/null +++ b/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2022, 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 8240756 + * @summary Non-English characters are printed with wrong glyphs on MacOS + * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops java.desktop/sun.font + * @requires os.family == "mac" + * @run main MultiSlotFontTest + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.image.BufferedImage; +import sun.font.StandardGlyphVector; +import sun.java2d.OSXOffScreenSurfaceData; +import sun.java2d.SunGraphics2D; +import sun.java2d.SurfaceData; +import sun.java2d.loops.SurfaceType; + +public class MultiSlotFontTest { + + private static final int WIDTH = 100; + private static final int HEIGHT = 60; + + private static final String TEST_STR = "\u3042\u3044\u3046\u3048\u304Aabc"; + private static final int EXPECTED_HEIGHT = 10; + private static final int EXPECTED_WIDTH = 77; + private static final int LIMIT_DIFF_HEIGHT = 3; + private static final int LIMIT_DIFF_WIDTH = 15; + + public static void main(String[] args) throws Exception { + MultiSlotFontTest test = new MultiSlotFontTest(); + } + + public MultiSlotFontTest() { + BufferedImage img = createImage(); + + SurfaceData sd = OSXOffScreenSurfaceData.createDataIC(img, + SurfaceType.IntRgb); + SunGraphics2D g2d = new SunGraphics2D(sd, + Color.BLACK, Color.WHITE, null); + Font font = g2d.getFont(); + + if (font.canDisplayUpTo(TEST_STR) != -1) { + System.out.println("There is no capable font. Skipping the test."); + System.out.println("Font: " + font); + return; + } + + FontRenderContext frc = new FontRenderContext(null, false, false); + StandardGlyphVector gv = new StandardGlyphVector(font, TEST_STR, frc); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.drawGlyphVector(gv, 0.0f, (float)(HEIGHT - 5)); + g2d.dispose(); + + Dimension d = getBounds(img); + + if (Math.abs(d.height - EXPECTED_HEIGHT) > LIMIT_DIFF_HEIGHT || + Math.abs(d.width - EXPECTED_WIDTH) > LIMIT_DIFF_WIDTH) { + debugOut(img); + throw new RuntimeException( + "Incorrect GlyphVector shape " + d + "," + gv); + } + } + + private static BufferedImage createImage() { + BufferedImage image = new BufferedImage(WIDTH, HEIGHT, + BufferedImage.TYPE_INT_RGB); + Graphics g = image.createGraphics(); + g.setColor(Color.WHITE); + g.fillRect(0, 0, WIDTH, HEIGHT); + g.dispose(); + return image; + } + + private Dimension getBounds(BufferedImage img) { + int top = HEIGHT; + int left = WIDTH; + int right = 0; + int bottom = 0; + for (int y = 0; y < HEIGHT; y++) { + for (int x = 0; x < WIDTH; x++) { + if ((img.getRGB(x, y) & 0xFFFFFF) == 0) { + if (top > y) top = y; + if (bottom < y) bottom = y; + if (left > x) left = x; + if (right < x) right = x; + } + } + } + return new Dimension(right - left, bottom - top); + } + + private void debugOut(BufferedImage img) { + for (int y = 0; y < HEIGHT; y++) { + for (int x = 0; x < WIDTH; x++) { + int c = img.getRGB(x, y) & 0xFFFFFF; + if (c == 0) { + System.out.print("*"); + } else { + System.out.print(" "); + } + } + System.out.println(); + } + } +} -- GitLab From 4df24c5df38eeacc73097f71383916e9a0933839 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 16 Mar 2022 02:02:10 +0000 Subject: [PATCH 056/237] 8283230: Improve @jls usage in ElementType Reviewed-by: jjg, iris --- .../share/classes/java/lang/annotation/ElementType.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/annotation/ElementType.java b/src/java.base/share/classes/java/lang/annotation/ElementType.java index c046272b12c..97275fb97ec 100644 --- a/src/java.base/share/classes/java/lang/annotation/ElementType.java +++ b/src/java.base/share/classes/java/lang/annotation/ElementType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -40,14 +40,14 @@ package java.lang.annotation; *

    The constants {@link #ANNOTATION_TYPE}, {@link #CONSTRUCTOR}, {@link * #FIELD}, {@link #LOCAL_VARIABLE}, {@link #METHOD}, {@link #PACKAGE}, {@link * #MODULE}, {@link #PARAMETER}, {@link #TYPE}, and {@link #TYPE_PARAMETER} - * correspond to the declaration contexts in JLS 9.6.4.1. + * correspond to the declaration contexts in JLS {@jls 9.6.4.1}. * *

    For example, an annotation whose interface is meta-annotated with * {@code @Target(ElementType.FIELD)} may only be written as a modifier for a * field declaration. * *

    The constant {@link #TYPE_USE} corresponds to the type contexts in JLS - * 4.11, as well as to two declaration contexts: class and interface + * {@jls 4.11}, as well as to two declaration contexts: class and interface * declarations (including annotation declarations) and type parameter * declarations. * -- GitLab From de4f04cb71a26ce03b96460cb8d1c1e28cd1ed38 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Wed, 16 Mar 2022 03:12:48 +0000 Subject: [PATCH 057/237] 8253495: CDS generates non-deterministic output Reviewed-by: erikj, kbarrett, ccheung, ihse --- make/scripts/compare.sh | 4 ++-- src/hotspot/share/cds/archiveBuilder.cpp | 5 +++-- src/hotspot/share/cds/archiveUtils.hpp | 5 +++-- src/hotspot/share/cds/dumpTimeClassInfo.hpp | 5 +++-- src/hotspot/share/cds/heapShared.cpp | 8 ++++---- src/hotspot/share/cds/heapShared.hpp | 8 ++------ src/hotspot/share/gc/shared/collectedHeap.cpp | 18 +++++++++++++---- src/hotspot/share/gc/shared/collectedHeap.hpp | 1 + src/hotspot/share/prims/jvm.cpp | 20 +++++++++++++++++++ src/hotspot/share/runtime/os.cpp | 10 ++++++++-- test/hotspot/jtreg/ProblemList.txt | 1 - .../jtreg/runtime/cds/DeterministicDump.java | 10 +++++++++- .../cds/appcds/javaldr/LockDuringDump.java | 4 ++-- .../appcds/javaldr/LockDuringDumpAgent.java | 16 +++++++++++++-- test/lib/jdk/test/lib/cds/CDSOptions.java | 7 ++++++- 15 files changed, 91 insertions(+), 31 deletions(-) diff --git a/make/scripts/compare.sh b/make/scripts/compare.sh index cc05476c997..a0006fa4cee 100644 --- a/make/scripts/compare.sh +++ b/make/scripts/compare.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2022, 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 @@ -324,7 +324,7 @@ compare_general_files() { ! -name "*.cpl" ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \ ! -name "*.lib" ! -name "*.jmod" ! -name "*.exe" \ ! -name "*.obj" ! -name "*.o" ! -name "jspawnhelper" ! -name "*.a" \ - ! -name "*.tar.gz" ! -name "*.jsa" ! -name "gtestLauncher" \ + ! -name "*.tar.gz" ! -name "classes_nocoops.jsa" ! -name "gtestLauncher" \ ! -name "*.map" \ | $GREP -v "./bin/" | $SORT | $FILTER) diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index cb5c0aeb8c7..89529b2cf59 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -522,7 +522,8 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref if (MetaspaceShared::is_in_shared_metaspace(obj)) { // Don't dump existing shared metadata again. return point_to_it; - } else if (ref->msotype() == MetaspaceObj::MethodDataType) { + } else if (ref->msotype() == MetaspaceObj::MethodDataType || + ref->msotype() == MetaspaceObj::MethodCountersType) { return set_to_null; } else { if (ref->msotype() == MetaspaceObj::ClassType) { diff --git a/src/hotspot/share/cds/archiveUtils.hpp b/src/hotspot/share/cds/archiveUtils.hpp index 588ad1b6da9..be8d8a0e84e 100644 --- a/src/hotspot/share/cds/archiveUtils.hpp +++ b/src/hotspot/share/cds/archiveUtils.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -30,6 +30,7 @@ #include "memory/virtualspace.hpp" #include "utilities/bitMap.hpp" #include "utilities/exceptions.hpp" +#include "utilities/macros.hpp" class BootstrapInfo; class ReservedSpace; @@ -147,7 +148,7 @@ public: char* expand_top_to(char* newtop); char* allocate(size_t num_bytes); - void append_intptr_t(intptr_t n, bool need_to_mark = false); + void append_intptr_t(intptr_t n, bool need_to_mark = false) NOT_CDS_RETURN; char* base() const { return _base; } char* top() const { return _top; } diff --git a/src/hotspot/share/cds/dumpTimeClassInfo.hpp b/src/hotspot/share/cds/dumpTimeClassInfo.hpp index 80f6d81442c..5b4f5cd9b9b 100644 --- a/src/hotspot/share/cds/dumpTimeClassInfo.hpp +++ b/src/hotspot/share/cds/dumpTimeClassInfo.hpp @@ -167,7 +167,8 @@ public: size_t runtime_info_bytesize() const; }; -inline unsigned DumpTimeSharedClassTable_hash(InstanceKlass* const& k) { +template +inline unsigned DumpTimeSharedClassTable_hash(T* const& k) { if (DumpSharedSpaces) { // Deterministic archive contents uintx delta = k->name() - MetaspaceShared::symbol_rs_base(); @@ -175,7 +176,7 @@ inline unsigned DumpTimeSharedClassTable_hash(InstanceKlass* const& k) { } else { // Deterministic archive is not possible because classes can be loaded // in multiple threads. - return primitive_hash(k); + return primitive_hash(k); } } diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 26a852b0158..14bca5d74b6 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -574,7 +574,7 @@ KlassSubGraphInfo* HeapShared::init_subgraph_info(Klass* k, bool is_full_module_ bool created; Klass* relocated_k = ArchiveBuilder::get_relocated_klass(k); KlassSubGraphInfo* info = - _dump_time_subgraph_info_table->put_if_absent(relocated_k, KlassSubGraphInfo(relocated_k, is_full_module_graph), + _dump_time_subgraph_info_table->put_if_absent(k, KlassSubGraphInfo(relocated_k, is_full_module_graph), &created); assert(created, "must not initialize twice"); return info; @@ -582,8 +582,7 @@ KlassSubGraphInfo* HeapShared::init_subgraph_info(Klass* k, bool is_full_module_ KlassSubGraphInfo* HeapShared::get_subgraph_info(Klass* k) { assert(DumpSharedSpaces, "dump time only"); - Klass* relocated_k = ArchiveBuilder::get_relocated_klass(k); - KlassSubGraphInfo* info = _dump_time_subgraph_info_table->get(relocated_k); + KlassSubGraphInfo* info = _dump_time_subgraph_info_table->get(k); assert(info != NULL, "must have been initialized"); return info; } @@ -744,7 +743,8 @@ struct CopyKlassSubGraphInfoToArchive : StackObj { (ArchivedKlassSubGraphInfoRecord*)ArchiveBuilder::ro_region_alloc(sizeof(ArchivedKlassSubGraphInfoRecord)); record->init(&info); - unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary((address)klass); + Klass* relocated_k = ArchiveBuilder::get_relocated_klass(klass); + unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary((address)relocated_k); u4 delta = ArchiveBuilder::current()->any_to_offset_u4(record); _writer->add(hash, delta); } diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 74d1f1b6e7e..d8fc71fc76e 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_CDS_HEAPSHARED_HPP #define SHARE_CDS_HEAPSHARED_HPP +#include "cds/dumpTimeClassInfo.hpp" #include "cds/metaspaceShared.hpp" #include "classfile/compactHashtable.hpp" #include "classfile/javaClasses.hpp" @@ -252,17 +253,12 @@ private: HeapShared::oop_hash> ArchivedObjectCache; static ArchivedObjectCache* _archived_object_cache; - static unsigned klass_hash(Klass* const& klass) { - // Generate deterministic hashcode even if SharedBaseAddress is changed due to ASLR. - return primitive_hash

    (address(klass) - SharedBaseAddress); - } - class DumpTimeKlassSubGraphInfoTable : public ResourceHashtable { + DumpTimeSharedClassTable_hash> { public: int _count; }; diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index f9ad0759b42..eb3213d12df 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -417,6 +417,11 @@ size_t CollectedHeap::filler_array_min_size() { return align_object_size(filler_array_hdr_size()); // align to MinObjAlignment } +void CollectedHeap::zap_filler_array_with(HeapWord* start, size_t words, juint value) { + Copy::fill_to_words(start + filler_array_hdr_size(), + words - filler_array_hdr_size(), value); +} + #ifdef ASSERT void CollectedHeap::fill_args_check(HeapWord* start, size_t words) { @@ -427,8 +432,7 @@ void CollectedHeap::fill_args_check(HeapWord* start, size_t words) void CollectedHeap::zap_filler_array(HeapWord* start, size_t words, bool zap) { if (ZapFillerObjects && zap) { - Copy::fill_to_words(start + filler_array_hdr_size(), - words - filler_array_hdr_size(), 0XDEAFBABE); + zap_filler_array_with(start, words, 0XDEAFBABE); } } #endif // ASSERT @@ -445,7 +449,13 @@ CollectedHeap::fill_with_array(HeapWord* start, size_t words, bool zap) ObjArrayAllocator allocator(Universe::intArrayKlassObj(), words, (int)len, /* do_zero */ false); allocator.initialize(start); - DEBUG_ONLY(zap_filler_array(start, words, zap);) + if (DumpSharedSpaces) { + // This array is written into the CDS archive. Make sure it + // has deterministic contents. + zap_filler_array_with(start, words, 0); + } else { + DEBUG_ONLY(zap_filler_array(start, words, zap);) + } } void diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index 89cca6777d6..fd6427fee60 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -157,6 +157,7 @@ class CollectedHeap : public CHeapObj { static inline size_t filler_array_hdr_size(); static inline size_t filler_array_min_size(); + static inline void zap_filler_array_with(HeapWord* start, size_t words, juint value); DEBUG_ONLY(static void fill_args_check(HeapWord* start, size_t words);) DEBUG_ONLY(static void zap_filler_array(HeapWord* start, size_t words, bool zap = true);) diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index f18fe51616c..c574cb3ecc8 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -2865,6 +2865,26 @@ static void thread_entry(JavaThread* thread, TRAPS) { JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) +#if INCLUDE_CDS + if (DumpSharedSpaces) { + // During java -Xshare:dump, if we allow multiple Java threads to + // execute in parallel, symbols and classes may be loaded in + // random orders which will make the resulting CDS archive + // non-deterministic. + // + // Lucikly, during java -Xshare:dump, it's important to run only + // the code in the main Java thread (which is NOT started here) that + // creates the module graph, etc. It's safe to not start the other + // threads which are launched by class static initializers + // (ReferenceHandler, FinalizerThread and CleanerImpl). + if (log_is_enabled(Info, cds)) { + ResourceMark rm; + oop t = JNIHandles::resolve_non_null(jthread); + log_info(cds)("JVM_StartThread() ignored: %s", t->klass()->external_name()); + } + return; + } +#endif JavaThread *native_thread = NULL; // We cannot hold the Threads_lock when we throw an exception, diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index e8165fe7ff3..6e2ee7654ea 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -634,6 +634,8 @@ void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { // Special handling for NMT preinit phase before arguments are parsed void* rc = NULL; if (NMTPreInit::handle_malloc(&rc, size)) { + // No need to fill with 0 because DumpSharedSpaces doesn't use these + // early allocations. return rc; } @@ -658,9 +660,13 @@ void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { void* const inner_ptr = MemTracker::record_malloc((address)outer_ptr, size, memflags, stack); - DEBUG_ONLY(::memset(inner_ptr, uninitBlockPad, size);) + if (DumpSharedSpaces) { + // Need to deterministically fill all the alignment gaps in C++ structures. + ::memset(inner_ptr, 0, size); + } else { + DEBUG_ONLY(::memset(inner_ptr, uninitBlockPad, size);) + } DEBUG_ONLY(break_if_ptr_caught(inner_ptr);) - return inner_ptr; } diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 518238d9c0a..870f1d3c596 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -94,7 +94,6 @@ gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8241293 macosx-x64 # :hotspot_runtime runtime/cds/appcds/jigsaw/modulepath/ModulePathAndCP_JFR.java 8253437 windows-x64 -runtime/cds/DeterministicDump.java 8253495 generic-all runtime/jni/terminatedThread/TestTerminatedThread.java 8219652 aix-ppc64 runtime/os/TestTracePageSizes.java#no-options 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#explicit-large-page-size 8267460 linux-aarch64 diff --git a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java index 9cdba1fa922..6e8ccffce27 100644 --- a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java +++ b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -54,6 +54,11 @@ public class DeterministicDump { baseArgs.add("-Xmx128M"); if (Platform.is64bit()) { + if (!compressed) { + System.out.println("CDS archives with uncompressed oops are still non-deterministic"); + System.out.println("See https://bugs.openjdk.java.net/browse/JDK-8282828"); + return; + } // These options are available only on 64-bit. String sign = (compressed) ? "+" : "-"; baseArgs.add("-XX:" + sign + "UseCompressedOops"); @@ -78,9 +83,12 @@ public class DeterministicDump { static String dump(ArrayList args, String... more) throws Exception { String logName = "SharedArchiveFile" + (id++); String archiveName = logName + ".jsa"; + String mapName = logName + ".map"; CDSOptions opts = (new CDSOptions()) .addPrefix("-Xlog:cds=debug") + .addPrefix("-Xlog:cds+map=trace:file=" + mapName + ":none:filesize=0") .setArchiveName(archiveName) + .addSuffix(args) .addSuffix(more); CDSTestUtils.createArchiveAndCheck(opts); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDump.java b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDump.java index 04652d2eb78..391596160d6 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDump.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDump.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -68,7 +68,7 @@ public class LockDuringDump { TestCommon.testDump(appJar, TestCommon.list(LockDuringDumpApp.class.getName()), "-XX:+UnlockDiagnosticVMOptions", agentArg, agentArg2); - if (i != 0) { + if (i != 0 && !out.getStdout().contains("LockDuringDumpAgent timeout")) { out.shouldContain("Let's hold the lock on the literal string"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDumpAgent.java b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDumpAgent.java index 5e053d83efc..57db61e9335 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDumpAgent.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/LockDuringDumpAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -51,9 +51,21 @@ public class LockDuringDumpAgent implements Runnable { static void waitForThreadStart() { try { + long started = System.currentTimeMillis(); + long timeout = 10000; + synchronized (LITERAL) { + Thread.sleep(1); + } synchronized (lock) { while (!threadStarted) { - lock.wait(); + lock.wait(timeout); + long elapsed = System.currentTimeMillis() - started; + if (elapsed >= timeout) { + System.out.println("This JVM may decide to not launch any Java threads during -Xshare:dump."); + System.out.println("This is OK because no string objects could be in a locked state during heap dump."); + System.out.println("LockDuringDumpAgent timeout after " + elapsed + " ms"); + return; + } } System.out.println("Thread has started"); } diff --git a/test/lib/jdk/test/lib/cds/CDSOptions.java b/test/lib/jdk/test/lib/cds/CDSOptions.java index cbc11db777b..a60afb90aed 100644 --- a/test/lib/jdk/test/lib/cds/CDSOptions.java +++ b/test/lib/jdk/test/lib/cds/CDSOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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 @@ -56,6 +56,11 @@ public class CDSOptions { return this; } + public CDSOptions addSuffix(ArrayList suffix) { + for (String s : suffix) this.suffix.add(s); + return this; + } + public CDSOptions addSuffix(String... suffix) { for (String s : suffix) this.suffix.add(s); return this; -- GitLab From 08cadb4754da0d5e68ee2df45f4098d203d14115 Mon Sep 17 00:00:00 2001 From: Swati Sharma Date: Wed, 16 Mar 2022 09:48:09 +0000 Subject: [PATCH 058/237] 8271195: Use largest available large page size smaller than LargePageSizeInBytes when available Co-authored-by: Jatin Bhateja Reviewed-by: ayang, tschatzl --- src/hotspot/os/linux/os_linux.cpp | 21 ++----- src/hotspot/share/memory/virtualspace.cpp | 34 +++++++--- .../openjdk/bench/vm/gc/MicroLargePages.java | 62 +++++++++++++++++++ 3 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 33acc06df53..f2ecca92c82 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -3972,23 +3972,14 @@ char* os::Linux::reserve_memory_special_shm(size_t bytes, size_t alignment, return addr; } -static void warn_on_commit_special_failure(char* req_addr, size_t bytes, +static void log_on_commit_special_failure(char* req_addr, size_t bytes, size_t page_size, int error) { assert(error == ENOMEM, "Only expect to fail if no memory is available"); - bool warn_on_failure = UseLargePages && - (!FLAG_IS_DEFAULT(UseLargePages) || - !FLAG_IS_DEFAULT(UseHugeTLBFS) || - !FLAG_IS_DEFAULT(LargePageSizeInBytes)); - - if (warn_on_failure) { - char msg[128]; - jio_snprintf(msg, sizeof(msg), "Failed to reserve and commit memory. req_addr: " - PTR_FORMAT " bytes: " SIZE_FORMAT " page size: " - SIZE_FORMAT " (errno = %d).", - req_addr, bytes, page_size, error); - warning("%s", msg); - } + log_info(pagesize)("Failed to reserve and commit memory with given page size. req_addr: " PTR_FORMAT + " size: " SIZE_FORMAT "%s, page size: " SIZE_FORMAT "%s, (errno = %d)", + p2i(req_addr), byte_size_in_exact_unit(bytes), exact_unit_for_byte_size(bytes), + byte_size_in_exact_unit(page_size), exact_unit_for_byte_size(page_size), error); } bool os::Linux::commit_memory_special(size_t bytes, @@ -4010,7 +4001,7 @@ bool os::Linux::commit_memory_special(size_t bytes, char* addr = (char*)::mmap(req_addr, bytes, prot, flags, -1, 0); if (addr == MAP_FAILED) { - warn_on_commit_special_failure(req_addr, bytes, page_size, errno); + log_on_commit_special_failure(req_addr, bytes, page_size, errno); return false; } diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index ad918dea29b..b02d723baab 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -139,6 +139,19 @@ static bool large_pages_requested() { (!FLAG_IS_DEFAULT(UseLargePages) || !FLAG_IS_DEFAULT(LargePageSizeInBytes)); } +static void log_on_large_pages_failure(char* req_addr, size_t bytes) { + if (large_pages_requested()) { + // Compressed oops logging. + log_debug(gc, heap, coops)("Reserve regular memory without large pages"); + // JVM style warning that we did not succeed in using large pages. + char msg[128]; + jio_snprintf(msg, sizeof(msg), "Failed to reserve and commit memory using large pages. " + "req_addr: " PTR_FORMAT " bytes: " SIZE_FORMAT, + req_addr, bytes); + warning("%s", msg); + } +} + static char* reserve_memory(char* requested_address, const size_t size, const size_t alignment, int fd, bool exec) { char* base; @@ -183,10 +196,6 @@ static char* reserve_memory_special(char* requested_address, const size_t size, "reserve_memory_special() returned an unaligned address, base: " PTR_FORMAT " alignment: " SIZE_FORMAT_HEX, p2i(base), alignment); - } else { - if (large_pages_requested()) { - log_debug(gc, heap, coops)("Reserve regular memory without large pages"); - } } return base; } @@ -235,14 +244,25 @@ void ReservedSpace::reserve(size_t size, // the caller requested large pages. To satisfy this request we use // explicit large pages and these have to be committed up front to ensure // no reservations are lost. + size_t used_page_size = page_size; + char* base = NULL; + + do { + base = reserve_memory_special(requested_address, size, alignment, used_page_size, executable); + if (base != NULL) { + break; + } + used_page_size = os::page_sizes().next_smaller(used_page_size); + } while (used_page_size > (size_t) os::vm_page_size()); - char* base = reserve_memory_special(requested_address, size, alignment, page_size, executable); if (base != NULL) { // Successful reservation using large pages. - initialize_members(base, size, alignment, page_size, true, executable); + initialize_members(base, size, alignment, used_page_size, true, executable); return; } - // Failed to reserve explicit large pages, fall back to normal reservation. + // Failed to reserve explicit large pages, do proper logging. + log_on_large_pages_failure(requested_address, size); + // Now fall back to normal reservation. page_size = os::vm_page_size(); } diff --git a/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java b/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java new file mode 100644 index 00000000000..67702cfe607 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/gc/MicroLargePages.java @@ -0,0 +1,62 @@ +// +// Copyright (c) 2022, 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. +// + +package org.openjdk.bench.vm.gc; + +import java.util.Arrays; +import java.util.concurrent.TimeUnit; +import org.openjdk.jmh.annotations.*; + +@OutputTimeUnit(TimeUnit.MINUTES) +@State(Scope.Thread) +@Fork(jvmArgsAppend = {"-Xmx256m", "-XX:+UseLargePages", "-XX:LargePageSizeInBytes=1g", "-Xlog:pagesize"}, value = 5) + +public class MicroLargePages { + + @Param({"2097152"}) + public int ARRAYSIZE; + + @Param({"1", "2", "4"}) + public int NUM; + + public long[][] INP; + public long[][] OUT; + + @Setup(Level.Trial) + public void BmSetup() { + INP = new long[NUM][ARRAYSIZE]; + OUT = new long[NUM][ARRAYSIZE]; + for (int i = 0; i < NUM; i++) { + Arrays.fill(INP[i], 10); + } + } + + @Benchmark + public void micro_HOP_DIST_4KB() { + for (int i = 0; i < NUM; i += 1) { + for (int j = 0; j < ARRAYSIZE; j += 512) { + OUT[i][j] = INP[i][j]; + } + } + } +} -- GitLab From 9b8afce3791080d664c5051a86592706f5b0ade0 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Wed, 16 Mar 2022 16:07:32 +0000 Subject: [PATCH 059/237] 8283260: gcc is not supported on mac Reviewed-by: erikj --- make/autoconf/flags-ldflags.m4 | 13 +++++-------- make/autoconf/toolchain.m4 | 6 +++--- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index e9d4557f866..8f77734c93c 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -95,13 +95,10 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], fi # Setup OS-dependent LDFLAGS - if test "x$TOOLCHAIN_TYPE" = xclang || test "x$TOOLCHAIN_TYPE" = xgcc; then - if test "x$OPENJDK_TARGET_OS" = xmacosx; then - # Assume clang or gcc. - # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead. - OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." - OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN" - fi + if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$TOOLCHAIN_TYPE" = xclang; then + # FIXME: We should really generalize SET_SHARED_LIBRARY_ORIGIN instead. + OS_LDFLAGS_JVM_ONLY="-Wl,-rpath,@loader_path/. -Wl,-rpath,@loader_path/.." + OS_LDFLAGS="-mmacosx-version-min=$MACOSX_VERSION_MIN" fi # Setup debug level-dependent LDFLAGS diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 2288dda7ed6..b79d161331d 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -39,7 +39,7 @@ VALID_TOOLCHAINS_all="gcc clang xlc microsoft" # These toolchains are valid on different platforms VALID_TOOLCHAINS_linux="gcc clang" -VALID_TOOLCHAINS_macosx="gcc clang" +VALID_TOOLCHAINS_macosx="clang" VALID_TOOLCHAINS_aix="xlc" VALID_TOOLCHAINS_windows="microsoft" @@ -901,8 +901,8 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS], BUILD_LDCXX="$BUILD_LD" else if test "x$OPENJDK_BUILD_OS" = xmacosx; then - UTIL_REQUIRE_PROGS(BUILD_CC, clang cc gcc) - UTIL_REQUIRE_PROGS(BUILD_CXX, clang++ CC g++) + UTIL_REQUIRE_PROGS(BUILD_CC, clang) + UTIL_REQUIRE_PROGS(BUILD_CXX, clang++) else UTIL_REQUIRE_PROGS(BUILD_CC, cc gcc) UTIL_REQUIRE_PROGS(BUILD_CXX, CC g++) -- GitLab From 0cf291bc31acf69c767c5d39d21b1195e6d761b2 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Wed, 16 Mar 2022 16:17:50 +0000 Subject: [PATCH 060/237] 8283234: Improve @jls usage in java.base Reviewed-by: iris --- .../classes/java/lang/StringConcatHelper.java | 4 ++-- .../classes/java/lang/invoke/MethodHandle.java | 8 ++++---- .../classes/java/lang/invoke/MethodHandles.java | 10 +++++----- .../java/lang/invoke/StringConcatFactory.java | 14 +++++++------- .../classes/java/lang/reflect/TypeVariable.java | 6 +++--- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index f267fd9e1d6..3867c10e8d6 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -430,7 +430,7 @@ final class StringConcatHelper { * Produce a String from a concatenation of single argument, which we * end up using for trivial concatenations like {@code "" + arg}. * - * This will always create a new Object to comply with JLS 15.18.1: + * This will always create a new Object to comply with JLS {@jls 15.18.1}: * "The String object is newly created unless the expression is a * compile-time constant expression". * diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index ec910dbf8fe..fb7ef0afbac 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -807,15 +807,15 @@ public abstract class MethodHandle implements Constable { * (The types do not need to be related in any particular way. * This is because a dynamic value of null can convert to any reference type.) *
  • If T0 and T1 are primitives, then a Java method invocation - * conversion (JLS 5.3) is applied, if one exists. + * conversion (JLS {@jls 5.3}) is applied, if one exists. * (Specifically, T0 must convert to T1 by a widening primitive conversion.) *
  • If T0 is a primitive and T1 a reference, - * a Java casting conversion (JLS 5.5) is applied if one exists. + * a Java casting conversion (JLS {@jls 5.5}) is applied if one exists. * (Specifically, the value is boxed from T0 to its wrapper class, * which is then widened as needed to T1.) *
  • If T0 is a reference and T1 a primitive, an unboxing * conversion will be applied at runtime, possibly followed - * by a Java method invocation conversion (JLS 5.3) + * by a Java method invocation conversion (JLS {@jls 5.3}) * on the primitive value. (These are the primitive widening conversions.) * T0 must be a wrapper class or a supertype of one. * (In the case where T0 is Object, these are the conversions diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index bdc26750992..dd8b01c73bc 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -1884,7 +1884,7 @@ public class MethodHandles { * as a normal class or interface has with its own defining loader. * This means that the hidden class may be unloaded if and only if * its defining loader is not reachable and thus may be reclaimed - * by a garbage collector (JLS 12.7). + * by a garbage collector (JLS {@jls 12.7}). * *

    By default, a hidden class or interface may be unloaded * even if the class loader that is marked as its defining loader is @@ -2024,7 +2024,7 @@ public class MethodHandles { * that {@linkplain Class#getClassLoader() defined it}. * This means that a class created by a class loader may be unloaded if and * only if its defining loader is not reachable and thus may be reclaimed - * by a garbage collector (JLS 12.7). + * by a garbage collector (JLS {@jls 12.7}). * * By default, however, a hidden class or interface may be unloaded even if * the class loader that is marked as its defining loader is @@ -4757,15 +4757,15 @@ return invoker; * the boolean is converted to a byte value, 1 for true, 0 for false. * (This treatment follows the usage of the bytecode verifier.) *

  • If T1 is boolean and T0 is another primitive, - * T0 is converted to byte via Java casting conversion (JLS 5.5), + * T0 is converted to byte via Java casting conversion (JLS {@jls 5.5}), * and the low order bit of the result is tested, as if by {@code (x & 1) != 0}. *
  • If T0 and T1 are primitives other than boolean, - * then a Java casting conversion (JLS 5.5) is applied. + * then a Java casting conversion (JLS {@jls 5.5}) is applied. * (Specifically, T0 will convert to T1 by * widening and/or narrowing.) *
  • If T0 is a reference and T1 a primitive, an unboxing * conversion will be applied at runtime, possibly followed - * by a Java casting conversion (JLS 5.5) on the primitive value, + * by a Java casting conversion (JLS {@jls 5.5}) on the primitive value, * possibly followed by a conversion from byte to boolean by testing * the low-order bit. *
  • If T0 is a reference and T1 a primitive, diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 5ff0cf84aec..7026591190e 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -142,10 +142,10 @@ public final class StringConcatFactory { *
      *
    • zero inputs, concatenation results in an empty string;
    • *
    • one input, concatenation results in the single - * input converted as per JLS 5.1.11 "String Conversion"; otherwise
    • + * input converted as per JLS {@jls 5.1.11} "String Conversion"; otherwise *
    • two or more inputs, the inputs are concatenated as per - * requirements stated in JLS 15.18.1 "String Concatenation Operator +". - * The inputs are converted as per JLS 5.1.11 "String Conversion", + * requirements stated in JLS {@jls 15.18.1} "String Concatenation Operator +". + * The inputs are converted as per JLS {@jls 5.1.11} "String Conversion", * and combined from left to right.
    • *
    * @@ -223,10 +223,10 @@ public final class StringConcatFactory { *
      *
    • zero inputs, concatenation results in an empty string;
    • *
    • one input, concatenation results in the single - * input converted as per JLS 5.1.11 "String Conversion"; otherwise
    • + * input converted as per JLS {@jls 5.1.11} "String Conversion"; otherwise *
    • two or more inputs, the inputs are concatenated as per - * requirements stated in JLS 15.18.1 "String Concatenation Operator +". - * The inputs are converted as per JLS 5.1.11 "String Conversion", + * requirements stated in JLS {@jls 15.18.1} "String Concatenation Operator +". + * The inputs are converted as per JLS {@jls 5.1.11} "String Conversion", * and combined from left to right.
    • *
    * diff --git a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java index 0064aed2a22..01746e34385 100644 --- a/src/java.base/share/classes/java/lang/reflect/TypeVariable.java +++ b/src/java.base/share/classes/java/lang/reflect/TypeVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -30,8 +30,8 @@ package java.lang.reflect; * A type variable is created the first time it is needed by a reflective * method, as specified in this package. If a type variable t is referenced * by a type (i.e, class, interface or annotation type) T, and T is declared - * by the nth enclosing class of T (see JLS 8.1.2), then the creation of t - * requires the resolution (see JVMS 5) of the ith enclosing class of T, + * by the nth enclosing class of T (see JLS {@jls 8.1.2}), then the creation of t + * requires the resolution (see JVMS {@jvms 5}) of the ith enclosing class of T, * for i = 0 to n, inclusive. Creating a type variable must not cause the * creation of its bounds. Repeated creation of a type variable has no effect. * -- GitLab From 3e393047e12147a81e2899784b943923fc34da8e Mon Sep 17 00:00:00 2001 From: XenoAmess Date: Wed, 16 Mar 2022 16:48:49 +0000 Subject: [PATCH 061/237] 8281631: HashMap copy constructor and putAll can over-allocate table Reviewed-by: smarks --- .../share/classes/java/util/HashMap.java | 14 +- .../share/classes/java/util/WeakHashMap.java | 10 +- test/jdk/ProblemList.txt | 1 + .../java/util/HashMap/WhiteBoxResizeTest.java | 305 ++++++++++++++---- 4 files changed, 258 insertions(+), 72 deletions(-) diff --git a/src/java.base/share/classes/java/util/HashMap.java b/src/java.base/share/classes/java/util/HashMap.java index 24fcd9516ca..997273aa104 100644 --- a/src/java.base/share/classes/java/util/HashMap.java +++ b/src/java.base/share/classes/java/util/HashMap.java @@ -495,9 +495,9 @@ public class HashMap extends AbstractMap int s = m.size(); if (s > 0) { if (table == null) { // pre-size - float ft = ((float)s / loadFactor) + 1.0F; - int t = ((ft < (float)MAXIMUM_CAPACITY) ? - (int)ft : MAXIMUM_CAPACITY); + double dt = Math.ceil(s / (double)loadFactor); + int t = ((dt < (double)MAXIMUM_CAPACITY) ? + (int)dt : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); } else { @@ -1527,12 +1527,12 @@ public class HashMap extends AbstractMap } else if (mappings == 0) { // use defaults } else if (mappings > 0) { - float fc = (float)mappings / lf + 1.0f; - int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ? + double dc = Math.ceil(mappings / (double)lf); + int cap = ((dc < DEFAULT_INITIAL_CAPACITY) ? DEFAULT_INITIAL_CAPACITY : - (fc >= MAXIMUM_CAPACITY) ? + (dc >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : - tableSizeFor((int)fc)); + tableSizeFor((int)dc)); float ft = (float)cap * lf; threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ? (int)ft : Integer.MAX_VALUE); diff --git a/src/java.base/share/classes/java/util/WeakHashMap.java b/src/java.base/share/classes/java/util/WeakHashMap.java index d74c7d65728..bc31985b66e 100644 --- a/src/java.base/share/classes/java/util/WeakHashMap.java +++ b/src/java.base/share/classes/java/util/WeakHashMap.java @@ -213,9 +213,7 @@ public class WeakHashMap if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load factor: "+ loadFactor); - int capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; + int capacity = HashMap.tableSizeFor(initialCapacity); table = newTable(capacity); this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); @@ -251,7 +249,7 @@ public class WeakHashMap * @since 1.3 */ public WeakHashMap(Map m) { - this(Math.max((int) ((float)m.size() / DEFAULT_LOAD_FACTOR + 1.0F), + this(Math.max((int) Math.ceil(m.size() / (double)DEFAULT_LOAD_FACTOR), DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); putAll(m); @@ -468,7 +466,7 @@ public class WeakHashMap modCount++; Entry e = tab[i]; tab[i] = new Entry<>(k, value, queue, h, e); - if (++size >= threshold) + if (++size > threshold) resize(tab.length * 2); return null; } @@ -557,7 +555,7 @@ public class WeakHashMap * to at most one extra resize. */ if (numKeysToBeAdded > threshold) { - int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); + int targetCapacity = (int)Math.ceil(numKeysToBeAdded / (double)loadFactor); if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length; diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index fc1979b6ed6..0bafc13a252 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -542,6 +542,7 @@ java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 8151492 generic- java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 8078602 generic-all java/lang/invoke/lambda/LambdaFileEncodingSerialization.java 8249079 linux-x64 java/lang/invoke/RicochetTest.java 8251969 generic-all +java/lang/Enum/ConstantDirectoryOptimalCapacity.java 8282120 generic-all ############################################################################ diff --git a/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java b/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java index e7374dff5cd..ad02b3000e2 100644 --- a/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java +++ b/test/jdk/java/util/HashMap/WhiteBoxResizeTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2018, Red Hat, Inc. All rights reserved. + * Copyright (c) 2022, 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 @@ -21,113 +22,299 @@ * questions. */ +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.ThreadLocalRandom; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.function.Consumer; import java.util.function.Supplier; -import java.util.stream.IntStream; -import static java.util.stream.Collectors.toMap; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; /* * @test - * @bug 8210280 + * @bug 8210280 8281631 * @modules java.base/java.util:open - * @summary White box tests for HashMap internals around table resize + * @summary White box tests for HashMap-related internals around table sizing * @run testng WhiteBoxResizeTest - * @key randomness */ public class WhiteBoxResizeTest { - final ThreadLocalRandom rnd = ThreadLocalRandom.current(); + final MethodHandle TABLE_SIZE_FOR; - final VarHandle THRESHOLD; - final VarHandle TABLE; + final VarHandle HM_TABLE; + final VarHandle WHM_TABLE; public WhiteBoxResizeTest() throws ReflectiveOperationException { - Class mClass = HashMap.class; - String nodeClassName = mClass.getName() + "$Node"; - Class nodeArrayClass = Class.forName("[L" + nodeClassName + ";"); - MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(mClass, MethodHandles.lookup()); - TABLE = lookup.findVarHandle(mClass, "table", nodeArrayClass); - this.TABLE_SIZE_FOR = lookup.findStatic( - mClass, "tableSizeFor", - MethodType.methodType(int.class, int.class)); - this.THRESHOLD = lookup.findVarHandle(mClass, "threshold", int.class); + MethodHandles.Lookup hmlookup = MethodHandles.privateLookupIn(HashMap.class, MethodHandles.lookup()); + TABLE_SIZE_FOR = hmlookup.findStatic( + HashMap.class, "tableSizeFor", MethodType.methodType(int.class, int.class)); + HM_TABLE = hmlookup.unreflectVarHandle(HashMap.class.getDeclaredField("table")); + + MethodHandles.Lookup whmlookup = MethodHandles.privateLookupIn(WeakHashMap.class, MethodHandles.lookup()); + WHM_TABLE = whmlookup.unreflectVarHandle(WeakHashMap.class.getDeclaredField("table")); } + /* + * utility methods + */ + int tableSizeFor(int n) { try { return (int) TABLE_SIZE_FOR.invoke(n); - } catch (Throwable t) { throw new AssertionError(t); } + } catch (Throwable t) { + throw new AssertionError(t); + } } - Object[] table(HashMap map) { + Object[] table(Map map) { try { - return (Object[]) TABLE.get(map); - } catch (Throwable t) { throw new AssertionError(t); } + VarHandle vh = map instanceof WeakHashMap ? WHM_TABLE : HM_TABLE; + return (Object[]) vh.get(map); + } catch (Throwable t) { + throw new AssertionError(t); + } } - int capacity(HashMap map) { + int capacity(Map map) { return table(map).length; } - @Test - public void testTableSizeFor() { - assertEquals(tableSizeFor(0), 1); - assertEquals(tableSizeFor(1), 1); - assertEquals(tableSizeFor(2), 2); - assertEquals(tableSizeFor(3), 4); - assertEquals(tableSizeFor(15), 16); - assertEquals(tableSizeFor(16), 16); - assertEquals(tableSizeFor(17), 32); - int maxSize = 1 << 30; - assertEquals(tableSizeFor(maxSize - 1), maxSize); - assertEquals(tableSizeFor(maxSize), maxSize); - assertEquals(tableSizeFor(maxSize + 1), maxSize); - assertEquals(tableSizeFor(Integer.MAX_VALUE), maxSize); + // creates a map with size mappings + Map makeMap(int size) { + Map map = new HashMap<>(); + putN(map, size); + return map; + } + + // creates a "fake" map: size() returns the given size, but + // the entrySet iterator returns only one entry + Map fakeMap(int size) { + return new AbstractMap<>() { + public Set> entrySet() { + return new AbstractSet>() { + public int size() { + return size; + } + + public Iterator> iterator() { + return Set.of(Map.entry("1", "1")).iterator(); + } + }; + } + }; + } + + void putN(Map map, int n) { + for (int i = 0; i < n; i++) { + String string = Integer.toString(i); + map.put(string, string); + } + } + + /* + * tests of tableSizeFor + */ + + @DataProvider(name = "tableSizeFor") + public Object[][] tableSizeForCases() { + final int MAX = 1 << 30; + return new Object[][] { + // tableSizeFor(arg), expected + { 0, 1 }, + { 1, 1 }, + { 2, 2 }, + { 3, 4 }, + { 4, 4 }, + { 5, 8 }, + { 15, 16 }, + { 16, 16 }, + { 17, 32 }, + { MAX-1, MAX }, + { MAX, MAX }, + { MAX+1, MAX }, + { Integer.MAX_VALUE, MAX } + }; + } + + @Test(dataProvider = "tableSizeFor") + public void tableSizeFor(int arg, int expected) { + assertEquals(tableSizeFor(arg), expected); } - @Test - public void capacityTestDefaultConstructor() { - capacityTestDefaultConstructor(new HashMap<>()); - capacityTestDefaultConstructor(new LinkedHashMap<>()); + /* + * tests for lazy table allocation + */ + + @DataProvider(name = "lazy") + public Object[][] lazyTableAllocationCases() { + return new Object[][]{ + {new HashMap<>()}, + // { new WeakHashMap<>() }, // WHM doesn't allocate lazily + {new LinkedHashMap<>()} + }; } - void capacityTestDefaultConstructor(HashMap map) { + @Test(dataProvider = "lazy") + public void lazyTableAllocation(Map map) { assertNull(table(map)); + } - map.put(1, 1); - assertEquals(capacity(map), 16); // default initial capacity + /* + * tests for default capacity (no-arg constructor) + */ - map.putAll(IntStream.range(0, 64).boxed().collect(toMap(i -> i, i -> i))); - assertEquals(capacity(map), 128); + @DataProvider(name = "defaultCapacity") + public Object[][] defaultCapacityCases() { + return new Supplier[][]{ + {() -> new HashMap<>()}, + {() -> new LinkedHashMap<>()}, + {() -> new WeakHashMap<>()} + }; } - @Test - public void capacityTestInitialCapacity() { - int initialCapacity = rnd.nextInt(2, 128); - List>> suppliers = List.of( - () -> new HashMap<>(initialCapacity), - () -> new HashMap<>(initialCapacity, 0.75f), - () -> new LinkedHashMap<>(initialCapacity), - () -> new LinkedHashMap<>(initialCapacity, 0.75f)); + @Test(dataProvider = "defaultCapacity") + public void defaultCapacity(Supplier> s) { + Map map = s.get(); + map.put("", ""); + assertEquals(capacity(map), 16); + } - for (Supplier> supplier : suppliers) { - HashMap map = supplier.get(); - assertNull(table(map)); + /* + * tests for requested capacity (int and int+float constructors) + */ - map.put(1, 1); - assertEquals(capacity(map), tableSizeFor(initialCapacity)); + @DataProvider(name = "requestedCapacity") + public Iterator requestedCapacityCases() { + ArrayList cases = new ArrayList<>(); + for (int i = 2; i < 128; i++) { + int cap = i; + cases.add(new Object[]{"rhm1", cap, (Supplier>) () -> new HashMap<>(cap)}); + cases.add(new Object[]{"rhm2", cap, (Supplier>) () -> new HashMap<>(cap, 0.75f)}); + cases.add(new Object[]{"rlm1", cap, (Supplier>) () -> new LinkedHashMap<>(cap)}); + cases.add(new Object[]{"rlm2", cap, (Supplier>) () -> new LinkedHashMap<>(cap, 0.75f)}); + cases.add(new Object[]{"rwm1", cap, (Supplier>) () -> new WeakHashMap<>(cap)}); + cases.add(new Object[]{"rwm2", cap, (Supplier>) () -> new WeakHashMap<>(cap, 0.75f)}); } + return cases.iterator(); + } + + @Test(dataProvider = "requestedCapacity") + public void requestedCapacity(String label, int cap, Supplier> s) { + Map map = s.get(); + map.put("", ""); + assertEquals(capacity(map), tableSizeFor(cap)); + } + + /* + * Tests for capacity after map is populated with a given number N of mappings. + * Maps are populated using a copy constructor on a map with N mappings, + * other constructors followed by N put() calls, and other constructors followed + * by putAll() on a map with N mappings. + * + * String labels encode the test case for ease of diagnosis if one of the test cases fails. + * For example, "plm2pn" is "populated LinkedHashMap, 2-arg constructor, followed by putN". + */ + + // helper method for one populated capacity case, to provide target types for lambdas + Object[] pcc(String label, + int size, + int expectedCapacity, + Supplier> supplier, + Consumer> consumer) { + return new Object[]{label, size, expectedCapacity, supplier, consumer}; + } + + List genPopulatedCapacityCases(int size, int cap) { + return Arrays.asList( + pcc("phmcpy", size, cap, () -> new HashMap<>(makeMap(size)), map -> { }), + pcc("phm0pn", size, cap, () -> new HashMap<>(), map -> { putN(map, size); }), + pcc("phm1pn", size, cap, () -> new HashMap<>(cap), map -> { putN(map, size); }), + pcc("phm2pn", size, cap, () -> new HashMap<>(cap, 0.75f), map -> { putN(map, size); }), + pcc("phm0pa", size, cap, () -> new HashMap<>(), map -> { map.putAll(makeMap(size)); }), + pcc("phm1pa", size, cap, () -> new HashMap<>(cap), map -> { map.putAll(makeMap(size)); }), + pcc("phm2pa", size, cap, () -> new HashMap<>(cap, 0.75f), map -> { map.putAll(makeMap(size)); }), + + pcc("plmcpy", size, cap, () -> new LinkedHashMap<>(makeMap(size)), map -> { }), + pcc("plm0pn", size, cap, () -> new LinkedHashMap<>(), map -> { putN(map, size); }), + pcc("plm1pn", size, cap, () -> new LinkedHashMap<>(cap), map -> { putN(map, size); }), + pcc("plm2pn", size, cap, () -> new LinkedHashMap<>(cap, 0.75f), map -> { putN(map, size); }), + pcc("plm0pa", size, cap, () -> new LinkedHashMap<>(), map -> { map.putAll(makeMap(size)); }), + pcc("plm1pa", size, cap, () -> new LinkedHashMap<>(cap), map -> { map.putAll(makeMap(size)); }), + pcc("plm2pa", size, cap, () -> new LinkedHashMap<>(cap, 0.75f), map -> { map.putAll(makeMap(size)); }), + + pcc("pwmcpy", size, cap, () -> new WeakHashMap<>(makeMap(size)), map -> { }), + pcc("pwm0pn", size, cap, () -> new WeakHashMap<>(), map -> { putN(map, size); }), + pcc("pwm1pn", size, cap, () -> new WeakHashMap<>(cap), map -> { putN(map, size); }), + pcc("pwm2pn", size, cap, () -> new WeakHashMap<>(cap, 0.75f), map -> { putN(map, size); }), + pcc("pwm0pa", size, cap, () -> new WeakHashMap<>(), map -> { map.putAll(makeMap(size)); }), + pcc("pwm1pa", size, cap, () -> new WeakHashMap<>(cap), map -> { map.putAll(makeMap(size)); }), + pcc("pwm2pa", size, cap, () -> new WeakHashMap<>(cap, 0.75f), map -> { map.putAll(makeMap(size)); }) + ); + } + + List genFakePopulatedCapacityCases(int size, int cap) { + return Arrays.asList( + pcc("fhmcpy", size, cap, () -> new HashMap<>(fakeMap(size)), map -> { }), + pcc("fhm0pa", size, cap, () -> new HashMap<>(), map -> { map.putAll(fakeMap(size)); }), + pcc("fhm1pa", size, cap, () -> new HashMap<>(cap), map -> { map.putAll(fakeMap(size)); }), + pcc("fhm2pa", size, cap, () -> new HashMap<>(cap, 0.75f), map -> { map.putAll(fakeMap(size)); }), + + pcc("flmcpy", size, cap, () -> new LinkedHashMap<>(fakeMap(size)), map -> { }), + pcc("flm0pa", size, cap, () -> new LinkedHashMap<>(), map -> { map.putAll(fakeMap(size)); }), + pcc("flm1pa", size, cap, () -> new LinkedHashMap<>(cap), map -> { map.putAll(fakeMap(size)); }), + pcc("flm2pa", size, cap, () -> new LinkedHashMap<>(cap, 0.75f), map -> { map.putAll(fakeMap(size)); }), + + pcc("fwmcpy", size, cap, () -> new WeakHashMap<>(fakeMap(size)), map -> { }), + // pcc("fwm0pa", size, cap, () -> new WeakHashMap<>(), map -> { map.putAll(fakeMap(size)); }), // see note + pcc("fwm1pa", size, cap, () -> new WeakHashMap<>(cap), map -> { map.putAll(fakeMap(size)); }), + pcc("fwm2pa", size, cap, () -> new WeakHashMap<>(cap, 0.75f), map -> { map.putAll(fakeMap(size)); }) + ); + + // Test case "fwm0pa" is commented out because WeakHashMap uses a different allocation + // policy from the other map implementations: it deliberately under-allocates in this case. + } + + @DataProvider(name = "populatedCapacity") + public Iterator populatedCapacityCases() { + ArrayList cases = new ArrayList<>(); + cases.addAll(genPopulatedCapacityCases(11, 16)); + cases.addAll(genPopulatedCapacityCases(12, 16)); + cases.addAll(genPopulatedCapacityCases(13, 32)); + cases.addAll(genPopulatedCapacityCases(64, 128)); + + // numbers in this range are truncated by a float computation with 0.75f + // but can get an exact result with a double computation with 0.75d + cases.addAll(genFakePopulatedCapacityCases(25165824, 33554432)); + cases.addAll(genFakePopulatedCapacityCases(25165825, 67108864)); + cases.addAll(genFakePopulatedCapacityCases(25165826, 67108864)); + + return cases.iterator(); } + + @Test(dataProvider = "populatedCapacity") + public void populatedCapacity(String label, // unused, included for diagnostics + int size, // unused, included for diagnostics + int expectedCapacity, + Supplier> s, + Consumer> c) { + Map map = s.get(); + c.accept(map); + assertEquals(capacity(map), expectedCapacity); + } + } -- GitLab From 3da5204b3c3a3f95bddcdcfe2628c2e0ed8a12d9 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Thu, 17 Mar 2022 00:05:57 +0000 Subject: [PATCH 062/237] 8283229: compiler/arguments/TestCodeEntryAlignment.java fails with release VMs Reviewed-by: dlong --- .../hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java index 15a60382245..0ea1aee6bd6 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java @@ -27,6 +27,7 @@ * @library /test/lib / * @bug 8281467 * @requires vm.flagless + * @requires vm.debug * @requires os.arch=="amd64" | os.arch=="x86_64" * * @summary Test large CodeEntryAlignments are accepted -- GitLab From a5ebcc0c04bedd87bc9a523b0a45b50fc4b0f5f0 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Thu, 17 Mar 2022 08:54:29 +0000 Subject: [PATCH 063/237] 8282072: G1: Rename CardSetPtr to CardSetContainerPtr Reviewed-by: ayang, tschatzl --- src/hotspot/share/gc/g1/g1CardSet.cpp | 405 +++++++++--------- src/hotspot/share/gc/g1/g1CardSet.hpp | 133 +++--- src/hotspot/share/gc/g1/g1CardSet.inline.hpp | 35 +- .../share/gc/g1/g1CardSetContainers.hpp | 58 +-- .../gc/g1/g1CardSetContainers.inline.hpp | 56 +-- .../share/gc/g1/heapRegionRemSet.inline.hpp | 6 +- test/hotspot/gtest/gc/g1/test_g1CardSet.cpp | 4 +- .../gtest/gc/g1/test_g1CardSetContainers.cpp | 2 +- 8 files changed, 346 insertions(+), 353 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index a87db1ff718..82092a1d502 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -26,25 +26,19 @@ #include "gc/g1/g1CardSet.inline.hpp" #include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1CardSetMemory.inline.hpp" -#include "gc/g1/g1FromCardCache.hpp" #include "gc/g1/heapRegion.inline.hpp" +#include "gc/shared/gcLogPrecious.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" #include "memory/allocation.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/globals_extension.hpp" -#include "runtime/mutex.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/globalDefinitions.hpp" -#include "utilities/lockFreeStack.hpp" -#include "utilities/spinYield.hpp" - -#include "gc/shared/gcLogPrecious.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" -#include "runtime/java.hpp" -G1CardSet::CardSetPtr G1CardSet::FullCardSet = (G1CardSet::CardSetPtr)-1; +G1CardSet::ContainerPtr G1CardSet::FullCardSet = (G1CardSet::ContainerPtr)-1; -static uint default_log2_card_region_per_region() { +static uint default_log2_card_regions_per_region() { uint log2_card_regions_per_heap_region = 0; const uint card_container_limit = G1CardSetContainer::LogCardsPerRegionLimit; @@ -62,7 +56,7 @@ G1CardSetConfiguration::G1CardSetConfiguration() : G1RemSetHowlNumBuckets, /* num_buckets_in_howl */ (double)G1RemSetCoarsenHowlToFullPercent / 100, /* cards_in_howl_threshold_percent */ (uint)HeapRegion::CardsPerRegion, /* max_cards_in_cardset */ - default_log2_card_region_per_region()) /* log2_card_region_per_region */ + default_log2_card_regions_per_region()) /* log2_card_regions_per_region */ { assert((_log2_card_regions_per_heap_region + _log2_cards_per_card_region) == (uint)HeapRegion::LogCardsPerRegion, "inconsistent heap region virtualization setup"); @@ -73,7 +67,7 @@ G1CardSetConfiguration::G1CardSetConfiguration(uint max_cards_in_array, uint max_buckets_in_howl, double cards_in_howl_threshold_percent, uint max_cards_in_card_set, - uint log2_card_region_per_region) : + uint log2_card_regions_per_region) : G1CardSetConfiguration(log2i_exact(max_cards_in_card_set), /* inline_ptr_bits_per_card */ max_cards_in_array, /* max_cards_in_array */ cards_in_bitmap_threshold_percent, /* cards_in_bitmap_threshold_percent */ @@ -82,7 +76,7 @@ G1CardSetConfiguration::G1CardSetConfiguration(uint max_cards_in_array, max_buckets_in_howl), cards_in_howl_threshold_percent, /* cards_in_howl_threshold_percent */ max_cards_in_card_set, /* max_cards_in_cardset */ - log2_card_region_per_region) + log2_card_regions_per_region) { } G1CardSetConfiguration::G1CardSetConfiguration(uint inline_ptr_bits_per_card, @@ -197,7 +191,7 @@ void G1CardSetCoarsenStats::print_on(outputStream* out) { } class G1CardSetHashTable : public CHeapObj { - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; // Did we insert at least one card in the table? bool volatile _inserted_card; @@ -231,12 +225,12 @@ class G1CardSetHashTable : public CHeapObj { }; class G1CardSetHashTableScan : public StackObj { - G1CardSet::CardSetPtrClosure* _scan_f; + G1CardSet::ContainerPtrClosure* _scan_f; public: - explicit G1CardSetHashTableScan(G1CardSet::CardSetPtrClosure* f) : _scan_f(f) { } + explicit G1CardSetHashTableScan(G1CardSet::ContainerPtrClosure* f) : _scan_f(f) { } bool operator()(G1CardSetHashTableValue* value) { - _scan_f->do_cardsetptr(value->_region_idx, value->_num_occupied, value->_card_set); + _scan_f->do_containerptr(value->_region_idx, value->_num_occupied, value->_container); return true; } }; @@ -284,19 +278,19 @@ public: return found.value(); } - void iterate_safepoint(G1CardSet::CardSetPtrClosure* cl2) { + void iterate_safepoint(G1CardSet::ContainerPtrClosure* cl2) { G1CardSetHashTableScan cl(cl2); _table.do_safepoint_scan(cl); } - void iterate(G1CardSet::CardSetPtrClosure* cl2) { + void iterate(G1CardSet::ContainerPtrClosure* cl2) { G1CardSetHashTableScan cl(cl2); _table.do_scan(Thread::current(), cl); } void reset() { if (Atomic::load(&_inserted_card)) { - _table.unsafe_reset(InitialLogTableSize); + _table.unsafe_reset(InitialLogTableSize); Atomic::store(&_inserted_card, false); } } @@ -343,93 +337,93 @@ G1CardSet::~G1CardSet() { _mm->flush(); } -uint G1CardSet::card_set_type_to_mem_object_type(uintptr_t type) const { - assert(type == G1CardSet::CardSetArrayOfCards || - type == G1CardSet::CardSetBitMap || - type == G1CardSet::CardSetHowl, "should not allocate card set type %zu", type); +uint G1CardSet::container_type_to_mem_object_type(uintptr_t type) const { + assert(type == G1CardSet::ContainerArrayOfCards || + type == G1CardSet::ContainerBitMap || + type == G1CardSet::ContainerHowl, "should not allocate container type %zu", type); return (uint)type; } uint8_t* G1CardSet::allocate_mem_object(uintptr_t type) { - return _mm->allocate(card_set_type_to_mem_object_type(type)); + return _mm->allocate(container_type_to_mem_object_type(type)); } -void G1CardSet::free_mem_object(CardSetPtr card_set) { - assert(card_set != G1CardSet::FreeCardSet, "should not free Free card set"); - assert(card_set != G1CardSet::FullCardSet, "should not free Full card set"); +void G1CardSet::free_mem_object(ContainerPtr container) { + assert(container != G1CardSet::FreeCardSet, "should not free container FreeCardSet"); + assert(container != G1CardSet::FullCardSet, "should not free container FullCardSet"); - uintptr_t type = card_set_type(card_set); - void* value = strip_card_set_type(card_set); + uintptr_t type = container_type(container); + void* value = strip_container_type(container); - assert(type == G1CardSet::CardSetArrayOfCards || - type == G1CardSet::CardSetBitMap || - type == G1CardSet::CardSetHowl, "should not free card set type %zu", type); + assert(type == G1CardSet::ContainerArrayOfCards || + type == G1CardSet::ContainerBitMap || + type == G1CardSet::ContainerHowl, "should not free card set type %zu", type); assert(static_cast(value)->refcount() == 1, "must be"); - _mm->free(card_set_type_to_mem_object_type(type), value); + _mm->free(container_type_to_mem_object_type(type), value); } -G1CardSet::CardSetPtr G1CardSet::acquire_card_set(CardSetPtr volatile* card_set_addr) { +G1CardSet::ContainerPtr G1CardSet::acquire_container(ContainerPtr volatile* container_addr) { // Update reference counts under RCU critical section to avoid a // use-after-cleapup bug where we increment a reference count for // an object whose memory has already been cleaned up and reused. GlobalCounter::CriticalSection cs(Thread::current()); while (true) { - // Get cardsetptr and increment refcount atomically wrt to memory reuse. - CardSetPtr card_set = Atomic::load_acquire(card_set_addr); - uint cs_type = card_set_type(card_set); - if (card_set == FullCardSet || cs_type == CardSetInlinePtr) { - return card_set; + // Get ContainerPtr and increment refcount atomically wrt to memory reuse. + ContainerPtr container = Atomic::load_acquire(container_addr); + uint cs_type = container_type(container); + if (container == FullCardSet || cs_type == ContainerInlinePtr) { + return container; } - G1CardSetContainer* card_set_on_heap = (G1CardSetContainer*)strip_card_set_type(card_set); + G1CardSetContainer* container_on_heap = (G1CardSetContainer*)strip_container_type(container); - if (card_set_on_heap->try_increment_refcount()) { - assert(card_set_on_heap->refcount() >= 3, "Smallest value is 3"); - return card_set; + if (container_on_heap->try_increment_refcount()) { + assert(container_on_heap->refcount() >= 3, "Smallest value is 3"); + return container; } } } -bool G1CardSet::release_card_set(CardSetPtr card_set) { - uint cs_type = card_set_type(card_set); - if (card_set == FullCardSet || cs_type == CardSetInlinePtr) { +bool G1CardSet::release_container(ContainerPtr container) { + uint cs_type = container_type(container); + if (container == FullCardSet || cs_type == ContainerInlinePtr) { return false; } - G1CardSetContainer* card_set_on_heap = (G1CardSetContainer*)strip_card_set_type(card_set); - return card_set_on_heap->decrement_refcount() == 1; + G1CardSetContainer* container_on_heap = (G1CardSetContainer*)strip_container_type(container); + return container_on_heap->decrement_refcount() == 1; } -void G1CardSet::release_and_maybe_free_card_set(CardSetPtr card_set) { - if (release_card_set(card_set)) { - free_mem_object(card_set); +void G1CardSet::release_and_maybe_free_container(ContainerPtr container) { + if (release_container(container)) { + free_mem_object(container); } } -void G1CardSet::release_and_must_free_card_set(CardSetPtr card_set) { - bool should_free = release_card_set(card_set); +void G1CardSet::release_and_must_free_container(ContainerPtr container) { + bool should_free = release_container(container); assert(should_free, "should have been the only one having a reference"); - free_mem_object(card_set); + free_mem_object(container); } class G1ReleaseCardsets : public StackObj { G1CardSet* _card_set; - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; - void coarsen_to_full(CardSetPtr* card_set_addr) { + void coarsen_to_full(ContainerPtr* container_addr) { while (true) { - CardSetPtr cur_card_set = Atomic::load_acquire(card_set_addr); - uint cs_type = G1CardSet::card_set_type(cur_card_set); - if (cur_card_set == G1CardSet::FullCardSet) { + ContainerPtr cur_container = Atomic::load_acquire(container_addr); + uint cs_type = G1CardSet::container_type(cur_container); + if (cur_container == G1CardSet::FullCardSet) { return; } - CardSetPtr old_value = Atomic::cmpxchg(card_set_addr, cur_card_set, G1CardSet::FullCardSet); + ContainerPtr old_value = Atomic::cmpxchg(container_addr, cur_container, G1CardSet::FullCardSet); - if (old_value == cur_card_set) { - _card_set->release_and_maybe_free_card_set(cur_card_set); + if (old_value == cur_container) { + _card_set->release_and_maybe_free_container(cur_container); return; } } @@ -438,51 +432,51 @@ class G1ReleaseCardsets : public StackObj { public: explicit G1ReleaseCardsets(G1CardSet* card_set) : _card_set(card_set) { } - void operator ()(CardSetPtr* card_set_addr) { - coarsen_to_full(card_set_addr); + void operator ()(ContainerPtr* container_addr) { + coarsen_to_full(container_addr); } }; -G1AddCardResult G1CardSet::add_to_array(CardSetPtr card_set, uint card_in_region) { - G1CardSetArray* array = card_set_ptr(card_set); +G1AddCardResult G1CardSet::add_to_array(ContainerPtr container, uint card_in_region) { + G1CardSetArray* array = container_ptr(container); return array->add(card_in_region); } -G1AddCardResult G1CardSet::add_to_howl(CardSetPtr parent_card_set, - uint card_region, - uint card_in_region, - bool increment_total) { - G1CardSetHowl* howl = card_set_ptr(parent_card_set); +G1AddCardResult G1CardSet::add_to_howl(ContainerPtr parent_container, + uint card_region, + uint card_in_region, + bool increment_total) { + G1CardSetHowl* howl = container_ptr(parent_container); G1AddCardResult add_result; - CardSetPtr to_transfer = nullptr; - CardSetPtr card_set; + ContainerPtr to_transfer = nullptr; + ContainerPtr container; uint bucket = _config->howl_bucket_index(card_in_region); - volatile CardSetPtr* bucket_entry = howl->get_card_set_addr(bucket); + ContainerPtr volatile* bucket_entry = howl->get_container_addr(bucket); while (true) { if (Atomic::load(&howl->_num_entries) >= _config->cards_in_howl_threshold()) { return Overflow; } - card_set = acquire_card_set(bucket_entry); - add_result = add_to_card_set(bucket_entry, card_set, card_region, card_in_region); + container = acquire_container(bucket_entry); + add_result = add_to_container(bucket_entry, container, card_region, card_in_region); if (add_result != Overflow) { break; } - // Card set has overflown. Coarsen or retry. - bool coarsened = coarsen_card_set(bucket_entry, card_set, card_in_region, true /* within_howl */); - _coarsen_stats.record_coarsening(card_set_type(card_set) + G1CardSetCoarsenStats::CoarsenHowlOffset, !coarsened); + // Card set container has overflown. Coarsen or retry. + bool coarsened = coarsen_container(bucket_entry, container, card_in_region, true /* within_howl */); + _coarsen_stats.record_coarsening(container_type(container) + G1CardSetCoarsenStats::CoarsenHowlOffset, !coarsened); if (coarsened) { - // We have been the one coarsening this card set (and in the process added that card). + // We successful coarsened this card set container (and in the process added the card). add_result = Added; - to_transfer = card_set; + to_transfer = container; break; } // Somebody else beat us to coarsening. Retry. - release_and_maybe_free_card_set(card_set); + release_and_maybe_free_container(container); } if (increment_total && add_result == Added) { @@ -490,91 +484,91 @@ G1AddCardResult G1CardSet::add_to_howl(CardSetPtr parent_card_set, } if (to_transfer != nullptr) { - transfer_cards_in_howl(parent_card_set, to_transfer, card_region); + transfer_cards_in_howl(parent_container, to_transfer, card_region); } - release_and_maybe_free_card_set(card_set); + release_and_maybe_free_container(container); return add_result; } -G1AddCardResult G1CardSet::add_to_bitmap(CardSetPtr card_set, uint card_in_region) { - G1CardSetBitMap* bitmap = card_set_ptr(card_set); +G1AddCardResult G1CardSet::add_to_bitmap(ContainerPtr container, uint card_in_region) { + G1CardSetBitMap* bitmap = container_ptr(container); uint card_offset = _config->howl_bitmap_offset(card_in_region); return bitmap->add(card_offset, _config->cards_in_howl_bitmap_threshold(), _config->max_cards_in_howl_bitmap()); } -G1AddCardResult G1CardSet::add_to_inline_ptr(CardSetPtr volatile* card_set_addr, CardSetPtr card_set, uint card_in_region) { - G1CardSetInlinePtr value(card_set_addr, card_set); +G1AddCardResult G1CardSet::add_to_inline_ptr(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_in_region) { + G1CardSetInlinePtr value(container_addr, container); return value.add(card_in_region, _config->inline_ptr_bits_per_card(), _config->max_cards_in_inline_ptr()); } -G1CardSet::CardSetPtr G1CardSet::create_coarsened_array_of_cards(uint card_in_region, bool within_howl) { +G1CardSet::ContainerPtr G1CardSet::create_coarsened_array_of_cards(uint card_in_region, bool within_howl) { uint8_t* data = nullptr; - CardSetPtr new_card_set; + ContainerPtr new_container; if (within_howl) { uint const size_in_bits = _config->max_cards_in_howl_bitmap(); - uint card_offset = _config->howl_bitmap_offset(card_in_region); - data = allocate_mem_object(CardSetBitMap); - new (data) G1CardSetBitMap(card_offset, size_in_bits); - new_card_set = make_card_set_ptr(data, CardSetBitMap); + uint container_offset = _config->howl_bitmap_offset(card_in_region); + data = allocate_mem_object(ContainerBitMap); + new (data) G1CardSetBitMap(container_offset, size_in_bits); + new_container = make_container_ptr(data, ContainerBitMap); } else { - data = allocate_mem_object(CardSetHowl); + data = allocate_mem_object(ContainerHowl); new (data) G1CardSetHowl(card_in_region, _config); - new_card_set = make_card_set_ptr(data, CardSetHowl); + new_container = make_container_ptr(data, ContainerHowl); } - return new_card_set; + return new_container; } -bool G1CardSet::coarsen_card_set(volatile CardSetPtr* card_set_addr, - CardSetPtr cur_card_set, - uint card_in_region, - bool within_howl) { - CardSetPtr new_card_set = nullptr; +bool G1CardSet::coarsen_container(ContainerPtr volatile* container_addr, + ContainerPtr cur_container, + uint card_in_region, + bool within_howl) { + ContainerPtr new_container = nullptr; - switch (card_set_type(cur_card_set)) { - case CardSetArrayOfCards : { - new_card_set = create_coarsened_array_of_cards(card_in_region, within_howl); + switch (container_type(cur_container)) { + case ContainerArrayOfCards: { + new_container = create_coarsened_array_of_cards(card_in_region, within_howl); break; } - case CardSetBitMap: { - new_card_set = FullCardSet; + case ContainerBitMap: { + new_container = FullCardSet; break; } - case CardSetInlinePtr: { + case ContainerInlinePtr: { uint const size = _config->max_cards_in_array(); - uint8_t* data = allocate_mem_object(CardSetArrayOfCards); + uint8_t* data = allocate_mem_object(ContainerArrayOfCards); new (data) G1CardSetArray(card_in_region, size); - new_card_set = make_card_set_ptr(data, CardSetArrayOfCards); + new_container = make_container_ptr(data, ContainerArrayOfCards); break; } - case CardSetHowl: { - new_card_set = FullCardSet; // anything will do at this point. + case ContainerHowl: { + new_container = FullCardSet; // anything will do at this point. break; } default: ShouldNotReachHere(); } - CardSetPtr old_value = Atomic::cmpxchg(card_set_addr, cur_card_set, new_card_set); // Memory order? - if (old_value == cur_card_set) { + ContainerPtr old_value = Atomic::cmpxchg(container_addr, cur_container, new_container); // Memory order? + if (old_value == cur_container) { // Success. Indicate that the cards from the current card set must be transferred // by this caller. // Release the hash table reference to the card. The caller still holds the // reference to this card set, so it can never be released (and we do not need to // check its result). - bool should_free = release_card_set(cur_card_set); + bool should_free = release_container(cur_container); assert(!should_free, "must have had more than one reference"); - // Free containers if cur_card_set is CardSetHowl - if (card_set_type(cur_card_set) == CardSetHowl) { + // Free containers if cur_container is ContainerHowl + if (container_type(cur_container) == ContainerHowl) { G1ReleaseCardsets rel(this); - card_set_ptr(cur_card_set)->iterate(rel, _config->num_buckets_in_howl()); + container_ptr(cur_container)->iterate(rel, _config->num_buckets_in_howl()); } return true; } else { // Somebody else beat us to coarsening that card set. Exit, but clean up first. - if (new_card_set != FullCardSet) { - assert(new_card_set != nullptr, "must not be"); - release_and_must_free_card_set(new_card_set); + if (new_container != FullCardSet) { + assert(new_container != nullptr, "must not be"); + release_and_must_free_container(new_container); } return false; } @@ -591,34 +585,34 @@ public: } }; -void G1CardSet::transfer_cards(G1CardSetHashTableValue* table_entry, CardSetPtr source_card_set, uint card_region) { - assert(source_card_set != FullCardSet, "Should not need to transfer from full"); - // Need to transfer old entries unless there is a Full card set in place now, i.e. - // the old type has been CardSetBitMap. "Full" contains all elements anyway. - if (card_set_type(source_card_set) != CardSetHowl) { +void G1CardSet::transfer_cards(G1CardSetHashTableValue* table_entry, ContainerPtr source_container, uint card_region) { + assert(source_container != FullCardSet, "Should not need to transfer from FullCardSet"); + // Need to transfer old entries unless there is a Full card set container in place now, i.e. + // the old type has been ContainerBitMap. "Full" contains all elements anyway. + if (container_type(source_container) != ContainerHowl) { G1TransferCard iter(this, card_region); - iterate_cards_during_transfer(source_card_set, iter); + iterate_cards_during_transfer(source_container, iter); } else { - assert(card_set_type(source_card_set) == CardSetHowl, "must be"); + assert(container_type(source_container) == ContainerHowl, "must be"); // Need to correct for that the Full remembered set occupies more cards than the // AoCS before. Atomic::add(&_num_occupied, _config->max_cards_in_region() - table_entry->_num_occupied, memory_order_relaxed); } } -void G1CardSet::transfer_cards_in_howl(CardSetPtr parent_card_set, - CardSetPtr source_card_set, - uint card_region) { - assert(card_set_type(parent_card_set) == CardSetHowl, "must be"); - assert(source_card_set != FullCardSet, "Should not need to transfer from full"); +void G1CardSet::transfer_cards_in_howl(ContainerPtr parent_container, + ContainerPtr source_container, + uint card_region) { + assert(container_type(parent_container) == ContainerHowl, "must be"); + assert(source_container != FullCardSet, "Should not need to transfer from full"); // Need to transfer old entries unless there is a Full card set in place now, i.e. - // the old type has been CardSetBitMap. - if (card_set_type(source_card_set) != CardSetBitMap) { - // We only need to transfer from anything below CardSetBitMap. + // the old type has been ContainerBitMap. + if (container_type(source_container) != ContainerBitMap) { + // We only need to transfer from anything below ContainerBitMap. G1TransferCard iter(this, card_region); - iterate_cards_during_transfer(source_card_set, iter); + iterate_cards_during_transfer(source_container, iter); } else { - uint diff = _config->max_cards_in_howl_bitmap() - card_set_ptr(source_card_set)->num_bits_set(); + uint diff = _config->max_cards_in_howl_bitmap() - container_ptr(source_container)->num_bits_set(); // Need to correct for that the Full remembered set occupies more cards than the // bitmap before. @@ -627,10 +621,10 @@ void G1CardSet::transfer_cards_in_howl(CardSetPtr parent_card_set, // G1CardSet::add_to_howl after coarsening. diff -= 1; - G1CardSetHowl* howling_array = card_set_ptr(parent_card_set); + G1CardSetHowl* howling_array = container_ptr(parent_container); Atomic::add(&howling_array->_num_entries, diff, memory_order_relaxed); - G1CardSetHashTableValue* table_entry = get_card_set(card_region); + G1CardSetHashTableValue* table_entry = get_container(card_region); assert(table_entry != nullptr, "Table entry not found for transferred cards"); Atomic::add(&table_entry->_num_occupied, diff, memory_order_relaxed); @@ -639,72 +633,75 @@ void G1CardSet::transfer_cards_in_howl(CardSetPtr parent_card_set, } } -G1AddCardResult G1CardSet::add_to_card_set(volatile CardSetPtr* card_set_addr, CardSetPtr card_set, uint card_region, uint card_in_region, bool increment_total) { - assert(card_set_addr != nullptr, "Cannot add to empty cardset"); +G1AddCardResult G1CardSet::add_to_container(ContainerPtr volatile* container_addr, + ContainerPtr container, + uint card_region, + uint card_in_region, + bool increment_total) { + assert(container_addr != nullptr, "must be"); G1AddCardResult add_result; - switch (card_set_type(card_set)) { - case CardSetInlinePtr: { - add_result = add_to_inline_ptr(card_set_addr, card_set, card_in_region); + switch (container_type(container)) { + case ContainerInlinePtr: { + add_result = add_to_inline_ptr(container_addr, container, card_in_region); break; } - case CardSetArrayOfCards : { - add_result = add_to_array(card_set, card_in_region); + case ContainerArrayOfCards: { + add_result = add_to_array(container, card_in_region); break; } - case CardSetBitMap: { - add_result = add_to_bitmap(card_set, card_in_region); + case ContainerBitMap: { + add_result = add_to_bitmap(container, card_in_region); break; } - case CardSetHowl: { - assert(CardSetHowl == card_set_type(FullCardSet), "must be"); - if (card_set == FullCardSet) { + case ContainerHowl: { + assert(ContainerHowl == container_type(FullCardSet), "must be"); + if (container == FullCardSet) { return Found; } - add_result = add_to_howl(card_set, card_region, card_in_region, increment_total); + add_result = add_to_howl(container, card_region, card_in_region, increment_total); break; } default: ShouldNotReachHere(); } - return add_result; } -G1CardSetHashTableValue* G1CardSet::get_or_add_card_set(uint card_region, bool* should_grow_table) { +G1CardSetHashTableValue* G1CardSet::get_or_add_container(uint card_region, bool* should_grow_table) { return _table->get_or_add(card_region, should_grow_table); } -G1CardSetHashTableValue* G1CardSet::get_card_set(uint card_region) { +G1CardSetHashTableValue* G1CardSet::get_container(uint card_region) { return _table->get(card_region); } G1AddCardResult G1CardSet::add_card(uint card_region, uint card_in_region, bool increment_total) { G1AddCardResult add_result; - CardSetPtr to_transfer = nullptr; - CardSetPtr card_set; + ContainerPtr to_transfer = nullptr; + ContainerPtr container; bool should_grow_table = false; - G1CardSetHashTableValue* table_entry = get_or_add_card_set(card_region, &should_grow_table); + G1CardSetHashTableValue* table_entry = get_or_add_container(card_region, &should_grow_table); while (true) { - card_set = acquire_card_set(&table_entry->_card_set); - add_result = add_to_card_set(&table_entry->_card_set, card_set, card_region, card_in_region, increment_total); + container = acquire_container(&table_entry->_container); + add_result = add_to_container(&table_entry->_container, container, card_region, card_in_region, increment_total); if (add_result != Overflow) { break; } // Card set has overflown. Coarsen or retry. - bool coarsened = coarsen_card_set(&table_entry->_card_set, card_set, card_in_region); - _coarsen_stats.record_coarsening(card_set_type(card_set), !coarsened); + bool coarsened = coarsen_container(&table_entry->_container, container, card_in_region); + _coarsen_stats.record_coarsening(container_type(container), !coarsened); if (coarsened) { - // We have been the one coarsening this card set (and in the process added that card). + // We successful coarsened this card set container (and in the process added the card). add_result = Added; - to_transfer = card_set; + to_transfer = container; break; } // Somebody else beat us to coarsening. Retry. - release_and_maybe_free_card_set(card_set); + release_and_maybe_free_container(container); } if (increment_total && add_result == Added) { @@ -718,7 +715,7 @@ G1AddCardResult G1CardSet::add_card(uint card_region, uint card_in_region, bool transfer_cards(table_entry, to_transfer, card_region); } - release_and_maybe_free_card_set(card_set); + release_and_maybe_free_container(container); return add_result; } @@ -727,29 +724,29 @@ bool G1CardSet::contains_card(uint card_region, uint card_in_region) { assert(card_in_region < _config->max_cards_in_region(), "Card %u is beyond max %u", card_in_region, _config->max_cards_in_region()); - // Protect the card set from reclamation. + // Protect the card set container from reclamation. GlobalCounter::CriticalSection cs(Thread::current()); - G1CardSetHashTableValue* table_entry = get_card_set(card_region); + G1CardSetHashTableValue* table_entry = get_container(card_region); if (table_entry == nullptr) { return false; } - CardSetPtr card_set = table_entry->_card_set; - if (card_set == FullCardSet) { + ContainerPtr container = table_entry->_container; + if (container == FullCardSet) { // contains_card() is not a performance critical method so we do not hide that // case in the switch below. return true; } - switch (card_set_type(card_set)) { - case CardSetInlinePtr: { - G1CardSetInlinePtr ptr(card_set); + switch (container_type(container)) { + case ContainerInlinePtr: { + G1CardSetInlinePtr ptr(container); return ptr.contains(card_in_region, _config->inline_ptr_bits_per_card()); } - case CardSetArrayOfCards : return card_set_ptr(card_set)->contains(card_in_region); - case CardSetBitMap: return card_set_ptr(card_set)->contains(card_in_region, _config->max_cards_in_howl_bitmap()); - case CardSetHowl: { - G1CardSetHowl* howling_array = card_set_ptr(card_set); + case ContainerArrayOfCards: return container_ptr(container)->contains(card_in_region); + case ContainerBitMap: return container_ptr(container)->contains(card_in_region, _config->max_cards_in_howl_bitmap()); + case ContainerHowl: { + G1CardSetHowl* howling_array = container_ptr(container); return howling_array->contains(card_in_region, _config); } @@ -759,53 +756,53 @@ bool G1CardSet::contains_card(uint card_region, uint card_in_region) { } void G1CardSet::print_info(outputStream* st, uint card_region, uint card_in_region) { - G1CardSetHashTableValue* table_entry = get_card_set(card_region); + G1CardSetHashTableValue* table_entry = get_container(card_region); if (table_entry == nullptr) { st->print("NULL card set"); return; } - CardSetPtr card_set = table_entry->_card_set; - if (card_set == FullCardSet) { + ContainerPtr container = table_entry->_container; + if (container == FullCardSet) { st->print("FULL card set)"); return; } - switch (card_set_type(card_set)) { - case CardSetInlinePtr: { + switch (container_type(container)) { + case ContainerInlinePtr: { st->print("InlinePtr not containing %u", card_in_region); break; } - case CardSetArrayOfCards : { + case ContainerArrayOfCards: { st->print("AoC not containing %u", card_in_region); break; } - case CardSetBitMap: { + case ContainerBitMap: { st->print("BitMap not containing %u", card_in_region); break; } - case CardSetHowl: { - st->print("CardSetHowl not containing %u", card_in_region); + case ContainerHowl: { + st->print("ContainerHowl not containing %u", card_in_region); break; } - default: st->print("Unknown card set type %u", card_set_type(card_set)); ShouldNotReachHere(); break; + default: st->print("Unknown card set container type %u", container_type(container)); ShouldNotReachHere(); break; } } template -void G1CardSet::iterate_cards_during_transfer(CardSetPtr const card_set, CardVisitor& cl) { - uint type = card_set_type(card_set); - assert(type == CardSetInlinePtr || type == CardSetArrayOfCards, +void G1CardSet::iterate_cards_during_transfer(ContainerPtr const container, CardVisitor& cl) { + uint type = container_type(container); + assert(type == ContainerInlinePtr || type == ContainerArrayOfCards, "invalid card set type %d to transfer from", - card_set_type(card_set)); + container_type(container)); switch (type) { - case CardSetInlinePtr: { - G1CardSetInlinePtr ptr(card_set); + case ContainerInlinePtr: { + G1CardSetInlinePtr ptr(container); ptr.iterate(cl, _config->inline_ptr_bits_per_card()); return; } - case CardSetArrayOfCards : { - card_set_ptr(card_set)->iterate(cl); + case ContainerArrayOfCards: { + container_ptr(container)->iterate(cl); return; } default: @@ -813,7 +810,7 @@ void G1CardSet::iterate_cards_during_transfer(CardSetPtr const card_set, CardVis } } -void G1CardSet::iterate_containers(CardSetPtrClosure* cl, bool at_safepoint) { +void G1CardSet::iterate_containers(ContainerPtrClosure* cl, bool at_safepoint) { if (at_safepoint) { _table->iterate_safepoint(cl); } else { @@ -844,7 +841,7 @@ public: }; template class CardOrRanges> -class G1CardSetContainersClosure : public G1CardSet::CardSetPtrClosure { +class G1CardSetContainersClosure : public G1CardSet::ContainerPtrClosure { G1CardSet* _card_set; Closure& _cl; @@ -855,9 +852,9 @@ public: _card_set(card_set), _cl(cl) { } - void do_cardsetptr(uint region_idx, size_t num_occupied, G1CardSet::CardSetPtr card_set) override { + void do_containerptr(uint region_idx, size_t num_occupied, G1CardSet::ContainerPtr container) override { CardOrRanges cl(_cl, region_idx); - _card_set->iterate_cards_or_ranges_in_container(card_set, cl); + _card_set->iterate_cards_or_ranges_in_container(container, cl); } }; @@ -879,13 +876,13 @@ size_t G1CardSet::occupied() const { } size_t G1CardSet::num_containers() { - class GetNumberOfContainers : public CardSetPtrClosure { + class GetNumberOfContainers : public ContainerPtrClosure { public: size_t _count; - GetNumberOfContainers() : CardSetPtrClosure(), _count(0) { } + GetNumberOfContainers() : ContainerPtrClosure(), _count(0) { } - void do_cardsetptr(uint region_idx, size_t num_occupied, CardSetPtr card_set) override { + void do_containerptr(uint region_idx, size_t num_occupied, ContainerPtr container) override { _count++; } } cl; diff --git a/src/hotspot/share/gc/g1/g1CardSet.hpp b/src/hotspot/share/gc/g1/g1CardSet.hpp index 465984d7138..946d8cb7338 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.hpp @@ -26,10 +26,7 @@ #define SHARE_GC_G1_G1CARDSET_HPP #include "memory/allocation.hpp" -#include "memory/padded.hpp" -#include "oops/oopsHierarchy.hpp" #include "utilities/concurrentHashTable.hpp" -#include "utilities/lockFreeStack.hpp" class G1CardSetAllocOptions; class G1CardSetHashTable; @@ -147,10 +144,10 @@ public: class G1CardSetCoarsenStats { public: // Number of entries in the statistics tables: since we index with the source - // cardset of the coarsening, this is the total number of combinations of - // card sets - 1. + // container of the coarsening, this is the total number of combinations of + // card set containers - 1. static constexpr size_t NumCoarsenCategories = 7; - // Coarsening statistics for the possible CardSetPtr in the Howl card set + // Coarsening statistics for the possible ContainerPtr in the Howl card set // start from this offset. static constexpr size_t CoarsenHowlOffset = 4; @@ -173,14 +170,14 @@ public: void print_on(outputStream* out); }; -// Sparse set of card indexes comprising a remembered set on the Java heap. Card +// Set of card indexes comprising a remembered set on the Java heap. Card // size is assumed to be card table card size. // // Technically it is implemented using a ConcurrentHashTable that stores a card // set container for every region containing at least one card. // // There are in total five different containers, encoded in the ConcurrentHashTable -// node as CardSetPtr. A CardSetPtr may cover the whole region or just a part of +// node as ContainerPtr. A ContainerPtr may cover the whole region or just a part of // it. // See its description below for more information. class G1CardSet : public CHeapObj { @@ -194,46 +191,46 @@ class G1CardSet : public CHeapObj { static G1CardSetCoarsenStats _coarsen_stats; // Coarsening statistics since VM start. static G1CardSetCoarsenStats _last_coarsen_stats; // Coarsening statistics at last GC. public: - // Two lower bits are used to encode the card storage types - static const uintptr_t CardSetPtrHeaderSize = 2; + // Two lower bits are used to encode the card set container types + static const uintptr_t ContainerPtrHeaderSize = 2; - // CardSetPtr represents the card storage type of a given covered area. It encodes - // a type in the LSBs, in addition to having a few significant values. + // ContainerPtr represents the card set container type of a given covered area. + // It encodes a type in the LSBs, in addition to having a few significant values. // // Possible encodings: // // 0...00000 free (Empty, should never happen) - // 1...11111 full All card indexes in the whole area this CardSetPtr covers are part of this container. - // X...XXX00 inline-ptr-cards A handful of card indexes covered by this CardSetPtr are encoded within the CardSetPtr. + // 1...11111 full All card indexes in the whole area this ContainerPtr covers are part of this container. + // X...XXX00 inline-ptr-cards A handful of card indexes covered by this ContainerPtr are encoded within the ContainerPtr. // X...XXX01 array of cards The container is a contiguous array of card indexes. // X...XXX10 bitmap The container uses a bitmap to determine whether a given index is part of this set. - // X...XXX11 howl This is a card set container containing an array of CardSetPtr, with each CardSetPtr + // X...XXX11 howl This is a card set container containing an array of ContainerPtr, with each ContainerPtr // limited to a sub-range of the original range. Currently only one level of this // container is supported. - typedef void* CardSetPtr; + using ContainerPtr = void*; // Coarsening happens in the order below: - // CardSetInlinePtr -> CardSetArrayOfCards -> CardSetHowl -> Full - // Corsening of containers inside the CardSetHowl happens in the order: - // CardSetInlinePtr -> CardSetArrayOfCards -> CardSetBitMap -> Full - static const uintptr_t CardSetInlinePtr = 0x0; - static const uintptr_t CardSetArrayOfCards = 0x1; - static const uintptr_t CardSetBitMap = 0x2; - static const uintptr_t CardSetHowl = 0x3; + // ContainerInlinePtr -> ContainerArrayOfCards -> ContainerHowl -> Full + // Corsening of containers inside the ContainerHowl happens in the order: + // ContainerInlinePtr -> ContainerArrayOfCards -> ContainerBitMap -> Full + static const uintptr_t ContainerInlinePtr = 0x0; + static const uintptr_t ContainerArrayOfCards = 0x1; + static const uintptr_t ContainerBitMap = 0x2; + static const uintptr_t ContainerHowl = 0x3; // The special sentinel values - static constexpr CardSetPtr FreeCardSet = nullptr; - // Unfortunately we can't make (G1CardSet::CardSetPtr)-1 constexpr because + static constexpr ContainerPtr FreeCardSet = nullptr; + // Unfortunately we can't make (G1CardSet::ContainerPtr)-1 constexpr because // reinterpret_casts are forbidden in constexprs. Use a regular static instead. - static CardSetPtr FullCardSet; + static ContainerPtr FullCardSet; - static const uintptr_t CardSetPtrTypeMask = ((uintptr_t)1 << CardSetPtrHeaderSize) - 1; + static const uintptr_t ContainerPtrTypeMask = ((uintptr_t)1 << ContainerPtrHeaderSize) - 1; - static CardSetPtr strip_card_set_type(CardSetPtr ptr) { return (CardSetPtr)((uintptr_t)ptr & ~CardSetPtrTypeMask); } + static ContainerPtr strip_container_type(ContainerPtr ptr) { return (ContainerPtr)((uintptr_t)ptr & ~ContainerPtrTypeMask); } - static uint card_set_type(CardSetPtr ptr) { return (uintptr_t)ptr & CardSetPtrTypeMask; } + static uint container_type(ContainerPtr ptr) { return (uintptr_t)ptr & ContainerPtrTypeMask; } template - static T* card_set_ptr(CardSetPtr ptr); + static T* container_ptr(ContainerPtr ptr); private: G1CardSetMemoryManager* _mm; @@ -245,42 +242,42 @@ private: // be (slightly) more cards in the card set than this value in reality. size_t _num_occupied; - CardSetPtr make_card_set_ptr(void* value, uintptr_t type); + ContainerPtr make_container_ptr(void* value, uintptr_t type); - CardSetPtr acquire_card_set(CardSetPtr volatile* card_set_addr); - // Returns true if the card set should be released - bool release_card_set(CardSetPtr card_set); + ContainerPtr acquire_container(ContainerPtr volatile* container_addr); + // Returns true if the card set container should be released + bool release_container(ContainerPtr container); // Release card set and free if needed. - void release_and_maybe_free_card_set(CardSetPtr card_set); + void release_and_maybe_free_container(ContainerPtr container); // Release card set and free (and it must be freeable). - void release_and_must_free_card_set(CardSetPtr card_set); + void release_and_must_free_container(ContainerPtr container); - // Coarsens the CardSet cur_card_set to the next level; tries to replace the - // previous CardSet with a new one which includes the given card_in_region. - // coarsen_card_set does not transfer cards from cur_card_set - // to the new card_set. Transfer is achieved by transfer_cards. - // Returns true if this was the thread that coarsened the CardSet (and added the card). - bool coarsen_card_set(CardSetPtr volatile* card_set_addr, - CardSetPtr cur_card_set, - uint card_in_region, bool within_howl = false); + // Coarsens the card set container cur_container to the next level; tries to replace the + // previous ContainerPtr with a new one which includes the given card_in_region. + // coarsen_container does not transfer cards from cur_container + // to the new container. Transfer is achieved by transfer_cards. + // Returns true if this was the thread that coarsened the container (and added the card). + bool coarsen_container(ContainerPtr volatile* container_addr, + ContainerPtr cur_container, + uint card_in_region, bool within_howl = false); - CardSetPtr create_coarsened_array_of_cards(uint card_in_region, bool within_howl); + ContainerPtr create_coarsened_array_of_cards(uint card_in_region, bool within_howl); // Transfer entries from source_card_set to a recently installed coarser storage type - // We only need to transfer anything finer than CardSetBitMap. "Full" contains + // We only need to transfer anything finer than ContainerBitMap. "Full" contains // all elements anyway. - void transfer_cards(G1CardSetHashTableValue* table_entry, CardSetPtr source_card_set, uint card_region); - void transfer_cards_in_howl(CardSetPtr parent_card_set, CardSetPtr source_card_set, uint card_region); + void transfer_cards(G1CardSetHashTableValue* table_entry, ContainerPtr source_container, uint card_region); + void transfer_cards_in_howl(ContainerPtr parent_container, ContainerPtr source_container, uint card_region); - G1AddCardResult add_to_card_set(CardSetPtr volatile* card_set_addr, CardSetPtr card_set, uint card_region, uint card, bool increment_total = true); + G1AddCardResult add_to_container(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_region, uint card, bool increment_total = true); - G1AddCardResult add_to_inline_ptr(CardSetPtr volatile* card_set_addr, CardSetPtr card_set, uint card_in_region); - G1AddCardResult add_to_array(CardSetPtr card_set, uint card_in_region); - G1AddCardResult add_to_bitmap(CardSetPtr card_set, uint card_in_region); - G1AddCardResult add_to_howl(CardSetPtr parent_card_set, uint card_region, uint card_in_region, bool increment_total = true); + G1AddCardResult add_to_inline_ptr(ContainerPtr volatile* container_addr, ContainerPtr container, uint card_in_region); + G1AddCardResult add_to_array(ContainerPtr container, uint card_in_region); + G1AddCardResult add_to_bitmap(ContainerPtr container, uint card_in_region); + G1AddCardResult add_to_howl(ContainerPtr parent_container, uint card_region, uint card_in_region, bool increment_total = true); - G1CardSetHashTableValue* get_or_add_card_set(uint card_region, bool* should_grow_table); - G1CardSetHashTableValue* get_card_set(uint card_region); + G1CardSetHashTableValue* get_or_add_container(uint card_region, bool* should_grow_table); + G1CardSetHashTableValue* get_container(uint card_region); // Iterate over cards of a card set container during transfer of the cards from // one container to another. Executes @@ -289,11 +286,11 @@ private: // // on the given class. template - void iterate_cards_during_transfer(CardSetPtr const card_set, CardVisitor& vl); + void iterate_cards_during_transfer(ContainerPtr const container, CardVisitor& vl); - uint card_set_type_to_mem_object_type(uintptr_t type) const; + uint container_type_to_mem_object_type(uintptr_t type) const; uint8_t* allocate_mem_object(uintptr_t type); - void free_mem_object(CardSetPtr card_set); + void free_mem_object(ContainerPtr container); public: G1CardSetConfiguration* config() const { return _config; } @@ -302,8 +299,8 @@ public: G1CardSet(G1CardSetConfiguration* config, G1CardSetMemoryManager* mm); virtual ~G1CardSet(); - // Adds the given card to this set, returning an appropriate result. If added, - // updates the total count. + // Adds the given card to this set, returning an appropriate result. + // If incremental_count is true and the card has been added, updates the total count. G1AddCardResult add_card(uint card_region, uint card_in_region, bool increment_total = true); bool contains_card(uint card_region, uint card_in_region); @@ -351,14 +348,14 @@ public: // start_iterate(). // template - void iterate_cards_or_ranges_in_container(CardSetPtr const card_set, CardOrRangeVisitor& cl); + void iterate_cards_or_ranges_in_container(ContainerPtr const container, CardOrRangeVisitor& cl); - class CardSetPtrClosure { + class ContainerPtrClosure { public: - virtual void do_cardsetptr(uint region_idx, size_t num_occupied, CardSetPtr card_set) = 0; + virtual void do_containerptr(uint region_idx, size_t num_occupied, ContainerPtr container) = 0; }; - void iterate_containers(CardSetPtrClosure* cl, bool safepoint = false); + void iterate_containers(ContainerPtrClosure* cl, bool safepoint = false); class CardClosure { public: @@ -370,13 +367,13 @@ public: class G1CardSetHashTableValue { public: - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; const uint _region_idx; uint volatile _num_occupied; - CardSetPtr volatile _card_set; + ContainerPtr volatile _container; - G1CardSetHashTableValue(uint region_idx, CardSetPtr card_set) : _region_idx(region_idx), _num_occupied(0), _card_set(card_set) { } + G1CardSetHashTableValue(uint region_idx, ContainerPtr container) : _region_idx(region_idx), _num_occupied(0), _container(container) { } }; class G1CardSetHashTableConfig : public StackObj { @@ -391,6 +388,6 @@ public: static void free_node(void* context, void* memory, Value const& value); }; -typedef ConcurrentHashTable CardSetHash; +using CardSetHash = ConcurrentHashTable; #endif // SHARE_GC_G1_G1CARDSET_HPP diff --git a/src/hotspot/share/gc/g1/g1CardSet.inline.hpp b/src/hotspot/share/gc/g1/g1CardSet.inline.hpp index 99938b4b74e..49d7928735a 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSet.inline.hpp @@ -28,55 +28,54 @@ #include "gc/g1/g1CardSet.hpp" #include "gc/g1/g1CardSetContainers.inline.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" -#include "runtime/atomic.hpp" #include "logging/log.hpp" template -inline T* G1CardSet::card_set_ptr(CardSetPtr ptr) { - return (T*)strip_card_set_type(ptr); +inline T* G1CardSet::container_ptr(ContainerPtr ptr) { + return (T*)strip_container_type(ptr); } -inline G1CardSet::CardSetPtr G1CardSet::make_card_set_ptr(void* value, uintptr_t type) { - assert(card_set_type(value) == 0, "Given ptr " PTR_FORMAT " already has type bits set", p2i(value)); - return (CardSetPtr)((uintptr_t)value | type); +inline G1CardSet::ContainerPtr G1CardSet::make_container_ptr(void* value, uintptr_t type) { + assert(container_type(value) == 0, "Given ptr " PTR_FORMAT " already has type bits set", p2i(value)); + return (ContainerPtr)((uintptr_t)value | type); } template -inline void G1CardSet::iterate_cards_or_ranges_in_container(CardSetPtr const card_set, CardOrRangeVisitor& cl) { - switch (card_set_type(card_set)) { - case CardSetInlinePtr: { +inline void G1CardSet::iterate_cards_or_ranges_in_container(ContainerPtr const container, CardOrRangeVisitor& cl) { + switch (container_type(container)) { + case ContainerInlinePtr: { if (cl.start_iterate(G1GCPhaseTimes::MergeRSMergedInline)) { - G1CardSetInlinePtr ptr(card_set); + G1CardSetInlinePtr ptr(container); ptr.iterate(cl, _config->inline_ptr_bits_per_card()); } return; } - case CardSetArrayOfCards : { + case ContainerArrayOfCards: { if (cl.start_iterate(G1GCPhaseTimes::MergeRSMergedArrayOfCards)) { - card_set_ptr(card_set)->iterate(cl); + container_ptr(container)->iterate(cl); } return; } - case CardSetBitMap: { + case ContainerBitMap: { // There is no first-level bitmap spanning the whole area. ShouldNotReachHere(); return; } - case CardSetHowl: { - assert(card_set_type(FullCardSet) == CardSetHowl, "Must be"); - if (card_set == FullCardSet) { + case ContainerHowl: { + assert(container_type(FullCardSet) == ContainerHowl, "Must be"); + if (container == FullCardSet) { if (cl.start_iterate(G1GCPhaseTimes::MergeRSMergedFull)) { cl(0, _config->max_cards_in_region()); } return; } if (cl.start_iterate(G1GCPhaseTimes::MergeRSMergedHowl)) { - card_set_ptr(card_set)->iterate(cl, _config); + container_ptr(container)->iterate(cl, _config); } return; } } - log_error(gc)("Unkown card set type %u", card_set_type(card_set)); + log_error(gc)("Unkown card set container type %u", container_type(container)); ShouldNotReachHere(); } diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp index 6736a18ab02..453594da3f9 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.hpp @@ -31,7 +31,7 @@ #include "utilities/bitMap.hpp" #include "utilities/globalDefinitions.hpp" -// A helper class to encode a few card indexes within a CardSetPtr. +// A helper class to encode a few card indexes within a ContainerPtr. // // The pointer value (either 32 or 64 bits) is split into two areas: // @@ -65,16 +65,16 @@ class G1CardSetInlinePtr : public StackObj { friend class G1CardSetContainersTest; - typedef G1CardSet::CardSetPtr CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; - CardSetPtr volatile * _value_addr; - CardSetPtr _value; + ContainerPtr volatile * _value_addr; + ContainerPtr _value; static const uint SizeFieldLen = 3; static const uint SizeFieldPos = 2; - static const uint HeaderSize = G1CardSet::CardSetPtrHeaderSize + SizeFieldLen; + static const uint HeaderSize = G1CardSet::ContainerPtrHeaderSize + SizeFieldLen; - static const uint BitsInValue = sizeof(CardSetPtr) * BitsPerByte; + static const uint BitsInValue = sizeof(ContainerPtr) * BitsPerByte; static const uintptr_t SizeFieldMask = (((uint)1 << SizeFieldLen) - 1) << SizeFieldPos; @@ -82,9 +82,9 @@ class G1CardSetInlinePtr : public StackObj { return (idx * bits_per_card + HeaderSize); } - static CardSetPtr merge(CardSetPtr orig_value, uint card_in_region, uint idx, uint bits_per_card); + static ContainerPtr merge(ContainerPtr orig_value, uint card_in_region, uint idx, uint bits_per_card); - static uint card_at(CardSetPtr value, uint const idx, uint const bits_per_card) { + static uint card_at(ContainerPtr value, uint const idx, uint const bits_per_card) { uint8_t card_pos = card_pos_for(idx, bits_per_card); uint result = ((uintptr_t)value >> card_pos) & (((uintptr_t)1 << bits_per_card) - 1); return result; @@ -93,14 +93,14 @@ class G1CardSetInlinePtr : public StackObj { uint find(uint const card_idx, uint const bits_per_card, uint start_at, uint num_cards); public: - G1CardSetInlinePtr() : _value_addr(nullptr), _value((CardSetPtr)G1CardSet::CardSetInlinePtr) { } + G1CardSetInlinePtr() : _value_addr(nullptr), _value((ContainerPtr)G1CardSet::ContainerInlinePtr) { } - G1CardSetInlinePtr(CardSetPtr value) : _value_addr(nullptr), _value(value) { - assert(G1CardSet::card_set_type(_value) == G1CardSet::CardSetInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInPtr.", p2i(_value)); + G1CardSetInlinePtr(ContainerPtr value) : _value_addr(nullptr), _value(value) { + assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); } - G1CardSetInlinePtr(CardSetPtr volatile* value_addr, CardSetPtr value) : _value_addr(value_addr), _value(value) { - assert(G1CardSet::card_set_type(_value) == G1CardSet::CardSetInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInPtr.", p2i(_value)); + G1CardSetInlinePtr(ContainerPtr volatile* value_addr, ContainerPtr value) : _value_addr(value_addr), _value(value) { + assert(G1CardSet::container_type(_value) == G1CardSet::ContainerInlinePtr, "Value " PTR_FORMAT " is not a valid G1CardSetInlinePtr.", p2i(_value)); } G1AddCardResult add(uint const card_idx, uint const bits_per_card, uint const max_cards_in_inline_ptr); @@ -110,13 +110,13 @@ public: template void iterate(CardVisitor& found, uint const bits_per_card); - operator CardSetPtr () { return _value; } + operator ContainerPtr () { return _value; } static uint max_cards_in_inline_ptr(uint bits_per_card) { return (BitsInValue - HeaderSize) / bits_per_card; } - static uint num_cards_in(CardSetPtr value) { + static uint num_cards_in(ContainerPtr value) { return ((uintptr_t)value & SizeFieldMask) >> SizeFieldPos; } }; @@ -139,7 +139,7 @@ public: // which requires that we increment the reference counts by 2 starting at _ref_count = 3. // // All but inline pointers are of this kind. For those, card entries are stored -// directly in the CardSetPtr of the ConcurrentHashTable node. +// directly in the ContainerPtr of the ConcurrentHashTable node. class G1CardSetContainer { uintptr_t _ref_count; protected: @@ -163,7 +163,7 @@ class G1CardSetArray : public G1CardSetContainer { public: typedef uint16_t EntryDataType; typedef uint EntryCountType; - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; private: EntryCountType _size; EntryCountType volatile _num_entries; @@ -217,7 +217,7 @@ class G1CardSetBitMap : public G1CardSetContainer { size_t _num_bits_set; BitMap::bm_word_t _bits[1]; - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; template static size_t header_size_in_bytes_internal() { @@ -252,10 +252,10 @@ public: class G1CardSetHowl : public G1CardSetContainer { public: typedef uint EntryCountType; - using CardSetPtr = G1CardSet::CardSetPtr; + using ContainerPtr = G1CardSet::ContainerPtr; EntryCountType volatile _num_entries; private: - CardSetPtr _buckets[2]; + ContainerPtr _buckets[2]; // Do not add class member variables beyond this point template @@ -263,32 +263,32 @@ private: return offset_of(Derived, _buckets); } - // Iterates over the given CardSetPtr with at index in this Howl card set, + // Iterates over the given ContainerPtr with at index in this Howl card set, // applying a CardOrRangeVisitor on it. template - void iterate_cardset(CardSetPtr const card_set, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config); + void iterate_cardset(ContainerPtr const container, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config); public: G1CardSetHowl(EntryCountType card_in_region, G1CardSetConfiguration* config); - CardSetPtr* get_card_set_addr(EntryCountType index) { + ContainerPtr* get_container_addr(EntryCountType index) { return &_buckets[index]; } bool contains(uint card_idx, G1CardSetConfiguration* config); - // Iterates over all CardSetPtrs in this Howl card set, applying a CardOrRangeVisitor + // Iterates over all ContainerPtrs in this Howl card set, applying a CardOrRangeVisitor // on it. template void iterate(CardOrRangeVisitor& found, G1CardSetConfiguration* config); - // Iterates over all CardSetPtrs in this Howl card set. Calls + // Iterates over all ContainerPtrs in this Howl card set. Calls // - // void operator ()(CardSetPtr* card_set_addr); + // void operator ()(ContainerPtr* card_set_addr); // // on all of them. - template - void iterate(CardSetPtrVisitor& found, uint num_card_sets); + template + void iterate(ContainerPtrVisitor& found, uint num_card_sets); static EntryCountType num_buckets(size_t size_in_bits, size_t num_cards_in_array, size_t max_buckets); @@ -300,7 +300,7 @@ public: static size_t header_size_in_bytes() { return header_size_in_bytes_internal(); } static size_t size_in_bytes(size_t num_arrays) { - return header_size_in_bytes() + sizeof(CardSetPtr) * num_arrays; + return header_size_in_bytes() + sizeof(ContainerPtr) * num_arrays; } }; diff --git a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp index 73d84fbf934..3949687a97c 100644 --- a/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetContainers.inline.hpp @@ -31,7 +31,7 @@ #include "utilities/globalDefinitions.hpp" #include "utilities/spinYield.hpp" -inline G1CardSetInlinePtr::CardSetPtr G1CardSetInlinePtr::merge(CardSetPtr orig_value, uint card_in_region, uint idx, uint bits_per_card) { +inline G1CardSetInlinePtr::ContainerPtr G1CardSetInlinePtr::merge(ContainerPtr orig_value, uint card_in_region, uint idx, uint bits_per_card) { assert((idx & (SizeFieldMask >> SizeFieldPos)) == idx, "Index %u too large to fit into size field", idx); assert(card_in_region < ((uint)1 << bits_per_card), "Card %u too large to fit into card value field", card_in_region); @@ -44,7 +44,7 @@ inline G1CardSetInlinePtr::CardSetPtr G1CardSetInlinePtr::merge(CardSetPtr orig_ uintptr_t value = ((uintptr_t)(idx + 1) << SizeFieldPos) | ((uintptr_t)card_in_region << card_pos); uintptr_t res = (((uintptr_t)orig_value & ~SizeFieldMask) | value); - return (CardSetPtr)res; + return (ContainerPtr)res; } inline G1AddCardResult G1CardSetInlinePtr::add(uint card_idx, uint bits_per_card, uint max_cards_in_inline_ptr) { @@ -64,8 +64,8 @@ inline G1AddCardResult G1CardSetInlinePtr::add(uint card_idx, uint bits_per_card if (num_cards >= max_cards_in_inline_ptr) { return Overflow; } - CardSetPtr new_value = merge(_value, card_idx, num_cards, bits_per_card); - CardSetPtr old_value = Atomic::cmpxchg(_value_addr, _value, new_value, memory_order_relaxed); + ContainerPtr new_value = merge(_value, card_idx, num_cards, bits_per_card); + ContainerPtr old_value = Atomic::cmpxchg(_value_addr, _value, new_value, memory_order_relaxed); if (_value == old_value) { return Added; } @@ -73,7 +73,7 @@ inline G1AddCardResult G1CardSetInlinePtr::add(uint card_idx, uint bits_per_card _value = old_value; // The value of the pointer may have changed to something different than // an inline card set. Exit then instead of overwriting. - if (G1CardSet::card_set_type(_value) != G1CardSet::CardSetInlinePtr) { + if (G1CardSet::container_type(_value) != G1CardSet::ContainerInlinePtr) { return Overflow; } } @@ -268,23 +268,23 @@ inline G1CardSetHowl::G1CardSetHowl(EntryCountType card_in_region, G1CardSetConf inline bool G1CardSetHowl::contains(uint card_idx, G1CardSetConfiguration* config) { EntryCountType bucket = config->howl_bucket_index(card_idx); - CardSetPtr* array_entry = get_card_set_addr(bucket); - CardSetPtr card_set = Atomic::load_acquire(array_entry); + ContainerPtr* array_entry = get_container_addr(bucket); + ContainerPtr container = Atomic::load_acquire(array_entry); - switch (G1CardSet::card_set_type(card_set)) { - case G1CardSet::CardSetArrayOfCards : { - return G1CardSet::card_set_ptr(card_set)->contains(card_idx); + switch (G1CardSet::container_type(container)) { + case G1CardSet::ContainerArrayOfCards: { + return G1CardSet::container_ptr(container)->contains(card_idx); } - case G1CardSet::CardSetBitMap: { + case G1CardSet::ContainerBitMap: { uint card_offset = config->howl_bitmap_offset(card_idx); - return G1CardSet::card_set_ptr(card_set)->contains(card_offset, config->max_cards_in_howl_bitmap()); + return G1CardSet::container_ptr(container)->contains(card_offset, config->max_cards_in_howl_bitmap()); } - case G1CardSet::CardSetInlinePtr: { - G1CardSetInlinePtr ptr(card_set); + case G1CardSet::ContainerInlinePtr: { + G1CardSetInlinePtr ptr(container); return ptr.contains(card_idx, config->inline_ptr_bits_per_card()); } - case G1CardSet::CardSetHowl: {// Fullcard set entry - assert(card_set == G1CardSet::FullCardSet, "Must be"); + case G1CardSet::ContainerHowl: {// Fullcard set entry + assert(container == G1CardSet::FullCardSet, "Must be"); return true; } } @@ -298,38 +298,38 @@ inline void G1CardSetHowl::iterate(CardOrRangeVisitor& found, G1CardSetConfigura } } -template -inline void G1CardSetHowl::iterate(CardSetPtrVisitor& found, uint num_card_sets) { +template +inline void G1CardSetHowl::iterate(ContainerPtrVisitor& found, uint num_card_sets) { for (uint i = 0; i < num_card_sets; ++i) { found(&_buckets[i]); } } template -inline void G1CardSetHowl::iterate_cardset(CardSetPtr const card_set, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config) { - switch (G1CardSet::card_set_type(card_set)) { - case G1CardSet::CardSetInlinePtr: { +inline void G1CardSetHowl::iterate_cardset(ContainerPtr const container, uint index, CardOrRangeVisitor& found, G1CardSetConfiguration* config) { + switch (G1CardSet::container_type(container)) { + case G1CardSet::ContainerInlinePtr: { if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlInline)) { - G1CardSetInlinePtr ptr(card_set); + G1CardSetInlinePtr ptr(container); ptr.iterate(found, config->inline_ptr_bits_per_card()); } return; } - case G1CardSet::CardSetArrayOfCards : { + case G1CardSet::ContainerArrayOfCards: { if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlArrayOfCards)) { - G1CardSet::card_set_ptr(card_set)->iterate(found); + G1CardSet::container_ptr(container)->iterate(found); } return; } - case G1CardSet::CardSetBitMap: { + case G1CardSet::ContainerBitMap: { if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlBitmap)) { uint offset = index << config->log2_max_cards_in_howl_bitmap(); - G1CardSet::card_set_ptr(card_set)->iterate(found, config->max_cards_in_howl_bitmap(), offset); + G1CardSet::container_ptr(container)->iterate(found, config->max_cards_in_howl_bitmap(), offset); } return; } - case G1CardSet::CardSetHowl: { // actually FullCardSet - assert(card_set == G1CardSet::FullCardSet, "Must be"); + case G1CardSet::ContainerHowl: { // actually FullCardSet + assert(container == G1CardSet::FullCardSet, "Must be"); if (found.start_iterate(G1GCPhaseTimes::MergeRSHowlFull)) { uint offset = index << config->log2_max_cards_in_howl_bitmap(); found(offset, config->max_cards_in_howl_bitmap()); diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp b/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp index 4bb8e6c4ff9..a0e920175e1 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.inline.hpp @@ -78,7 +78,7 @@ public: }; template class CardOrRanges> -class G1HeapRegionRemSetMergeCardClosure : public G1CardSet::CardSetPtrClosure { +class G1HeapRegionRemSetMergeCardClosure : public G1CardSet::ContainerPtrClosure { G1CardSet* _card_set; Closure& _cl; uint _log_card_regions_per_region; @@ -98,11 +98,11 @@ public: _log_card_region_size(log_card_region_size) { } - void do_cardsetptr(uint card_region_idx, size_t num_occupied, G1CardSet::CardSetPtr card_set) override { + void do_containerptr(uint card_region_idx, size_t num_occupied, G1CardSet::ContainerPtr container) override { CardOrRanges cl(_cl, card_region_idx >> _log_card_regions_per_region, (card_region_idx & _card_regions_per_region_mask) << _log_card_region_size); - _card_set->iterate_cards_or_ranges_in_container(card_set, cl); + _card_set->iterate_cards_or_ranges_in_container(container, cl); } }; diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp index 914c64aacc5..004fd71cb2f 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSet.cpp @@ -165,13 +165,13 @@ void G1CardSetTest::translate_cards(uint cards_per_region, uint region_idx, uint } } -class G1CountCardsOccupied : public G1CardSet::CardSetPtrClosure { +class G1CountCardsOccupied : public G1CardSet::ContainerPtrClosure { size_t _num_occupied; public: G1CountCardsOccupied() : _num_occupied(0) { } - void do_cardsetptr(uint region_idx, size_t num_occupied, G1CardSet::CardSetPtr card_set) override { + void do_containerptr(uint region_idx, size_t num_occupied, G1CardSet::ContainerPtr container) override { _num_occupied += num_occupied; } diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp index 9283fc3303f..0ad3aed18cc 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp @@ -83,7 +83,7 @@ void G1CardSetContainersTest::cardset_inlineptr_test(uint bits_per_card) { G1AddCardResult res; - G1CardSet::CardSetPtr value = G1CardSetInlinePtr(); + G1CardSet::ContainerPtr value = G1CardSetInlinePtr(); for (uint i = 0; i < CardsPerSet; i++) { { -- GitLab From 096bca4a9c5e8ac2668dd965df92153ea1d80add Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 17 Mar 2022 09:10:08 +0000 Subject: [PATCH 064/237] 8282473: Refactor swing classes javadoc to use @throws instead of @exception Reviewed-by: aivanov, dmarkov, prr --- .../classes/javax/swing/AbstractButton.java | 18 ++--- .../javax/swing/AbstractListModel.java | 2 +- .../classes/javax/swing/BorderFactory.java | 2 +- .../share/classes/javax/swing/BoxLayout.java | 16 ++--- .../javax/swing/DefaultBoundedRangeModel.java | 2 +- .../javax/swing/DefaultButtonModel.java | 2 +- .../classes/javax/swing/DefaultListModel.java | 2 +- .../swing/DefaultListSelectionModel.java | 4 +- .../swing/DefaultSingleSelectionModel.java | 2 +- .../share/classes/javax/swing/JApplet.java | 12 ++-- .../classes/javax/swing/JColorChooser.java | 12 ++-- .../share/classes/javax/swing/JComboBox.java | 6 +- .../share/classes/javax/swing/JComponent.java | 8 +-- .../classes/javax/swing/JEditorPane.java | 12 ++-- .../classes/javax/swing/JFileChooser.java | 14 ++-- .../share/classes/javax/swing/JFrame.java | 20 +++--- .../classes/javax/swing/JInternalFrame.java | 18 ++--- .../share/classes/javax/swing/JLabel.java | 8 +-- .../share/classes/javax/swing/JLayer.java | 2 +- .../share/classes/javax/swing/JList.java | 10 +-- .../share/classes/javax/swing/JMenu.java | 26 ++++---- .../classes/javax/swing/JOptionPane.java | 40 +++++------ .../classes/javax/swing/JPasswordField.java | 2 +- .../share/classes/javax/swing/JPopupMenu.java | 6 +- .../classes/javax/swing/JProgressBar.java | 2 +- .../share/classes/javax/swing/JRootPane.java | 6 +- .../share/classes/javax/swing/JScrollBar.java | 4 +- .../classes/javax/swing/JScrollPane.java | 8 +-- .../share/classes/javax/swing/JSeparator.java | 4 +- .../share/classes/javax/swing/JSlider.java | 2 +- .../share/classes/javax/swing/JSpinner.java | 14 ++-- .../share/classes/javax/swing/JSplitPane.java | 16 ++--- .../classes/javax/swing/JTabbedPane.java | 66 +++++++++---------- .../share/classes/javax/swing/JTable.java | 26 ++++---- .../share/classes/javax/swing/JTextArea.java | 22 +++---- .../share/classes/javax/swing/JTextField.java | 6 +- .../share/classes/javax/swing/JTextPane.java | 4 +- .../share/classes/javax/swing/JToolBar.java | 4 +- .../share/classes/javax/swing/JTree.java | 6 +- .../share/classes/javax/swing/JViewport.java | 2 +- .../share/classes/javax/swing/JWindow.java | 10 +-- .../classes/javax/swing/OverlayLayout.java | 2 +- .../share/classes/javax/swing/Popup.java | 2 +- .../classes/javax/swing/PopupFactory.java | 4 +- .../classes/javax/swing/ProgressMonitor.java | 2 +- .../javax/swing/RootPaneContainer.java | 4 +- .../classes/javax/swing/ScrollPaneLayout.java | 6 +- .../classes/javax/swing/SizeSequence.java | 4 +- .../classes/javax/swing/SwingUtilities.java | 8 +-- .../share/classes/javax/swing/Timer.java | 2 +- .../classes/javax/swing/TransferHandler.java | 4 +- .../AbstractColorChooserPanel.java | 2 +- .../javax/swing/event/EventListenerList.java | 2 +- .../classes/javax/swing/plaf/TextUI.java | 10 +-- .../javax/swing/plaf/basic/BasicHTML.java | 4 +- .../swing/plaf/basic/BasicTabbedPaneUI.java | 2 +- .../swing/plaf/basic/BasicTextFieldUI.java | 6 +- .../javax/swing/plaf/basic/BasicTextUI.java | 12 ++-- .../swing/plaf/basic/BasicTransferable.java | 4 +- .../javax/swing/table/AbstractTableModel.java | 2 +- .../swing/table/DefaultTableColumnModel.java | 10 +-- .../javax/swing/table/DefaultTableModel.java | 12 ++-- .../javax/swing/table/JTableHeader.java | 2 +- .../javax/swing/table/TableColumnModel.java | 4 +- .../javax/swing/text/AbstractDocument.java | 34 +++++----- .../javax/swing/text/AbstractWriter.java | 14 ++-- .../javax/swing/text/AsyncBoxView.java | 14 ++-- .../classes/javax/swing/text/BoxView.java | 14 ++-- .../javax/swing/text/ComponentView.java | 8 +-- .../javax/swing/text/CompositeView.java | 18 ++--- .../javax/swing/text/DefaultCaret.java | 2 +- .../javax/swing/text/DefaultEditorKit.java | 16 ++--- .../javax/swing/text/DefaultHighlighter.java | 4 +- .../swing/text/DefaultStyledDocument.java | 10 +-- .../classes/javax/swing/text/Document.java | 10 +-- .../javax/swing/text/DocumentFilter.java | 12 ++-- .../classes/javax/swing/text/EditorKit.java | 16 ++--- .../classes/javax/swing/text/FieldView.java | 2 +- .../classes/javax/swing/text/GapContent.java | 10 +-- .../javax/swing/text/GlyphPainter2.java | 4 +- .../classes/javax/swing/text/GlyphView.java | 12 ++-- .../classes/javax/swing/text/Highlighter.java | 4 +- .../classes/javax/swing/text/IconView.java | 4 +- .../javax/swing/text/JTextComponent.java | 24 +++---- .../javax/swing/text/NavigationFilter.java | 4 +- .../javax/swing/text/ParagraphView.java | 2 +- .../javax/swing/text/PasswordView.java | 6 +- .../javax/swing/text/PlainDocument.java | 2 +- .../classes/javax/swing/text/PlainView.java | 12 ++-- .../javax/swing/text/StringContent.java | 10 +-- .../javax/swing/text/StyleContext.java | 14 ++-- .../javax/swing/text/StyledEditorKit.java | 4 +- .../classes/javax/swing/text/TableView.java | 2 +- .../classes/javax/swing/text/Utilities.java | 24 +++---- .../share/classes/javax/swing/text/View.java | 14 ++-- .../javax/swing/text/WrappedPlainView.java | 10 +-- .../classes/javax/swing/text/ZoneView.java | 4 +- .../javax/swing/text/html/AccessibleHTML.java | 2 +- .../javax/swing/text/html/BlockView.java | 8 +-- .../javax/swing/text/html/FormView.java | 2 +- .../javax/swing/text/html/HRuleView.java | 2 +- .../javax/swing/text/html/HTMLDocument.java | 2 +- .../javax/swing/text/html/HTMLEditorKit.java | 12 ++-- .../javax/swing/text/html/HTMLWriter.java | 36 +++++----- .../javax/swing/text/html/ImageView.java | 2 +- .../swing/text/html/MinimalHTMLWriter.java | 42 ++++++------ .../swing/text/html/OptionListModel.java | 2 +- .../javax/swing/text/html/StyleSheet.java | 2 +- .../javax/swing/text/html/TableView.java | 2 +- .../javax/swing/text/rtf/RTFEditorKit.java | 16 ++--- .../swing/tree/DefaultMutableTreeNode.java | 28 ++++---- .../javax/swing/tree/DefaultTreeModel.java | 2 +- .../swing/tree/DefaultTreeSelectionModel.java | 4 +- .../swing/undo/AbstractUndoableEdit.java | 4 +- 114 files changed, 533 insertions(+), 533 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/AbstractButton.java b/src/java.desktop/share/classes/javax/swing/AbstractButton.java index 8a2936cd499..4f79ac8e2b3 100644 --- a/src/java.desktop/share/classes/javax/swing/AbstractButton.java +++ b/src/java.desktop/share/classes/javax/swing/AbstractButton.java @@ -876,7 +876,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl *
  • {@code SwingConstants.LEADING} *
  • {@code SwingConstants.TRAILING} (the default) *
- * @exception IllegalArgumentException if textPosition + * @throws IllegalArgumentException if textPosition * is not one of the legal values listed above */ @BeanProperty(visualUpdate = true, enumerationValues = { @@ -953,7 +953,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * {@code IllegalArgumentException} that is thrown for an invalid * value * @return the {@code key} argument - * @exception IllegalArgumentException if key is not one of the legal + * @throws IllegalArgumentException if key is not one of the legal * values listed above * @see #setHorizontalTextPosition * @see #setHorizontalAlignment @@ -984,7 +984,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * {@code IllegalArgumentException} that is thrown for an invalid * value * @return the {@code key} argument - * @exception IllegalArgumentException if key is not one of the legal + * @throws IllegalArgumentException if key is not one of the legal * values listed above */ protected int checkVerticalKey(int key, String exception) { @@ -1571,7 +1571,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * * @since 1.4 * @param index Index into the String to underline - * @exception IllegalArgumentException will be thrown if index + * @throws IllegalArgumentException will be thrown if index * is >= length of the text, or < -1 * @see #getDisplayedMnemonicIndex */ @@ -1654,7 +1654,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * @see #getMultiClickThreshhold * @param threshhold the amount of time required between mouse * press events to generate corresponding action events - * @exception IllegalArgumentException if threshhold < 0 + * @throws IllegalArgumentException if threshhold < 0 * @since 1.4 */ public void setMultiClickThreshhold(long threshhold) { @@ -1791,10 +1791,10 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * @param index the position in the container's list at which to * insert the component, where -1 * means append to the end - * @exception IllegalArgumentException if index is invalid - * @exception IllegalArgumentException if adding the container's parent + * @throws IllegalArgumentException if index is invalid + * @throws IllegalArgumentException if adding the container's parent * to itself - * @exception IllegalArgumentException if adding a window to a container + * @throws IllegalArgumentException if adding a window to a container * @since 1.5 */ protected void addImpl(Component comp, Object constraints, int index) { @@ -3064,7 +3064,7 @@ public abstract class AbstractButton extends JComponent implements ItemSelectabl * * @param i zero-based index of the key bindings * @return a javax.lang.Object which specifies the key binding - * @exception IllegalArgumentException if the index is + * @throws IllegalArgumentException if the index is * out of bounds * @see #getAccessibleKeyBindingCount */ diff --git a/src/java.desktop/share/classes/javax/swing/AbstractListModel.java b/src/java.desktop/share/classes/javax/swing/AbstractListModel.java index 0396c956597..815fbea8407 100644 --- a/src/java.desktop/share/classes/javax/swing/AbstractListModel.java +++ b/src/java.desktop/share/classes/javax/swing/AbstractListModel.java @@ -218,7 +218,7 @@ public abstract class AbstractListModel implements ListModel, Serializable * on this model, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType doesn't + * @throws ClassCastException if listenerType doesn't * specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/BorderFactory.java b/src/java.desktop/share/classes/javax/swing/BorderFactory.java index 3fcb5620e69..2e4b18848a2 100644 --- a/src/java.desktop/share/classes/javax/swing/BorderFactory.java +++ b/src/java.desktop/share/classes/javax/swing/BorderFactory.java @@ -332,7 +332,7 @@ public class BorderFactory * @param type one of EtchedBorder.RAISED, or * EtchedBorder.LOWERED * @return the Border object - * @exception IllegalArgumentException if type is not either + * @throws IllegalArgumentException if type is not either * EtchedBorder.RAISED or * EtchedBorder.LOWERED * @since 1.3 diff --git a/src/java.desktop/share/classes/javax/swing/BoxLayout.java b/src/java.desktop/share/classes/javax/swing/BoxLayout.java index bc84a4fa582..d20a05ce4ef 100644 --- a/src/java.desktop/share/classes/javax/swing/BoxLayout.java +++ b/src/java.desktop/share/classes/javax/swing/BoxLayout.java @@ -169,7 +169,7 @@ public class BoxLayout implements LayoutManager2, Serializable { * {@code BoxLayout.X_AXIS, BoxLayout.Y_AXIS, * BoxLayout.LINE_AXIS} or {@code BoxLayout.PAGE_AXIS} * - * @exception AWTError if the value of {@code axis} is invalid + * @throws AWTError if the value of {@code axis} is invalid */ @ConstructorProperties({"target", "axis"}) public BoxLayout(Container target, int axis) { @@ -234,7 +234,7 @@ public class BoxLayout implements LayoutManager2, Serializable { * * @param target the affected container * - * @exception AWTError if the target isn't the container specified to the + * @throws AWTError if the target isn't the container specified to the * BoxLayout constructor */ public synchronized void invalidateLayout(Container target) { @@ -280,7 +280,7 @@ public class BoxLayout implements LayoutManager2, Serializable { * * @param target the container that needs to be laid out * @return the dimensions >= 0 && <= Integer.MAX_VALUE - * @exception AWTError if the target isn't the container specified to the + * @throws AWTError if the target isn't the container specified to the * BoxLayout constructor * @see Container * @see #minimumLayoutSize @@ -306,7 +306,7 @@ public class BoxLayout implements LayoutManager2, Serializable { * * @param target the container that needs to be laid out * @return the dimensions >= 0 && <= Integer.MAX_VALUE - * @exception AWTError if the target isn't the container specified to the + * @throws AWTError if the target isn't the container specified to the * BoxLayout constructor * @see #preferredLayoutSize * @see #maximumLayoutSize @@ -331,7 +331,7 @@ public class BoxLayout implements LayoutManager2, Serializable { * * @param target the container that needs to be laid out * @return the dimensions >= 0 && <= Integer.MAX_VALUE - * @exception AWTError if the target isn't the container specified to the + * @throws AWTError if the target isn't the container specified to the * BoxLayout constructor * @see #preferredLayoutSize * @see #minimumLayoutSize @@ -358,7 +358,7 @@ public class BoxLayout implements LayoutManager2, Serializable { * * @param target the container * @return the alignment >= 0.0f && <= 1.0f - * @exception AWTError if the target isn't the container specified to the + * @throws AWTError if the target isn't the container specified to the * BoxLayout constructor */ public synchronized float getLayoutAlignmentX(Container target) { @@ -375,7 +375,7 @@ public class BoxLayout implements LayoutManager2, Serializable { * * @param target the container * @return the alignment >= 0.0f && <= 1.0f - * @exception AWTError if the target isn't the container specified to the + * @throws AWTError if the target isn't the container specified to the * BoxLayout constructor */ public synchronized float getLayoutAlignmentY(Container target) { @@ -390,7 +390,7 @@ public class BoxLayout implements LayoutManager2, Serializable { * * @param target the container to lay out * - * @exception AWTError if the target isn't the container specified to the + * @throws AWTError if the target isn't the container specified to the * BoxLayout constructor */ public void layoutContainer(Container target) { diff --git a/src/java.desktop/share/classes/javax/swing/DefaultBoundedRangeModel.java b/src/java.desktop/share/classes/javax/swing/DefaultBoundedRangeModel.java index 7e254d5c8b3..e9bd3d96a6a 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultBoundedRangeModel.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultBoundedRangeModel.java @@ -417,7 +417,7 @@ public class DefaultBoundedRangeModel implements BoundedRangeModel, Serializable * on this model, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType doesn't + * @throws ClassCastException if listenerType doesn't * specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/DefaultButtonModel.java b/src/java.desktop/share/classes/javax/swing/DefaultButtonModel.java index 453b1d0ab0e..d391011167a 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultButtonModel.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultButtonModel.java @@ -488,7 +488,7 @@ public class DefaultButtonModel implements ButtonModel, Serializable { * on this model, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType doesn't + * @throws ClassCastException if listenerType doesn't * specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/DefaultListModel.java b/src/java.desktop/share/classes/javax/swing/DefaultListModel.java index 88210b77c9c..9d519927b67 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultListModel.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultListModel.java @@ -345,7 +345,7 @@ public class DefaultListModel extends AbstractListModel * * @param element the component to insert * @param index where to insert the new component - * @exception ArrayIndexOutOfBoundsException if the index was invalid + * @throws ArrayIndexOutOfBoundsException if the index was invalid * @see #add(int,Object) * @see Vector#insertElementAt(Object,int) */ diff --git a/src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java b/src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java index 55b8fbba66c..aa69c2d1ab0 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java @@ -284,7 +284,7 @@ public class DefaultListSelectionModel implements ListSelectionModel, Cloneable, * on this model, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType doesn't + * @throws ClassCastException if listenerType doesn't * specify a class or interface that implements * java.util.EventListener * @@ -750,7 +750,7 @@ public class DefaultListSelectionModel implements ListSelectionModel, Cloneable, * Returns a clone of this selection model with the same selection. * listenerLists are not duplicated. * - * @exception CloneNotSupportedException if the selection model does not + * @throws CloneNotSupportedException if the selection model does not * both (a) implement the Cloneable interface and (b) define a * clone method. */ diff --git a/src/java.desktop/share/classes/javax/swing/DefaultSingleSelectionModel.java b/src/java.desktop/share/classes/javax/swing/DefaultSingleSelectionModel.java index c5c2539d41f..122e635fba1 100644 --- a/src/java.desktop/share/classes/javax/swing/DefaultSingleSelectionModel.java +++ b/src/java.desktop/share/classes/javax/swing/DefaultSingleSelectionModel.java @@ -178,7 +178,7 @@ Serializable { * on this model, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType doesn't + * @throws ClassCastException if listenerType doesn't * specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/JApplet.java b/src/java.desktop/share/classes/javax/swing/JApplet.java index a1d51bf0069..e5ad62322e6 100644 --- a/src/java.desktop/share/classes/javax/swing/JApplet.java +++ b/src/java.desktop/share/classes/javax/swing/JApplet.java @@ -135,7 +135,7 @@ public class JApplet extends Applet implements Accessible, * This constructor sets the component's locale property to the value * returned by JComponent.getDefaultLocale. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @see JComponent#getDefaultLocale @@ -312,10 +312,10 @@ public class JApplet extends Applet implements Accessible, * @param comp the component to be enhanced * @param constraints the constraints to be respected * @param index the index - * @exception IllegalArgumentException if index is invalid - * @exception IllegalArgumentException if adding the container's parent + * @throws IllegalArgumentException if index is invalid + * @throws IllegalArgumentException if adding the container's parent * to itself - * @exception IllegalArgumentException if adding a window to a container + * @throws IllegalArgumentException if adding a window to a container * * @see #setRootPaneCheckingEnabled * @see javax.swing.RootPaneContainer @@ -423,7 +423,7 @@ public class JApplet extends Applet implements Accessible, * Sets the contentPane property. This method is called by the constructor. * @param contentPane the contentPane object for this applet * - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the content pane parameter is null * @see #getContentPane * @see RootPaneContainer#setContentPane @@ -437,7 +437,7 @@ public class JApplet extends Applet implements Accessible, /** * Returns the layeredPane object for this applet. * - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the layered pane parameter is null * @see #setLayeredPane * @see RootPaneContainer#getLayeredPane diff --git a/src/java.desktop/share/classes/javax/swing/JColorChooser.java b/src/java.desktop/share/classes/javax/swing/JColorChooser.java index 29bf7009b4f..945c6f60697 100644 --- a/src/java.desktop/share/classes/javax/swing/JColorChooser.java +++ b/src/java.desktop/share/classes/javax/swing/JColorChooser.java @@ -150,7 +150,7 @@ public class JColorChooser extends JComponent implements Accessible { * @param title the String containing the dialog's title * @param initialColor the initial Color set when the color-chooser is shown * @return the selected color or null if the user opted out - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -173,7 +173,7 @@ public class JColorChooser extends JComponent implements Accessible { * @param colorTransparencySelectionEnabled true if the transparency of * a color can be selected * @return the selected color or null if the user opted out - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -217,7 +217,7 @@ public class JColorChooser extends JComponent implements Accessible { * @param okListener the ActionListener invoked when "OK" is pressed * @param cancelListener the ActionListener invoked when "Cancel" is pressed * @return a new dialog containing the color-chooser pane - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -343,7 +343,7 @@ public class JColorChooser extends JComponent implements Accessible { * @param r an int specifying the amount of Red * @param g an int specifying the amount of Green * @param b an int specifying the amount of Blue - * @exception IllegalArgumentException if r,g,b values are out of range + * @throws IllegalArgumentException if r,g,b values are out of range * @see java.awt.Color */ public void setColor(int r, int g, int b) { @@ -386,7 +386,7 @@ public class JColorChooser extends JComponent implements Accessible { * TransferHandler. * * @param b the value to set the dragEnabled property to - * @exception HeadlessException if + * @throws HeadlessException if * b is true and * GraphicsEnvironment.isHeadless() * returns true @@ -464,7 +464,7 @@ public class JColorChooser extends JComponent implements Accessible { * * @param panel a string that specifies the panel to be removed * @return the color panel - * @exception IllegalArgumentException if panel is not in list of + * @throws IllegalArgumentException if panel is not in list of * known chooser panels */ public AbstractColorChooserPanel removeChooserPanel( AbstractColorChooserPanel panel ) { diff --git a/src/java.desktop/share/classes/javax/swing/JComboBox.java b/src/java.desktop/share/classes/javax/swing/JComboBox.java index fdbbdc68657..f035c186896 100644 --- a/src/java.desktop/share/classes/javax/swing/JComboBox.java +++ b/src/java.desktop/share/classes/javax/swing/JComboBox.java @@ -638,7 +638,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible { * * @param anIndex an integer specifying the list item to select, * where 0 specifies the first item in the list and -1 indicates no selection - * @exception IllegalArgumentException if anIndex < -1 or + * @throws IllegalArgumentException if anIndex < -1 or * anIndex is greater than or equal to size */ @BeanProperty(bound = false, preferred = true, description @@ -815,7 +815,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible { /** * Checks that the dataModel is an instance of * MutableComboBoxModel. If not, it throws an exception. - * @exception RuntimeException if dataModel is not an + * @throws RuntimeException if dataModel is not an * instance of MutableComboBoxModel. */ void checkMutableComboBoxModel() { @@ -2298,7 +2298,7 @@ implements ItemSelectable,ListDataListener,ActionListener, Accessible { * @return this component's locale. If this component does not have * a locale, the locale of its parent is returned. * - * @exception IllegalComponentStateException + * @throws IllegalComponentStateException * If the Component does not have its own locale and has not yet been * added to a containment hierarchy such that the locale can be * determined from the containing parent. diff --git a/src/java.desktop/share/classes/javax/swing/JComponent.java b/src/java.desktop/share/classes/javax/swing/JComponent.java index c572a12ebb4..87b8c3175bd 100644 --- a/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -2455,7 +2455,7 @@ public abstract class JComponent extends Container implements Serializable, * * @param condition one of the values listed above * @param map the InputMap to use for the given condition - * @exception IllegalArgumentException if condition is + * @throws IllegalArgumentException if condition is * WHEN_IN_FOCUSED_WINDOW and map * is not an instance of ComponentInputMap; or * if condition is not one of the legal values @@ -2554,7 +2554,7 @@ public abstract class JComponent extends Container implements Serializable, * @return the InputMap for the given condition; * if create is false and the InputMap * hasn't been created, returns null - * @exception IllegalArgumentException if condition + * @throws IllegalArgumentException if condition * is not one of the legal values listed above */ final InputMap getInputMap(int condition, boolean create) { @@ -4623,7 +4623,7 @@ public abstract class JComponent extends Container implements Serializable, * @param propertyName the name of the property that was listened on * @param oldValue the old value of the property * @param newValue the new value of the property - * @exception java.beans.PropertyVetoException when the attempt to set the + * @throws java.beans.PropertyVetoException when the attempt to set the * property is vetoed by the component */ protected void fireVetoableChange(String propertyName, Object oldValue, Object newValue) @@ -4799,7 +4799,7 @@ public abstract class JComponent extends Container implements Serializable, * FooListeners on this component, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType + * @throws ClassCastException if listenerType * doesn't specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/JEditorPane.java b/src/java.desktop/share/classes/javax/swing/JEditorPane.java index 6b9189d550d..f347621a687 100644 --- a/src/java.desktop/share/classes/javax/swing/JEditorPane.java +++ b/src/java.desktop/share/classes/javax/swing/JEditorPane.java @@ -312,7 +312,7 @@ public class JEditorPane extends JTextComponent { * Creates a JEditorPane based on a specified URL for input. * * @param initialPage the URL - * @exception IOException if the URL is null + * @throws IOException if the URL is null * or cannot be accessed */ public JEditorPane(URL initialPage) throws IOException { @@ -325,7 +325,7 @@ public class JEditorPane extends JTextComponent { * a URL specification. * * @param url the URL - * @exception IOException if the URL is null or + * @throws IOException if the URL is null or * cannot be accessed */ public JEditorPane(String url) throws IOException { @@ -340,7 +340,7 @@ public class JEditorPane extends JTextComponent { * * @param type mime type of the given text * @param text the text to initialize with; may be null - * @exception NullPointerException if the type parameter + * @throws NullPointerException if the type parameter * is null */ public JEditorPane(String type, String text) { @@ -462,7 +462,7 @@ public class JEditorPane extends JTextComponent { * thread is done whether the load was successful or not. * * @param page the URL of the page - * @exception IOException for a null or invalid + * @throws IOException for a null or invalid * page specification, or exception from the stream being read * @see #getPage */ @@ -578,7 +578,7 @@ public class JEditorPane extends JTextComponent { * * @param in the stream from which to read * @param desc an object describing the stream - * @exception IOException as thrown by the stream being + * @throws IOException as thrown by the stream being * used to initialize * @see JTextComponent#read * @see #setDocument @@ -925,7 +925,7 @@ public class JEditorPane extends JTextComponent { * Sets the current URL being displayed. * * @param url the URL for display - * @exception IOException for a null or invalid URL + * @throws IOException for a null or invalid URL * specification */ public void setPage(String url) throws IOException { diff --git a/src/java.desktop/share/classes/javax/swing/JFileChooser.java b/src/java.desktop/share/classes/javax/swing/JFileChooser.java index 8d286e05f3b..2e0a80f788b 100644 --- a/src/java.desktop/share/classes/javax/swing/JFileChooser.java +++ b/src/java.desktop/share/classes/javax/swing/JFileChooser.java @@ -446,7 +446,7 @@ public class JFileChooser extends JComponent implements Accessible { * TransferHandler. * * @param b the value to set the dragEnabled property to - * @exception HeadlessException if + * @throws HeadlessException if * b is true and * GraphicsEnvironment.isHeadless() * returns true @@ -658,7 +658,7 @@ public class JFileChooser extends JComponent implements Accessible { *
  • JFileChooser.ERROR_OPTION if an error occurs or the * dialog is dismissed * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @see #showDialog @@ -683,7 +683,7 @@ public class JFileChooser extends JComponent implements Accessible { *
  • JFileChooser.ERROR_OPTION if an error occurs or the * dialog is dismissed * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @see #showDialog @@ -743,7 +743,7 @@ public class JFileChooser extends JComponent implements Accessible { *
  • JFileChooser.ERROR_OPTION if an error occurs or the * dialog is dismissed * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -800,7 +800,7 @@ public class JFileChooser extends JComponent implements Accessible { * @param parent the parent component of the dialog; * can be null * @return a new JDialog containing this instance - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.4 @@ -924,7 +924,7 @@ public class JFileChooser extends JComponent implements Accessible { *
  • JFileChooser.CUSTOM_DIALOG * * - * @exception IllegalArgumentException if dialogType is + * @throws IllegalArgumentException if dialogType is * not legal * * @see #getDialogType @@ -1311,7 +1311,7 @@ public class JFileChooser extends JComponent implements Accessible { *
  • JFileChooser.FILES_AND_DIRECTORIES * * - * @exception IllegalArgumentException if mode is an + * @throws IllegalArgumentException if mode is an * illegal file selection mode * * @see #getFileSelectionMode diff --git a/src/java.desktop/share/classes/javax/swing/JFrame.java b/src/java.desktop/share/classes/javax/swing/JFrame.java index 339268fd165..9b37ae77ab0 100644 --- a/src/java.desktop/share/classes/javax/swing/JFrame.java +++ b/src/java.desktop/share/classes/javax/swing/JFrame.java @@ -169,7 +169,7 @@ public class JFrame extends Frame implements WindowConstants, * This constructor sets the component's locale property to the value * returned by JComponent.getDefaultLocale. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @see Component#setSize @@ -193,7 +193,7 @@ public class JFrame extends Frame implements WindowConstants, * to construct the new Frame; * if gc is null, the system * default GraphicsConfiguration is assumed - * @exception IllegalArgumentException if gc is not from + * @throws IllegalArgumentException if gc is not from * a screen device. This exception is always thrown when * GraphicsEnvironment.isHeadless() returns true. * @see java.awt.GraphicsEnvironment#isHeadless @@ -213,7 +213,7 @@ public class JFrame extends Frame implements WindowConstants, * returned by JComponent.getDefaultLocale. * * @param title the title for the frame - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @see Component#setSize @@ -239,7 +239,7 @@ public class JFrame extends Frame implements WindowConstants, * to construct the new JFrame with; * if gc is null, the system * default GraphicsConfiguration is assumed - * @exception IllegalArgumentException if gc is not from + * @throws IllegalArgumentException if gc is not from * a screen device. This exception is always thrown when * GraphicsEnvironment.isHeadless() returns true. * @see java.awt.GraphicsEnvironment#isHeadless @@ -357,7 +357,7 @@ public class JFrame extends Frame implements WindowConstants, * * @param operation the operation which should be performed when the * user closes the frame - * @exception IllegalArgumentException if defaultCloseOperation value + * @throws IllegalArgumentException if defaultCloseOperation value * isn't one of the above valid values * @see #addWindowListener * @see #getDefaultCloseOperation @@ -540,10 +540,10 @@ public class JFrame extends Frame implements WindowConstants, * @param comp the component to be enhanced * @param constraints the constraints to be respected * @param index the index - * @exception IllegalArgumentException if index is invalid - * @exception IllegalArgumentException if adding the container's parent + * @throws IllegalArgumentException if index is invalid + * @throws IllegalArgumentException if adding the container's parent * to itself - * @exception IllegalArgumentException if adding a window to a container + * @throws IllegalArgumentException if adding a window to a container * * @see #setRootPaneCheckingEnabled * @see javax.swing.RootPaneContainer @@ -668,7 +668,7 @@ public class JFrame extends Frame implements WindowConstants, * * @param contentPane the contentPane object for this frame * - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the content pane parameter is null * @see #getContentPane * @see RootPaneContainer#setContentPane @@ -696,7 +696,7 @@ public class JFrame extends Frame implements WindowConstants, * This method is called by the constructor. * @param layeredPane the layeredPane object for this frame * - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the layered pane parameter is null * @see #getLayeredPane * @see RootPaneContainer#setLayeredPane diff --git a/src/java.desktop/share/classes/javax/swing/JInternalFrame.java b/src/java.desktop/share/classes/javax/swing/JInternalFrame.java index 62efd03c0db..9caa5f966e3 100644 --- a/src/java.desktop/share/classes/javax/swing/JInternalFrame.java +++ b/src/java.desktop/share/classes/javax/swing/JInternalFrame.java @@ -497,10 +497,10 @@ public class JInternalFrame extends JComponent implements * @param comp the component to be enhanced * @param constraints the constraints to be respected * @param index the index - * @exception IllegalArgumentException if index is invalid - * @exception IllegalArgumentException if adding the container's parent + * @throws IllegalArgumentException if index is invalid + * @throws IllegalArgumentException if adding the container's parent * to itself - * @exception IllegalArgumentException if adding a window to a container + * @throws IllegalArgumentException if adding a window to a container * * @see #setRootPaneCheckingEnabled * @see javax.swing.RootPaneContainer @@ -628,7 +628,7 @@ public class JInternalFrame extends JComponent implements * * @param c the content pane for this internal frame * - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the content pane parameter is null * @see RootPaneContainer#getContentPane */ @@ -657,7 +657,7 @@ public class JInternalFrame extends JComponent implements * * @param layered the JLayeredPane for this internal frame * - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the layered pane parameter is null * @see RootPaneContainer#setLayeredPane */ @@ -794,7 +794,7 @@ public class JInternalFrame extends JComponent implements * * @param b must be true * - * @exception PropertyVetoException when the attempt to set the + * @throws PropertyVetoException when the attempt to set the * property is vetoed by the JInternalFrame * * @see #isClosed() @@ -906,7 +906,7 @@ public class JInternalFrame extends JComponent implements * * @param b a boolean, where true means to iconify this internal frame and * false means to de-iconify it - * @exception PropertyVetoException when the attempt to set the + * @throws PropertyVetoException when the attempt to set the * property is vetoed by the JInternalFrame * * @see InternalFrameEvent#INTERNAL_FRAME_ICONIFIED @@ -985,7 +985,7 @@ public class JInternalFrame extends JComponent implements * * @param b a boolean, where true maximizes this internal frame and false * restores it - * @exception PropertyVetoException when the attempt to set the + * @throws PropertyVetoException when the attempt to set the * property is vetoed by the JInternalFrame */ @BeanProperty(description @@ -1047,7 +1047,7 @@ public class JInternalFrame extends JComponent implements * @param selected a boolean, where true means this internal frame * should become selected (currently active) * and false means it should become deselected - * @exception PropertyVetoException when the attempt to set the + * @throws PropertyVetoException when the attempt to set the * property is vetoed by the JInternalFrame * * @see #isShowing diff --git a/src/java.desktop/share/classes/javax/swing/JLabel.java b/src/java.desktop/share/classes/javax/swing/JLabel.java index 8dff4a8fd25..eed6a157cc1 100644 --- a/src/java.desktop/share/classes/javax/swing/JLabel.java +++ b/src/java.desktop/share/classes/javax/swing/JLabel.java @@ -551,7 +551,7 @@ public class JLabel extends JComponent implements SwingConstants, Accessible * * @since 1.4 * @param index Index into the String to underline - * @exception IllegalArgumentException will be thrown if index + * @throws IllegalArgumentException will be thrown if index * is >= length of the text, or < -1 */ @BeanProperty(visualUpdate = true, description @@ -595,7 +595,7 @@ public class JLabel extends JComponent implements SwingConstants, Accessible * @param message the IllegalArgumentException detail message * @return the key value if {@code key} is a a legal value for the * horizontalAlignment properties - * @exception IllegalArgumentException if key isn't LEFT, CENTER, RIGHT, + * @throws IllegalArgumentException if key isn't LEFT, CENTER, RIGHT, * LEADING or TRAILING. * @see #setHorizontalTextPosition * @see #setHorizontalAlignment @@ -622,7 +622,7 @@ public class JLabel extends JComponent implements SwingConstants, Accessible * @param message the IllegalArgumentException detail message * @return the key value if {@code key} is a legal value for the * verticalAlignment or verticalTextPosition properties - * @exception IllegalArgumentException if key isn't TOP, CENTER, or BOTTOM. + * @throws IllegalArgumentException if key isn't TOP, CENTER, or BOTTOM. * @see #setVerticalAlignment * @see #setVerticalTextPosition */ @@ -1637,7 +1637,7 @@ public class JLabel extends JComponent implements SwingConstants, Accessible * * @param i zero-based index of the key bindings * @return a javax.lang.Object which specifies the key binding - * @exception IllegalArgumentException if the index is + * @throws IllegalArgumentException if the index is * out of bounds * @see #getAccessibleKeyBindingCount */ diff --git a/src/java.desktop/share/classes/javax/swing/JLayer.java b/src/java.desktop/share/classes/javax/swing/JLayer.java index 0ade190ce42..c2076299e44 100644 --- a/src/java.desktop/share/classes/javax/swing/JLayer.java +++ b/src/java.desktop/share/classes/javax/swing/JLayer.java @@ -316,7 +316,7 @@ public final class JLayer * a {@code JLayer}. * * @param mgr the specified layout manager - * @exception IllegalArgumentException this method is not supported + * @throws IllegalArgumentException this method is not supported */ public void setLayout(LayoutManager mgr) { if (mgr != null) { diff --git a/src/java.desktop/share/classes/javax/swing/JList.java b/src/java.desktop/share/classes/javax/swing/JList.java index ac4a1e3fe3a..220f86aca4e 100644 --- a/src/java.desktop/share/classes/javax/swing/JList.java +++ b/src/java.desktop/share/classes/javax/swing/JList.java @@ -445,7 +445,7 @@ public class JList extends JComponent implements Scrollable, Accessible * allowing for tooltips to be provided by the cell renderers. * * @param dataModel the model for the list - * @exception IllegalArgumentException if the model is {@code null} + * @throws IllegalArgumentException if the model is {@code null} */ public JList(ListModel dataModel) { @@ -1202,7 +1202,7 @@ public class JList extends JComponent implements Scrollable, Accessible * list's {@code TransferHandler}. * * @param b whether or not to enable automatic drag handling - * @exception HeadlessException if + * @throws HeadlessException if * b is true and * GraphicsEnvironment.isHeadless() * returns true @@ -1493,7 +1493,7 @@ public class JList extends JComponent implements Scrollable, Accessible * Position.Bias.Forward or Position.Bias.Backward. * @return the index of the next list element that * starts with the prefix; otherwise {@code -1} - * @exception IllegalArgumentException if prefix is {@code null} + * @throws IllegalArgumentException if prefix is {@code null} * or startIndex is out of bounds * @since 1.4 */ @@ -1695,7 +1695,7 @@ public class JList extends JComponent implements Scrollable, Accessible * * @param model the ListModel that provides the * list of items for display - * @exception IllegalArgumentException if model is + * @throws IllegalArgumentException if model is * null * @see #getModel * @see #clearSelection @@ -1910,7 +1910,7 @@ public class JList extends JComponent implements Scrollable, Accessible * * @param selectionModel the ListSelectionModel that * implements the selections - * @exception IllegalArgumentException if selectionModel + * @throws IllegalArgumentException if selectionModel * is null * @see #getSelectionModel */ diff --git a/src/java.desktop/share/classes/javax/swing/JMenu.java b/src/java.desktop/share/classes/javax/swing/JMenu.java index dbac4812ca8..1565440969a 100644 --- a/src/java.desktop/share/classes/javax/swing/JMenu.java +++ b/src/java.desktop/share/classes/javax/swing/JMenu.java @@ -508,7 +508,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * to manage the idiosyncrasies of the various UI implementations. * * @param d the number of milliseconds to delay - * @exception IllegalArgumentException if d + * @throws IllegalArgumentException if d * is less than 0 */ @BeanProperty(bound = false, expert = true, description @@ -674,7 +674,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @param s the text for the menu item to add * @param pos an integer specifying the position at which to add the * new menu item - * @exception IllegalArgumentException when the value of + * @throws IllegalArgumentException when the value of * pos < 0 */ public void insert(String s, int pos) { @@ -693,7 +693,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @param pos an integer specifying the position at which to add the * new JMenuitem * @return the new menu item - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * pos < 0 */ public JMenuItem insert(JMenuItem mi, int pos) { @@ -713,7 +713,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @param pos an integer specifying the position at which to add the * new menu item * @return the new menu item - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * pos < 0 */ public JMenuItem insert(Action a, int pos) { @@ -734,7 +734,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * * @param index an integer specifying the position at which to * insert the menu separator - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * index < 0 */ public void insertSeparator(int index) { @@ -755,7 +755,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @param pos an integer specifying the position * @return the menu item at the specified position; or null * if the item as the specified position is not a menu item - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * {@code pos} < 0 */ public JMenuItem getItem(int pos) { @@ -790,7 +790,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * yet implemented. * * @return true if the menu can be torn off, else false - * @exception Error if invoked -- this method is not yet implemented + * @throws Error if invoked -- this method is not yet implemented */ @BeanProperty(bound = false) public boolean isTearOff() { @@ -812,7 +812,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * Removes the menu item at the specified index from this menu. * * @param pos the position of the item to be removed - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * pos < 0, or if pos * is greater than the number of menu items */ @@ -1024,7 +1024,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * notification on this event type. The event instance * is created lazily. * - * @exception Error if there is a null listener + * @throws Error if there is a null listener * @see EventListenerList */ protected void fireMenuSelected() { @@ -1054,7 +1054,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * notification on this event type. The event instance * is created lazily. * - * @exception Error if there is a null listener + * @throws Error if there is a null listener * @see EventListenerList */ protected void fireMenuDeselected() { @@ -1084,7 +1084,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * notification on this event type. The event instance * is created lazily. * - * @exception Error if there is a null listener + * @throws Error if there is a null listener * @see EventListenerList */ protected void fireMenuCanceled() { @@ -1238,7 +1238,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * * @param o the new component orientation of this menu and * the components contained within it. - * @exception NullPointerException if orientation is null. + * @throws NullPointerException if orientation is null. * @see java.awt.Component#setComponentOrientation * @see java.awt.Component#getComponentOrientation * @since 1.4 @@ -1275,7 +1275,7 @@ public class JMenu extends JMenuItem implements Accessible,MenuElement * @param keyStroke the keystroke combination which will invoke * the JMenuItem's actionlisteners * without navigating the menu hierarchy - * @exception Error if invoked -- this method is not defined for JMenu. + * @throws Error if invoked -- this method is not defined for JMenu. * Use setMnemonic instead */ public void setAccelerator(KeyStroke keyStroke) { diff --git a/src/java.desktop/share/classes/javax/swing/JOptionPane.java b/src/java.desktop/share/classes/javax/swing/JOptionPane.java index 99eee90347b..28a547dc2cb 100644 --- a/src/java.desktop/share/classes/javax/swing/JOptionPane.java +++ b/src/java.desktop/share/classes/javax/swing/JOptionPane.java @@ -435,7 +435,7 @@ public class JOptionPane extends JComponent implements Accessible * the screen. * * @param message the Object to display - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @return user's input @@ -471,7 +471,7 @@ public class JOptionPane extends JComponent implements Accessible * @param parentComponent the parent Component for the * dialog * @param message the Object to display - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @return user's input @@ -523,7 +523,7 @@ public class JOptionPane extends JComponent implements Accessible * QUESTION_MESSAGE, * or PLAIN_MESSAGE * @return user's input - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -566,7 +566,7 @@ public class JOptionPane extends JComponent implements Accessible * field * @return user's input, or null meaning the user * canceled the input - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -609,7 +609,7 @@ public class JOptionPane extends JComponent implements Accessible * or if the parentComponent has no * Frame, a default Frame is used * @param message the Object to display - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -637,7 +637,7 @@ public class JOptionPane extends JComponent implements Accessible * WARNING_MESSAGE, * QUESTION_MESSAGE, * or PLAIN_MESSAGE - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -666,7 +666,7 @@ public class JOptionPane extends JComponent implements Accessible * or PLAIN_MESSAGE * @param icon an icon to display in the dialog that helps the user * identify the kind of message that is being displayed - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -690,7 +690,7 @@ public class JOptionPane extends JComponent implements Accessible * default Frame is used * @param message the Object to display * @return an integer indicating the option selected by the user - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -718,7 +718,7 @@ public class JOptionPane extends JComponent implements Accessible * YES_NO_CANCEL_OPTION, * or OK_CANCEL_OPTION * @return an int indicating the option selected by the user - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -757,7 +757,7 @@ public class JOptionPane extends JComponent implements Accessible * QUESTION_MESSAGE, * or PLAIN_MESSAGE * @return an integer indicating the option selected by the user - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -795,7 +795,7 @@ public class JOptionPane extends JComponent implements Accessible * or PLAIN_MESSAGE * @param icon the icon to display in the dialog * @return an int indicating the option selected by the user - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -856,7 +856,7 @@ public class JOptionPane extends JComponent implements Accessible * @return an integer indicating the option chosen by the user, * or CLOSED_OPTION if the user closed * the dialog - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -919,7 +919,7 @@ public class JOptionPane extends JComponent implements Accessible * no Frame, a default Frame is used * @param title the title string for the dialog * @return a new JDialog containing this instance - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -946,7 +946,7 @@ public class JOptionPane extends JComponent implements Accessible * * @param title the title string for the dialog * @return a new JDialog containing this instance - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -1508,7 +1508,7 @@ public class JOptionPane extends JComponent implements Accessible * frame's title bar * @return a JInternalFrame containing a * JOptionPane - * @exception RuntimeException if parentComponent does + * @throws RuntimeException if parentComponent does * not have a valid parent */ public JInternalFrame createInternalFrame(Component parentComponent, @@ -1600,7 +1600,7 @@ public class JOptionPane extends JComponent implements Accessible * or getRootFrame * if the component is null, * or does not have a valid Frame parent - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see #getRootFrame @@ -1626,7 +1626,7 @@ public class JOptionPane extends JComponent implements Accessible * frame if the component is null, * or does not have a valid * Frame or Dialog parent - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see java.awt.GraphicsEnvironment#isHeadless @@ -1683,7 +1683,7 @@ public class JOptionPane extends JComponent implements Accessible * which a frame is not provided. * * @return the default Frame to use - * @exception HeadlessException if + * @throws HeadlessException if * GraphicsEnvironment.isHeadless returns * true * @see #setRootFrame @@ -2050,7 +2050,7 @@ public class JOptionPane extends JComponent implements Accessible * ERROR_MESSAGE, INFORMATION_MESSAGE, * WARNING_MESSAGE, * QUESTION_MESSAGE, or PLAIN_MESSAGE - * @exception RuntimeException if newType is not one of the + * @throws RuntimeException if newType is not one of the * legal values listed above * @see #getMessageType @@ -2096,7 +2096,7 @@ public class JOptionPane extends JComponent implements Accessible * YES_NO_OPTION, * YES_NO_CANCEL_OPTION, * or OK_CANCEL_OPTION - * @exception RuntimeException if newType is not one of + * @throws RuntimeException if newType is not one of * the legal values listed above * * @see #getOptionType diff --git a/src/java.desktop/share/classes/javax/swing/JPasswordField.java b/src/java.desktop/share/classes/javax/swing/JPasswordField.java index 577998cb336..c6450d0605a 100644 --- a/src/java.desktop/share/classes/javax/swing/JPasswordField.java +++ b/src/java.desktop/share/classes/javax/swing/JPasswordField.java @@ -288,7 +288,7 @@ public class JPasswordField extends JTextField { * @param offs the offset >= 0 * @param len the length >= 0 * @return the text - * @exception BadLocationException if the offset or length are invalid + * @throws BadLocationException if the offset or length are invalid */ @Deprecated public String getText(int offs, int len) throws BadLocationException { diff --git a/src/java.desktop/share/classes/javax/swing/JPopupMenu.java b/src/java.desktop/share/classes/javax/swing/JPopupMenu.java index ef9ad42ef81..a6811fad5eb 100644 --- a/src/java.desktop/share/classes/javax/swing/JPopupMenu.java +++ b/src/java.desktop/share/classes/javax/swing/JPopupMenu.java @@ -475,7 +475,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { * Removes the component at the specified index from this popup menu. * * @param pos the position of the item to be removed - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * pos < 0, or if the value of * pos is greater than the * number of items @@ -573,7 +573,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { * @param a the Action object to insert * @param index specifies the position at which to insert the * Action, where 0 is the first - * @exception IllegalArgumentException if index < 0 + * @throws IllegalArgumentException if index < 0 * @see Action */ public void insert(Action a, int index) { @@ -589,7 +589,7 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { * @param component the Component to insert * @param index specifies the position at which * to insert the component, where 0 is the first - * @exception IllegalArgumentException if index < 0 + * @throws IllegalArgumentException if index < 0 */ public void insert(Component component, int index) { if (index < 0) { diff --git a/src/java.desktop/share/classes/javax/swing/JProgressBar.java b/src/java.desktop/share/classes/javax/swing/JProgressBar.java index 90945bb67e3..edba6e4a5da 100644 --- a/src/java.desktop/share/classes/javax/swing/JProgressBar.java +++ b/src/java.desktop/share/classes/javax/swing/JProgressBar.java @@ -394,7 +394,7 @@ public class JProgressBar extends JComponent implements SwingConstants, Accessib * is {@code SwingConstants.HORIZONTAL}. * * @param newOrientation HORIZONTAL or VERTICAL - * @exception IllegalArgumentException if newOrientation + * @throws IllegalArgumentException if newOrientation * is an illegal value * @see #getOrientation */ diff --git a/src/java.desktop/share/classes/javax/swing/JRootPane.java b/src/java.desktop/share/classes/javax/swing/JRootPane.java index dcc6d6bb4ef..48e06a917fc 100644 --- a/src/java.desktop/share/classes/javax/swing/JRootPane.java +++ b/src/java.desktop/share/classes/javax/swing/JRootPane.java @@ -578,7 +578,7 @@ public class JRootPane extends JComponent implements Accessible { * replace it with an opaque JComponent. * * @param content the Container to use for component-contents - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the content pane parameter is null */ public void setContentPane(Container content) { @@ -605,7 +605,7 @@ public class JRootPane extends JComponent implements Accessible { * typically holds a content pane and an optional JMenuBar. * * @param layered the JLayeredPane to use - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the layered pane parameter is null */ public void setLayeredPane(JLayeredPane layered) { @@ -647,7 +647,7 @@ public class JRootPane extends JComponent implements Accessible { * * @param glass the Component to use as the glass pane * for this JRootPane - * @exception NullPointerException if the glass parameter is + * @throws NullPointerException if the glass parameter is * null */ public void setGlassPane(Component glass) { diff --git a/src/java.desktop/share/classes/javax/swing/JScrollBar.java b/src/java.desktop/share/classes/javax/swing/JScrollBar.java index 6bb997a6150..ba65f21a954 100644 --- a/src/java.desktop/share/classes/javax/swing/JScrollBar.java +++ b/src/java.desktop/share/classes/javax/swing/JScrollBar.java @@ -155,7 +155,7 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible * That way, when the user jumps the knob to an adjacent position, * one or two lines of the original contents remain in view. * - * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL + * @throws IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL * * @see #setOrientation * @see #setValue @@ -279,7 +279,7 @@ public class JScrollBar extends JComponent implements Adjustable, Accessible * HORIZONTAL. * * @param orientation an orientation of the {@code JScrollBar} - * @exception IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL + * @throws IllegalArgumentException if orientation is not one of VERTICAL, HORIZONTAL * @see #getOrientation */ @BeanProperty(preferred = true, visualUpdate = true, enumerationValues = { diff --git a/src/java.desktop/share/classes/javax/swing/JScrollPane.java b/src/java.desktop/share/classes/javax/swing/JScrollPane.java index 2c3302178df..3d5385a34d1 100644 --- a/src/java.desktop/share/classes/javax/swing/JScrollPane.java +++ b/src/java.desktop/share/classes/javax/swing/JScrollPane.java @@ -418,7 +418,7 @@ public class JScrollPane extends JComponent implements ScrollPaneConstants, Acce * will invoke syncWithScrollPane on it. * * @param layout the specified layout manager - * @exception ClassCastException if layout is not a + * @throws ClassCastException if layout is not a * ScrollPaneLayout * @see java.awt.Container#getLayout * @see java.awt.Container#setLayout @@ -476,7 +476,7 @@ public class JScrollPane extends JComponent implements ScrollPaneConstants, Acce * * * @param policy one of the three values listed above - * @exception IllegalArgumentException if policy + * @throws IllegalArgumentException if policy * is not one of the legal values shown above * @see #getVerticalScrollBarPolicy */ @@ -521,7 +521,7 @@ public class JScrollPane extends JComponent implements ScrollPaneConstants, Acce * * * @param policy one of the three values listed above - * @exception IllegalArgumentException if policy + * @throws IllegalArgumentException if policy * is not one of the legal values shown above * @see #getHorizontalScrollBarPolicy */ @@ -1195,7 +1195,7 @@ public class JScrollPane extends JComponent implements ScrollPaneConstants, Acce *
  • upperLeft *
  • upperRight * - * @exception IllegalArgumentException if corner key is invalid + * @throws IllegalArgumentException if corner key is invalid */ public void setCorner(String key, Component corner) { diff --git a/src/java.desktop/share/classes/javax/swing/JSeparator.java b/src/java.desktop/share/classes/javax/swing/JSeparator.java index 69d17382acd..10a724a7e2e 100644 --- a/src/java.desktop/share/classes/javax/swing/JSeparator.java +++ b/src/java.desktop/share/classes/javax/swing/JSeparator.java @@ -97,7 +97,7 @@ public class JSeparator extends JComponent implements SwingConstants, Accessible * @param orientation an integer specifying * SwingConstants.HORIZONTAL or * SwingConstants.VERTICAL - * @exception IllegalArgumentException if orientation + * @throws IllegalArgumentException if orientation * is neither SwingConstants.HORIZONTAL nor * SwingConstants.VERTICAL */ @@ -190,7 +190,7 @@ public class JSeparator extends JComponent implements SwingConstants, Accessible * The default value of this property is HORIZONTAL. * @param orientation either SwingConstants.HORIZONTAL * or SwingConstants.VERTICAL - * @exception IllegalArgumentException if orientation + * @throws IllegalArgumentException if orientation * is neither SwingConstants.HORIZONTAL * nor SwingConstants.VERTICAL * diff --git a/src/java.desktop/share/classes/javax/swing/JSlider.java b/src/java.desktop/share/classes/javax/swing/JSlider.java index 0d826fe7e49..4682acb8a54 100644 --- a/src/java.desktop/share/classes/javax/swing/JSlider.java +++ b/src/java.desktop/share/classes/javax/swing/JSlider.java @@ -920,7 +920,7 @@ public class JSlider extends JComponent implements SwingConstants, Accessible { * @return a new {@code Hashtable} of labels * @see #setLabelTable * @see #setPaintLabels - * @exception IllegalArgumentException if {@code start} is + * @throws IllegalArgumentException if {@code start} is * out of range, or if {@code increment} is less than or equal * to zero */ diff --git a/src/java.desktop/share/classes/javax/swing/JSpinner.java b/src/java.desktop/share/classes/javax/swing/JSpinner.java index a371c557439..245212131f2 100644 --- a/src/java.desktop/share/classes/javax/swing/JSpinner.java +++ b/src/java.desktop/share/classes/javax/swing/JSpinner.java @@ -1015,7 +1015,7 @@ public class JSpinner extends JComponent implements Accessible * on the new JFormattedTextField. * * @param spinner the spinner whose model this editor will monitor - * @exception IllegalArgumentException if the spinners model is not + * @throws IllegalArgumentException if the spinners model is not * an instance of SpinnerDateModel * * @see #getModel @@ -1039,7 +1039,7 @@ public class JSpinner extends JComponent implements Accessible * @param dateFormatPattern the initial pattern for the * SimpleDateFormat object that's used to display * and parse the value of the text field. - * @exception IllegalArgumentException if the spinners model is not + * @throws IllegalArgumentException if the spinners model is not * an instance of SpinnerDateModel * * @see #getModel @@ -1064,7 +1064,7 @@ public class JSpinner extends JComponent implements Accessible * will monitor * @param format DateFormat object that's used to display * and parse the value of the text field. - * @exception IllegalArgumentException if the spinners model is not + * @throws IllegalArgumentException if the spinners model is not * an instance of SpinnerDateModel * * @see #getModel @@ -1202,7 +1202,7 @@ public class JSpinner extends JComponent implements Accessible * on the new JFormattedTextField. * * @param spinner the spinner whose model this editor will monitor - * @exception IllegalArgumentException if the spinners model is not + * @throws IllegalArgumentException if the spinners model is not * an instance of SpinnerNumberModel * * @see #getModel @@ -1225,7 +1225,7 @@ public class JSpinner extends JComponent implements Accessible * @param decimalFormatPattern the initial pattern for the * DecimalFormat object that's used to display * and parse the value of the text field. - * @exception IllegalArgumentException if the spinners model is not + * @throws IllegalArgumentException if the spinners model is not * an instance of SpinnerNumberModel or if * decimalFormatPattern is not a legal * argument to DecimalFormat @@ -1251,7 +1251,7 @@ public class JSpinner extends JComponent implements Accessible * @param format the initial pattern for the * DecimalFormat object that's used to display * and parse the value of the text field. - * @exception IllegalArgumentException if the spinners model is not + * @throws IllegalArgumentException if the spinners model is not * an instance of SpinnerNumberModel * * @see #getTextField @@ -1346,7 +1346,7 @@ public class JSpinner extends JComponent implements Accessible * on the new JFormattedTextField. * * @param spinner the spinner whose model this editor will monitor - * @exception IllegalArgumentException if the spinners model is not + * @throws IllegalArgumentException if the spinners model is not * an instance of SpinnerListModel * * @see #getModel diff --git a/src/java.desktop/share/classes/javax/swing/JSplitPane.java b/src/java.desktop/share/classes/javax/swing/JSplitPane.java index bd5e85ed4a6..5a3cfef943e 100644 --- a/src/java.desktop/share/classes/javax/swing/JSplitPane.java +++ b/src/java.desktop/share/classes/javax/swing/JSplitPane.java @@ -262,7 +262,7 @@ public class JSplitPane extends JComponent implements Accessible * * @param newOrientation JSplitPane.HORIZONTAL_SPLIT or * JSplitPane.VERTICAL_SPLIT - * @exception IllegalArgumentException if orientation + * @throws IllegalArgumentException if orientation * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT. */ @ConstructorProperties({"orientation"}) @@ -281,7 +281,7 @@ public class JSplitPane extends JComponent implements Accessible * @param newContinuousLayout a boolean, true for the components to * redraw continuously as the divider changes position, false * to wait until the divider position stops changing to redraw - * @exception IllegalArgumentException if orientation + * @throws IllegalArgumentException if orientation * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT */ public JSplitPane(int newOrientation, @@ -304,7 +304,7 @@ public class JSplitPane extends JComponent implements Accessible * appear on the right * of a horizontally-split pane, or at the bottom of a * vertically-split pane - * @exception IllegalArgumentException if orientation + * @throws IllegalArgumentException if orientation * is not one of: HORIZONTAL_SPLIT or VERTICAL_SPLIT */ public JSplitPane(int newOrientation, @@ -334,7 +334,7 @@ public class JSplitPane extends JComponent implements Accessible * appear on the right * of a horizontally-split pane, or at the bottom of a * vertically-split pane - * @exception IllegalArgumentException if orientation + * @throws IllegalArgumentException if orientation * is not one of HORIZONTAL_SPLIT or VERTICAL_SPLIT */ public JSplitPane(int newOrientation, @@ -622,7 +622,7 @@ public class JSplitPane extends JComponent implements Accessible * * * @param orientation an integer specifying the orientation - * @exception IllegalArgumentException if orientation is not one of: + * @throws IllegalArgumentException if orientation is not one of: * HORIZONTAL_SPLIT or VERTICAL_SPLIT. */ @BeanProperty(enumerationValues = { @@ -701,7 +701,7 @@ public class JSplitPane extends JComponent implements Accessible * extra space. * * @param value as described above - * @exception IllegalArgumentException if value is < 0 or > 1 + * @throws IllegalArgumentException if value is < 0 or > 1 * @since 1.3 */ @BeanProperty(description @@ -754,7 +754,7 @@ public class JSplitPane extends JComponent implements Accessible * @param proportionalLocation a double-precision floating point value * that specifies a percentage, from zero (top/left) to 1.0 * (bottom/right) - * @exception IllegalArgumentException if the specified location is < 0 + * @throws IllegalArgumentException if the specified location is < 0 * or > 1.0 */ @BeanProperty(description @@ -964,7 +964,7 @@ public class JSplitPane extends JComponent implements Accessible * (position) for this component * @param index an integer specifying the index in the container's * list. - * @exception IllegalArgumentException if the constraints + * @throws IllegalArgumentException if the constraints * object does not match an existing component * @see java.awt.Container#addImpl(Component, Object, int) */ diff --git a/src/java.desktop/share/classes/javax/swing/JTabbedPane.java b/src/java.desktop/share/classes/javax/swing/JTabbedPane.java index 4acf4f8a930..2bdd93a7e8d 100644 --- a/src/java.desktop/share/classes/javax/swing/JTabbedPane.java +++ b/src/java.desktop/share/classes/javax/swing/JTabbedPane.java @@ -215,7 +215,7 @@ public class JTabbedPane extends JComponent * * @param tabPlacement the placement for the tabs relative to the content * @param tabLayoutPolicy the policy for laying out tabs when all tabs will not fit on one run - * @exception IllegalArgumentException if tab placement or tab layout policy are not + * @throws IllegalArgumentException if tab placement or tab layout policy are not * one of the above supported values * @see #addTab * @since 1.4 @@ -505,7 +505,7 @@ public class JTabbedPane extends JComponent * The default value, if not set, is SwingConstants.TOP. * * @param tabPlacement the placement for the tabs relative to the content - * @exception IllegalArgumentException if tab placement value isn't one + * @throws IllegalArgumentException if tab placement value isn't one * of the above valid values */ @BeanProperty(preferred = true, visualUpdate = true, enumerationValues = { @@ -561,7 +561,7 @@ public class JTabbedPane extends JComponent * ignored. * * @param tabLayoutPolicy the policy used to layout the tabs - * @exception IllegalArgumentException if layoutPolicy value isn't one + * @throws IllegalArgumentException if layoutPolicy value isn't one * of the above valid values * @see #getTabLayoutPolicy * @since 1.4 @@ -609,7 +609,7 @@ public class JTabbedPane extends JComponent * the results will be implementation defined. * * @param index the index to be selected - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < -1 || index >= tab count)} * * @see #getSelectedIndex @@ -696,7 +696,7 @@ public class JTabbedPane extends JComponent * corresponding to the specified component. * * @param c the selected {@code Component} for this {@code TabbedPane} - * @exception IllegalArgumentException if component not found in tabbed + * @throws IllegalArgumentException if component not found in tabbed * pane * @see #getSelectedComponent */ @@ -963,7 +963,7 @@ public class JTabbedPane extends JComponent * its visibility is reset to true to ensure it will be visible * if added to other containers. * @param index the index of the tab to be removed - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #addTab @@ -1084,7 +1084,7 @@ public class JTabbedPane extends JComponent * * @param index the index of the component to remove from the * tabbedpane - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * @see #addTab * @see #removeTabAt @@ -1148,7 +1148,7 @@ public class JTabbedPane extends JComponent * * @param index the index of the item being queried * @return the title at index - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * @see #setTitleAt */ @@ -1161,7 +1161,7 @@ public class JTabbedPane extends JComponent * * @param index the index of the item being queried * @return the icon at index - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setIconAt @@ -1180,7 +1180,7 @@ public class JTabbedPane extends JComponent * * @param index the index of the item being queried * @return the icon at index - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setDisabledIconAt @@ -1198,7 +1198,7 @@ public class JTabbedPane extends JComponent * * @param index the index of the item being queried * @return a string containing the tool tip text at index - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setToolTipTextAt @@ -1214,7 +1214,7 @@ public class JTabbedPane extends JComponent * @param index the index of the item being queried * @return the Color of the tab background at * index - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setBackgroundAt @@ -1229,7 +1229,7 @@ public class JTabbedPane extends JComponent * @param index the index of the item being queried * @return the Color of the tab foreground at * index - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setForegroundAt @@ -1245,7 +1245,7 @@ public class JTabbedPane extends JComponent * @param index the index of the item being queried * @return true if the tab at index is enabled; * false otherwise - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setEnabledAt @@ -1259,7 +1259,7 @@ public class JTabbedPane extends JComponent * * @param index the index of the item being queried * @return the Component at index - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setComponentAt @@ -1278,7 +1278,7 @@ public class JTabbedPane extends JComponent * @param tabIndex the index of the tab that the mnemonic refers to * @return the key code which represents the mnemonic; * -1 if a mnemonic is not specified for the tab - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * (tabIndex < 0 || * tabIndex >= tab count) * @see #setDisplayedMnemonicIndexAt(int,int) @@ -1299,7 +1299,7 @@ public class JTabbedPane extends JComponent * @param tabIndex the index of the tab that the mnemonic refers to * @return index representing mnemonic character if one exists; * otherwise returns -1 - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * (tabIndex < 0 || * tabIndex >= tab count) * @see #setDisplayedMnemonicIndexAt(int,int) @@ -1324,7 +1324,7 @@ public class JTabbedPane extends JComponent * index, or null if tab at * index is not currently visible in the UI, * or if there is no UI set on this tabbedpane - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} */ public Rectangle getBoundsAt(int index) { @@ -1346,7 +1346,7 @@ public class JTabbedPane extends JComponent * * @param index the tab index where the title should be set * @param title the title to be displayed in the tab - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #getTitleAt @@ -1386,7 +1386,7 @@ public class JTabbedPane extends JComponent * * @param index the tab index where the icon should be set * @param icon the icon to be displayed in the tab - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setDisabledIconAt @@ -1428,7 +1428,7 @@ public class JTabbedPane extends JComponent * * @param index the tab index where the disabled icon should be set * @param disabledIcon the icon to be displayed in the tab when disabled - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #getDisabledIconAt @@ -1451,7 +1451,7 @@ public class JTabbedPane extends JComponent * * @param index the tab index where the tooltip text should be set * @param toolTipText the tooltip text to be displayed for the tab - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #getToolTipTextAt @@ -1486,7 +1486,7 @@ public class JTabbedPane extends JComponent * * @param index the tab index where the background should be set * @param background the color to be displayed in the tab's background - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #getBackgroundAt @@ -1517,7 +1517,7 @@ public class JTabbedPane extends JComponent * * @param index the tab index where the foreground should be set * @param foreground the color to be displayed as the tab's foreground - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #getForegroundAt @@ -1542,7 +1542,7 @@ public class JTabbedPane extends JComponent * * @param index the tab index which should be enabled/disabled * @param enabled whether or not the tab should be enabled - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #isEnabledAt @@ -1562,7 +1562,7 @@ public class JTabbedPane extends JComponent * * @param index the tab index where this component is being placed * @param component the component for the tab - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #getComponentAt @@ -1638,10 +1638,10 @@ public class JTabbedPane extends JComponent * @since 1.4 * @param tabIndex the index of the tab that the mnemonic refers to * @param mnemonicIndex index into the String to underline - * @exception IndexOutOfBoundsException if tabIndex is + * @throws IndexOutOfBoundsException if tabIndex is * out of range ({@code tabIndex < 0 || tabIndex >= tab * count}) - * @exception IllegalArgumentException will be thrown if + * @throws IllegalArgumentException will be thrown if * mnemonicIndex is >= length of the tab * title , or < -1 * @see #setMnemonicAt(int,int) @@ -1678,7 +1678,7 @@ public class JTabbedPane extends JComponent * @since 1.4 * @param tabIndex the index of the tab that the mnemonic refers to * @param mnemonic the key code which represents the mnemonic - * @exception IndexOutOfBoundsException if tabIndex is out + * @throws IndexOutOfBoundsException if tabIndex is out * of range ({@code tabIndex < 0 || tabIndex >= tab count}) * @see #getMnemonicAt(int) * @see #setDisplayedMnemonicIndexAt(int,int) @@ -2001,7 +2001,7 @@ public class JTabbedPane extends JComponent * * @param i zero-based index of child * @return the Accessible child of the object - * @exception IllegalArgumentException if index is out of bounds + * @throws IllegalArgumentException if index is out of bounds */ public Accessible getAccessibleChild(int i) { if (i < 0 || i >= getTabCount()) { @@ -2426,9 +2426,9 @@ public class JTabbedPane extends JComponent * @param index the tab index where the component should be set * @param component the component to render the title for the * specified tab - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} - * @exception IllegalArgumentException if component has already been + * @throws IllegalArgumentException if component has already been * added to this JTabbedPane * * @see #getTabComponentAt @@ -2456,7 +2456,7 @@ public class JTabbedPane extends JComponent * * @param index the index of the item being queried * @return the tab component at index - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * {@code (index < 0 || index >= tab count)} * * @see #setTabComponentAt diff --git a/src/java.desktop/share/classes/javax/swing/JTable.java b/src/java.desktop/share/classes/javax/swing/JTable.java index c70ec2f935e..5d27be29454 100644 --- a/src/java.desktop/share/classes/javax/swing/JTable.java +++ b/src/java.desktop/share/classes/javax/swing/JTable.java @@ -991,7 +991,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * the row margin. * * @param rowHeight new row height - * @exception IllegalArgumentException if rowHeight is + * @throws IllegalArgumentException if rowHeight is * less than 1 * @see #getRowHeight */ @@ -1037,7 +1037,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * @param row the row whose height is being changed * @param rowHeight new row height, in pixels - * @exception IllegalArgumentException if rowHeight is + * @throws IllegalArgumentException if rowHeight is * less than 1 * @since 1.3 */ @@ -1126,7 +1126,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * The default color is look and feel dependent. * * @param gridColor the new color of the grid lines - * @exception IllegalArgumentException if gridColor is null + * @throws IllegalArgumentException if gridColor is null * @see #getGridColor */ @BeanProperty(description @@ -1485,7 +1485,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * table's {@code TransferHandler}. * * @param b whether or not to enable automatic drag handling - * @exception HeadlessException if + * @throws HeadlessException if * b is true and * GraphicsEnvironment.isHeadless() * returns true @@ -2220,7 +2220,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * Selects the rows from index0 to index1, * inclusive. * - * @exception IllegalArgumentException if index0 or + * @throws IllegalArgumentException if index0 or * index1 lie outside * [0, getRowCount()-1] * @param index0 one end of the interval @@ -2234,7 +2234,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * Selects the columns from index0 to index1, * inclusive. * - * @exception IllegalArgumentException if index0 or + * @throws IllegalArgumentException if index0 or * index1 lie outside * [0, getColumnCount()-1] * @param index0 one end of the interval @@ -2248,7 +2248,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * Adds the rows from index0 to index1, inclusive, to * the current selection. * - * @exception IllegalArgumentException if index0 or index1 + * @throws IllegalArgumentException if index0 or index1 * lie outside [0, getRowCount()-1] * @param index0 one end of the interval * @param index1 the other end of the interval @@ -2261,7 +2261,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * Adds the columns from index0 to index1, * inclusive, to the current selection. * - * @exception IllegalArgumentException if index0 or + * @throws IllegalArgumentException if index0 or * index1 lie outside * [0, getColumnCount()-1] * @param index0 one end of the interval @@ -2274,7 +2274,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable /** * Deselects the rows from index0 to index1, inclusive. * - * @exception IllegalArgumentException if index0 or + * @throws IllegalArgumentException if index0 or * index1 lie outside * [0, getRowCount()-1] * @param index0 one end of the interval @@ -2287,7 +2287,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable /** * Deselects the columns from index0 to index1, inclusive. * - * @exception IllegalArgumentException if index0 or + * @throws IllegalArgumentException if index0 or * index1 lie outside * [0, getColumnCount()-1] * @param index0 one end of the interval @@ -2596,7 +2596,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * equals. * * @return the TableColumn object that matches the identifier - * @exception IllegalArgumentException if identifier is null or no TableColumn has this identifier + * @throws IllegalArgumentException if identifier is null or no TableColumn has this identifier * * @param identifier the identifier object */ @@ -8355,7 +8355,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * * @return this component's locale; if this component does * not have a locale, the locale of its parent is returned - * @exception IllegalComponentStateException if the + * @throws IllegalComponentStateException if the * Component does not have its own locale * and has not yet been added to a containment hierarchy * such that the locale can be determined from the @@ -9161,7 +9161,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * * @return this component's locale; if this component does * not have a locale, the locale of its parent is returned - * @exception IllegalComponentStateException if the + * @throws IllegalComponentStateException if the * Component does not have its own locale * and has not yet been added to a containment hierarchy * such that the locale can be determined from the diff --git a/src/java.desktop/share/classes/javax/swing/JTextArea.java b/src/java.desktop/share/classes/javax/swing/JTextArea.java index ecc9342f05a..03b3bc7e9bd 100644 --- a/src/java.desktop/share/classes/javax/swing/JTextArea.java +++ b/src/java.desktop/share/classes/javax/swing/JTextArea.java @@ -166,7 +166,7 @@ public class JTextArea extends JTextComponent { * * @param rows the number of rows >= 0 * @param columns the number of columns >= 0 - * @exception IllegalArgumentException if the rows or columns + * @throws IllegalArgumentException if the rows or columns * arguments are negative. */ public JTextArea(int rows, int columns) { @@ -180,7 +180,7 @@ public class JTextArea extends JTextComponent { * @param text the text to be displayed, or null * @param rows the number of rows >= 0 * @param columns the number of columns >= 0 - * @exception IllegalArgumentException if the rows or columns + * @throws IllegalArgumentException if the rows or columns * arguments are negative. */ public JTextArea(String text, int rows, int columns) { @@ -206,7 +206,7 @@ public class JTextArea extends JTextComponent { * @param text the text to be displayed, null if none * @param rows the number of rows >= 0 * @param columns the number of columns >= 0 - * @exception IllegalArgumentException if the rows or columns + * @throws IllegalArgumentException if the rows or columns * arguments are negative. */ public JTextArea(Document doc, String text, int rows, int columns) { @@ -370,7 +370,7 @@ public class JTextArea extends JTextComponent { * * @param offset the offset >= 0 * @return the line number >= 0 - * @exception BadLocationException thrown if the offset is + * @throws BadLocationException thrown if the offset is * less than zero or greater than the document length. */ public int getLineOfOffset(int offset) throws BadLocationException { @@ -401,7 +401,7 @@ public class JTextArea extends JTextComponent { * * @param line the line number to translate >= 0 * @return the offset >= 0 - * @exception BadLocationException thrown if the line is + * @throws BadLocationException thrown if the line is * less than zero or greater or equal to the number of * lines contained in the document (as reported by * getLineCount). @@ -424,7 +424,7 @@ public class JTextArea extends JTextComponent { * * @param line the line >= 0 * @return the offset >= 0 - * @exception BadLocationException Thrown if the line is + * @throws BadLocationException Thrown if the line is * less than zero or greater or equal to the number of * lines contained in the document (as reported by * getLineCount). @@ -452,7 +452,7 @@ public class JTextArea extends JTextComponent { * * @param str the text to insert * @param pos the position at which to insert >= 0 - * @exception IllegalArgumentException if pos is an + * @throws IllegalArgumentException if pos is an * invalid position in the model * @see TextComponent#setText * @see #replaceRange @@ -493,7 +493,7 @@ public class JTextArea extends JTextComponent { * @param str the text to use as the replacement * @param start the start position >= 0 * @param end the end position >= start - * @exception IllegalArgumentException if part of the range is an + * @throws IllegalArgumentException if part of the range is an * invalid position in the model * @see #insert */ @@ -532,7 +532,7 @@ public class JTextArea extends JTextComponent { * setting the new value. * * @param rows the number of rows >= 0 - * @exception IllegalArgumentException if rows is less than 0 + * @throws IllegalArgumentException if rows is less than 0 * @see #getRows */ @BeanProperty(bound = false, description @@ -576,7 +576,7 @@ public class JTextArea extends JTextComponent { * after setting the new value. * * @param columns the number of columns >= 0 - * @exception IllegalArgumentException if columns is less than 0 + * @throws IllegalArgumentException if columns is less than 0 * @see #getColumns */ @BeanProperty(bound = false, description @@ -726,7 +726,7 @@ public class JTextArea extends JTextComponent { * @param direction Less than zero to scroll up/left, * greater than zero for down/right. * @return The "unit" increment for scrolling in the specified direction - * @exception IllegalArgumentException for an invalid orientation + * @throws IllegalArgumentException for an invalid orientation * @see JScrollBar#setUnitIncrement * @see #getRowHeight * @see #getColumnWidth diff --git a/src/java.desktop/share/classes/javax/swing/JTextField.java b/src/java.desktop/share/classes/javax/swing/JTextField.java index 3abe09d0565..0d66209d8af 100644 --- a/src/java.desktop/share/classes/javax/swing/JTextField.java +++ b/src/java.desktop/share/classes/javax/swing/JTextField.java @@ -242,7 +242,7 @@ public class JTextField extends JTextComponent implements SwingConstants { * the preferred width >= 0; if columns * is set to zero, the preferred width will be whatever * naturally results from the component implementation - * @exception IllegalArgumentException if columns < 0 + * @throws IllegalArgumentException if columns < 0 */ public JTextField(Document doc, String text, int columns) { if (columns < 0) { @@ -343,7 +343,7 @@ public class JTextField extends JTextComponent implements SwingConstants { * and a PropertyChange event ("horizontalAlignment") is fired. * * @param alignment the alignment - * @exception IllegalArgumentException if alignment + * @throws IllegalArgumentException if alignment * is not a valid key */ @BeanProperty(preferred = true, enumerationValues = { @@ -393,7 +393,7 @@ public class JTextField extends JTextComponent implements SwingConstants { * and then invalidate the layout. * * @param columns the number of columns >= 0 - * @exception IllegalArgumentException if columns + * @throws IllegalArgumentException if columns * is less than 0 */ @BeanProperty(bound = false, description diff --git a/src/java.desktop/share/classes/javax/swing/JTextPane.java b/src/java.desktop/share/classes/javax/swing/JTextPane.java index 41e16034c23..228181f31f7 100644 --- a/src/java.desktop/share/classes/javax/swing/JTextPane.java +++ b/src/java.desktop/share/classes/javax/swing/JTextPane.java @@ -138,7 +138,7 @@ public class JTextPane extends JEditorPane { * must be a StyledDocument. * * @param doc the document to display/edit - * @exception IllegalArgumentException if doc can't + * @throws IllegalArgumentException if doc can't * be narrowed to a StyledDocument which is the * required type of model for this text component */ @@ -480,7 +480,7 @@ public class JTextPane extends JEditorPane { * establishes the content type of the editor. * * @param kit the desired editor behavior - * @exception IllegalArgumentException if kit is not a + * @throws IllegalArgumentException if kit is not a * StyledEditorKit */ public final void setEditorKit(EditorKit kit) { diff --git a/src/java.desktop/share/classes/javax/swing/JToolBar.java b/src/java.desktop/share/classes/javax/swing/JToolBar.java index 114ef0d169c..4d93a1bceef 100644 --- a/src/java.desktop/share/classes/javax/swing/JToolBar.java +++ b/src/java.desktop/share/classes/javax/swing/JToolBar.java @@ -142,7 +142,7 @@ public class JToolBar extends JComponent implements SwingConstants, Accessible * @param name the name of the tool bar * @param orientation the initial orientation -- it must be * either HORIZONTAL or VERTICAL - * @exception IllegalArgumentException if orientation is neither + * @throws IllegalArgumentException if orientation is neither * HORIZONTAL nor VERTICAL * @since 1.3 */ @@ -406,7 +406,7 @@ public class JToolBar extends JComponent implements SwingConstants, Accessible * * @param o the new orientation -- either HORIZONTAL or * VERTICAL - * @exception IllegalArgumentException if orientation is neither + * @throws IllegalArgumentException if orientation is neither * HORIZONTAL nor VERTICAL * @see #getOrientation */ diff --git a/src/java.desktop/share/classes/javax/swing/JTree.java b/src/java.desktop/share/classes/javax/swing/JTree.java index ae90ea8be8b..e6e591bad27 100644 --- a/src/java.desktop/share/classes/javax/swing/JTree.java +++ b/src/java.desktop/share/classes/javax/swing/JTree.java @@ -1251,7 +1251,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * tree's {@code TransferHandler}. * * @param b whether or not to enable automatic drag handling - * @exception HeadlessException if + * @throws HeadlessException if * b is true and * GraphicsEnvironment.isHeadless() * returns true @@ -3087,7 +3087,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * Position.Bias.Forward or Position.Bias.Backward. * @return the TreePath of the next tree element that * starts with the prefix; otherwise null - * @exception IllegalArgumentException if prefix is null + * @throws IllegalArgumentException if prefix is null * or startingRow is out of bounds * @since 1.4 */ @@ -5053,7 +5053,7 @@ public class JTree extends JComponent implements Scrollable, Accessible * * @return This component's locale. If this component does not have * a locale, the locale of its parent is returned. - * @exception IllegalComponentStateException + * @throws IllegalComponentStateException * If the Component does not have its own locale and has not yet * been added to a containment hierarchy such that the locale can be * determined from the containing parent. diff --git a/src/java.desktop/share/classes/javax/swing/JViewport.java b/src/java.desktop/share/classes/javax/swing/JViewport.java index e3974a84f27..ff082acc694 100644 --- a/src/java.desktop/share/classes/javax/swing/JViewport.java +++ b/src/java.desktop/share/classes/javax/swing/JViewport.java @@ -565,7 +565,7 @@ public class JViewport extends JComponent implements Accessible * a JViewPort. * * @param border the Border to set - * @exception IllegalArgumentException this method is not implemented + * @throws IllegalArgumentException this method is not implemented */ public final void setBorder(Border border) { if (border != null) { diff --git a/src/java.desktop/share/classes/javax/swing/JWindow.java b/src/java.desktop/share/classes/javax/swing/JWindow.java index 69269c9f284..a306ea6d4ea 100644 --- a/src/java.desktop/share/classes/javax/swing/JWindow.java +++ b/src/java.desktop/share/classes/javax/swing/JWindow.java @@ -387,10 +387,10 @@ public class JWindow extends Window implements Accessible, * @param comp the component to be enhanced * @param constraints the constraints to be respected * @param index the index - * @exception IllegalArgumentException if index is invalid - * @exception IllegalArgumentException if adding the container's parent + * @throws IllegalArgumentException if index is invalid + * @throws IllegalArgumentException if adding the container's parent * to itself - * @exception IllegalArgumentException if adding a window to a container + * @throws IllegalArgumentException if adding a window to a container * * @see #setRootPaneCheckingEnabled * @see javax.swing.RootPaneContainer @@ -504,7 +504,7 @@ public class JWindow extends Window implements Accessible, * * @param contentPane the new contentPane * - * @exception IllegalComponentStateException (a runtime + * @throws IllegalComponentStateException (a runtime * exception) if the content pane parameter is null * @see #getContentPane * @see RootPaneContainer#setContentPane @@ -532,7 +532,7 @@ public class JWindow extends Window implements Accessible, * * @param layeredPane the new layeredPane object * - * @exception IllegalComponentStateException (a runtime + * @throws IllegalComponentStateException (a runtime * exception) if the content pane parameter is null * @see #getLayeredPane * @see RootPaneContainer#setLayeredPane diff --git a/src/java.desktop/share/classes/javax/swing/OverlayLayout.java b/src/java.desktop/share/classes/javax/swing/OverlayLayout.java index 0067f6fd6bd..71ca34f1aa0 100644 --- a/src/java.desktop/share/classes/javax/swing/OverlayLayout.java +++ b/src/java.desktop/share/classes/javax/swing/OverlayLayout.java @@ -217,7 +217,7 @@ public class OverlayLayout implements LayoutManager2,Serializable { * * @param target the container to lay out * - * @exception AWTError if the target isn't the container specified to the + * @throws AWTError if the target isn't the container specified to the * constructor */ public void layoutContainer(Container target) { diff --git a/src/java.desktop/share/classes/javax/swing/Popup.java b/src/java.desktop/share/classes/javax/swing/Popup.java index 605ecd6fd78..15c90ad3be7 100644 --- a/src/java.desktop/share/classes/javax/swing/Popup.java +++ b/src/java.desktop/share/classes/javax/swing/Popup.java @@ -82,7 +82,7 @@ public class Popup { * @param contents Contents of the Popup * @param x Initial x screen coordinate * @param y Initial y screen coordinate - * @exception IllegalArgumentException if contents is null + * @throws IllegalArgumentException if contents is null */ protected Popup(Component owner, Component contents, int x, int y) { this(); diff --git a/src/java.desktop/share/classes/javax/swing/PopupFactory.java b/src/java.desktop/share/classes/javax/swing/PopupFactory.java index 462675fa828..a30aba6f2fc 100644 --- a/src/java.desktop/share/classes/javax/swing/PopupFactory.java +++ b/src/java.desktop/share/classes/javax/swing/PopupFactory.java @@ -127,7 +127,7 @@ public class PopupFactory { * factory is null. * * @param factory Shared PopupFactory - * @exception IllegalArgumentException if factory is null + * @throws IllegalArgumentException if factory is null * @see #getPopup */ public static void setSharedInstance(PopupFactory factory) { @@ -186,7 +186,7 @@ public class PopupFactory { * @param contents Contents of the Popup * @param x Initial x screen coordinate * @param y Initial y screen coordinate - * @exception IllegalArgumentException if contents is null + * @throws IllegalArgumentException if contents is null * @return Popup containing Contents */ public Popup getPopup(Component owner, Component contents, diff --git a/src/java.desktop/share/classes/javax/swing/ProgressMonitor.java b/src/java.desktop/share/classes/javax/swing/ProgressMonitor.java index 8733d5b3cfe..6f2d1eda4b6 100644 --- a/src/java.desktop/share/classes/javax/swing/ProgressMonitor.java +++ b/src/java.desktop/share/classes/javax/swing/ProgressMonitor.java @@ -794,7 +794,7 @@ public class ProgressMonitor implements Accessible * @return this component's locale. If this component does not have * a locale, the locale of its parent is returned. * - * @exception IllegalComponentStateException + * @throws IllegalComponentStateException * If the Component does not have its own locale and has not yet been * added to a containment hierarchy such that the locale can be * determined from the containing parent. diff --git a/src/java.desktop/share/classes/javax/swing/RootPaneContainer.java b/src/java.desktop/share/classes/javax/swing/RootPaneContainer.java index 76dc2286f87..b05e0c52e55 100644 --- a/src/java.desktop/share/classes/javax/swing/RootPaneContainer.java +++ b/src/java.desktop/share/classes/javax/swing/RootPaneContainer.java @@ -103,7 +103,7 @@ public interface RootPaneContainer * Generally implemented with * getRootPane().setContentPane(contentPane); * - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the content pane parameter is null * @param contentPane the Container to use for the contents of this * JRootPane @@ -134,7 +134,7 @@ public interface RootPaneContainer * getRootPane().setLayeredPane(layeredPane); * * @param layeredPane the layered pane - * @exception java.awt.IllegalComponentStateException (a runtime + * @throws java.awt.IllegalComponentStateException (a runtime * exception) if the layered pane parameter is null * @see #getLayeredPane * @see JRootPane#getLayeredPane diff --git a/src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java b/src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java index 9f9e6660666..0b8d8576f14 100644 --- a/src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java +++ b/src/java.desktop/share/classes/javax/swing/ScrollPaneLayout.java @@ -230,7 +230,7 @@ public class ScrollPaneLayout * * @param s the component identifier * @param c the component to be added - * @exception IllegalArgumentException if s is an invalid key + * @throws IllegalArgumentException if s is an invalid key */ public void addLayoutComponent(String s, Component c) { @@ -328,7 +328,7 @@ public class ScrollPaneLayout * with the Swing 1.0.2 (and earlier) versions of this class. * * @param x an integer giving the display policy - * @exception IllegalArgumentException if x is an invalid + * @throws IllegalArgumentException if x is an invalid * vertical scroll bar policy, as listed above */ public void setVerticalScrollBarPolicy(int x) { @@ -366,7 +366,7 @@ public class ScrollPaneLayout * with the Swing 1.0.2 (and earlier) versions of this class. * * @param x an int giving the display policy - * @exception IllegalArgumentException if x is not a valid + * @throws IllegalArgumentException if x is not a valid * horizontal scrollbar policy, as listed above */ public void setHorizontalScrollBarPolicy(int x) { diff --git a/src/java.desktop/share/classes/javax/swing/SizeSequence.java b/src/java.desktop/share/classes/javax/swing/SizeSequence.java index 899a64570f3..c6877dc8b2b 100644 --- a/src/java.desktop/share/classes/javax/swing/SizeSequence.java +++ b/src/java.desktop/share/classes/javax/swing/SizeSequence.java @@ -142,7 +142,7 @@ public class SizeSequence { * all initialized to have size 0. * * @param numEntries the number of sizes to track - * @exception NegativeArraySizeException if + * @throws NegativeArraySizeException if * numEntries < 0 */ public SizeSequence(int numEntries) { @@ -355,7 +355,7 @@ public class SizeSequence { * in the group * @param length the number of entries in the group * @param value the size to be assigned to each new entry - * @exception ArrayIndexOutOfBoundsException if the parameters + * @throws ArrayIndexOutOfBoundsException if the parameters * are outside of the range: * (0 <= start < (getSizes().length)) AND (length >= 0) */ diff --git a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java index 5e3965e69b8..1d58541dfee 100644 --- a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java +++ b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java @@ -1466,10 +1466,10 @@ public class SwingUtilities implements SwingConstants * java.awt.EventQueue.invokeAndWait(). * * @param doRun the instance of {@code Runnable} - * @exception InterruptedException if we're interrupted while waiting for + * @throws InterruptedException if we're interrupted while waiting for * the event dispatching thread to finish executing * doRun.run() - * @exception InvocationTargetException if an exception is thrown + * @throws InvocationTargetException if an exception is thrown * while running doRun * * @see #invokeLater @@ -1984,7 +1984,7 @@ public class SwingUtilities implements SwingConstants * Returns a toolkit-private, shared, invisible Frame * to be the owner for JDialogs and JWindows created with * {@code null} owners. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -2002,7 +2002,7 @@ public class SwingUtilities implements SwingConstants /** * Returns a SharedOwnerFrame's shutdown listener to dispose the SharedOwnerFrame * if it has no more displayable children. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ diff --git a/src/java.desktop/share/classes/javax/swing/Timer.java b/src/java.desktop/share/classes/javax/swing/Timer.java index 6b4f95be108..ced691f4e06 100644 --- a/src/java.desktop/share/classes/javax/swing/Timer.java +++ b/src/java.desktop/share/classes/javax/swing/Timer.java @@ -341,7 +341,7 @@ public class Timer implements Serializable * on this timer, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType doesn't + * @throws ClassCastException if listenerType doesn't * specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/TransferHandler.java b/src/java.desktop/share/classes/javax/swing/TransferHandler.java index f2622880e7f..445234e4bda 100644 --- a/src/java.desktop/share/classes/javax/swing/TransferHandler.java +++ b/src/java.desktop/share/classes/javax/swing/TransferHandler.java @@ -1172,9 +1172,9 @@ public class TransferHandler implements Serializable { * * @param flavor the requested flavor for the data * @see DataFlavor#getRepresentationClass - * @exception IOException if the data is no longer available + * @throws IOException if the data is no longer available * in the requested flavor. - * @exception UnsupportedFlavorException if the requested data flavor is + * @throws UnsupportedFlavorException if the requested data flavor is * not supported. */ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { diff --git a/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java b/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java index 2f2163c8939..9a428492512 100644 --- a/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java +++ b/src/java.desktop/share/classes/javax/swing/colorchooser/AbstractColorChooserPanel.java @@ -161,7 +161,7 @@ public abstract class AbstractColorChooserPanel extends JPanel { * If you override this, be sure to call super. * * @param enclosingChooser the chooser to which the panel is to be added - * @exception RuntimeException if the chooser panel has already been + * @throws RuntimeException if the chooser panel has already been * installed */ public void installChooserPanel(JColorChooser enclosingChooser) { diff --git a/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java b/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java index 1be0228864c..81ae2393008 100644 --- a/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java +++ b/src/java.desktop/share/classes/javax/swing/event/EventListenerList.java @@ -144,7 +144,7 @@ public class EventListenerList implements Serializable { * @param the type of {@code EventListener} to search for * @param t the type of {@code EventListener} classes to be returned * @return all of the listeners of the specified type. - * @exception ClassCastException if the supplied class + * @throws ClassCastException if the supplied class * is not assignable to EventListener * * @since 1.3 diff --git a/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java b/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java index cba6691ba58..3c96fdabffd 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/TextUI.java @@ -49,7 +49,7 @@ public abstract class TextUI extends ComponentUI * @param t the text component for which this UI is installed * @param pos the local location in the model to translate >= 0 * @return the coordinates as a {@code Rectangle} - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * * @deprecated replaced by @@ -66,7 +66,7 @@ public abstract class TextUI extends ComponentUI * @param pos the local location in the model to translate >= 0 * @param bias the bias for the position * @return the coordinates as a {@code Rectangle} - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * * @deprecated replaced by @@ -86,7 +86,7 @@ public abstract class TextUI extends ComponentUI * @param pos the local location in the model to translate {@code >= 0} * @param bias the bias for the position * @return the coordinates as a {@code Rectangle2D} - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * * @since 9 @@ -178,8 +178,8 @@ public abstract class TextUI extends ComponentUI * @param biasRet an array to contain the bias for the returned position * @return the location within the model that best represents the next * location visual position - * @exception BadLocationException for a bad location within a document model - * @exception IllegalArgumentException for an invalid direction + * @throws BadLocationException for a bad location within a document model + * @throws IllegalArgumentException for an invalid direction */ public abstract int getNextVisualPositionFrom(JTextComponent t, int pos, Position.Bias b, diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicHTML.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicHTML.java index 3e1108fb25b..5a7f88ff3ce 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicHTML.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicHTML.java @@ -585,9 +585,9 @@ public class BasicHTML { * position is a boundary of two views. * @param a the allocated region to render into * @return the bounding box of the given position is returned - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document - * @exception IllegalArgumentException for an invalid bias argument + * @throws IllegalArgumentException for an invalid bias argument * @see View#viewToModel */ public Shape modelToView(int p0, Position.Bias b0, int p1, diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java index 360e98eee7a..92d5896bca2 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTabbedPaneUI.java @@ -775,7 +775,7 @@ public class BasicTabbedPaneUI extends TabbedPaneUI implements SwingConstants { * Returns the baseline for the specified tab. * * @param tab index of tab to get baseline for - * @exception IndexOutOfBoundsException if index is out of range + * @throws IndexOutOfBoundsException if index is out of range * (index < 0 || index >= tab count) * @return baseline or a value < 0 indicating there is no reasonable * baseline diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextFieldUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextFieldUI.java index 2e67a99720a..5d767d3b703 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextFieldUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextFieldUI.java @@ -345,7 +345,7 @@ public class BasicTextFieldUI extends BasicTextUI { * @param pos the position to convert >= 0 * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see View#modelToView */ @@ -367,9 +367,9 @@ public class BasicTextFieldUI extends BasicTextUI { * position is a boundary of two views. * @param a the allocated region to render into * @return the bounding box of the given position is returned - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document - * @exception IllegalArgumentException for an invalid bias argument + * @throws IllegalArgumentException for an invalid bias argument * @see View#viewToModel */ public Shape modelToView(int p0, Position.Bias b0, diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java index 6e98a57e5c3..881b9557b0c 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java @@ -1045,7 +1045,7 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * @param tc the text component for which this UI is installed * @param pos the local location in the model to translate >= 0 * @return the coordinates as a rectangle, null if the model is not painted - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView * @@ -1067,7 +1067,7 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * @param tc the text component for which this UI is installed * @param pos the local location in the model to translate >= 0 * @return the coordinates as a rectangle, null if the model is not painted - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView * @@ -1626,9 +1626,9 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * position is a boundary of two views. * @param a the allocated region to render into * @return the bounding box of the given position is returned - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document - * @exception IllegalArgumentException for an invalid bias argument + * @throws IllegalArgumentException for an invalid bias argument * @see View#viewToModel */ public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias b1, Shape a) throws BadLocationException { @@ -1674,9 +1674,9 @@ public abstract class BasicTextUI extends TextUI implements ViewFactory { * SwingConstants.NORTH, or SwingConstants.SOUTH. * @return the location within the model that best represents the next * location visual position. - * @exception BadLocationException the given position is not a valid + * @throws BadLocationException the given position is not a valid * position within the document - * @exception IllegalArgumentException for an invalid direction + * @throws IllegalArgumentException for an invalid direction */ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTransferable.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTransferable.java index 544c2ebe731..116226188c9 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTransferable.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTransferable.java @@ -130,9 +130,9 @@ class BasicTransferable implements Transferable, UIResource { * * @param flavor the requested flavor for the data * @see DataFlavor#getRepresentationClass - * @exception IOException if the data is no longer available + * @throws IOException if the data is no longer available * in the requested flavor. - * @exception UnsupportedFlavorException if the requested data flavor is + * @throws UnsupportedFlavorException if the requested data flavor is * not supported. */ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException { diff --git a/src/java.desktop/share/classes/javax/swing/table/AbstractTableModel.java b/src/java.desktop/share/classes/javax/swing/table/AbstractTableModel.java index 886d0ad64b0..99208f3cd26 100644 --- a/src/java.desktop/share/classes/javax/swing/table/AbstractTableModel.java +++ b/src/java.desktop/share/classes/javax/swing/table/AbstractTableModel.java @@ -331,7 +331,7 @@ public abstract class AbstractTableModel implements TableModel, Serializable * FooListeners on this component, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType + * @throws ClassCastException if listenerType * doesn't specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java b/src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java index ab5ff974eb9..e1a6264a478 100644 --- a/src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java +++ b/src/java.desktop/share/classes/javax/swing/table/DefaultTableColumnModel.java @@ -109,7 +109,7 @@ public class DefaultTableColumnModel implements TableColumnModel, * event to its listeners. * * @param aColumn the TableColumn to be added - * @exception IllegalArgumentException if aColumn is + * @throws IllegalArgumentException if aColumn is * null * @see #removeColumn */ @@ -170,7 +170,7 @@ public class DefaultTableColumnModel implements TableColumnModel, * * @param columnIndex the index of column to be moved * @param newIndex new index to move the column - * @exception IllegalArgumentException if column or + * @throws IllegalArgumentException if column or * newIndex * are not in the valid range */ @@ -258,7 +258,7 @@ public class DefaultTableColumnModel implements TableColumnModel, * @return the index of the first column in the * tableColumns array whose identifier * is equal to identifier - * @exception IllegalArgumentException if identifier + * @throws IllegalArgumentException if identifier * is null, or if no * TableColumn has this * identifier @@ -368,7 +368,7 @@ public class DefaultTableColumnModel implements TableColumnModel, * an exception is thrown. * * @param newModel the new selection model - * @exception IllegalArgumentException if newModel + * @throws IllegalArgumentException if newModel * is null * @see #getSelectionModel */ @@ -636,7 +636,7 @@ public class DefaultTableColumnModel implements TableColumnModel, * FooListeners on this model, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType + * @throws ClassCastException if listenerType * doesn't specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/table/DefaultTableModel.java b/src/java.desktop/share/classes/javax/swing/table/DefaultTableModel.java index 08dfc85b0a9..cdb3f29b76a 100644 --- a/src/java.desktop/share/classes/javax/swing/table/DefaultTableModel.java +++ b/src/java.desktop/share/classes/javax/swing/table/DefaultTableModel.java @@ -375,7 +375,7 @@ public class DefaultTableModel extends AbstractTableModel implements Serializabl * * @param row the row index of the row to be inserted * @param rowData optional data of the row being added - * @exception ArrayIndexOutOfBoundsException if the row was invalid + * @throws ArrayIndexOutOfBoundsException if the row was invalid */ public void insertRow(int row, Vector rowData) { dataVector.insertElementAt(rowData, row); @@ -390,7 +390,7 @@ public class DefaultTableModel extends AbstractTableModel implements Serializabl * * @param row the row index of the row to be inserted * @param rowData optional data of the row being added - * @exception ArrayIndexOutOfBoundsException if the row was invalid + * @throws ArrayIndexOutOfBoundsException if the row was invalid */ public void insertRow(int row, Object[] rowData) { insertRow(row, convertToVector(rowData)); @@ -438,7 +438,7 @@ public class DefaultTableModel extends AbstractTableModel implements Serializabl * @param start the starting row index to be moved * @param end the ending row index to be moved * @param to the destination of the rows to be moved - * @exception ArrayIndexOutOfBoundsException if any of the elements + * @throws ArrayIndexOutOfBoundsException if any of the elements * would be moved out of the table's range * */ @@ -463,7 +463,7 @@ public class DefaultTableModel extends AbstractTableModel implements Serializabl * of the row being removed will be sent to all the listeners. * * @param row the row index of the row to be removed - * @exception ArrayIndexOutOfBoundsException if the row was invalid + * @throws ArrayIndexOutOfBoundsException if the row was invalid */ public void removeRow(int row) { dataVector.removeElementAt(row); @@ -652,7 +652,7 @@ public class DefaultTableModel extends AbstractTableModel implements Serializabl * @param row the row whose value is to be queried * @param column the column whose value is to be queried * @return the value Object at the specified cell - * @exception ArrayIndexOutOfBoundsException if an invalid row or + * @throws ArrayIndexOutOfBoundsException if an invalid row or * column was given */ public Object getValueAt(int row, int column) { @@ -669,7 +669,7 @@ public class DefaultTableModel extends AbstractTableModel implements Serializabl * @param aValue the new value; this can be null * @param row the row whose value is to be changed * @param column the column whose value is to be changed - * @exception ArrayIndexOutOfBoundsException if an invalid row or + * @throws ArrayIndexOutOfBoundsException if an invalid row or * column was given */ public void setValueAt(Object aValue, int row, int column) { diff --git a/src/java.desktop/share/classes/javax/swing/table/JTableHeader.java b/src/java.desktop/share/classes/javax/swing/table/JTableHeader.java index f36b5646e3d..561d6a71c75 100644 --- a/src/java.desktop/share/classes/javax/swing/table/JTableHeader.java +++ b/src/java.desktop/share/classes/javax/swing/table/JTableHeader.java @@ -550,7 +550,7 @@ public class JTableHeader extends JComponent implements TableColumnModelListener * for listener notifications from the new column model. * * @param columnModel the new data source for this table - * @exception IllegalArgumentException + * @throws IllegalArgumentException * if newModel is null * @see #getColumnModel */ diff --git a/src/java.desktop/share/classes/javax/swing/table/TableColumnModel.java b/src/java.desktop/share/classes/javax/swing/table/TableColumnModel.java index eaaa8447ef7..4cf4870b5e3 100644 --- a/src/java.desktop/share/classes/javax/swing/table/TableColumnModel.java +++ b/src/java.desktop/share/classes/javax/swing/table/TableColumnModel.java @@ -79,7 +79,7 @@ public interface TableColumnModel * * @param columnIndex the index of column to be moved * @param newIndex index of the column's new location - * @exception IllegalArgumentException if columnIndex or + * @throws IllegalArgumentException if columnIndex or * newIndex * are not in the valid range */ @@ -119,7 +119,7 @@ public interface TableColumnModel * @param columnIdentifier the identifier object * @return the index of the first table column * whose identifier is equal to identifier - * @exception IllegalArgumentException if identifier + * @throws IllegalArgumentException if identifier * is null, or no * TableColumn has this * identifier diff --git a/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java b/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java index 1b97006bc34..db19b81e8e5 100644 --- a/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java +++ b/src/java.desktop/share/classes/javax/swing/text/AbstractDocument.java @@ -344,7 +344,7 @@ public abstract class AbstractDocument implements Document, Serializable { * FooListeners on this component, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType + * @throws ClassCastException if listenerType * doesn't specify a class or interface that implements * java.util.EventListener * @@ -604,7 +604,7 @@ public abstract class AbstractDocument implements Document, Serializable { * * @param offs the starting offset >= 0 * @param len the number of characters to remove >= 0 - * @exception BadLocationException the given remove position is not a valid + * @throws BadLocationException the given remove position is not a valid * position within the document * @see Document#remove */ @@ -674,7 +674,7 @@ public abstract class AbstractDocument implements Document, Serializable { * null * is legal, and typically treated as an empty attributeset, * but exact interpretation is left to the subclass - * @exception BadLocationException the given position is not a valid + * @throws BadLocationException the given position is not a valid * position within the document * @since 1.4 */ @@ -718,7 +718,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @param offs the starting offset >= 0 * @param str the string to insert; does nothing with null/empty strings * @param a the attributes for the inserted content - * @exception BadLocationException the given insert position is not a valid + * @throws BadLocationException the given insert position is not a valid * position within the document * @see Document#insertString */ @@ -792,7 +792,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @param offset the starting offset >= 0 * @param length the number of characters to retrieve >= 0 * @return the text - * @exception BadLocationException the range given includes a position + * @throws BadLocationException the range given includes a position * that is not a valid position within the document * @see Document#getText */ @@ -833,7 +833,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @param offset the starting offset >= 0 * @param length the number of characters to retrieve >= 0 * @param txt the Segment object to retrieve the text into - * @exception BadLocationException the range given includes a position + * @throws BadLocationException the range given includes a position * that is not a valid position within the document */ public void getText(int offset, int length, Segment txt) throws BadLocationException { @@ -854,7 +854,7 @@ public abstract class AbstractDocument implements Document, Serializable { * * @param offs the position in the model >= 0 * @return the position - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see Document#createPosition */ @@ -1354,7 +1354,7 @@ public abstract class AbstractDocument implements Document, Serializable { * Document will be left in a locked state so that no * reading or writing can be done. * - * @exception IllegalStateException thrown on illegal lock + * @throws IllegalStateException thrown on illegal lock * attempt. If the document is implemented properly, this can * only happen if a document listener attempts to mutate the * document. This situation violates the bean event model @@ -1633,7 +1633,7 @@ public abstract class AbstractDocument implements Document, Serializable { * * @param offset the offset in the content >= 0 * @return a Position - * @exception BadLocationException for an invalid offset + * @throws BadLocationException for an invalid offset */ public Position createPosition(int offset) throws BadLocationException; @@ -1652,7 +1652,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @return if the implementation supports a history mechanism, * a reference to an Edit implementation will be returned, * otherwise returns null - * @exception BadLocationException thrown if the area covered by + * @throws BadLocationException thrown if the area covered by * the arguments is not contained in the character sequence */ public UndoableEdit insertString(int where, String str) throws BadLocationException; @@ -1666,7 +1666,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @return If the implementation supports a history mechanism, * a reference to an Edit implementation will be returned, * otherwise null. - * @exception BadLocationException Thrown if the area covered by + * @throws BadLocationException Thrown if the area covered by * the arguments is not contained in the character sequence. */ public UndoableEdit remove(int where, int nitems) throws BadLocationException; @@ -1677,7 +1677,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @param where Offset into the sequence to fetch >= 0. * @param len number of characters to copy >= 0. * @return the string - * @exception BadLocationException Thrown if the area covered by + * @throws BadLocationException Thrown if the area covered by * the arguments is not contained in the character sequence. */ public String getString(int where, int len) throws BadLocationException; @@ -1688,7 +1688,7 @@ public abstract class AbstractDocument implements Document, Serializable { * @param where the starting offset >= 0 * @param len the number of characters >= 0 * @param txt the target location to copy into - * @exception BadLocationException Thrown if the area covered by + * @throws BadLocationException Thrown if the area covered by * the arguments is not contained in the character sequence. */ public void getChars(int where, int len, Segment txt) throws BadLocationException; @@ -2819,7 +2819,7 @@ public abstract class AbstractDocument implements Document, Serializable { /** * Redoes a change. * - * @exception CannotRedoException if the change cannot be redone + * @throws CannotRedoException if the change cannot be redone */ public void redo() throws CannotRedoException { writeLock(); @@ -2843,7 +2843,7 @@ public abstract class AbstractDocument implements Document, Serializable { /** * Undoes a change. * - * @exception CannotUndoException if the change cannot be undone + * @throws CannotUndoException if the change cannot be undone */ public void undo() throws CannotUndoException { writeLock(); @@ -3187,7 +3187,7 @@ public abstract class AbstractDocument implements Document, Serializable { /** * Redoes a change. * - * @exception CannotRedoException if the change cannot be redone + * @throws CannotRedoException if the change cannot be redone */ public void redo() throws CannotRedoException { super.redo(); @@ -3204,7 +3204,7 @@ public abstract class AbstractDocument implements Document, Serializable { /** * Undoes a change. * - * @exception CannotUndoException if the change cannot be undone + * @throws CannotUndoException if the change cannot be undone */ public void undo() throws CannotUndoException { super.undo(); diff --git a/src/java.desktop/share/classes/javax/swing/text/AbstractWriter.java b/src/java.desktop/share/classes/javax/swing/text/AbstractWriter.java index 0ca0fecb5a8..07a8301f0b5 100644 --- a/src/java.desktop/share/classes/javax/swing/text/AbstractWriter.java +++ b/src/java.desktop/share/classes/javax/swing/text/AbstractWriter.java @@ -270,7 +270,7 @@ public abstract class AbstractWriter { * when encountered. * * @param elem an Element - * @exception BadLocationException if pos represents an invalid + * @throws BadLocationException if pos represents an invalid * location within the document * @return the text as a String */ @@ -286,8 +286,8 @@ public abstract class AbstractWriter { * out. * * @param elem an Element. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ protected void text(Element elem) throws BadLocationException, @@ -462,7 +462,7 @@ public abstract class AbstractWriter { * line is empty, this will not make it so that the current line is * still considered empty. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void indent() throws IOException { int max = getIndentLevel() * getIndentSpace(); @@ -485,7 +485,7 @@ public abstract class AbstractWriter { * the write method that takes a char[]. * * @param ch a char. - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void write(char ch) throws IOException { if (tempChars == null) { @@ -500,7 +500,7 @@ public abstract class AbstractWriter { * write method that takes a char[]. * * @param content a String. - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void write(String content) throws IOException { if (content == null) { @@ -671,7 +671,7 @@ public abstract class AbstractWriter { * pairs. It throws an IOException when encountered. * * @param attr an AttributeSet. - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeAttributes(AttributeSet attr) throws IOException { diff --git a/src/java.desktop/share/classes/javax/swing/text/AsyncBoxView.java b/src/java.desktop/share/classes/javax/swing/text/AsyncBoxView.java index a9e4c58fbaa..ac0dd40b28a 100644 --- a/src/java.desktop/share/classes/javax/swing/text/AsyncBoxView.java +++ b/src/java.desktop/share/classes/javax/swing/text/AsyncBoxView.java @@ -640,7 +640,7 @@ public class AsyncBoxView extends View { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getPreferredSpan(int axis) { float margin = getInsetSpan(axis); @@ -665,7 +665,7 @@ public class AsyncBoxView extends View { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getMinimumSpan(int axis) { if (axis == this.axis) { @@ -693,7 +693,7 @@ public class AsyncBoxView extends View { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getMaximumSpan(int axis) { if (axis == this.axis) { @@ -773,9 +773,9 @@ public class AsyncBoxView extends View { * next character represented by the offset, in case the * position is a boundary of two views. * @return the bounding box of the given position is returned - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document - * @exception IllegalArgumentException for an invalid bias argument + * @throws IllegalArgumentException for an invalid bias argument * @see View#viewToModel */ public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { @@ -864,9 +864,9 @@ public class AsyncBoxView extends View { * @param biasRet an array contain the bias that was checked * @return the location within the model that best represents the next * location visual position - * @exception BadLocationException the given position is not a valid + * @throws BadLocationException the given position is not a valid * position within the document - * @exception IllegalArgumentException if direction is invalid + * @throws IllegalArgumentException if direction is invalid */ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, diff --git a/src/java.desktop/share/classes/javax/swing/text/BoxView.java b/src/java.desktop/share/classes/javax/swing/text/BoxView.java index afaefacccf5..cc21e039021 100644 --- a/src/java.desktop/share/classes/javax/swing/text/BoxView.java +++ b/src/java.desktop/share/classes/javax/swing/text/BoxView.java @@ -293,7 +293,7 @@ public class BoxView extends CompositeView { * @param axis may be either View.X_AXIS or * View.Y_AXIS * @return the weight - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public int getResizeWeight(int axis) { checkRequests(axis); @@ -473,7 +473,7 @@ public class BoxView extends CompositeView { * @param pos the position to convert >= 0 * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document * @see View#modelToView */ @@ -519,7 +519,7 @@ public class BoxView extends CompositeView { * origin and 1.0 indicates alignment to the full span * away from the origin; an alignment of 0.5 would be the * center of the view - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public float getAlignment(int axis) { checkRequests(axis); @@ -540,7 +540,7 @@ public class BoxView extends CompositeView { * typically the view is told to render into the span * that is returned, although there is no guarantee; * the parent may choose to resize or break the view - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getPreferredSpan(int axis) { checkRequests(axis); @@ -563,7 +563,7 @@ public class BoxView extends CompositeView { * typically the view is told to render into the span * that is returned, although there is no guarantee; * the parent may choose to resize or break the view - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getMinimumSpan(int axis) { checkRequests(axis); @@ -586,7 +586,7 @@ public class BoxView extends CompositeView { * typically the view is told to render into the span * that is returned, although there is no guarantee; * the parent may choose to resize or break the view - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getMaximumSpan(int axis) { checkRequests(axis); @@ -919,7 +919,7 @@ public class BoxView extends CompositeView { /** * Checks the request cache and update if needed. * @param axis the axis being studied - * @exception IllegalArgumentException if axis is + * @throws IllegalArgumentException if axis is * neither View.X_AXIS nor View.Y_AXIS */ void checkRequests(int axis) { diff --git a/src/java.desktop/share/classes/javax/swing/text/ComponentView.java b/src/java.desktop/share/classes/javax/swing/text/ComponentView.java index a4aaa30e512..0d8743f86ed 100644 --- a/src/java.desktop/share/classes/javax/swing/text/ComponentView.java +++ b/src/java.desktop/share/classes/javax/swing/text/ComponentView.java @@ -132,7 +132,7 @@ public class ComponentView extends View { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public float getPreferredSpan(int axis) { if ((axis != X_AXIS) && (axis != Y_AXIS)) { @@ -160,7 +160,7 @@ public class ComponentView extends View { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public float getMinimumSpan(int axis) { if ((axis != X_AXIS) && (axis != Y_AXIS)) { @@ -188,7 +188,7 @@ public class ComponentView extends View { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public float getMaximumSpan(int axis) { if ((axis != X_AXIS) && (axis != Y_AXIS)) { @@ -325,7 +325,7 @@ public class ComponentView extends View { * @param pos the position to convert >=0 * @param a the allocated region to render into * @return the bounding box of the given position is returned - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/CompositeView.java b/src/java.desktop/share/classes/javax/swing/text/CompositeView.java index 343c02feddc..5220395d35a 100644 --- a/src/java.desktop/share/classes/javax/swing/text/CompositeView.java +++ b/src/java.desktop/share/classes/javax/swing/text/CompositeView.java @@ -244,7 +244,7 @@ public abstract class CompositeView extends View { * @param b a bias value of either Position.Bias.Forward * or Position.Bias.Backward * @return the bounding box of the given position - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document * @see View#modelToView */ @@ -294,9 +294,9 @@ public abstract class CompositeView extends View { * position is a boundary of two views * @param a the allocated region to render into * @return the bounding box of the given position is returned - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document - * @exception IllegalArgumentException for an invalid bias argument + * @throws IllegalArgumentException for an invalid bias argument * @see View#viewToModel */ public Shape modelToView(int p0, Position.Bias b0, int p1, Position.Bias b1, Shape a) throws BadLocationException { @@ -458,9 +458,9 @@ public abstract class CompositeView extends View { * @param biasRet an array containing the bias that was checked * @return the location within the model that best represents the next * location visual position - * @exception BadLocationException the given position is not a valid + * @throws BadLocationException the given position is not a valid * position within the document - * @exception IllegalArgumentException if direction is invalid + * @throws IllegalArgumentException if direction is invalid */ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, Position.Bias[] biasRet) @@ -715,8 +715,8 @@ public abstract class CompositeView extends View { * @param biasRet an array containing the bias that was checked * @return the location within the model that best represents the next * north or south location - * @exception BadLocationException for a bad location within a document model - * @exception IllegalArgumentException if direction is invalid + * @throws BadLocationException for a bad location within a document model + * @throws IllegalArgumentException if direction is invalid * @see #getNextVisualPositionFrom */ protected int getNextNorthSouthVisualPositionFrom(int pos, Position.Bias b, @@ -748,8 +748,8 @@ public abstract class CompositeView extends View { * @param biasRet an array containing the bias that was checked * @return the location within the model that best represents the next * west or east location - * @exception BadLocationException for a bad location within a document model - * @exception IllegalArgumentException if direction is invalid + * @throws BadLocationException for a bad location within a document model + * @throws IllegalArgumentException if direction is invalid * @see #getNextVisualPositionFrom */ protected int getNextEastWestVisualPositionFrom(int pos, Position.Bias b, diff --git a/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java b/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java index a980268bd94..ff4d37224e3 100644 --- a/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java +++ b/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java @@ -870,7 +870,7 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou * FooListeners on this component, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType + * @throws ClassCastException if listenerType * doesn't specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/text/DefaultEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/DefaultEditorKit.java index ee1db4739ce..2d9971d3794 100644 --- a/src/java.desktop/share/classes/javax/swing/text/DefaultEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/DefaultEditorKit.java @@ -142,8 +142,8 @@ public class DefaultEditorKit extends EditorKit { * @param doc The destination for the insertion. * @param pos The location in the document to place the * content >=0. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public void read(InputStream in, Document doc, int pos) @@ -161,8 +161,8 @@ public class DefaultEditorKit extends EditorKit { * @param pos The location in the document to fetch the * content >=0. * @param len The amount to write out >=0. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public void write(OutputStream out, Document doc, int pos, int len) @@ -193,8 +193,8 @@ public class DefaultEditorKit extends EditorKit { * @param doc The destination for the insertion. * @param pos The location in the document to place the * content >=0. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public void read(Reader in, Document doc, int pos) @@ -303,8 +303,8 @@ public class DefaultEditorKit extends EditorKit { * @param pos The location in the document to fetch the * content from >=0. * @param len The amount to write out >=0. - * @exception IOException on any I/O error - * @exception BadLocationException if pos is not within 0 and + * @throws IOException on any I/O error + * @throws BadLocationException if pos is not within 0 and * the length of the document. */ public void write(Writer out, Document doc, int pos, int len) diff --git a/src/java.desktop/share/classes/javax/swing/text/DefaultHighlighter.java b/src/java.desktop/share/classes/javax/swing/text/DefaultHighlighter.java index 4e874ec1f00..0465b9157e2 100644 --- a/src/java.desktop/share/classes/javax/swing/text/DefaultHighlighter.java +++ b/src/java.desktop/share/classes/javax/swing/text/DefaultHighlighter.java @@ -110,7 +110,7 @@ public class DefaultHighlighter extends LayeredHighlighter { * @param p the painter to use to actually render the highlight * @return an object that can be used as a tag * to refer to the highlight - * @exception BadLocationException if the specified location is invalid + * @throws BadLocationException if the specified location is invalid */ public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter p) throws BadLocationException { if (p0 < 0) { @@ -222,7 +222,7 @@ public class DefaultHighlighter extends LayeredHighlighter { * @param tag the highlight tag * @param p0 the beginning of the range >= 0 * @param p1 the end of the range >= p0 - * @exception BadLocationException if the specified location is invalid + * @throws BadLocationException if the specified location is invalid */ public void changeHighlight(Object tag, int p0, int p1) throws BadLocationException { if (p0 < 0) { diff --git a/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java b/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java index f549f522ff2..5d373177eaf 100644 --- a/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java +++ b/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java @@ -182,7 +182,7 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc * * @param offset the starting offset >= 0 * @param data the element data - * @exception BadLocationException for an invalid starting offset + * @throws BadLocationException for an invalid starting offset */ protected void insert(int offset, ElementSpec[] data) throws BadLocationException { if (data == null || data.length == 0) { @@ -2548,7 +2548,7 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc /** * Redoes a change. * - * @exception CannotRedoException if the change cannot be redone + * @throws CannotRedoException if the change cannot be redone */ public void redo() throws CannotRedoException { super.redo(); @@ -2562,7 +2562,7 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc /** * Undoes a change. * - * @exception CannotUndoException if the change cannot be undone + * @throws CannotUndoException if the change cannot be undone */ public void undo() throws CannotUndoException { super.undo(); @@ -2604,7 +2604,7 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc /** * Redoes a change. * - * @exception CannotRedoException if the change cannot be redone + * @throws CannotRedoException if the change cannot be redone */ public void redo() throws CannotRedoException { super.redo(); @@ -2614,7 +2614,7 @@ public class DefaultStyledDocument extends AbstractDocument implements StyledDoc /** * Undoes a change. * - * @exception CannotUndoException if the change cannot be undone + * @throws CannotUndoException if the change cannot be undone */ public void undo() throws CannotUndoException { super.undo(); diff --git a/src/java.desktop/share/classes/javax/swing/text/Document.java b/src/java.desktop/share/classes/javax/swing/text/Document.java index e0f4ac791d5..09f162733cf 100644 --- a/src/java.desktop/share/classes/javax/swing/text/Document.java +++ b/src/java.desktop/share/classes/javax/swing/text/Document.java @@ -453,7 +453,7 @@ public interface Document { * * @param offs the offset from the beginning >= 0 * @param len the number of characters to remove >= 0 - * @exception BadLocationException some portion of the removal range + * @throws BadLocationException some portion of the removal range * was not a valid part of the document. The location in the exception * is the first bad position encountered. * @see javax.swing.event.DocumentEvent @@ -490,7 +490,7 @@ public interface Document { * @param str the string to insert * @param a the attributes to associate with the inserted * content. This may be null if there are no attributes. - * @exception BadLocationException the given insert position is not a valid + * @throws BadLocationException the given insert position is not a valid * position within the document * @see javax.swing.event.DocumentEvent * @see javax.swing.event.DocumentListener @@ -507,7 +507,7 @@ public interface Document { * start of the text >= 0 * @param length the length of the desired string >= 0 * @return the text, in a String of length >= 0 - * @exception BadLocationException some portion of the given range + * @throws BadLocationException some portion of the given range * was not a valid part of the document. The location in the exception * is the first bad position encountered. */ @@ -546,7 +546,7 @@ public interface Document { * @param length the length of the desired string >= 0 * @param txt the Segment object to return the text in * - * @exception BadLocationException Some portion of the given range + * @throws BadLocationException Some portion of the given range * was not a valid part of the document. The location in the exception * is the first bad position encountered. */ @@ -582,7 +582,7 @@ public interface Document { * * @param offs the offset from the start of the document >= 0 * @return the position - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document */ public Position createPosition(int offs) throws BadLocationException; diff --git a/src/java.desktop/share/classes/javax/swing/text/DocumentFilter.java b/src/java.desktop/share/classes/javax/swing/text/DocumentFilter.java index 5f69882ff8e..d0334bce45e 100644 --- a/src/java.desktop/share/classes/javax/swing/text/DocumentFilter.java +++ b/src/java.desktop/share/classes/javax/swing/text/DocumentFilter.java @@ -75,7 +75,7 @@ public class DocumentFilter { * @param fb FilterBypass that can be used to mutate Document * @param offset the offset from the beginning >= 0 * @param length the number of characters to remove >= 0 - * @exception BadLocationException some portion of the removal range + * @throws BadLocationException some portion of the removal range * was not a valid part of the document. The location in the exception * is the first bad position encountered. */ @@ -97,7 +97,7 @@ public class DocumentFilter { * @param string the string to insert * @param attr the attributes to associate with the inserted * content. This may be null if there are no attributes. - * @exception BadLocationException the given insert position is not a + * @throws BadLocationException the given insert position is not a * valid position within the document */ public void insertString(FilterBypass fb, int offset, String string, @@ -117,7 +117,7 @@ public class DocumentFilter { * @param text Text to insert, null indicates no text to insert * @param attrs AttributeSet indicating attributes of inserted text, * null is legal. - * @exception BadLocationException the given insert position is not a + * @throws BadLocationException the given insert position is not a * valid position within the document */ public void replace(FilterBypass fb, int offset, int length, String text, @@ -153,7 +153,7 @@ public class DocumentFilter { * * @param offset the offset from the beginning >= 0 * @param length the number of characters to remove >= 0 - * @exception BadLocationException some portion of the removal range + * @throws BadLocationException some portion of the removal range * was not a valid part of the document. The location in the * exception is the first bad position encountered. */ @@ -169,7 +169,7 @@ public class DocumentFilter { * @param string the string to insert * @param attr the attributes to associate with the inserted * content. This may be null if there are no attributes. - * @exception BadLocationException the given insert position is not a + * @throws BadLocationException the given insert position is not a * valid position within the document */ public abstract void insertString(int offset, String string, @@ -186,7 +186,7 @@ public class DocumentFilter { * @param string Text to insert, null indicates no text to insert * @param attrs AttributeSet indicating attributes of inserted text, * null is legal. - * @exception BadLocationException the given insert is not a + * @throws BadLocationException the given insert is not a * valid position within the document */ public abstract void replace(int offset, int length, String string, diff --git a/src/java.desktop/share/classes/javax/swing/text/EditorKit.java b/src/java.desktop/share/classes/javax/swing/text/EditorKit.java index 9163a6361e4..cd491fb5bac 100644 --- a/src/java.desktop/share/classes/javax/swing/text/EditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/EditorKit.java @@ -141,8 +141,8 @@ public abstract class EditorKit implements Cloneable, Serializable { * @param doc The destination for the insertion. * @param pos The location in the document to place the * content >= 0. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public abstract void read(InputStream in, Document doc, int pos) @@ -157,8 +157,8 @@ public abstract class EditorKit implements Cloneable, Serializable { * @param pos The location in the document to fetch the * content from >= 0. * @param len The amount to write out >= 0. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public abstract void write(OutputStream out, Document doc, int pos, int len) @@ -178,8 +178,8 @@ public abstract class EditorKit implements Cloneable, Serializable { * @param doc The destination for the insertion. * @param pos The location in the document to place the * content >= 0. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public abstract void read(Reader in, Document doc, int pos) @@ -199,8 +199,8 @@ public abstract class EditorKit implements Cloneable, Serializable { * @param pos The location in the document to fetch the * content >= 0. * @param len The amount to write out >= 0. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public abstract void write(Writer out, Document doc, int pos, int len) diff --git a/src/java.desktop/share/classes/javax/swing/text/FieldView.java b/src/java.desktop/share/classes/javax/swing/text/FieldView.java index 936a78700be..b5ad6369945 100644 --- a/src/java.desktop/share/classes/javax/swing/text/FieldView.java +++ b/src/java.desktop/share/classes/javax/swing/text/FieldView.java @@ -258,7 +258,7 @@ public class FieldView extends PlainView { * @param pos the position to convert >= 0 * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/GapContent.java b/src/java.desktop/share/classes/javax/swing/text/GapContent.java index c59c350541b..6c96b2b0ec3 100644 --- a/src/java.desktop/share/classes/javax/swing/text/GapContent.java +++ b/src/java.desktop/share/classes/javax/swing/text/GapContent.java @@ -130,7 +130,7 @@ public class GapContent extends GapVector implements AbstractDocument.Content, S * @param where the starting position >= 0, < length() * @param str the non-null string to insert * @return an UndoableEdit object for undoing - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid * @see AbstractDocument.Content#insertString */ public UndoableEdit insertString(int where, String str) throws BadLocationException { @@ -148,7 +148,7 @@ public class GapContent extends GapVector implements AbstractDocument.Content, S * @param where the starting position >= 0, where + nitems < length() * @param nitems the number of characters to remove >= 0 * @return an UndoableEdit object for undoing - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid * @see AbstractDocument.Content#remove */ public UndoableEdit remove(int where, int nitems) throws BadLocationException { @@ -168,7 +168,7 @@ public class GapContent extends GapVector implements AbstractDocument.Content, S * @param where the starting position >= 0 * @param len the length to retrieve >= 0 * @return a string representing the content - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid * @see AbstractDocument.Content#getString */ public String getString(int where, int len) throws BadLocationException { @@ -186,7 +186,7 @@ public class GapContent extends GapVector implements AbstractDocument.Content, S * @param where the starting position >= 0, where + len <= length() * @param len the number of characters to retrieve >= 0 * @param chars the Segment object to return the characters in - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid * @see AbstractDocument.Content#getChars */ public void getChars(int where, int len, Segment chars) throws BadLocationException { @@ -237,7 +237,7 @@ public class GapContent extends GapVector implements AbstractDocument.Content, S * * @param offset the offset to track >= 0 * @return the position - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid */ public Position createPosition(int offset) throws BadLocationException { while ( queue.poll() != null ) { diff --git a/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java b/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java index 3a070bb4040..59e2a9da491 100644 --- a/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java +++ b/src/java.desktop/share/classes/javax/swing/text/GlyphPainter2.java @@ -231,8 +231,8 @@ class GlyphPainter2 extends GlyphView.GlyphPainter { * SwingConstants.NORTH, or SwingConstants.SOUTH. * @return the location within the model that best represents the next * location visual position. - * @exception BadLocationException - * @exception IllegalArgumentException for an invalid direction + * @throws BadLocationException + * @throws IllegalArgumentException for an invalid direction */ public int getNextVisualPositionFrom(GlyphView v, int pos, Position.Bias b, Shape a, diff --git a/src/java.desktop/share/classes/javax/swing/text/GlyphView.java b/src/java.desktop/share/classes/javax/swing/text/GlyphView.java index b075356593c..8a4828f62d5 100644 --- a/src/java.desktop/share/classes/javax/swing/text/GlyphView.java +++ b/src/java.desktop/share/classes/javax/swing/text/GlyphView.java @@ -637,7 +637,7 @@ public class GlyphView extends View implements TabableView, Cloneable { * @param b either Position.Bias.Forward * or Position.Bias.Backward * @return the bounding box of the given position - * @exception BadLocationException if the given position does not represent a + * @throws BadLocationException if the given position does not represent a * valid location in the associated document * @see View#modelToView */ @@ -885,9 +885,9 @@ public class GlyphView extends View implements TabableView, Cloneable { * SwingConstants.NORTH, or SwingConstants.SOUTH. * @return the location within the model that best represents the next * location visual position. - * @exception BadLocationException the given position is not a valid + * @throws BadLocationException the given position is not a valid * position within the document - * @exception IllegalArgumentException for an invalid direction + * @throws IllegalArgumentException for an invalid direction */ public int getNextVisualPositionFrom(int pos, Position.Bias b, Shape a, int direction, @@ -1199,7 +1199,7 @@ public class GlyphView extends View implements TabableView, Cloneable { * or Position.Bias.Backward * @param a Bounds of the View * @return the bounding box of the given position - * @exception BadLocationException if the given position does not represent a + * @throws BadLocationException if the given position does not represent a * valid location in the associated document * @see View#modelToView */ @@ -1283,8 +1283,8 @@ public class GlyphView extends View implements TabableView, Cloneable { * is returned as the zero-th element of this array * @return the location within the model that best represents the next * location visual position. - * @exception BadLocationException for a bad location within a document model - * @exception IllegalArgumentException for an invalid direction + * @throws BadLocationException for a bad location within a document model + * @throws IllegalArgumentException for an invalid direction */ public int getNextVisualPositionFrom(GlyphView v, int pos, Position.Bias b, Shape a, int direction, diff --git a/src/java.desktop/share/classes/javax/swing/text/Highlighter.java b/src/java.desktop/share/classes/javax/swing/text/Highlighter.java index 10243f10cdd..7913e47b948 100644 --- a/src/java.desktop/share/classes/javax/swing/text/Highlighter.java +++ b/src/java.desktop/share/classes/javax/swing/text/Highlighter.java @@ -70,7 +70,7 @@ public interface Highlighter { * @param p1 the end of the range >= p0 * @param p the painter to use for the actual highlighting * @return an object that refers to the highlight - * @exception BadLocationException for an invalid range specification + * @throws BadLocationException for an invalid range specification */ public Object addHighlight(int p0, int p1, HighlightPainter p) throws BadLocationException; @@ -95,7 +95,7 @@ public interface Highlighter { * @param tag which highlight to change * @param p0 the beginning of the range >= 0 * @param p1 the end of the range >= p0 - * @exception BadLocationException for an invalid range specification + * @throws BadLocationException for an invalid range specification */ public void changeHighlight(Object tag, int p0, int p1) throws BadLocationException; diff --git a/src/java.desktop/share/classes/javax/swing/text/IconView.java b/src/java.desktop/share/classes/javax/swing/text/IconView.java index c908e973753..76cb653c9ae 100644 --- a/src/java.desktop/share/classes/javax/swing/text/IconView.java +++ b/src/java.desktop/share/classes/javax/swing/text/IconView.java @@ -81,7 +81,7 @@ public class IconView extends View { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public float getPreferredSpan(int axis) { switch (axis) { @@ -123,7 +123,7 @@ public class IconView extends View { * @param pos the position to convert >= 0 * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java b/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java index cbdd308cc84..d618dc6a2a1 100644 --- a/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java +++ b/src/java.desktop/share/classes/javax/swing/text/JTextComponent.java @@ -672,7 +672,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * component's {@code TransferHandler}. * * @param b whether or not to enable automatic drag handling - * @exception HeadlessException if + * @throws HeadlessException if * b is true and * GraphicsEnvironment.isHeadless() * returns true @@ -1358,7 +1358,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @param offs the offset ≥ 0 * @param len the length ≥ 0 * @return the text - * @exception BadLocationException if the offset or length are invalid + * @throws BadLocationException if the offset or length are invalid */ public String getText(int offs, int len) throws BadLocationException { return getDocument().getText(offs, len); @@ -1376,7 +1376,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @return the coordinates as a rectangle, with (r.x, r.y) as the location * in the coordinate system, or null if the component does * not yet have a positive size. - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView * @@ -1400,7 +1400,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @return the coordinates as a rectangle, with (r.x, r.y) as the location * in the coordinate system, or null if the component does * not yet have a positive size. - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see TextUI#modelToView2D * @@ -1545,7 +1545,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * an exception is thrown. * * @param pos the position - * @exception IllegalArgumentException if the value supplied + * @throws IllegalArgumentException if the value supplied * for position is less than zero or greater * than the component's text length * @see #setCaretPosition @@ -1617,7 +1617,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * of documents (such as html for example) might be * able to make use of this information; if non-null, * it is added as a property of the document - * @exception IOException as thrown by the stream being + * @throws IOException as thrown by the stream being * used to initialize * @see EditorKit#createDefaultDocument * @see #setDocument @@ -1643,7 +1643,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * text. * * @param out the output stream - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ public void write(Writer out) throws IOException { Document doc = getDocument(); @@ -1672,7 +1672,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * an exception is thrown. * * @param position the position - * @exception IllegalArgumentException if the value supplied + * @throws IllegalArgumentException if the value supplied * for position is less than zero or greater * than the component's text length */ @@ -1743,7 +1743,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * use DocumentListener. * * @return the text - * @exception NullPointerException if the document is null + * @throws NullPointerException if the document is null * @see #setText */ public String getText() { @@ -1763,7 +1763,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * null or the document empty, returns null. * * @return the text - * @exception IllegalArgumentException if the selection doesn't + * @throws IllegalArgumentException if the selection doesn't * have a valid mapping into the document for some reason * @see #setText */ @@ -2013,7 +2013,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @param direction less than zero to scroll up/left, greater than * zero for down/right * @return the "unit" increment for scrolling in the specified direction - * @exception IllegalArgumentException for an invalid orientation + * @throws IllegalArgumentException for an invalid orientation * @see JScrollBar#setUnitIncrement */ public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { @@ -2043,7 +2043,7 @@ public abstract class JTextComponent extends JComponent implements Scrollable, A * @param direction less than zero to scroll up/left, greater than zero * for down/right * @return the "block" increment for scrolling in the specified direction - * @exception IllegalArgumentException for an invalid orientation + * @throws IllegalArgumentException for an invalid orientation * @see JScrollBar#setBlockIncrement */ public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { diff --git a/src/java.desktop/share/classes/javax/swing/text/NavigationFilter.java b/src/java.desktop/share/classes/javax/swing/text/NavigationFilter.java index 648625e8974..a7d85a71e02 100644 --- a/src/java.desktop/share/classes/javax/swing/text/NavigationFilter.java +++ b/src/java.desktop/share/classes/javax/swing/text/NavigationFilter.java @@ -105,8 +105,8 @@ public class NavigationFilter { * @param biasRet Used to return resulting Bias of next position * @return the location within the model that best represents the next * location visual position - * @exception BadLocationException for a bad location within a document model - * @exception IllegalArgumentException if direction + * @throws BadLocationException for a bad location within a document model + * @throws IllegalArgumentException if direction * doesn't have one of the legal values above */ public int getNextVisualPositionFrom(JTextComponent text, int pos, diff --git a/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java b/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java index f8d0e390cb2..e24583af13b 100644 --- a/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java +++ b/src/java.desktop/share/classes/javax/swing/text/ParagraphView.java @@ -876,7 +876,7 @@ public class ParagraphView extends FlowView implements TabExpander { * @param pos the position to convert * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not represent a + * @throws BadLocationException if the given position does not represent a * valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/PasswordView.java b/src/java.desktop/share/classes/javax/swing/text/PasswordView.java index 38bb0eec13e..bdf8d5cdfe6 100644 --- a/src/java.desktop/share/classes/javax/swing/text/PasswordView.java +++ b/src/java.desktop/share/classes/javax/swing/text/PasswordView.java @@ -61,7 +61,7 @@ public class PasswordView extends FieldView { * @param p0 the starting offset in the model >= 0 * @param p1 the ending offset in the model >= p0 * @return the X location of the end of the range >= 0 - * @exception BadLocationException if p0 or p1 are out of range + * @throws BadLocationException if p0 or p1 are out of range * * @deprecated replaced by * {@link #drawUnselectedText(Graphics2D, float, float, int, int)} @@ -131,7 +131,7 @@ public class PasswordView extends FieldView { * @param p0 the starting offset in the model >= 0 * @param p1 the ending offset in the model >= p0 * @return the X location of the end of the range >= 0 - * @exception BadLocationException if p0 or p1 are out of range + * @throws BadLocationException if p0 or p1 are out of range * * @deprecated replaced by * {@link #drawSelectedText(Graphics2D, float, float, int, int)} @@ -240,7 +240,7 @@ public class PasswordView extends FieldView { * @param pos the position to convert >= 0 * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/PlainDocument.java b/src/java.desktop/share/classes/javax/swing/text/PlainDocument.java index cd397d12a68..ad6a0bdf2d3 100644 --- a/src/java.desktop/share/classes/javax/swing/text/PlainDocument.java +++ b/src/java.desktop/share/classes/javax/swing/text/PlainDocument.java @@ -107,7 +107,7 @@ public class PlainDocument extends AbstractDocument { * @param offs the starting offset >= 0 * @param str the string to insert; does nothing with null/empty strings * @param a the attributes for the inserted content - * @exception BadLocationException the given insert position is not a valid + * @throws BadLocationException the given insert position is not a valid * position within the document * @see Document#insertString */ diff --git a/src/java.desktop/share/classes/javax/swing/text/PlainView.java b/src/java.desktop/share/classes/javax/swing/text/PlainView.java index 725dec9bb7d..0c245196d99 100644 --- a/src/java.desktop/share/classes/javax/swing/text/PlainView.java +++ b/src/java.desktop/share/classes/javax/swing/text/PlainView.java @@ -179,7 +179,7 @@ public class PlainView extends View implements TabExpander { * @param p0 the beginning position in the model >= 0 * @param p1 the ending position in the model >= 0 * @return the X location of the end of the range >= 0 - * @exception BadLocationException if the range is invalid + * @throws BadLocationException if the range is invalid * * @deprecated replaced by * {@link #drawUnselectedText(Graphics2D, float, float, int, int)} @@ -224,7 +224,7 @@ public class PlainView extends View implements TabExpander { * @param p0 the beginning position in the model {@code >= 0} * @param p1 the ending position in the model {@code >= 0} * @return the X location of the end of the range {@code >= 0} - * @exception BadLocationException if the range is invalid + * @throws BadLocationException if the range is invalid * * @since 9 */ @@ -245,7 +245,7 @@ public class PlainView extends View implements TabExpander { * @param p0 the beginning position in the model >= 0 * @param p1 the ending position in the model >= 0 * @return the location of the end of the range - * @exception BadLocationException if the range is invalid + * @throws BadLocationException if the range is invalid * * @deprecated replaced by * {@link #drawSelectedText(Graphics2D, float, float, int, int)} @@ -294,7 +294,7 @@ public class PlainView extends View implements TabExpander { * @param p0 the beginning position in the model {@code >= 0} * @param p1 the ending position in the model {@code >= 0} * @return the location of the end of the range - * @exception BadLocationException if the range is invalid + * @throws BadLocationException if the range is invalid * * @since 9 */ @@ -351,7 +351,7 @@ public class PlainView extends View implements TabExpander { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public float getPreferredSpan(int axis) { updateMetrics(); @@ -468,7 +468,7 @@ public class PlainView extends View implements TabExpander { * @param pos the position to convert >= 0 * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/StringContent.java b/src/java.desktop/share/classes/javax/swing/text/StringContent.java index 7f154df38ed..04bd4d7e0b4 100644 --- a/src/java.desktop/share/classes/javax/swing/text/StringContent.java +++ b/src/java.desktop/share/classes/javax/swing/text/StringContent.java @@ -90,7 +90,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab * @param where the starting position >= 0 && < length() * @param str the non-null string to insert * @return an UndoableEdit object for undoing - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid * @see AbstractDocument.Content#insertString */ public UndoableEdit insertString(int where, String str) throws BadLocationException { @@ -111,7 +111,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab * @param where the starting position >= 0 * @param nitems the number of characters to remove >= 0 * @return an UndoableEdit object for undoing - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid * @see AbstractDocument.Content#remove */ public UndoableEdit remove(int where, int nitems) throws BadLocationException { @@ -134,7 +134,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab * @param where the starting position >= 0 * @param len the length to retrieve >= 0 * @return a string representing the content; may be empty - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid * @see AbstractDocument.Content#getString */ public String getString(int where, int len) throws BadLocationException { @@ -150,7 +150,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab * @param where the starting position >= 0 * @param len the number of characters to retrieve >= 0 * @param chars the Segment object to return the characters in - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid * @see AbstractDocument.Content#getChars */ public void getChars(int where, int len, Segment chars) throws BadLocationException { @@ -168,7 +168,7 @@ public final class StringContent implements AbstractDocument.Content, Serializab * * @param offset the offset to create a position for >= 0 * @return the position - * @exception BadLocationException if the specified position is invalid + * @throws BadLocationException if the specified position is invalid */ public Position createPosition(int offset) throws BadLocationException { // some small documents won't have any sticky positions diff --git a/src/java.desktop/share/classes/javax/swing/text/StyleContext.java b/src/java.desktop/share/classes/javax/swing/text/StyleContext.java index 9e01aecd3fb..70da1356b99 100644 --- a/src/java.desktop/share/classes/javax/swing/text/StyleContext.java +++ b/src/java.desktop/share/classes/javax/swing/text/StyleContext.java @@ -579,7 +579,7 @@ public class StyleContext implements Serializable, AbstractDocument.AttributeCon * Context-specific handling of writing out attributes * @param out the output stream * @param a the attribute set - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ public void writeAttributes(ObjectOutputStream out, AttributeSet a) throws IOException { @@ -591,9 +591,9 @@ public class StyleContext implements Serializable, AbstractDocument.AttributeCon * @param in the object stream to read the attribute data from. * @param a the attribute set to place the attribute * definitions in. - * @exception ClassNotFoundException passed upward if encountered + * @throws ClassNotFoundException passed upward if encountered * when reading the object stream. - * @exception IOException passed upward if encountered when + * @throws IOException passed upward if encountered when * reading the object stream. */ public void readAttributes(ObjectInputStream in, @@ -613,7 +613,7 @@ public class StyleContext implements Serializable, AbstractDocument.AttributeCon * * @param out the output stream * @param a the attribute set - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ public static void writeAttributeSet(ObjectOutputStream out, AttributeSet a) throws IOException { @@ -660,9 +660,9 @@ public class StyleContext implements Serializable, AbstractDocument.AttributeCon * @param in the object stream to read the attribute data from. * @param a the attribute set to place the attribute * definitions in. - * @exception ClassNotFoundException passed upward if encountered + * @throws ClassNotFoundException passed upward if encountered * when reading the object stream. - * @exception IOException passed upward if encountered when + * @throws IOException passed upward if encountered when * reading the object stream. */ public static void readAttributeSet(ObjectInputStream in, @@ -1077,7 +1077,7 @@ public class StyleContext implements Serializable, AbstractDocument.AttributeCon * Returns the next element of this enumeration. * * @return the next element of this enumeration. - * @exception NoSuchElementException if no more elements exist. + * @throws NoSuchElementException if no more elements exist. * @since 1.0 */ public Object nextElement() { diff --git a/src/java.desktop/share/classes/javax/swing/text/StyledEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/StyledEditorKit.java index 00ad982cbf4..a4984efce6c 100644 --- a/src/java.desktop/share/classes/javax/swing/text/StyledEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/StyledEditorKit.java @@ -411,7 +411,7 @@ public class StyledEditorKit extends DefaultEditorKit { * * @param e the editor * @return the document - * @exception IllegalArgumentException for the wrong document type + * @throws IllegalArgumentException for the wrong document type */ protected final StyledDocument getStyledDocument(JEditorPane e) { Document d = e.getDocument(); @@ -426,7 +426,7 @@ public class StyledEditorKit extends DefaultEditorKit { * * @param e the editor pane * @return the kit - * @exception IllegalArgumentException for the wrong document type + * @throws IllegalArgumentException for the wrong document type */ protected final StyledEditorKit getStyledEditorKit(JEditorPane e) { EditorKit k = e.getEditorKit(); diff --git a/src/java.desktop/share/classes/javax/swing/text/TableView.java b/src/java.desktop/share/classes/javax/swing/text/TableView.java index bd1c677ffae..d18bd5a93db 100644 --- a/src/java.desktop/share/classes/javax/swing/text/TableView.java +++ b/src/java.desktop/share/classes/javax/swing/text/TableView.java @@ -805,7 +805,7 @@ public abstract class TableView extends BoxView { * * @param axis may be either View.X_AXIS or View.Y_AXIS * @return the resize weight - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public int getResizeWeight(int axis) { return 1; diff --git a/src/java.desktop/share/classes/javax/swing/text/Utilities.java b/src/java.desktop/share/classes/javax/swing/text/Utilities.java index ae93b5a40b5..62f323f076a 100644 --- a/src/java.desktop/share/classes/javax/swing/text/Utilities.java +++ b/src/java.desktop/share/classes/javax/swing/text/Utilities.java @@ -683,7 +683,7 @@ public class Utilities { * @param offs the offset in the document >= 0 * @return the position >= 0 if the request can be computed, otherwise * a value of -1 will be returned. - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range */ @SuppressWarnings("deprecation") public static final int getRowStart(JTextComponent c, int offs) throws BadLocationException { @@ -714,7 +714,7 @@ public class Utilities { * @param offs the offset in the document >= 0 * @return the position >= 0 if the request can be computed, otherwise * a value of -1 will be returned. - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range */ @SuppressWarnings("deprecation") public static final int getRowEnd(JTextComponent c, int offs) throws BadLocationException { @@ -747,7 +747,7 @@ public class Utilities { * @param x the X coordinate >= 0 * @return the position >= 0 if the request can be computed, otherwise * a value of -1 will be returned. - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range * * @deprecated replaced by * {@link #getPositionAbove(JTextComponent, int, float)} @@ -802,7 +802,7 @@ public class Utilities { * @param x the X coordinate {@code >= 0} * @return the position {@code >= 0} if the request can be computed, otherwise * a value of -1 will be returned. - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range * * @since 9 */ @@ -822,7 +822,7 @@ public class Utilities { * @param x the X coordinate >= 0 * @return the position >= 0 if the request can be computed, otherwise * a value of -1 will be returned. - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range * * @deprecated replaced by * {@link #getPositionBelow(JTextComponent, int, float)} @@ -878,7 +878,7 @@ public class Utilities { * @param x the X coordinate {@code >= 0} * @return the position {@code >= 0} if the request can be computed, otherwise * a value of -1 will be returned. - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range * * @since 9 */ @@ -894,7 +894,7 @@ public class Utilities { * @param c the editor * @param offs the offset in the document >= 0 * @return the location in the model of the word start >= 0 - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range */ public static final int getWordStart(JTextComponent c, int offs) throws BadLocationException { Document doc = c.getDocument(); @@ -928,7 +928,7 @@ public class Utilities { * @param c the editor * @param offs the offset in the document >= 0 * @return the location in the model of the word end >= 0 - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range */ public static final int getWordEnd(JTextComponent c, int offs) throws BadLocationException { Document doc = c.getDocument(); @@ -961,7 +961,7 @@ public class Utilities { * @param c the editor * @param offs the offset in the document >= 0 * @return the location in the model of the word start >= 0 - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range */ public static final int getNextWord(JTextComponent c, int offs) throws BadLocationException { int nextWord; @@ -1039,7 +1039,7 @@ public class Utilities { * @param c the editor * @param offs the offset in the document >= 0 * @return the location in the model of the word start >= 0 - * @exception BadLocationException if the offset is out of range + * @throws BadLocationException if the offset is out of range */ public static final int getPreviousWord(JTextComponent c, int offs) throws BadLocationException { int prevWord; @@ -1271,8 +1271,8 @@ public class Utilities { * @param biasRet an array contain the bias that was checked * @return the location within the model that best represents the next * location visual position - * @exception BadLocationException - * @exception IllegalArgumentException if direction is invalid + * @throws BadLocationException + * @throws IllegalArgumentException if direction is invalid */ static int getNextVisualPositionFrom(View v, int pos, Position.Bias b, Shape alloc, int direction, diff --git a/src/java.desktop/share/classes/javax/swing/text/View.java b/src/java.desktop/share/classes/javax/swing/text/View.java index a3ad927e3a8..eb10efb0e83 100644 --- a/src/java.desktop/share/classes/javax/swing/text/View.java +++ b/src/java.desktop/share/classes/javax/swing/text/View.java @@ -495,9 +495,9 @@ public abstract class View implements SwingConstants { * @param biasRet the returned bias * @return the location within the model that best represents the next * location visual position - * @exception BadLocationException the given position is not a valid + * @throws BadLocationException the given position is not a valid * position within the document - * @exception IllegalArgumentException if direction + * @throws IllegalArgumentException if direction * doesn't have one of the legal values above */ @SuppressWarnings("deprecation") @@ -585,9 +585,9 @@ public abstract class View implements SwingConstants { * * @return the bounding box, in view coordinate space, * of the character at the specified position - * @exception BadLocationException if the specified position does + * @throws BadLocationException if the specified position does * not represent a valid location in the associated document - * @exception IllegalArgumentException if b is not one of the + * @throws IllegalArgumentException if b is not one of the * legal Position.Bias values listed above * @see View#viewToModel */ @@ -615,9 +615,9 @@ public abstract class View implements SwingConstants { * @param a the area of the view, which encompasses the requested region * @return the bounding box which is a union of the region specified * by the first and last character positions - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document - * @exception IllegalArgumentException if b0 or + * @throws IllegalArgumentException if b0 or * b1 are not one of the * legal Position.Bias values listed above * @see View#viewToModel @@ -1337,7 +1337,7 @@ public abstract class View implements SwingConstants { * @param pos the position to convert >= 0 * @param a the allocated region in which to render * @return the bounding box of the given position is returned - * @exception BadLocationException if the given position does + * @throws BadLocationException if the given position does * not represent a valid location in the associated document * @see View#modelToView * @deprecated diff --git a/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java b/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java index b229fa69f9f..d3587c8b40b 100644 --- a/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java +++ b/src/java.desktop/share/classes/javax/swing/text/WrappedPlainView.java @@ -207,7 +207,7 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @param p0 the beginning position in the model >= 0 * @param p1 the ending position in the model >= p0 * @return the X location of the end of the range >= 0 - * @exception BadLocationException if the range is invalid + * @throws BadLocationException if the range is invalid * * @deprecated replaced by * {@link #drawUnselectedText(Graphics2D, float, float, int, int)} @@ -252,7 +252,7 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @param p0 the beginning position in the model >= 0 * @param p1 the ending position in the model >= p0 * @return the X location of the end of the range >= 0 - * @exception BadLocationException if the range is invalid + * @throws BadLocationException if the range is invalid * * @since 9 */ @@ -272,7 +272,7 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @param p0 the beginning position in the model >= 0 * @param p1 the ending position in the model >= p0 * @return the location of the end of the range. - * @exception BadLocationException if the range is invalid + * @throws BadLocationException if the range is invalid * * @deprecated replaced by * {@link #drawSelectedText(Graphics2D, float, float, int, int)} @@ -320,7 +320,7 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @param p0 the beginning position in the model >= 0 * @param p1 the ending position in the model >= p0 * @return the location of the end of the range. - * @exception BadLocationException if the range is invalid + * @throws BadLocationException if the range is invalid * * @since 9 */ @@ -748,7 +748,7 @@ public class WrappedPlainView extends BoxView implements TabExpander { * @param pos the position to convert * @param a the allocated region to render into * @return the bounding box of the given position is returned - * @exception BadLocationException if the given position does not represent a + * @throws BadLocationException if the given position does not represent a * valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/ZoneView.java b/src/java.desktop/share/classes/javax/swing/text/ZoneView.java index 1deb927fb6e..595eafc336b 100644 --- a/src/java.desktop/share/classes/javax/swing/text/ZoneView.java +++ b/src/java.desktop/share/classes/javax/swing/text/ZoneView.java @@ -134,7 +134,7 @@ public class ZoneView extends BoxView { * * @param mzl the desired maximum number of zones * to be actively loaded, must be greater than 0 - * @exception IllegalArgumentException if mzl is < 1 + * @throws IllegalArgumentException if mzl is < 1 */ public void setMaxZonesLoaded(int mzl) { if (mzl < 1) { @@ -579,7 +579,7 @@ public class ZoneView extends BoxView { * @param pos the position to convert * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not represent a + * @throws BadLocationException if the given position does not represent a * valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java b/src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java index 12cd5a74a72..77623a541e0 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/AccessibleHTML.java @@ -384,7 +384,7 @@ class AccessibleHTML implements Accessible { * @return this component's locale. If this component does not have * a locale, the locale of its parent is returned. * - * @exception IllegalComponentStateException + * @throws IllegalComponentStateException * If the Component does not have its own locale and has not yet been * added to a containment hierarchy such that the locale can be * determined from the containing parent. diff --git a/src/java.desktop/share/classes/javax/swing/text/html/BlockView.java b/src/java.desktop/share/classes/javax/swing/text/html/BlockView.java index 524a57d93c1..dc2a5e22477 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/BlockView.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/BlockView.java @@ -300,7 +300,7 @@ public class BlockView extends BoxView { * * @param axis may be either X_AXIS or Y_AXIS * @return the weight - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public int getResizeWeight(int axis) { switch (axis) { @@ -356,7 +356,7 @@ public class BlockView extends BoxView { * typically the view is told to render into the span * that is returned, although there is no guarantee; * the parent may choose to resize or break the view - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getPreferredSpan(int axis) { return super.getPreferredSpan(axis); @@ -372,7 +372,7 @@ public class BlockView extends BoxView { * typically the view is told to render into the span * that is returned, although there is no guarantee; * the parent may choose to resize or break the view - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getMinimumSpan(int axis) { return super.getMinimumSpan(axis); @@ -388,7 +388,7 @@ public class BlockView extends BoxView { * typically the view is told to render into the span * that is returned, although there is no guarantee; * the parent may choose to resize or break the view - * @exception IllegalArgumentException for an invalid axis type + * @throws IllegalArgumentException for an invalid axis type */ public float getMaximumSpan(int axis) { return super.getMaximumSpan(axis); diff --git a/src/java.desktop/share/classes/javax/swing/text/html/FormView.java b/src/java.desktop/share/classes/javax/swing/text/html/FormView.java index 467651a9d98..b0855832a1d 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/FormView.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/FormView.java @@ -380,7 +380,7 @@ public class FormView extends ComponentView implements ActionListener { * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view. - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public float getMaximumSpan(int axis) { switch (axis) { diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HRuleView.java b/src/java.desktop/share/classes/javax/swing/text/html/HRuleView.java index 885f0b7f2c9..29a7fce803d 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HRuleView.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HRuleView.java @@ -245,7 +245,7 @@ class HRuleView extends View { * @param pos the position to convert * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java index 46d84e3cadc..f4bbb772e78 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLDocument.java @@ -427,7 +427,7 @@ public class HTMLDocument extends DefaultStyledDocument { * * @param offset the starting offset * @param data the element data - * @exception BadLocationException if the given position does not + * @throws BadLocationException if the given position does not * represent a valid location in the associated document. */ protected void insert(int offset, ElementSpec[] data) throws BadLocationException { diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java index 8d78819b0e8..a5c1067f03f 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLEditorKit.java @@ -298,10 +298,10 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { * @param doc the destination for the insertion * @param pos the location in the document to place the * content - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document - * @exception RuntimeException (will eventually be a BadLocationException) + * @throws RuntimeException (will eventually be a BadLocationException) * if pos is invalid */ public void read(Reader in, Document doc, int pos) throws IOException, BadLocationException { @@ -337,7 +337,7 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { * * @throws BadLocationException if {@code offset} is invalid * @throws IOException on I/O error - * @exception RuntimeException (will eventually be a BadLocationException) + * @throws RuntimeException (will eventually be a BadLocationException) * if pos is invalid */ public void insertHTML(HTMLDocument doc, int offset, String html, @@ -367,8 +367,8 @@ public class HTMLEditorKit extends StyledEditorKit implements Accessible { * @param pos the location in the document to fetch the * content * @param len the amount to write out - * @exception IOException on any I/O error - * @exception BadLocationException if {@code pos} represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if {@code pos} represents an invalid * location within the document */ public void write(Writer out, Document doc, int pos, int len) diff --git a/src/java.desktop/share/classes/javax/swing/text/html/HTMLWriter.java b/src/java.desktop/share/classes/javax/swing/text/html/HTMLWriter.java index c11214d71e3..270e4615309 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/HTMLWriter.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/HTMLWriter.java @@ -125,8 +125,8 @@ public class HTMLWriter extends AbstractWriter { * Element tree and controls the writing out of * all the tags and its attributes. * - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. * */ @@ -248,7 +248,7 @@ public class HTMLWriter extends AbstractWriter { * HTML.Attribute.ENDTAG. * * @param attr an AttributeSet - * @exception IOException on any I/O error + * @throws IOException on any I/O error * */ protected void writeAttributes(AttributeSet attr) throws IOException { @@ -273,8 +273,8 @@ public class HTMLWriter extends AbstractWriter { * corresponding end tag). * * @param elem an Element - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ protected void emptyTag(Element elem) throws BadLocationException, IOException { @@ -451,8 +451,8 @@ public class HTMLWriter extends AbstractWriter { * element. * * @param attr an AttributeSet - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ protected void textAreaContent(AttributeSet attr) throws BadLocationException, IOException { @@ -485,8 +485,8 @@ public class HTMLWriter extends AbstractWriter { * out. * * @param elem an Element - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ protected void text(Element elem) throws BadLocationException, IOException { @@ -523,7 +523,7 @@ public class HTMLWriter extends AbstractWriter { * Writes out the content of the SELECT form element. * * @param attr the AttributeSet associated with the form element - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void selectContent(AttributeSet attr) throws IOException { Object model = attr.getAttribute(StyleConstants.ModelAttribute); @@ -552,7 +552,7 @@ public class HTMLWriter extends AbstractWriter { /** * Writes out the content of the Option form element. * @param option an Option - * @exception IOException on any I/O error + * @throws IOException on any I/O error * */ protected void writeOption(Option option) throws IOException { @@ -580,7 +580,7 @@ public class HTMLWriter extends AbstractWriter { * Writes out an end tag for the element. * * @param elem an Element - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void endTag(Element elem) throws IOException { if (synthesizedElement(elem)) { @@ -615,8 +615,8 @@ public class HTMLWriter extends AbstractWriter { * Writes out comments. * * @param elem an Element - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ protected void comment(Element elem) throws BadLocationException, IOException { @@ -637,8 +637,8 @@ public class HTMLWriter extends AbstractWriter { * Writes out comment string. * * @param string the comment - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ void writeComment(String string) throws IOException { @@ -712,7 +712,7 @@ public class HTMLWriter extends AbstractWriter { * written out. * * @param attr a set of attributes - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeEmbeddedTags(AttributeSet attr) throws IOException { @@ -767,7 +767,7 @@ public class HTMLWriter extends AbstractWriter { * end tag is written out. * * @param attr a set of attributes - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void closeOutUnwantedEmbeddedTags(AttributeSet attr) throws IOException { diff --git a/src/java.desktop/share/classes/javax/swing/text/html/ImageView.java b/src/java.desktop/share/classes/javax/swing/text/html/ImageView.java index 6f0a7cbdff4..7d2583509c1 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/ImageView.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/ImageView.java @@ -557,7 +557,7 @@ public class ImageView extends View { * @param pos the position to convert * @param a the allocated region to render into * @return the bounding box of the given position - * @exception BadLocationException if the given position does not represent a + * @throws BadLocationException if the given position does not represent a * valid location in the associated document * @see View#modelToView */ diff --git a/src/java.desktop/share/classes/javax/swing/text/html/MinimalHTMLWriter.java b/src/java.desktop/share/classes/javax/swing/text/html/MinimalHTMLWriter.java index caa8dd07051..712cb350ee9 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/MinimalHTMLWriter.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/MinimalHTMLWriter.java @@ -128,8 +128,8 @@ public class MinimalHTMLWriter extends AbstractWriter { * Generates HTML output * from a StyledDocument. * - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. * */ @@ -152,7 +152,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * The attribute name and value are separated by a colon. * Each pair is separated by a semicolon. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeAttributes(AttributeSet attr) throws IOException { Enumeration attributeNames = attr.getAttributeNames(); @@ -178,7 +178,7 @@ public class MinimalHTMLWriter extends AbstractWriter { /** * Writes out text. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void text(Element elem) throws IOException, BadLocationException { String contentStr = getText(elem); @@ -196,7 +196,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * indented. Also increments the indent level. * * @param tag a start tag - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeStartTag(String tag) throws IOException { indent(); @@ -211,7 +211,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * indented. Also decrements the indent level. * * @param endTag an end tag - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeEndTag(String endTag) throws IOException { decrIndent(); @@ -230,7 +230,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * document is viewable in applications/browsers * that do not support the tag. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeHeader() throws IOException { writeStartTag(""); @@ -248,7 +248,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * Writes out all the named styles as the * content of the <style> tag. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeStyles() throws IOException { /* @@ -338,7 +338,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * that all other tags that have been opened are * appropriately closed off. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeEndParagraph() throws IOException { writeEndMask(fontMask); @@ -359,7 +359,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * style. * * @param elem an element - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeStartParagraph(Element elem) throws IOException { AttributeSet attr = elem.getAttributes(); @@ -377,7 +377,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * elements. * * @param elem an element - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeLeaf(Element elem) throws IOException { indent(); @@ -434,8 +434,8 @@ public class MinimalHTMLWriter extends AbstractWriter { * * @param elem an element * @param needsIndenting indention will be added if {@code needsIndenting} is {@code true} - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ protected void writeContent(Element elem, boolean needsIndenting) @@ -457,7 +457,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * text based on its attribute settings. * * @param attr a set of attributes - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeHTMLTags(AttributeSet attr) throws IOException { @@ -522,7 +522,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * Writes out start tags <u>, <i>, and <b> based on * the mask settings. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ private void writeStartMask(int mask) throws IOException { if (mask != 0) { @@ -542,7 +542,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * Writes out end tags for <u>, <i>, and <b> based on * the mask settings. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ private void writeEndMask(int mask) throws IOException { if (mask != 0) { @@ -569,7 +569,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * attributes just like inline styles. * * @param attr a set of attributes - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void writeNonHTMLAttributes(AttributeSet attr) throws IOException { @@ -636,7 +636,7 @@ public class MinimalHTMLWriter extends AbstractWriter { *

    * Writes out an end tag for the <font> tag. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void endFontTag() throws IOException { write(NEWLINE); @@ -655,7 +655,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * new start tag. * * @param style a font style - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ protected void startFontTag(String style) throws IOException { boolean callIndent = false; @@ -676,7 +676,7 @@ public class MinimalHTMLWriter extends AbstractWriter { * any enclosing font tag before writing out a * new start tag. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ private void startSpanTag(String style) throws IOException { boolean callIndent = false; @@ -693,7 +693,7 @@ public class MinimalHTMLWriter extends AbstractWriter { /** * Writes out an end tag for the <span> tag. * - * @exception IOException on any I/O error + * @throws IOException on any I/O error */ private void endSpanTag() throws IOException { write(NEWLINE); diff --git a/src/java.desktop/share/classes/javax/swing/text/html/OptionListModel.java b/src/java.desktop/share/classes/javax/swing/text/html/OptionListModel.java index 2b84b54b3e1..c7f0ff34a9b 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/OptionListModel.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/OptionListModel.java @@ -464,7 +464,7 @@ class OptionListModel extends DefaultListModel implements ListSelectionMod * listenerLists are not duplicated. * * @return a clone of the receiver - * @exception CloneNotSupportedException if the receiver does not + * @throws CloneNotSupportedException if the receiver does not * both (a) implement the Cloneable interface * and (b) define a clone method */ diff --git a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java index 9ce35f47ee9..35002f9fff2 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/StyleSheet.java @@ -1886,7 +1886,7 @@ public class StyleSheet extends StyleContext { * used to get the AttributeSet, and may be used to * resolve percentage arguments. * @return the inset needed for the margin, border and padding. - * @exception IllegalArgumentException for an invalid direction + * @throws IllegalArgumentException for an invalid direction */ public float getInset(int side, View v) { AttributeSet a = v.getAttributes(); diff --git a/src/java.desktop/share/classes/javax/swing/text/html/TableView.java b/src/java.desktop/share/classes/javax/swing/text/html/TableView.java index c088bf0eb9a..11b383acd31 100644 --- a/src/java.desktop/share/classes/javax/swing/text/html/TableView.java +++ b/src/java.desktop/share/classes/javax/swing/text/html/TableView.java @@ -1611,7 +1611,7 @@ import javax.swing.text.*; * * @param axis may be either View.X_AXIS or View.Y_AXIS * @return the resize weight - * @exception IllegalArgumentException for an invalid axis + * @throws IllegalArgumentException for an invalid axis */ public int getResizeWeight(int axis) { return 1; diff --git a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFEditorKit.java b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFEditorKit.java index 794c2cfee40..f841d9119f5 100644 --- a/src/java.desktop/share/classes/javax/swing/text/rtf/RTFEditorKit.java +++ b/src/java.desktop/share/classes/javax/swing/text/rtf/RTFEditorKit.java @@ -70,8 +70,8 @@ public class RTFEditorKit extends StyledEditorKit { * @param doc The destination for the insertion. * @param pos The location in the document to place the * content. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public void read(InputStream in, Document doc, int pos) throws IOException, BadLocationException { @@ -97,8 +97,8 @@ public class RTFEditorKit extends StyledEditorKit { * @param pos The location in the document to fetch the * content. * @param len The amount to write out. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public void write(OutputStream out, Document doc, int pos, int len) @@ -117,8 +117,8 @@ public class RTFEditorKit extends StyledEditorKit { * @param doc The destination for the insertion. * @param pos The location in the document to place the * content. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public void read(Reader in, Document doc, int pos) @@ -143,8 +143,8 @@ public class RTFEditorKit extends StyledEditorKit { * @param pos The location in the document to fetch the * content. * @param len The amount to write out. - * @exception IOException on any I/O error - * @exception BadLocationException if pos represents an invalid + * @throws IOException on any I/O error + * @throws BadLocationException if pos represents an invalid * location within the document. */ public void write(Writer out, Document doc, int pos, int len) diff --git a/src/java.desktop/share/classes/javax/swing/tree/DefaultMutableTreeNode.java b/src/java.desktop/share/classes/javax/swing/tree/DefaultMutableTreeNode.java index 7735895502e..11efb12e7a2 100644 --- a/src/java.desktop/share/classes/javax/swing/tree/DefaultMutableTreeNode.java +++ b/src/java.desktop/share/classes/javax/swing/tree/DefaultMutableTreeNode.java @@ -174,12 +174,12 @@ public class DefaultMutableTreeNode implements Cloneable, * @param newChild the MutableTreeNode to insert under this node * @param childIndex the index in this node's child array * where this node is to be inserted - * @exception ArrayIndexOutOfBoundsException if + * @throws ArrayIndexOutOfBoundsException if * childIndex is out of bounds - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * newChild is null or is an * ancestor of this node - * @exception IllegalStateException if this node does not allow + * @throws IllegalStateException if this node does not allow * children * @see #isNodeDescendant */ @@ -211,7 +211,7 @@ public class DefaultMutableTreeNode implements Cloneable, * * @param childIndex the index in this node's child array * of the child to remove - * @exception ArrayIndexOutOfBoundsException if + * @throws ArrayIndexOutOfBoundsException if * childIndex is out of bounds */ public void remove(int childIndex) { @@ -247,7 +247,7 @@ public class DefaultMutableTreeNode implements Cloneable, * Returns the child at the specified index in this node's child array. * * @param index an index into this node's child array - * @exception ArrayIndexOutOfBoundsException if index + * @throws ArrayIndexOutOfBoundsException if index * is out of bounds * @return the TreeNode in this node's child array at the specified index */ @@ -278,7 +278,7 @@ public class DefaultMutableTreeNode implements Cloneable, * where n is the number of children. * * @param aChild the TreeNode to search for among this node's children - * @exception IllegalArgumentException if aChild + * @throws IllegalArgumentException if aChild * is null * @return an int giving the index of the node in this node's child * array, or -1 if the specified node is a not @@ -382,7 +382,7 @@ public class DefaultMutableTreeNode implements Cloneable, * null parent. * * @param aChild a child of this node to remove - * @exception IllegalArgumentException if aChild + * @throws IllegalArgumentException if aChild * is null or is not a child of this node */ public void remove(MutableTreeNode aChild) { @@ -412,9 +412,9 @@ public class DefaultMutableTreeNode implements Cloneable, * * @see #insert * @param newChild node to add as a child of this node - * @exception IllegalArgumentException if newChild + * @throws IllegalArgumentException if newChild * is null - * @exception IllegalStateException if this node does not allow + * @throws IllegalStateException if this node does not allow * children */ public void add(MutableTreeNode newChild) { @@ -846,7 +846,7 @@ public class DefaultMutableTreeNode implements Cloneable, * @param ancestor the node to start enumeration from * @see #isNodeAncestor * @see #isNodeDescendant - * @exception IllegalArgumentException if ancestor is + * @throws IllegalArgumentException if ancestor is * not an ancestor of this node * @return an enumeration for following the path from an ancestor of * this node to this one @@ -890,7 +890,7 @@ public class DefaultMutableTreeNode implements Cloneable, * throws NoSuchElementException. * * @return the first child of this node - * @exception NoSuchElementException if this node has no children + * @throws NoSuchElementException if this node has no children */ public TreeNode getFirstChild() { if (getChildCount() == 0) { @@ -905,7 +905,7 @@ public class DefaultMutableTreeNode implements Cloneable, * throws NoSuchElementException. * * @return the last child of this node - * @exception NoSuchElementException if this node has no children + * @throws NoSuchElementException if this node has no children */ public TreeNode getLastChild() { if (getChildCount() == 0) { @@ -925,7 +925,7 @@ public class DefaultMutableTreeNode implements Cloneable, * * @param aChild the child node to look for next child after it * @see #children - * @exception IllegalArgumentException if aChild is + * @throws IllegalArgumentException if aChild is * null or is not a child of this node * @return the child of this node that immediately follows * aChild @@ -957,7 +957,7 @@ public class DefaultMutableTreeNode implements Cloneable, * and is O(n) where n is the number of children. * * @param aChild the child node to look for previous child before it - * @exception IllegalArgumentException if aChild is null + * @throws IllegalArgumentException if aChild is null * or is not a child of this node * @return the child of this node that immediately precedes * aChild diff --git a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeModel.java b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeModel.java index 4cdec3f6b38..511cde568c0 100644 --- a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeModel.java +++ b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeModel.java @@ -672,7 +672,7 @@ public class DefaultTreeModel implements Serializable, TreeModel { * FooListeners on this component, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType + * @throws ClassCastException if listenerType * doesn't specify a class or interface that implements * java.util.EventListener * diff --git a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeSelectionModel.java b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeSelectionModel.java index e1bdc4fc94b..ff7ed27302d 100644 --- a/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeSelectionModel.java +++ b/src/java.desktop/share/classes/javax/swing/tree/DefaultTreeSelectionModel.java @@ -679,7 +679,7 @@ public class DefaultTreeSelectionModel implements Cloneable, Serializable, TreeS * FooListeners on this component, * or an empty array if no such * listeners have been added - * @exception ClassCastException if listenerType + * @throws ClassCastException if listenerType * doesn't specify a class or interface that implements * java.util.EventListener * @@ -1187,7 +1187,7 @@ public class DefaultTreeSelectionModel implements Cloneable, Serializable, TreeS * This method does not duplicate * selection listeners and property listeners. * - * @exception CloneNotSupportedException never thrown by instances of + * @throws CloneNotSupportedException never thrown by instances of * this class */ public Object clone() throws CloneNotSupportedException { diff --git a/src/java.desktop/share/classes/javax/swing/undo/AbstractUndoableEdit.java b/src/java.desktop/share/classes/javax/swing/undo/AbstractUndoableEdit.java index 7184557d1e7..94f5eb69a74 100644 --- a/src/java.desktop/share/classes/javax/swing/undo/AbstractUndoableEdit.java +++ b/src/java.desktop/share/classes/javax/swing/undo/AbstractUndoableEdit.java @@ -102,7 +102,7 @@ public class AbstractUndoableEdit implements UndoableEdit, Serializable { * operation represented by this edit. Override should begin with * a call to super. * - * @exception CannotUndoException if canUndo + * @throws CannotUndoException if canUndo * returns false * @see #canUndo */ @@ -134,7 +134,7 @@ public class AbstractUndoableEdit implements UndoableEdit, Serializable { * Subclasses should override to redo the operation represented by * this edit. Override should begin with a call to super. * - * @exception CannotRedoException if canRedo + * @throws CannotRedoException if canRedo * returns false * @see #canRedo */ -- GitLab From 249d553659ab75a2271e98c77e7d62f662ffa684 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 17 Mar 2022 09:15:54 +0000 Subject: [PATCH 065/237] 8282602: Refactor awt classes javadoc to use @throws instead of @exception Reviewed-by: aivanov, prr --- .../classes/java/awt/AWTEventMulticaster.java | 4 +- .../share/classes/java/awt/BorderLayout.java | 8 +- .../classes/java/awt/BufferCapabilities.java | 2 +- .../share/classes/java/awt/Button.java | 6 +- .../share/classes/java/awt/Canvas.java | 8 +- .../share/classes/java/awt/CardLayout.java | 2 +- .../share/classes/java/awt/Checkbox.java | 12 +-- .../classes/java/awt/CheckboxMenuItem.java | 8 +- .../share/classes/java/awt/Choice.java | 16 ++-- .../share/classes/java/awt/Color.java | 2 +- .../share/classes/java/awt/Component.java | 36 ++++----- .../share/classes/java/awt/Container.java | 42 +++++------ .../share/classes/java/awt/Cursor.java | 4 +- .../share/classes/java/awt/Dialog.java | 74 +++++++++---------- .../share/classes/java/awt/EventQueue.java | 8 +- .../share/classes/java/awt/FileDialog.java | 18 ++--- .../share/classes/java/awt/Frame.java | 12 +-- .../java/awt/GraphicsConfiguration.java | 4 +- .../classes/java/awt/GraphicsDevice.java | 4 +- .../classes/java/awt/GraphicsEnvironment.java | 8 +- .../share/classes/java/awt/GridBagLayout.java | 2 +- .../share/classes/java/awt/GridLayout.java | 6 +- .../share/classes/java/awt/Image.java | 4 +- .../share/classes/java/awt/Label.java | 8 +- .../share/classes/java/awt/List.java | 16 ++-- .../share/classes/java/awt/MediaTracker.java | 8 +- .../share/classes/java/awt/Menu.java | 12 +-- .../share/classes/java/awt/MenuBar.java | 2 +- .../share/classes/java/awt/MenuComponent.java | 2 +- .../share/classes/java/awt/MenuItem.java | 8 +- .../share/classes/java/awt/MouseInfo.java | 6 +- .../share/classes/java/awt/Polygon.java | 6 +- .../share/classes/java/awt/PopupMenu.java | 12 +-- .../classes/java/awt/RenderingHints.java | 16 ++-- .../share/classes/java/awt/Scrollbar.java | 14 ++-- .../share/classes/java/awt/TextArea.java | 14 ++-- .../share/classes/java/awt/TextComponent.java | 6 +- .../share/classes/java/awt/TextField.java | 12 +-- .../share/classes/java/awt/Toolkit.java | 46 ++++++------ .../share/classes/java/awt/Window.java | 30 ++++---- .../classes/java/awt/dnd/DragSource.java | 6 +- .../classes/java/awt/dnd/DropTarget.java | 10 +-- .../java/awt/event/InputMethodEvent.java | 2 +- .../classes/java/awt/font/TextLayout.java | 2 +- .../java/awt/geom/AffineTransform.java | 8 +- .../classes/java/awt/geom/CubicCurve2D.java | 2 +- .../classes/java/awt/geom/Dimension2D.java | 2 +- .../java/awt/geom/FlatteningPathIterator.java | 6 +- .../share/classes/java/awt/geom/Line2D.java | 2 +- .../share/classes/java/awt/geom/Path2D.java | 8 +- .../share/classes/java/awt/geom/Point2D.java | 2 +- .../classes/java/awt/geom/QuadCurve2D.java | 2 +- .../java/awt/geom/RectangularShape.java | 2 +- .../classes/java/awt/im/InputContext.java | 6 +- .../java/awt/im/InputMethodHighlight.java | 6 +- .../classes/java/awt/im/spi/InputMethod.java | 6 +- .../java/awt/im/spi/InputMethodContext.java | 4 +- .../awt/im/spi/InputMethodDescriptor.java | 4 +- .../classes/java/awt/image/BufferedImage.java | 10 +-- .../java/awt/image/ByteLookupTable.java | 4 +- .../java/awt/image/ColorConvertOp.java | 8 +- .../java/awt/image/DirectColorModel.java | 30 ++++---- .../classes/java/awt/image/ImageFilter.java | 4 +- .../image/MultiPixelPackedSampleModel.java | 14 ++-- .../classes/java/awt/image/PixelGrabber.java | 4 +- .../java/awt/image/RGBImageFilter.java | 2 +- .../share/classes/java/awt/image/Raster.java | 4 +- .../java/awt/image/ShortLookupTable.java | 4 +- .../image/SinglePixelPackedSampleModel.java | 2 +- .../java/awt/image/WritableRaster.java | 2 +- .../classes/java/awt/print/PageFormat.java | 2 +- .../classes/java/awt/print/Printable.java | 2 +- .../classes/java/awt/print/PrinterJob.java | 20 ++--- 73 files changed, 350 insertions(+), 350 deletions(-) diff --git a/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java b/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java index a9f102643f4..b7584fc84dd 100644 --- a/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java +++ b/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java @@ -1097,9 +1097,9 @@ public class AWTEventMulticaster implements * FooListeners by the specified multicast * listener, or an empty array if no such listeners have been * chained by the specified multicast listener - * @exception NullPointerException if the specified + * @throws NullPointerException if the specified * {@code listenertype} parameter is {@code null} - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/BorderLayout.java b/src/java.desktop/share/classes/java/awt/BorderLayout.java index 88edc23dec4..e3b92a7996a 100644 --- a/src/java.desktop/share/classes/java/awt/BorderLayout.java +++ b/src/java.desktop/share/classes/java/awt/BorderLayout.java @@ -419,7 +419,7 @@ public class BorderLayout implements LayoutManager2, * @param constraints an object that specifies how and where * the component is added to the layout. * @see java.awt.Container#add(java.awt.Component, java.lang.Object) - * @exception IllegalArgumentException if the constraint object is not + * @throws IllegalArgumentException if the constraint object is not * a string, or if it not one of the five specified constants. * @since 1.1 */ @@ -514,7 +514,7 @@ public class BorderLayout implements LayoutManager2, * {@code LINE_START}, {@code LINE_END} * @return the component at the given location, or {@code null} if * the location is empty - * @exception IllegalArgumentException if the constraint object is + * @throws IllegalArgumentException if the constraint object is * not one of the nine specified constants * @see #addLayoutComponent(java.awt.Component, java.lang.Object) * @since 1.5 @@ -562,9 +562,9 @@ public class BorderLayout implements LayoutManager2, * {@code Container}'s component orientation. * @return the component at the given location, or {@code null} if * the location is empty - * @exception IllegalArgumentException if the constraint object is + * @throws IllegalArgumentException if the constraint object is * not one of the five specified constants - * @exception NullPointerException if the target parameter is null + * @throws NullPointerException if the target parameter is null * @see #addLayoutComponent(java.awt.Component, java.lang.Object) * @since 1.5 */ diff --git a/src/java.desktop/share/classes/java/awt/BufferCapabilities.java b/src/java.desktop/share/classes/java/awt/BufferCapabilities.java index 22df13cfb50..6edeae843aa 100644 --- a/src/java.desktop/share/classes/java/awt/BufferCapabilities.java +++ b/src/java.desktop/share/classes/java/awt/BufferCapabilities.java @@ -47,7 +47,7 @@ public class BufferCapabilities implements Cloneable { * cannot be {@code null} * @param flipContents the contents of the back buffer after page-flipping, * {@code null} if page flipping is not used (implies blitting) - * @exception IllegalArgumentException if frontCaps or backCaps are + * @throws IllegalArgumentException if frontCaps or backCaps are * {@code null} */ public BufferCapabilities(ImageCapabilities frontCaps, diff --git a/src/java.desktop/share/classes/java/awt/Button.java b/src/java.desktop/share/classes/java/awt/Button.java index 35acb8d2928..524008e401a 100644 --- a/src/java.desktop/share/classes/java/awt/Button.java +++ b/src/java.desktop/share/classes/java/awt/Button.java @@ -140,7 +140,7 @@ public class Button extends Component implements Accessible { /** * Constructs a button with an empty string for its label. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -153,7 +153,7 @@ public class Button extends Component implements Accessible { * * @param label a string label for the button, or * {@code null} for no label - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -339,7 +339,7 @@ public class Button extends Component implements Accessible { * FooListeners on this button, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/Canvas.java b/src/java.desktop/share/classes/java/awt/Canvas.java index 1ee5380c6df..7d90e148b6c 100644 --- a/src/java.desktop/share/classes/java/awt/Canvas.java +++ b/src/java.desktop/share/classes/java/awt/Canvas.java @@ -166,8 +166,8 @@ public class Canvas extends Component implements Accessible { * Each time this method is called, * the existing buffer strategy for this component is discarded. * @param numBuffers number of buffers to create, including the front buffer - * @exception IllegalArgumentException if numBuffers is less than 1. - * @exception IllegalStateException if the component is not displayable + * @throws IllegalArgumentException if numBuffers is less than 1. + * @throws IllegalStateException if the component is not displayable * @see #isDisplayable * @see #getBufferStrategy * @since 1.4 @@ -187,11 +187,11 @@ public class Canvas extends Component implements Accessible { * @param numBuffers number of buffers to create * @param caps the required capabilities for creating the buffer strategy; * cannot be {@code null} - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met; this may happen, for example, if there is not enough * accelerated memory currently available, or if page flipping is specified * but not possible. - * @exception IllegalArgumentException if numBuffers is less than 1, or if + * @throws IllegalArgumentException if numBuffers is less than 1, or if * caps is {@code null} * @see #getBufferStrategy * @since 1.4 diff --git a/src/java.desktop/share/classes/java/awt/CardLayout.java b/src/java.desktop/share/classes/java/awt/CardLayout.java index d53c86a9d45..915376d0320 100644 --- a/src/java.desktop/share/classes/java/awt/CardLayout.java +++ b/src/java.desktop/share/classes/java/awt/CardLayout.java @@ -206,7 +206,7 @@ public class CardLayout implements LayoutManager2, * @param constraints a tag that identifies a particular * card in the layout. * @see java.awt.CardLayout#show(java.awt.Container, java.lang.String) - * @exception IllegalArgumentException if the constraint is not a string. + * @throws IllegalArgumentException if the constraint is not a string. */ public void addLayoutComponent(Component comp, Object constraints) { synchronized (comp.getTreeLock()) { diff --git a/src/java.desktop/share/classes/java/awt/Checkbox.java b/src/java.desktop/share/classes/java/awt/Checkbox.java index e72d249f8e3..f4a642cb329 100644 --- a/src/java.desktop/share/classes/java/awt/Checkbox.java +++ b/src/java.desktop/share/classes/java/awt/Checkbox.java @@ -146,7 +146,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * Creates a check box with an empty string for its label. * The state of this check box is set to "off," and it is not * part of any check box group. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -161,7 +161,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * * @param label a string label for this check box, * or {@code null} for no label. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -178,7 +178,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * @param label a string label for this check box, * or {@code null} for no label * @param state the initial state of this check box - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -196,7 +196,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * @param state the initial state of this check box. * @param group a check box group for this check box, * or {@code null} for no group. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -222,7 +222,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * @param group a check box group for this check box, * or {@code null} for no group. * @param state the initial state of this check box. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless @@ -508,7 +508,7 @@ public class Checkbox extends Component implements ItemSelectable, Accessible { * FooListeners on this checkbox, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java b/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java index 4df4ddbef85..f95d1d39424 100644 --- a/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java +++ b/src/java.desktop/share/classes/java/awt/CheckboxMenuItem.java @@ -110,7 +110,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access /** * Create a check box menu item with an empty label. * The item's state is initially set to "off." - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -125,7 +125,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access * @param label a string label for the check box menu item, * or {@code null} for an unlabeled menu item. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -140,7 +140,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access * @param state the initial state of the menu item, where * {@code true} indicates "on" and * {@code false} indicates "off." - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -316,7 +316,7 @@ public class CheckboxMenuItem extends MenuItem implements ItemSelectable, Access * FooListeners on this checkbox menuitem, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/Choice.java b/src/java.desktop/share/classes/java/awt/Choice.java index d8e8ab4c026..2b04239fd31 100644 --- a/src/java.desktop/share/classes/java/awt/Choice.java +++ b/src/java.desktop/share/classes/java/awt/Choice.java @@ -124,7 +124,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * By default, the first item added to the choice menu becomes the * selected item, until a different selection is made by the user * by calling one of the {@code select} methods. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @see #select(int) @@ -205,7 +205,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { /** * Adds an item to this {@code Choice} menu. * @param item the item to be added - * @exception NullPointerException if the item's value is + * @throws NullPointerException if the item's value is * {@code null} * @since 1.1 */ @@ -219,7 +219,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { *

    * Adds an item to this {@code Choice} menu. * @param item the item to be added - * @exception NullPointerException if the item's value is equal to + * @throws NullPointerException if the item's value is equal to * {@code null} */ public void addItem(String item) { @@ -238,7 +238,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * invoking this method. * @param item the item to be added * @param index the new item position - * @exception NullPointerException if the item's value is equal to + * @throws NullPointerException if the item's value is equal to * {@code null} */ private void insertNoInvalidate(String item, int index) { @@ -274,7 +274,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * the selected item. * @param item the non-{@code null} item to be inserted * @param index the position at which the item should be inserted - * @exception IllegalArgumentException if index is less than 0 + * @throws IllegalArgumentException if index is less than 0 */ public void insert(String item, int index) { synchronized (this) { @@ -300,7 +300,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * item remains selected (and the selected index is * updated accordingly). * @param item the item to remove from this {@code Choice} menu - * @exception IllegalArgumentException if the item doesn't + * @throws IllegalArgumentException if the item doesn't * exist in the choice menu * @since 1.1 */ @@ -430,7 +430,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * {@code ItemEvent} is by user interaction. * * @param pos the position of the selected item - * @exception IllegalArgumentException if the specified + * @throws IllegalArgumentException if the specified * position is greater than the * number of items or less than zero * @see #getSelectedItem @@ -561,7 +561,7 @@ public class Choice extends Component implements ItemSelectable, Accessible { * FooListeners on this choice, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/Color.java b/src/java.desktop/share/classes/java/awt/Color.java index aae90be8616..6bb4befd8e8 100644 --- a/src/java.desktop/share/classes/java/awt/Color.java +++ b/src/java.desktop/share/classes/java/awt/Color.java @@ -722,7 +722,7 @@ public class Color implements Paint, java.io.Serializable { * an opaque color as a 24-bit integer * @return the new {@code Color} object. * @see java.lang.Integer#decode - * @exception NumberFormatException if the specified string cannot + * @throws NumberFormatException if the specified string cannot * be interpreted as a decimal, * octal, or hexadecimal integer. * @since 1.1 diff --git a/src/java.desktop/share/classes/java/awt/Component.java b/src/java.desktop/share/classes/java/awt/Component.java index 813f9bd0c79..cfd4cbe025a 100644 --- a/src/java.desktop/share/classes/java/awt/Component.java +++ b/src/java.desktop/share/classes/java/awt/Component.java @@ -1420,7 +1420,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * pointer. If the return value of this method is {@code null}, mouse * pointer is not directly above the {@code Component}. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @see #isShowing * @see Container#getMousePosition * @return mouse coordinates relative to this {@code Component}, or null @@ -1984,7 +1984,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * @return this component's locale; if this component does not * have a locale, the locale of its parent is returned * @see #setLocale - * @exception IllegalComponentStateException if the {@code Component} + * @throws IllegalComponentStateException if the {@code Component} * does not have its own locale and has not yet been added to * a containment hierarchy such that the locale can be determined * from the containing parent @@ -3827,8 +3827,8 @@ public abstract class Component implements ImageObserver, MenuContainer, * Each time this method is called, * the existing buffer strategy for this component is discarded. * @param numBuffers number of buffers to create, including the front buffer - * @exception IllegalArgumentException if numBuffers is less than 1. - * @exception IllegalStateException if the component is not displayable + * @throws IllegalArgumentException if numBuffers is less than 1. + * @throws IllegalStateException if the component is not displayable * @see #isDisplayable * @see Window#getBufferStrategy() * @see Canvas#getBufferStrategy() @@ -3884,11 +3884,11 @@ public abstract class Component implements ImageObserver, MenuContainer, * @param numBuffers number of buffers to create * @param caps the required capabilities for creating the buffer strategy; * cannot be {@code null} - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met; this may happen, for example, if there is not enough * accelerated memory currently available, or if page flipping is specified * but not possible. - * @exception IllegalArgumentException if numBuffers is less than 1, or if + * @throws IllegalArgumentException if numBuffers is less than 1, or if * caps is {@code null} * @see Window#getBufferStrategy() * @see Canvas#getBufferStrategy() @@ -4032,12 +4032,12 @@ public abstract class Component implements ImageObserver, MenuContainer, * @see Applet * @param numBuffers the number of buffers * @param caps the capabilities of the buffers - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met - * @exception ClassCastException if the component is not a canvas or + * @throws ClassCastException if the component is not a canvas or * window. - * @exception IllegalStateException if the component has no peer - * @exception IllegalArgumentException if {@code numBuffers} is less than two, + * @throws IllegalStateException if the component has no peer + * @throws IllegalArgumentException if {@code numBuffers} is less than two, * or if {@code BufferCapabilities.isPageFlipping} is not * {@code true}. * @see #createBuffers(int, BufferCapabilities) @@ -4066,10 +4066,10 @@ public abstract class Component implements ImageObserver, MenuContainer, * @param caps the capabilities of the buffers. * {@code BufferCapabilities.isPageFlipping} must be * {@code true}. - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met - * @exception IllegalStateException if the component has no peer - * @exception IllegalArgumentException if numBuffers is less than two, + * @throws IllegalStateException if the component has no peer + * @throws IllegalArgumentException if numBuffers is less than two, * or if {@code BufferCapabilities.isPageFlipping} is not * {@code true}. * @see java.awt.BufferCapabilities#isPageFlipping() @@ -4135,7 +4135,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * Provides direct access to the back buffer as an image. * * @return the back buffer as an image - * @exception IllegalStateException if the buffers have not yet + * @throws IllegalStateException if the buffers have not yet * been created */ protected Image getBackBuffer() { @@ -4154,7 +4154,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * for the contents of the back buffer. This should be one of the * values of the {@code BufferCapabilities.FlipContents} * property. - * @exception IllegalStateException if the buffers have not yet + * @throws IllegalStateException if the buffers have not yet * been created * @see java.awt.BufferCapabilities#getFlipContents() */ @@ -6060,7 +6060,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * @return an array of all objects registered as * FooListeners on this component, * or an empty array if no such listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * @throws NullPointerException if {@code listenerType} is {@code null} @@ -8352,7 +8352,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * Adds the specified popup menu to the component. * @param popup the popup menu to be added to the component. * @see #remove(MenuComponent) - * @exception NullPointerException if {@code popup} is {@code null} + * @throws NullPointerException if {@code popup} is {@code null} * @since 1.1 */ public void add(PopupMenu popup) { @@ -9192,7 +9192,7 @@ public abstract class Component implements ImageObserver, MenuContainer, * * @param orientation the new component orientation of this component and * the components contained within it. - * @exception NullPointerException if {@code orientation} is null. + * @throws NullPointerException if {@code orientation} is null. * @see #setComponentOrientation * @see #getComponentOrientation * @see #invalidate diff --git a/src/java.desktop/share/classes/java/awt/Container.java b/src/java.desktop/share/classes/java/awt/Container.java index 5b4489f3cac..f63c507a829 100644 --- a/src/java.desktop/share/classes/java/awt/Container.java +++ b/src/java.desktop/share/classes/java/awt/Container.java @@ -340,7 +340,7 @@ public class Container extends Component { * * @param n the index of the component to get. * @return the nth component in this container. - * @exception ArrayIndexOutOfBoundsException + * @throws ArrayIndexOutOfBoundsException * if the nth value does not exist. * @see Component#getTreeLock() */ @@ -429,7 +429,7 @@ public class Container extends Component { * display the added component. * * @param comp the component to be added - * @exception NullPointerException if {@code comp} is {@code null} + * @throws NullPointerException if {@code comp} is {@code null} * @see #addImpl * @see #invalidate * @see #validate @@ -456,7 +456,7 @@ public class Container extends Component { * @param name the name of the component to be added * @param comp the component to be added * @return the component added - * @exception NullPointerException if {@code comp} is {@code null} + * @throws NullPointerException if {@code comp} is {@code null} * @see #add(Component, Object) * @see #invalidate */ @@ -479,8 +479,8 @@ public class Container extends Component { * @param comp the component to be added * @param index the position at which to insert the component, * or {@code -1} to append the component to the end - * @exception NullPointerException if {@code comp} is {@code null} - * @exception IllegalArgumentException if {@code index} is invalid (see + * @throws NullPointerException if {@code comp} is {@code null} + * @throws IllegalArgumentException if {@code index} is invalid (see * {@link #addImpl} for details) * @return the component {@code comp} * @see #addImpl @@ -764,17 +764,17 @@ public class Container extends Component { * @param index the position in the container's list to * insert the component, where {@code getComponentCount()} * appends to the end - * @exception NullPointerException if {@code comp} is + * @throws NullPointerException if {@code comp} is * {@code null} - * @exception IllegalArgumentException if {@code comp} is one of the + * @throws IllegalArgumentException if {@code comp} is one of the * container's parents - * @exception IllegalArgumentException if {@code index} is not in + * @throws IllegalArgumentException if {@code index} is not in * the range {@code [0, getComponentCount()]} for moving * between containers, or not in the range * {@code [0, getComponentCount()-1]} for moving inside * a container - * @exception IllegalArgumentException if adding a container to itself - * @exception IllegalArgumentException if adding a {@code Window} + * @throws IllegalArgumentException if adding a container to itself + * @throws IllegalArgumentException if adding a {@code Window} * to a container * @see #getComponentZOrder(java.awt.Component) * @see #invalidate @@ -989,7 +989,7 @@ public class Container extends Component { * @param comp the component to be added * @param constraints an object expressing * layout constraints for this component - * @exception NullPointerException if {@code comp} is {@code null} + * @throws NullPointerException if {@code comp} is {@code null} * @see #addImpl * @see #invalidate * @see #validate @@ -1019,8 +1019,8 @@ public class Container extends Component { * @param index the position in the container's list at which to insert * the component; {@code -1} means insert at the end * component - * @exception NullPointerException if {@code comp} is {@code null} - * @exception IllegalArgumentException if {@code index} is invalid (see + * @throws NullPointerException if {@code comp} is {@code null} + * @throws IllegalArgumentException if {@code index} is invalid (see * {@link #addImpl} for details) * @see #addImpl * @see #invalidate @@ -1082,16 +1082,16 @@ public class Container extends Component { * @param index the position in the container's list at which to * insert the component, where {@code -1} * means append to the end - * @exception IllegalArgumentException if {@code index} is invalid; + * @throws IllegalArgumentException if {@code index} is invalid; * if {@code comp} is a child of this container, the valid * range is {@code [-1, getComponentCount()-1]}; if component is * not a child of this container, the valid range is * {@code [-1, getComponentCount()]} * - * @exception IllegalArgumentException if {@code comp} is an ancestor of + * @throws IllegalArgumentException if {@code comp} is an ancestor of * this container - * @exception IllegalArgumentException if adding a window to a container - * @exception NullPointerException if {@code comp} is {@code null} + * @throws IllegalArgumentException if adding a window to a container + * @throws NullPointerException if {@code comp} is {@code null} * @see #add(Component) * @see #add(Component, int) * @see #add(Component, java.lang.Object) @@ -2213,10 +2213,10 @@ public class Container extends Component { * @return an array of all objects registered as * FooListeners on this container, * or an empty array if no such listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} - * @exception NullPointerException if {@code listenerType} is {@code null} + * @throws NullPointerException if {@code listenerType} is {@code null} * * @see #getContainerListeners * @@ -2622,7 +2622,7 @@ public class Container extends Component { * a non-null value if the mouse pointer is above {@code Container} or any * of its descendants. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @param allowChildren true if children should be taken into account * @see Component#getMousePosition * @return mouse coordinates relative to this {@code Component}, or null @@ -3556,7 +3556,7 @@ public class Container extends Component { * * @param o the new component orientation of this container and * the components contained within it. - * @exception NullPointerException if {@code orientation} is null. + * @throws NullPointerException if {@code orientation} is null. * @see Component#setComponentOrientation * @see Component#getComponentOrientation * @see #invalidate diff --git a/src/java.desktop/share/classes/java/awt/Cursor.java b/src/java.desktop/share/classes/java/awt/Cursor.java index 936d17da46f..cfccf06723b 100644 --- a/src/java.desktop/share/classes/java/awt/Cursor.java +++ b/src/java.desktop/share/classes/java/awt/Cursor.java @@ -285,9 +285,9 @@ public class Cursor implements java.io.Serializable { * * @param name a string describing the desired system-specific custom cursor * @return the system specific custom cursor named - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true - * @exception AWTException in case of erroneous retrieving of the cursor + * @throws AWTException in case of erroneous retrieving of the cursor */ public static Cursor getSystemCustomCursor(final String name) throws AWTException, HeadlessException { diff --git a/src/java.desktop/share/classes/java/awt/Dialog.java b/src/java.desktop/share/classes/java/awt/Dialog.java index 1a54d707306..2c126e74ffc 100644 --- a/src/java.desktop/share/classes/java/awt/Dialog.java +++ b/src/java.desktop/share/classes/java/awt/Dialog.java @@ -329,9 +329,9 @@ public class Dialog extends Window { * * @param owner the owner of the dialog or {@code null} if * this dialog has no owner - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -352,9 +352,9 @@ public class Dialog extends Window { * windows when shown. If {@code false}, the dialog is {@code MODELESS}; * if {@code true}, the modality type property is set to * {@code DEFAULT_MODALITY_TYPE} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -376,9 +376,9 @@ public class Dialog extends Window { * this dialog has no owner * @param title the title of the dialog or {@code null} if this dialog * has no title - * @exception IllegalArgumentException if the {@code owner}'s + * @throws IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -401,9 +401,9 @@ public class Dialog extends Window { * windows when shown. If {@code false}, the dialog is {@code MODELESS}; * if {@code true}, the modality type property is set to * {@code DEFAULT_MODALITY_TYPE} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -433,9 +433,9 @@ public class Dialog extends Window { * @param gc the {@code GraphicsConfiguration} of the target screen device; * if {@code null}, the default system {@code GraphicsConfiguration} * is assumed - * @exception java.lang.IllegalArgumentException if {@code gc} + * @throws java.lang.IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -459,9 +459,9 @@ public class Dialog extends Window { * * @param owner the owner of the dialog or {@code null} if this * dialog has no owner - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -478,9 +478,9 @@ public class Dialog extends Window { * has no owner * @param title the title of the dialog or {@code null} if this dialog * has no title - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -502,9 +502,9 @@ public class Dialog extends Window { * windows when shown. If {@code false}, the dialog is {@code MODELESS}; * if {@code true}, the modality type property is set to * {@code DEFAULT_MODALITY_TYPE} - * @exception IllegalArgumentException if the {@code owner}'s + * @throws IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -536,9 +536,9 @@ public class Dialog extends Window { * @param gc the {@code GraphicsConfiguration} of the target screen device; * if {@code null}, the default system {@code GraphicsConfiguration} * is assumed - * @exception java.lang.IllegalArgumentException if {@code gc} + * @throws java.lang.IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.Dialog.ModalityType @@ -565,12 +565,12 @@ public class Dialog extends Window { * {@link java.awt.Dialog Dialog}, {@link java.awt.Frame Frame}, any * of their descendants or {@code null} * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -591,12 +591,12 @@ public class Dialog extends Window { * @param title the title of the dialog or {@code null} if this dialog * has no title * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -618,14 +618,14 @@ public class Dialog extends Window { * windows when shown. {@code null} value and unsupported modality * types are equivalent to {@code MODELESS} * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} - * @exception SecurityException if the calling thread does not have permission + * @throws SecurityException if the calling thread does not have permission * to create modal dialogs with the given {@code modalityType} * * @see java.awt.Dialog.ModalityType @@ -653,14 +653,14 @@ public class Dialog extends Window { * windows when shown. {@code null} value and unsupported modality * types are equivalent to {@code MODELESS} * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if the {@code owner}'s + * @throws java.lang.IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} - * @exception SecurityException if the calling thread does not have permission + * @throws SecurityException if the calling thread does not have permission * to create modal dialogs with the given {@code modalityType} * * @see java.awt.Dialog.ModalityType @@ -704,14 +704,14 @@ public class Dialog extends Window { * if {@code null}, the default system {@code GraphicsConfiguration} * is assumed * - * @exception java.lang.IllegalArgumentException if the {@code owner} + * @throws java.lang.IllegalArgumentException if the {@code owner} * is not an instance of {@link java.awt.Dialog Dialog} or {@link * java.awt.Frame Frame} - * @exception java.lang.IllegalArgumentException if {@code gc} + * @throws java.lang.IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} - * @exception SecurityException if the calling thread does not have permission + * @throws SecurityException if the calling thread does not have permission * to create modal dialogs with the given {@code modalityType} * * @see java.awt.Dialog.ModalityType @@ -848,7 +848,7 @@ public class Dialog extends Window { * @param type specifies whether dialog blocks input to other * windows when shown. {@code null} value and unsupported modality * types are equivalent to {@code MODELESS} - * @exception SecurityException if the calling thread does not have permission + * @throws SecurityException if the calling thread does not have permission * to create modal dialogs with the given {@code modalityType} * * @see java.awt.Dialog#getModalityType diff --git a/src/java.desktop/share/classes/java/awt/EventQueue.java b/src/java.desktop/share/classes/java/awt/EventQueue.java index e7d1dcc8286..4dce257f727 100644 --- a/src/java.desktop/share/classes/java/awt/EventQueue.java +++ b/src/java.desktop/share/classes/java/awt/EventQueue.java @@ -544,7 +544,7 @@ public class EventQueue { * returns it. This method will block until an event has * been posted by another thread. * @return the next {@code AWTEvent} - * @exception InterruptedException + * @throws InterruptedException * if any thread has interrupted this thread */ public AWTEvent getNextEvent() throws InterruptedException { @@ -946,7 +946,7 @@ public class EventQueue { * Warning: To avoid deadlock, do not declare this method * synchronized in a subclass. * - * @exception EmptyStackException if no previous push was made + * @throws EmptyStackException if no previous push was made * on this {@code EventQueue} * @see java.awt.EventQueue#push * @since 1.2 @@ -1331,9 +1331,9 @@ public class EventQueue { * synchronously in the * {@link #isDispatchThread event dispatch thread} * of {@link Toolkit#getSystemEventQueue the system EventQueue} - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread - * @exception InvocationTargetException if an throwable is thrown + * @throws InvocationTargetException if an throwable is thrown * when running {@code runnable} * @see #invokeLater * @see Toolkit#getSystemEventQueue diff --git a/src/java.desktop/share/classes/java/awt/FileDialog.java b/src/java.desktop/share/classes/java/awt/FileDialog.java index b6a501b44e9..399544b9547 100644 --- a/src/java.desktop/share/classes/java/awt/FileDialog.java +++ b/src/java.desktop/share/classes/java/awt/FileDialog.java @@ -232,7 +232,7 @@ public class FileDialog extends Dialog { * @param title the title of the dialog * @param mode the mode of the dialog; either * {@code FileDialog.LOAD} or {@code FileDialog.SAVE} - * @exception IllegalArgumentException if an illegal file + * @throws IllegalArgumentException if an illegal file * dialog mode is supplied * @see java.awt.FileDialog#LOAD * @see java.awt.FileDialog#SAVE @@ -255,10 +255,10 @@ public class FileDialog extends Dialog { * displayed. * * @param parent the owner of the dialog - * @exception java.lang.IllegalArgumentException if the {@code parent}'s + * @throws java.lang.IllegalArgumentException if the {@code parent}'s * {@code GraphicsConfiguration} * is not from a screen device; - * @exception java.lang.IllegalArgumentException if {@code parent} + * @throws java.lang.IllegalArgumentException if {@code parent} * is {@code null}; this exception is always thrown when * {@code GraphicsEnvironment.isHeadless} * returns {@code true} @@ -285,10 +285,10 @@ public class FileDialog extends Dialog { * @param title the title of the dialog; a {@code null} value * will be accepted without causing a * {@code NullPointerException} to be thrown - * @exception java.lang.IllegalArgumentException if the {@code parent}'s + * @throws java.lang.IllegalArgumentException if the {@code parent}'s * {@code GraphicsConfiguration} * is not from a screen device; - * @exception java.lang.IllegalArgumentException if {@code parent} + * @throws java.lang.IllegalArgumentException if {@code parent} * is {@code null}; this exception is always thrown when * {@code GraphicsEnvironment.isHeadless} * returns {@code true} @@ -321,12 +321,12 @@ public class FileDialog extends Dialog { * {@code NullPointerException} to be thrown * @param mode the mode of the dialog; either * {@code FileDialog.LOAD} or {@code FileDialog.SAVE} - * @exception java.lang.IllegalArgumentException if an illegal + * @throws java.lang.IllegalArgumentException if an illegal * file dialog mode is supplied; - * @exception java.lang.IllegalArgumentException if the {@code parent}'s + * @throws java.lang.IllegalArgumentException if the {@code parent}'s * {@code GraphicsConfiguration} * is not from a screen device; - * @exception java.lang.IllegalArgumentException if {@code parent} + * @throws java.lang.IllegalArgumentException if {@code parent} * is {@code null}; this exception is always thrown when * {@code GraphicsEnvironment.isHeadless} * returns {@code true} @@ -408,7 +408,7 @@ public class FileDialog extends Dialog { * @see java.awt.FileDialog#LOAD * @see java.awt.FileDialog#SAVE * @see java.awt.FileDialog#getMode - * @exception IllegalArgumentException if an illegal file + * @throws IllegalArgumentException if an illegal file * dialog mode is supplied * @since 1.1 */ diff --git a/src/java.desktop/share/classes/java/awt/Frame.java b/src/java.desktop/share/classes/java/awt/Frame.java index 6dde9373c38..e01ef082d42 100644 --- a/src/java.desktop/share/classes/java/awt/Frame.java +++ b/src/java.desktop/share/classes/java/awt/Frame.java @@ -383,7 +383,7 @@ public class Frame extends Window implements MenuContainer { * Constructs a new instance of {@code Frame} that is * initially invisible. The title of the {@code Frame} * is empty. - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless() * @see Component#setSize @@ -401,9 +401,9 @@ public class Frame extends Window implements MenuContainer { * of the target screen device. If {@code gc} * is {@code null}, the system default * {@code GraphicsConfiguration} is assumed. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code gc} is not from a screen device. - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless() * @since 1.3 @@ -418,7 +418,7 @@ public class Frame extends Window implements MenuContainer { * @param title the title to be displayed in the frame's border. * A {@code null} value * is treated as an empty string, "". - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless() * @see java.awt.Component#setSize @@ -440,9 +440,9 @@ public class Frame extends Window implements MenuContainer { * of the target screen device. If {@code gc} is * {@code null}, the system default * {@code GraphicsConfiguration} is assumed. - * @exception IllegalArgumentException if {@code gc} + * @throws IllegalArgumentException if {@code gc} * is not from a screen device. - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless() * @see java.awt.Component#setSize diff --git a/src/java.desktop/share/classes/java/awt/GraphicsConfiguration.java b/src/java.desktop/share/classes/java/awt/GraphicsConfiguration.java index b698f0f3706..58d502ac03f 100644 --- a/src/java.desktop/share/classes/java/awt/GraphicsConfiguration.java +++ b/src/java.desktop/share/classes/java/awt/GraphicsConfiguration.java @@ -261,7 +261,7 @@ public abstract class GraphicsConfiguration { * @param width the width of the returned {@code VolatileImage} * @param height the height of the returned {@code VolatileImage} * @param caps the image capabilities - * @exception AWTException if the supplied image capabilities could not + * @throws AWTException if the supplied image capabilities could not * be met by this graphics configuration * @since 1.4 */ @@ -294,7 +294,7 @@ public abstract class GraphicsConfiguration { * @see Transparency#BITMASK * @see Transparency#TRANSLUCENT * @throws IllegalArgumentException if the transparency is not a valid value - * @exception AWTException if the supplied image capabilities could not + * @throws AWTException if the supplied image capabilities could not * be met by this graphics configuration * @see Component#createVolatileImage(int, int) * @since 1.5 diff --git a/src/java.desktop/share/classes/java/awt/GraphicsDevice.java b/src/java.desktop/share/classes/java/awt/GraphicsDevice.java index d878f610fca..c08c5580ae7 100644 --- a/src/java.desktop/share/classes/java/awt/GraphicsDevice.java +++ b/src/java.desktop/share/classes/java/awt/GraphicsDevice.java @@ -418,10 +418,10 @@ public abstract class GraphicsDevice { * * * @param dm The new display mode of this graphics device. - * @exception IllegalArgumentException if the {@code DisplayMode} + * @throws IllegalArgumentException if the {@code DisplayMode} * supplied is {@code null}, or is not available in the array returned * by {@code getDisplayModes} - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code isDisplayChangeSupported} returns {@code false} * @see #getDisplayMode * @see #getDisplayModes diff --git a/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java b/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java index 438f9f399a0..79102059b0e 100644 --- a/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java +++ b/src/java.desktop/share/classes/java/awt/GraphicsEnvironment.java @@ -191,7 +191,7 @@ public abstract class GraphicsEnvironment { * objects. * @return an array containing all the {@code GraphicsDevice} * objects that represent screen devices - * @exception HeadlessException if isHeadless() returns true + * @throws HeadlessException if isHeadless() returns true * @see #isHeadless() */ public abstract GraphicsDevice[] getScreenDevices() @@ -201,7 +201,7 @@ public abstract class GraphicsEnvironment { * Returns the default screen {@code GraphicsDevice}. * @return the {@code GraphicsDevice} that represents the * default screen device - * @exception HeadlessException if isHeadless() returns true + * @throws HeadlessException if isHeadless() returns true * @see #isHeadless() */ public abstract GraphicsDevice getDefaultScreenDevice() @@ -383,7 +383,7 @@ public abstract class GraphicsEnvironment { * within the available display area using getMaximumWindowBounds(). * @return the point where Windows should be centered * - * @exception HeadlessException if isHeadless() returns true + * @throws HeadlessException if isHeadless() returns true * @see #getMaximumWindowBounds * @since 1.4 */ @@ -409,7 +409,7 @@ public abstract class GraphicsEnvironment { * {@code Toolkit.getScreenInsets()}. * @return the maximum bounds for centered Windows * - * @exception HeadlessException if isHeadless() returns true + * @throws HeadlessException if isHeadless() returns true * @see #getCenterPoint * @see GraphicsConfiguration#getBounds * @see Toolkit#getScreenInsets diff --git a/src/java.desktop/share/classes/java/awt/GridBagLayout.java b/src/java.desktop/share/classes/java/awt/GridBagLayout.java index ff3bec8b115..e0692ac0624 100644 --- a/src/java.desktop/share/classes/java/awt/GridBagLayout.java +++ b/src/java.desktop/share/classes/java/awt/GridBagLayout.java @@ -688,7 +688,7 @@ java.io.Serializable { * @param comp the component to be added * @param constraints an object that determines how * the component is added to the layout - * @exception IllegalArgumentException if {@code constraints} + * @throws IllegalArgumentException if {@code constraints} * is not a {@code GridBagConstraint} */ public void addLayoutComponent(Component comp, Object constraints) { diff --git a/src/java.desktop/share/classes/java/awt/GridLayout.java b/src/java.desktop/share/classes/java/awt/GridLayout.java index 4a3b66f4332..5c9265bc912 100644 --- a/src/java.desktop/share/classes/java/awt/GridLayout.java +++ b/src/java.desktop/share/classes/java/awt/GridLayout.java @@ -186,7 +186,7 @@ public class GridLayout implements LayoutManager, java.io.Serializable { * any number of columns * @param hgap the horizontal gap * @param vgap the vertical gap - * @exception IllegalArgumentException if the value of both + * @throws IllegalArgumentException if the value of both * {@code rows} and {@code cols} is * set to zero */ @@ -212,7 +212,7 @@ public class GridLayout implements LayoutManager, java.io.Serializable { /** * Sets the number of rows in this layout to the specified value. * @param rows the number of rows in this layout - * @exception IllegalArgumentException if the value of both + * @throws IllegalArgumentException if the value of both * {@code rows} and {@code cols} is set to zero * @since 1.1 */ @@ -240,7 +240,7 @@ public class GridLayout implements LayoutManager, java.io.Serializable { * of columns displayed in the layout is determined by the total * number of components and the number of rows specified. * @param cols the number of columns in this layout - * @exception IllegalArgumentException if the value of both + * @throws IllegalArgumentException if the value of both * {@code rows} and {@code cols} is set to zero * @since 1.1 */ diff --git a/src/java.desktop/share/classes/java/awt/Image.java b/src/java.desktop/share/classes/java/awt/Image.java index 7e627323269..1ad4ec9226f 100644 --- a/src/java.desktop/share/classes/java/awt/Image.java +++ b/src/java.desktop/share/classes/java/awt/Image.java @@ -105,7 +105,7 @@ public abstract class Image { * Creates a graphics context for drawing to an off-screen image. * This method can only be called for off-screen images. * @return a graphics context to draw to the off-screen image. - * @exception UnsupportedOperationException if called for a + * @throws UnsupportedOperationException if called for a * non-off-screen image. * @see java.awt.Graphics * @see java.awt.Component#createImage(int, int) @@ -162,7 +162,7 @@ public abstract class Image { * @param hints flags to indicate the type of algorithm to use * for image resampling. * @return a scaled version of the image. - * @exception IllegalArgumentException if {@code width} + * @throws IllegalArgumentException if {@code width} * or {@code height} is zero. * @see java.awt.Image#SCALE_DEFAULT * @see java.awt.Image#SCALE_FAST diff --git a/src/java.desktop/share/classes/java/awt/Label.java b/src/java.desktop/share/classes/java/awt/Label.java index b061efb5170..ad8ff4c2b82 100644 --- a/src/java.desktop/share/classes/java/awt/Label.java +++ b/src/java.desktop/share/classes/java/awt/Label.java @@ -114,7 +114,7 @@ public class Label extends Component implements Accessible { /** * Constructs an empty label. * The text of the label is the empty string {@code ""}. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -129,7 +129,7 @@ public class Label extends Component implements Accessible { * A {@code null} value * will be accepted without causing a NullPointerException * to be thrown. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -147,7 +147,7 @@ public class Label extends Component implements Accessible { * will be accepted without causing a NullPointerException * to be thrown. * @param alignment the alignment value. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -216,7 +216,7 @@ public class Label extends Component implements Accessible { * Possible values are {@code Label.LEFT}, * {@code Label.RIGHT}, and {@code Label.CENTER}. * @param alignment the alignment to be set. - * @exception IllegalArgumentException if an improper value for + * @throws IllegalArgumentException if an improper value for * {@code alignment} is given. * @see java.awt.Label#getAlignment */ diff --git a/src/java.desktop/share/classes/java/awt/List.java b/src/java.desktop/share/classes/java/awt/List.java index f29374ab6bc..fe1a5dc5530 100644 --- a/src/java.desktop/share/classes/java/awt/List.java +++ b/src/java.desktop/share/classes/java/awt/List.java @@ -193,7 +193,7 @@ public class List extends Component implements ItemSelectable, Accessible { * not allowed. Note that this is a convenience method for * {@code List(0, false)}. Also note that the number of visible * lines in the list cannot be changed after it has been created. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -209,7 +209,7 @@ public class List extends Component implements ItemSelectable, Accessible { * of visible rows in the list cannot be changed after it has * been created. * @param rows the number of items to show. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -238,7 +238,7 @@ public class List extends Component implements ItemSelectable, Accessible { * @param multipleMode if {@code true}, * then multiple selections are allowed; * otherwise, only one item can be selected at a time. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -411,7 +411,7 @@ public class List extends Component implements ItemSelectable, Accessible { * with the new string. * @param newValue a new string to replace an existing item * @param index the position of the item to replace - * @exception ArrayIndexOutOfBoundsException if {@code index} + * @throws ArrayIndexOutOfBoundsException if {@code index} * is out of range */ public synchronized void replaceItem(String newValue, int index) { @@ -448,7 +448,7 @@ public class List extends Component implements ItemSelectable, Accessible { * If the specified item is selected, and is the only selected * item in the list, the list is set to have no selection. * @param item the item to remove from the list - * @exception IllegalArgumentException + * @throws IllegalArgumentException * if the item doesn't exist in the list * @since 1.1 */ @@ -470,7 +470,7 @@ public class List extends Component implements ItemSelectable, Accessible { * @param position the index of the item to delete * @see #add(String, int) * @since 1.1 - * @exception ArrayIndexOutOfBoundsException + * @throws ArrayIndexOutOfBoundsException * if the {@code position} is less than 0 or * greater than {@code getItemCount()-1} */ @@ -1053,7 +1053,7 @@ public class List extends Component implements ItemSelectable, Accessible { * FooListeners on this list, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * @@ -1631,7 +1631,7 @@ public class List extends Component implements ItemSelectable, Accessible { * @return This component's locale. If this component does not have * a locale, the locale of its parent is returned. * - * @exception IllegalComponentStateException + * @throws IllegalComponentStateException * If the Component does not have its own locale and has not yet * been added to a containment hierarchy such that the locale can * be determined from the containing parent. diff --git a/src/java.desktop/share/classes/java/awt/MediaTracker.java b/src/java.desktop/share/classes/java/awt/MediaTracker.java index e2b754c40af..37e372d0d1f 100644 --- a/src/java.desktop/share/classes/java/awt/MediaTracker.java +++ b/src/java.desktop/share/classes/java/awt/MediaTracker.java @@ -396,7 +396,7 @@ public class MediaTracker implements java.io.Serializable { * @see java.awt.MediaTracker#waitForAll(long) * @see java.awt.MediaTracker#isErrorAny * @see java.awt.MediaTracker#isErrorID - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread */ public void waitForAll() throws InterruptedException { @@ -421,7 +421,7 @@ public class MediaTracker implements java.io.Serializable { * @see java.awt.MediaTracker#waitForAll(long) * @see java.awt.MediaTracker#isErrorAny * @see java.awt.MediaTracker#isErrorID - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread. */ public synchronized boolean waitForAll(long ms) @@ -627,7 +627,7 @@ public class MediaTracker implements java.io.Serializable { * @see java.awt.MediaTracker#waitForAll * @see java.awt.MediaTracker#isErrorAny() * @see java.awt.MediaTracker#isErrorID(int) - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread. */ public void waitForID(int id) throws InterruptedException { @@ -655,7 +655,7 @@ public class MediaTracker implements java.io.Serializable { * @see java.awt.MediaTracker#statusID * @see java.awt.MediaTracker#isErrorAny() * @see java.awt.MediaTracker#isErrorID(int) - * @exception InterruptedException if any thread has + * @throws InterruptedException if any thread has * interrupted this thread. */ public synchronized boolean waitForID(int id, long ms) diff --git a/src/java.desktop/share/classes/java/awt/Menu.java b/src/java.desktop/share/classes/java/awt/Menu.java index 5f24c7cb8bd..79c3dfe0d82 100644 --- a/src/java.desktop/share/classes/java/awt/Menu.java +++ b/src/java.desktop/share/classes/java/awt/Menu.java @@ -125,7 +125,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { /** * Constructs a new menu with an empty label. This menu is not * a tear-off menu. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -139,7 +139,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * a tear-off menu. * @param label the menu's label in the menu bar, or in * another menu of which this menu is a submenu. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -158,7 +158,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * another menu of which this menu is a submenu. * @param tearOff if {@code true}, the menu * is a tear-off menu. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -313,7 +313,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * item should be inserted. * @see java.awt.Menu#add(java.lang.String) * @see java.awt.Menu#add(java.awt.MenuItem) - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * {@code index} is less than zero * @since 1.1 */ @@ -357,7 +357,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * should be inserted * @see java.awt.Menu#add(java.lang.String) * @see java.awt.Menu#add(java.awt.MenuItem) - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * {@code index} is less than zero * @since 1.1 */ @@ -378,7 +378,7 @@ public class Menu extends MenuItem implements MenuContainer, Accessible { * Inserts a separator at the specified position. * @param index the position at which the * menu separator should be inserted. - * @exception IllegalArgumentException if the value of + * @throws IllegalArgumentException if the value of * {@code index} is less than 0. * @see java.awt.Menu#addSeparator * @since 1.1 diff --git a/src/java.desktop/share/classes/java/awt/MenuBar.java b/src/java.desktop/share/classes/java/awt/MenuBar.java index 2f78371407a..c1016f5bd0b 100644 --- a/src/java.desktop/share/classes/java/awt/MenuBar.java +++ b/src/java.desktop/share/classes/java/awt/MenuBar.java @@ -127,7 +127,7 @@ public class MenuBar extends MenuComponent implements MenuContainer, Accessible /** * Creates a new menu bar. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ diff --git a/src/java.desktop/share/classes/java/awt/MenuComponent.java b/src/java.desktop/share/classes/java/awt/MenuComponent.java index 2550eea7f52..a2d28fb9e3e 100644 --- a/src/java.desktop/share/classes/java/awt/MenuComponent.java +++ b/src/java.desktop/share/classes/java/awt/MenuComponent.java @@ -176,7 +176,7 @@ public abstract class MenuComponent implements java.io.Serializable { /** * Creates a {@code MenuComponent}. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns {@code true} * @see java.awt.GraphicsEnvironment#isHeadless diff --git a/src/java.desktop/share/classes/java/awt/MenuItem.java b/src/java.desktop/share/classes/java/awt/MenuItem.java index d1f6f59aa15..adc37db7111 100644 --- a/src/java.desktop/share/classes/java/awt/MenuItem.java +++ b/src/java.desktop/share/classes/java/awt/MenuItem.java @@ -185,7 +185,7 @@ public class MenuItem extends MenuComponent implements Accessible { /** * Constructs a new MenuItem with an empty label and no keyboard * shortcut. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -201,7 +201,7 @@ public class MenuItem extends MenuComponent implements Accessible { * menu items. By default, all menu items except for * separators are enabled. * @param label the label for this menu item. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.0 @@ -218,7 +218,7 @@ public class MenuItem extends MenuComponent implements Accessible { * @param label the label for this menu item. * @param s the instance of {@code MenuShortcut} * associated with this menu item. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -616,7 +616,7 @@ public class MenuItem extends MenuComponent implements Accessible { * FooListeners on this menu item, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/MouseInfo.java b/src/java.desktop/share/classes/java/awt/MouseInfo.java index 76b5ed6e397..3dd115e0724 100644 --- a/src/java.desktop/share/classes/java/awt/MouseInfo.java +++ b/src/java.desktop/share/classes/java/awt/MouseInfo.java @@ -62,8 +62,8 @@ public class MouseInfo { * permission before creating and returning a {@code PointerInfo} * object. This may result in a {@code SecurityException}. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true - * @exception SecurityException if a security manager exists and its + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws SecurityException if a security manager exists and its * {@code checkPermission} method doesn't allow the operation * @see GraphicsConfiguration * @see SecurityManager#checkPermission @@ -124,7 +124,7 @@ public class MouseInfo { * by requesting the {@code "awt.mouse.numButtons"} desktop property * which is set by the underlying native platform. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @return number of buttons on the mouse * @see Toolkit#getDesktopProperty * @since 1.5 diff --git a/src/java.desktop/share/classes/java/awt/Polygon.java b/src/java.desktop/share/classes/java/awt/Polygon.java index 64f049cd1c7..e74ce5cb10f 100644 --- a/src/java.desktop/share/classes/java/awt/Polygon.java +++ b/src/java.desktop/share/classes/java/awt/Polygon.java @@ -139,12 +139,12 @@ public class Polygon implements Shape, java.io.Serializable { * @param ypoints an array of Y coordinates * @param npoints the total number of points in the * {@code Polygon} - * @exception NegativeArraySizeException if the value of + * @throws NegativeArraySizeException if the value of * {@code npoints} is negative. - * @exception IndexOutOfBoundsException if {@code npoints} is + * @throws IndexOutOfBoundsException if {@code npoints} is * greater than the length of {@code xpoints} * or the length of {@code ypoints}. - * @exception NullPointerException if {@code xpoints} or + * @throws NullPointerException if {@code xpoints} or * {@code ypoints} is {@code null}. * @since 1.0 */ diff --git a/src/java.desktop/share/classes/java/awt/PopupMenu.java b/src/java.desktop/share/classes/java/awt/PopupMenu.java index fd56461df55..e9b88d2a12f 100644 --- a/src/java.desktop/share/classes/java/awt/PopupMenu.java +++ b/src/java.desktop/share/classes/java/awt/PopupMenu.java @@ -69,7 +69,7 @@ public class PopupMenu extends Menu { /** * Creates a new popup menu with an empty name. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -82,7 +82,7 @@ public class PopupMenu extends Menu { * * @param label a non-{@code null} string specifying * the popup menu's label - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -149,12 +149,12 @@ public class PopupMenu extends Menu { * @param origin the component which defines the coordinate space * @param x the x coordinate position to popup the menu * @param y the y coordinate position to popup the menu - * @exception NullPointerException if the parent is {@code null} - * @exception IllegalArgumentException if this {@code PopupMenu} + * @throws NullPointerException if the parent is {@code null} + * @throws IllegalArgumentException if this {@code PopupMenu} * has a non-{@code Component} parent - * @exception IllegalArgumentException if the origin is not in the + * @throws IllegalArgumentException if the origin is not in the * parent's hierarchy - * @exception RuntimeException if the parent is not showing on screen + * @throws RuntimeException if the parent is not showing on screen */ @SuppressWarnings("deprecation") public void show(Component origin, int x, int y) { diff --git a/src/java.desktop/share/classes/java/awt/RenderingHints.java b/src/java.desktop/share/classes/java/awt/RenderingHints.java index d69ed339eee..46d2fda1031 100644 --- a/src/java.desktop/share/classes/java/awt/RenderingHints.java +++ b/src/java.desktop/share/classes/java/awt/RenderingHints.java @@ -1064,7 +1064,7 @@ public class RenderingHints * {@code RenderingHints} is to be tested. * @return {@code true} if this {@code RenderingHints} * contains a mapping for the specified key. - * @exception ClassCastException if the key can not + * @throws ClassCastException if the key can not * be cast to {@code RenderingHints.Key} */ public boolean containsKey(Object key) { @@ -1099,7 +1099,7 @@ public class RenderingHints * @return the value to which the key is mapped in this object or * {@code null} if the key is not mapped to any value in * this object. - * @exception ClassCastException if the key can not + * @throws ClassCastException if the key can not * be cast to {@code RenderingHints.Key} * @see #put(Object, Object) */ @@ -1117,11 +1117,11 @@ public class RenderingHints * @param value the rendering hint value. * @return the previous value of the specified key in this object * or {@code null} if it did not have one. - * @exception NullPointerException if the key is + * @throws NullPointerException if the key is * {@code null}. - * @exception ClassCastException if the key can not + * @throws ClassCastException if the key can not * be cast to {@code RenderingHints.Key} - * @exception IllegalArgumentException if the + * @throws IllegalArgumentException if the * {@link Key#isCompatibleValue(java.lang.Object) * Key.isCompatibleValue()} * method of the specified key returns false for the @@ -1163,7 +1163,7 @@ public class RenderingHints * {@code RenderingHints} object. This method does nothing if the * key is not in this {@code RenderingHints} object. * @param key the rendering hints key that needs to be removed - * @exception ClassCastException if the key can not + * @throws ClassCastException if the key can not * be cast to {@code RenderingHints.Key} * @return the value to which the key had previously been mapped in this * {@code RenderingHints} object, or {@code null} @@ -1179,10 +1179,10 @@ public class RenderingHints * any mappings that this {@code RenderingHints} had for any * of the keys currently in the specified {@code Map}. * @param m the specified {@code Map} - * @exception ClassCastException class of a key or value + * @throws ClassCastException class of a key or value * in the specified {@code Map} prevents it from being * stored in this {@code RenderingHints}. - * @exception IllegalArgumentException some aspect + * @throws IllegalArgumentException some aspect * of a key or value in the specified {@code Map} * prevents it from being stored in * this {@code RenderingHints}. diff --git a/src/java.desktop/share/classes/java/awt/Scrollbar.java b/src/java.desktop/share/classes/java/awt/Scrollbar.java index 34cd3ecc799..c8f100cc1c2 100644 --- a/src/java.desktop/share/classes/java/awt/Scrollbar.java +++ b/src/java.desktop/share/classes/java/awt/Scrollbar.java @@ -349,7 +349,7 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * * * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -366,9 +366,9 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * indicating a horizontal or vertical scroll bar, respectively. * * @param orientation indicates the orientation of the scroll bar - * @exception IllegalArgumentException when an illegal value for + * @throws IllegalArgumentException when an illegal value for * the {@code orientation} argument is supplied - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -394,9 +394,9 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * represented by the size of the bubble * @param minimum the minimum value of the scroll bar * @param maximum the maximum value of the scroll bar - * @exception IllegalArgumentException when an illegal value for + * @throws IllegalArgumentException when an illegal value for * the {@code orientation} argument is supplied - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see #setValues * @see java.awt.GraphicsEnvironment#isHeadless @@ -457,7 +457,7 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * {@code Scrollbar.HORIZONTAL} or * {@code Scrollbar.VERTICAL} * @see java.awt.Scrollbar#getOrientation - * @exception IllegalArgumentException if the value supplied + * @throws IllegalArgumentException if the value supplied * for {@code orientation} is not a * legal value * @since 1.1 @@ -1062,7 +1062,7 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * @return an array of all objects registered as * FooListeners on this component, * or an empty array if no such listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/TextArea.java b/src/java.desktop/share/classes/java/awt/TextArea.java index 5e3e5ca6b33..4c7baa52e4e 100644 --- a/src/java.desktop/share/classes/java/awt/TextArea.java +++ b/src/java.desktop/share/classes/java/awt/TextArea.java @@ -157,7 +157,7 @@ public class TextArea extends TextComponent { * This text area is created with scrollbar visibility equal to * {@link #SCROLLBARS_BOTH}, so both vertical and horizontal * scrollbars will be visible for this text area. - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -173,7 +173,7 @@ public class TextArea extends TextComponent { * @param text the text to be displayed; if * {@code text} is {@code null}, the empty * string {@code ""} will be displayed - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -191,7 +191,7 @@ public class TextArea extends TextComponent { * text area. * @param rows the number of rows * @param columns the number of columns - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -212,7 +212,7 @@ public class TextArea extends TextComponent { * string {@code ""} will be displayed * @param rows the number of rows * @param columns the number of columns - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -252,7 +252,7 @@ public class TextArea extends TextComponent { * @param scrollbars a constant that determines what * scrollbars are created to view the text area * @since 1.1 - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless() */ @@ -421,7 +421,7 @@ public class TextArea extends TextComponent { * @param rows the number of rows * @see #getRows() * @see #setColumns(int) - * @exception IllegalArgumentException if the value + * @throws IllegalArgumentException if the value * supplied for {@code rows} * is less than {@code 0} * @since 1.1 @@ -452,7 +452,7 @@ public class TextArea extends TextComponent { * @param columns the number of columns * @see #getColumns() * @see #setRows(int) - * @exception IllegalArgumentException if the value + * @throws IllegalArgumentException if the value * supplied for {@code columns} * is less than {@code 0} * @since 1.1 diff --git a/src/java.desktop/share/classes/java/awt/TextComponent.java b/src/java.desktop/share/classes/java/awt/TextComponent.java index 5dc8d4068cc..b471b4e5ec6 100644 --- a/src/java.desktop/share/classes/java/awt/TextComponent.java +++ b/src/java.desktop/share/classes/java/awt/TextComponent.java @@ -137,7 +137,7 @@ public class TextComponent extends Component implements Accessible { * @param text the text to be displayed; if * {@code text} is {@code null}, the empty * string {@code ""} will be displayed - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} * returns true * @see java.awt.GraphicsEnvironment#isHeadless @@ -511,7 +511,7 @@ public class TextComponent extends Component implements Accessible { * is thrown. * * @param position the position of the text insertion caret - * @exception IllegalArgumentException if {@code position} + * @throws IllegalArgumentException if {@code position} * is less than zero * @since 1.1 */ @@ -645,7 +645,7 @@ public class TextComponent extends Component implements Accessible { * FooListeners on this text component, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/TextField.java b/src/java.desktop/share/classes/java/awt/TextField.java index 5ca720ee80e..d2bfa0360b9 100644 --- a/src/java.desktop/share/classes/java/awt/TextField.java +++ b/src/java.desktop/share/classes/java/awt/TextField.java @@ -152,7 +152,7 @@ public class TextField extends TextComponent { /** * Constructs a new text field. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -167,7 +167,7 @@ public class TextField extends TextComponent { * string {@code ""} will be displayed. * If {@code text} contains EOL and/or LF characters, then * each will be replaced by space character. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -182,7 +182,7 @@ public class TextField extends TextComponent { * @param columns the number of columns. If * {@code columns} is less than {@code 0}, * {@code columns} is set to {@code 0}. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -203,7 +203,7 @@ public class TextField extends TextComponent { * @param columns the number of columns. If * {@code columns} is less than {@code 0}, * {@code columns} is set to {@code 0}. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -369,7 +369,7 @@ public class TextField extends TextComponent { * approximate average character width that is platform-dependent. * @param columns the number of columns. * @see java.awt.TextField#getColumns - * @exception IllegalArgumentException if the value + * @throws IllegalArgumentException if the value * supplied for {@code columns} * is less than {@code 0}. * @since 1.1 @@ -585,7 +585,7 @@ public class TextField extends TextComponent { * FooListeners on this textfield, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/Toolkit.java b/src/java.desktop/share/classes/java/awt/Toolkit.java index f3f4bcbb5c8..7399ced02bb 100644 --- a/src/java.desktop/share/classes/java/awt/Toolkit.java +++ b/src/java.desktop/share/classes/java/awt/Toolkit.java @@ -149,7 +149,7 @@ public abstract class Toolkit { * with the current system color values. * * @param systemColors an integer array. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.1 @@ -181,7 +181,7 @@ public abstract class Toolkit { * @param dynamic If true, Containers should re-layout their * components as the Container is being resized. If false, * the layout will be validated after resizing is completed. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see #isDynamicLayoutSet() * @see #isDynamicLayoutActive() @@ -208,7 +208,7 @@ public abstract class Toolkit { * * @return true if validation of Containers is done dynamically, * false if validation is done after resizing is finished. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see #setDynamicLayout(boolean dynamic) * @see #isDynamicLayoutActive() @@ -274,7 +274,7 @@ public abstract class Toolkit { * available from {@code GraphicsConfiguration} and * {@code GraphicsDevice}. * @return the size of this toolkit's screen, in pixels. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsConfiguration#getBounds * @see java.awt.GraphicsDevice#getDisplayMode @@ -286,7 +286,7 @@ public abstract class Toolkit { /** * Returns the screen resolution in dots-per-inch. * @return this toolkit's screen resolution, in dots-per-inch. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -297,7 +297,7 @@ public abstract class Toolkit { * Gets the insets of the screen. * @param gc a {@code GraphicsConfiguration} * @return the insets of this toolkit's screen, in pixels. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.4 @@ -324,7 +324,7 @@ public abstract class Toolkit { * {@code getColorModel} method * of the {@code Component} class. * @return the color model of this toolkit's screen. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.image.ColorModel @@ -973,7 +973,7 @@ public abstract class Toolkit { * checkPermission} method to check {@code AWTPermission("accessClipboard")}. * * @return the system Clipboard - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.datatransfer.Clipboard @@ -1020,7 +1020,7 @@ public abstract class Toolkit { * @return the system selection as a {@code Clipboard}, or * {@code null} if the native platform does not support a * system selection {@code Clipboard} - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * * @see java.awt.datatransfer.Clipboard @@ -1057,7 +1057,7 @@ public abstract class Toolkit { * Control key isn't the correct key for accelerators. * @return the modifier mask on the {@code Event} class * that is used for menu shortcuts on this toolkit. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @see java.awt.MenuBar @@ -1111,12 +1111,12 @@ public abstract class Toolkit { * @param keyCode the key code * @return {@code true} if the given key is currently in its "on" state; * otherwise {@code false} - * @exception java.lang.IllegalArgumentException if {@code keyCode} + * @throws java.lang.IllegalArgumentException if {@code keyCode} * is not one of the valid key codes - * @exception java.lang.UnsupportedOperationException if the host system doesn't + * @throws java.lang.UnsupportedOperationException if the host system doesn't * allow getting the state of this key programmatically, or if the keyboard * doesn't have this key - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.3 @@ -1147,12 +1147,12 @@ public abstract class Toolkit { * * @param keyCode the key code * @param on the state of the key - * @exception java.lang.IllegalArgumentException if {@code keyCode} + * @throws java.lang.IllegalArgumentException if {@code keyCode} * is not one of the valid key codes - * @exception java.lang.UnsupportedOperationException if the host system doesn't + * @throws java.lang.UnsupportedOperationException if the host system doesn't * allow setting the state of this key programmatically, or if the keyboard * doesn't have this key - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.3 @@ -1193,10 +1193,10 @@ public abstract class Toolkit { * hotSpot values must be less than the Dimension returned by * {@code getBestCursorSize} * @param name a localized description of the cursor, for Java Accessibility use - * @exception IndexOutOfBoundsException if the hotSpot values are outside + * @throws IndexOutOfBoundsException if the hotSpot values are outside * the bounds of the cursor * @return the cursor created - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -1232,7 +1232,7 @@ public abstract class Toolkit { * to use. * @return the closest matching supported cursor size, or a dimension of 0,0 if * the Toolkit implementation doesn't support custom cursors. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -1262,7 +1262,7 @@ public abstract class Toolkit { * * @return the maximum number of colors, or zero if custom cursors are not * supported by this Toolkit implementation. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -1310,7 +1310,7 @@ public abstract class Toolkit { * @param state one of named frame state constants. * @return {@code true} is this frame state is supported by * this Toolkit implementation, {@code false} otherwise. - * @exception HeadlessException + * @throws HeadlessException * if {@code GraphicsEnvironment.isHeadless()} * returns {@code true}. * @see java.awt.Window#addWindowStateListener @@ -2203,7 +2203,7 @@ public abstract class Toolkit { * returned is unmodifiable. * @param highlight input method highlight * @return style attribute map, or {@code null} - * @exception HeadlessException if + * @throws HeadlessException if * {@code GraphicsEnvironment.isHeadless} returns true * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.3 @@ -2360,7 +2360,7 @@ public abstract class Toolkit { * initialized with {@code true}. * Changing this value after the {@code Toolkit} class initialization will have no effect. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true + * @throws HeadlessException if GraphicsEnvironment.isHeadless() returns true * @return {@code true} if events from extra mouse buttons are allowed to be processed and posted; * {@code false} otherwise * @see System#getProperty(String propertyName) diff --git a/src/java.desktop/share/classes/java/awt/Window.java b/src/java.desktop/share/classes/java/awt/Window.java index 59e63abbb3c..c58b2a5e94a 100644 --- a/src/java.desktop/share/classes/java/awt/Window.java +++ b/src/java.desktop/share/classes/java/awt/Window.java @@ -442,9 +442,9 @@ public class Window extends Container implements Accessible { * @param gc the {@code GraphicsConfiguration} of the target screen * device. If {@code gc} is {@code null}, the system default * {@code GraphicsConfiguration} is assumed - * @exception IllegalArgumentException if {@code gc} + * @throws IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -544,7 +544,7 @@ public class Window extends Container implements Accessible { * If that check fails with a {@code SecurityException} then a warning * banner is created. * - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -566,9 +566,9 @@ public class Window extends Container implements Accessible { * * @param owner the {@code Frame} to act as owner or {@code null} * if this window has no owner - * @exception IllegalArgumentException if the {@code owner}'s + * @throws IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless} returns {@code true} * * @see java.awt.GraphicsEnvironment#isHeadless @@ -593,9 +593,9 @@ public class Window extends Container implements Accessible { * * @param owner the {@code Window} to act as owner or * {@code null} if this window has no owner - * @exception IllegalArgumentException if the {@code owner}'s + * @throws IllegalArgumentException if the {@code owner}'s * {@code GraphicsConfiguration} is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns * {@code true} * @@ -627,9 +627,9 @@ public class Window extends Container implements Accessible { * @param gc the {@code GraphicsConfiguration} of the target * screen device; if {@code gc} is {@code null}, * the system default {@code GraphicsConfiguration} is assumed - * @exception IllegalArgumentException if {@code gc} + * @throws IllegalArgumentException if {@code gc} * is not from a screen device - * @exception HeadlessException when + * @throws HeadlessException when * {@code GraphicsEnvironment.isHeadless()} returns * {@code true} * @@ -1964,10 +1964,10 @@ public class Window extends Container implements Accessible { * FooListeners on this window, * or an empty array if no such * listeners have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} - * @exception NullPointerException if {@code listenerType} is {@code null} + * @throws NullPointerException if {@code listenerType} is {@code null} * * @see #getWindowListeners * @since 1.3 @@ -3372,8 +3372,8 @@ public class Window extends Container implements Accessible { * Each time this method is called, * the existing buffer strategy for this component is discarded. * @param numBuffers number of buffers to create - * @exception IllegalArgumentException if numBuffers is less than 1. - * @exception IllegalStateException if the component is not displayable + * @throws IllegalArgumentException if numBuffers is less than 1. + * @throws IllegalStateException if the component is not displayable * @see #isDisplayable * @see #getBufferStrategy * @since 1.4 @@ -3393,11 +3393,11 @@ public class Window extends Container implements Accessible { * @param numBuffers number of buffers to create, including the front buffer * @param caps the required capabilities for creating the buffer strategy; * cannot be {@code null} - * @exception AWTException if the capabilities supplied could not be + * @throws AWTException if the capabilities supplied could not be * supported or met; this may happen, for example, if there is not enough * accelerated memory currently available, or if page flipping is specified * but not possible. - * @exception IllegalArgumentException if numBuffers is less than 1, or if + * @throws IllegalArgumentException if numBuffers is less than 1, or if * caps is {@code null} * @see #getBufferStrategy * @since 1.4 diff --git a/src/java.desktop/share/classes/java/awt/dnd/DragSource.java b/src/java.desktop/share/classes/java/awt/dnd/DragSource.java index 8bbdfc24c06..71bf6d27c83 100644 --- a/src/java.desktop/share/classes/java/awt/dnd/DragSource.java +++ b/src/java.desktop/share/classes/java/awt/dnd/DragSource.java @@ -217,7 +217,7 @@ public class DragSource implements Serializable { * the underlying platform. * * @return the platform DragSource - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -255,7 +255,7 @@ public class DragSource implements Serializable { /** * Creates a new {@code DragSource}. * - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -682,7 +682,7 @@ public class DragSource implements Serializable { * FooListeners on this * {@code DragSource}, or an empty array if no such listeners * have been added - * @exception ClassCastException if {@code listenerType} + * @throws ClassCastException if {@code listenerType} * doesn't specify a class or interface that implements * {@code java.util.EventListener} * diff --git a/src/java.desktop/share/classes/java/awt/dnd/DropTarget.java b/src/java.desktop/share/classes/java/awt/dnd/DropTarget.java index 7ba9c9711da..fbd086792a5 100644 --- a/src/java.desktop/share/classes/java/awt/dnd/DropTarget.java +++ b/src/java.desktop/share/classes/java/awt/dnd/DropTarget.java @@ -89,7 +89,7 @@ public class DropTarget implements DropTargetListener, Serializable { * @param dtl The {@code DropTargetListener} for this {@code DropTarget} * @param act Is the {@code DropTarget} accepting drops. * @param fm The {@code FlavorMap} to use, or null for the default {@code FlavorMap} - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -136,7 +136,7 @@ public class DropTarget implements DropTargetListener, Serializable { * @param ops The default acceptable actions for this {@code DropTarget} * @param dtl The {@code DropTargetListener} for this {@code DropTarget} * @param act Is the {@code DropTarget} accepting drops. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -149,7 +149,7 @@ public class DropTarget implements DropTargetListener, Serializable { /** * Creates a {@code DropTarget}. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -165,7 +165,7 @@ public class DropTarget implements DropTargetListener, Serializable { * The Component will receive drops only if it is enabled. * @param c The {@code Component} with which this {@code DropTarget} is associated * @param dtl The {@code DropTargetListener} for this {@code DropTarget} - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -185,7 +185,7 @@ public class DropTarget implements DropTargetListener, Serializable { * @param c The {@code Component} with which this {@code DropTarget} is associated * @param ops The default acceptable actions for this {@code DropTarget} * @param dtl The {@code DropTargetListener} for this {@code DropTarget} - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ diff --git a/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java b/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java index 94cfcc0bf40..12ad1a03171 100644 --- a/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java +++ b/src/java.desktop/share/classes/java/awt/event/InputMethodEvent.java @@ -436,7 +436,7 @@ public class InputMethodEvent extends AWTEvent { * belongs to. * * @param source the source of the event - * @exception IllegalArgumentException if source is null. + * @throws IllegalArgumentException if source is null. * @return most recent event time in the {@code EventQueue} */ private static long getMostRecentEventTimeForSource(Object source) { diff --git a/src/java.desktop/share/classes/java/awt/font/TextLayout.java b/src/java.desktop/share/classes/java/awt/font/TextLayout.java index ddc5199b843..352d3c81df2 100644 --- a/src/java.desktop/share/classes/java/awt/font/TextLayout.java +++ b/src/java.desktop/share/classes/java/awt/font/TextLayout.java @@ -789,7 +789,7 @@ public final class TextLayout implements Cloneable { * For best results, it should not be too different from the current * advance of the line. * @return a {@code TextLayout} justified to the specified width. - * @exception Error if this layout has already been justified, an Error is + * @throws Error if this layout has already been justified, an Error is * thrown. */ public TextLayout getJustifiedLayout(float justificationWidth) { diff --git a/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java b/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java index 44324e2d3b9..7f6fc7c34f9 100644 --- a/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java +++ b/src/java.desktop/share/classes/java/awt/geom/AffineTransform.java @@ -2667,7 +2667,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * @return a new {@code AffineTransform} object representing the * inverse transformation. * @see #getDeterminant - * @exception NoninvertibleTransformException + * @throws NoninvertibleTransformException * if the matrix cannot be inverted. * @since 1.2 */ @@ -2762,7 +2762,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * transform has no inverse, in which case an exception will be * thrown if the {@code invert} method is called. * @see #getDeterminant - * @exception NoninvertibleTransformException + * @throws NoninvertibleTransformException * if the matrix cannot be inverted. * @since 1.6 */ @@ -3464,7 +3464,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * @param ptDst the resulting transformed point * @return {@code ptDst}, which contains the result of the * inverse transform. - * @exception NoninvertibleTransformException if the matrix cannot be + * @throws NoninvertibleTransformException if the matrix cannot be * inverted. * @since 1.2 */ @@ -3550,7 +3550,7 @@ public class AffineTransform implements Cloneable, java.io.Serializable { * @param dstOff the offset to the location of the first * transformed point that is stored in the destination array * @param numPts the number of point objects to be transformed - * @exception NoninvertibleTransformException if the matrix cannot be + * @throws NoninvertibleTransformException if the matrix cannot be * inverted. * @since 1.2 */ diff --git a/src/java.desktop/share/classes/java/awt/geom/CubicCurve2D.java b/src/java.desktop/share/classes/java/awt/geom/CubicCurve2D.java index 76d366c0ec6..cf33fb30438 100644 --- a/src/java.desktop/share/classes/java/awt/geom/CubicCurve2D.java +++ b/src/java.desktop/share/classes/java/awt/geom/CubicCurve2D.java @@ -1564,7 +1564,7 @@ public abstract class CubicCurve2D implements Shape, Cloneable { * Creates a new object of the same class as this object. * * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.2 */ diff --git a/src/java.desktop/share/classes/java/awt/geom/Dimension2D.java b/src/java.desktop/share/classes/java/awt/geom/Dimension2D.java index 180d96a3840..0a2015b15a9 100644 --- a/src/java.desktop/share/classes/java/awt/geom/Dimension2D.java +++ b/src/java.desktop/share/classes/java/awt/geom/Dimension2D.java @@ -99,7 +99,7 @@ public abstract class Dimension2D implements Cloneable { * Creates a new object of the same class as this object. * * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.2 */ diff --git a/src/java.desktop/share/classes/java/awt/geom/FlatteningPathIterator.java b/src/java.desktop/share/classes/java/awt/geom/FlatteningPathIterator.java index 40159f2db5f..123e6d60b92 100644 --- a/src/java.desktop/share/classes/java/awt/geom/FlatteningPathIterator.java +++ b/src/java.desktop/share/classes/java/awt/geom/FlatteningPathIterator.java @@ -109,7 +109,7 @@ public class FlatteningPathIterator implements PathIterator { * control points and the flattened curve * @param limit the maximum number of recursive subdivisions * allowed for any curved segment - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code flatness} or {@code limit} * is less than zero */ @@ -336,7 +336,7 @@ public class FlatteningPathIterator implements PathIterator { * @param coords an array that holds the data returned from * this method * @return the path segment type of the current path segment. - * @exception NoSuchElementException if there + * @throws NoSuchElementException if there * are no more elements in the flattening path to be * returned. * @see PathIterator#SEG_MOVETO @@ -371,7 +371,7 @@ public class FlatteningPathIterator implements PathIterator { * @param coords an array that holds the data returned from * this method * @return the path segment type of the current path segment. - * @exception NoSuchElementException if there + * @throws NoSuchElementException if there * are no more elements in the flattening path to be * returned. * @see PathIterator#SEG_MOVETO diff --git a/src/java.desktop/share/classes/java/awt/geom/Line2D.java b/src/java.desktop/share/classes/java/awt/geom/Line2D.java index 3d79e44dfee..305b51942d9 100644 --- a/src/java.desktop/share/classes/java/awt/geom/Line2D.java +++ b/src/java.desktop/share/classes/java/awt/geom/Line2D.java @@ -1111,7 +1111,7 @@ public abstract class Line2D implements Shape, Cloneable { * Creates a new object of the same class as this object. * * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.2 */ diff --git a/src/java.desktop/share/classes/java/awt/geom/Path2D.java b/src/java.desktop/share/classes/java/awt/geom/Path2D.java index 6168664452b..e777f276602 100644 --- a/src/java.desktop/share/classes/java/awt/geom/Path2D.java +++ b/src/java.desktop/share/classes/java/awt/geom/Path2D.java @@ -842,7 +842,7 @@ public abstract class Path2D implements Shape, Cloneable { * Creates a new object of the same class as this object. * * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.6 */ @@ -1638,7 +1638,7 @@ public abstract class Path2D implements Shape, Cloneable { * Creates a new object of the same class as this object. * * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.6 */ @@ -2018,7 +2018,7 @@ public abstract class Path2D implements Shape, Cloneable { * * @param rule an integer representing the specified * winding rule - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code rule} is not either * {@link #WIND_EVEN_ODD} or * {@link #WIND_NON_ZERO} @@ -2530,7 +2530,7 @@ public abstract class Path2D implements Shape, Cloneable { * Creates a new object of the same class as this object. * * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.6 */ diff --git a/src/java.desktop/share/classes/java/awt/geom/Point2D.java b/src/java.desktop/share/classes/java/awt/geom/Point2D.java index bffb5594cfa..2b0a2aabef1 100644 --- a/src/java.desktop/share/classes/java/awt/geom/Point2D.java +++ b/src/java.desktop/share/classes/java/awt/geom/Point2D.java @@ -387,7 +387,7 @@ public abstract class Point2D implements Cloneable { * Creates a new object of the same class and with the * same contents as this object. * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.2 */ diff --git a/src/java.desktop/share/classes/java/awt/geom/QuadCurve2D.java b/src/java.desktop/share/classes/java/awt/geom/QuadCurve2D.java index f7dce7ea8e3..6f4990df49c 100644 --- a/src/java.desktop/share/classes/java/awt/geom/QuadCurve2D.java +++ b/src/java.desktop/share/classes/java/awt/geom/QuadCurve2D.java @@ -1388,7 +1388,7 @@ public abstract class QuadCurve2D implements Shape, Cloneable { * as this object. * * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.2 */ diff --git a/src/java.desktop/share/classes/java/awt/geom/RectangularShape.java b/src/java.desktop/share/classes/java/awt/geom/RectangularShape.java index 892eb634559..d0b0792792e 100644 --- a/src/java.desktop/share/classes/java/awt/geom/RectangularShape.java +++ b/src/java.desktop/share/classes/java/awt/geom/RectangularShape.java @@ -382,7 +382,7 @@ public abstract class RectangularShape implements Shape, Cloneable { * Creates a new object of the same class and with the same * contents as this object. * @return a clone of this instance. - * @exception OutOfMemoryError if there is not enough memory. + * @throws OutOfMemoryError if there is not enough memory. * @see java.lang.Cloneable * @since 1.2 */ diff --git a/src/java.desktop/share/classes/java/awt/im/InputContext.java b/src/java.desktop/share/classes/java/awt/im/InputContext.java index 2a73793df2b..5476d9e2518 100644 --- a/src/java.desktop/share/classes/java/awt/im/InputContext.java +++ b/src/java.desktop/share/classes/java/awt/im/InputContext.java @@ -140,7 +140,7 @@ public class InputContext { * @param locale The desired new locale. * @return true if the input method or keyboard layout that's active after * this call supports the desired locale. - * @exception NullPointerException if {@code locale} is null + * @throws NullPointerException if {@code locale} is null */ public boolean selectInputMethod(Locale locale) { // real implementation is in sun.awt.im.InputContext @@ -268,7 +268,7 @@ public class InputContext { * If no input method is available, then the event will never be consumed. * * @param event The event - * @exception NullPointerException if {@code event} is null + * @throws NullPointerException if {@code event} is null */ public void dispatchEvent(AWTEvent event) { // real implementation is in sun.awt.im.InputContext @@ -286,7 +286,7 @@ public class InputContext { * If no input methods are available, then this method has no effect. * * @param client Client component - * @exception NullPointerException if {@code client} is null + * @throws NullPointerException if {@code client} is null */ public void removeNotify(Component client) { // real implementation is in sun.awt.im.InputContext diff --git a/src/java.desktop/share/classes/java/awt/im/InputMethodHighlight.java b/src/java.desktop/share/classes/java/awt/im/InputMethodHighlight.java index 7fcf3c9549b..4b8d4d5c9ea 100644 --- a/src/java.desktop/share/classes/java/awt/im/InputMethodHighlight.java +++ b/src/java.desktop/share/classes/java/awt/im/InputMethodHighlight.java @@ -111,7 +111,7 @@ public class InputMethodHighlight { * @param state The conversion state for the text range - RAW_TEXT or CONVERTED_TEXT * @see InputMethodHighlight#RAW_TEXT * @see InputMethodHighlight#CONVERTED_TEXT - * @exception IllegalArgumentException if a state other than RAW_TEXT or CONVERTED_TEXT is given + * @throws IllegalArgumentException if a state other than RAW_TEXT or CONVERTED_TEXT is given */ public InputMethodHighlight(boolean selected, int state) { this(selected, state, 0, null); @@ -125,7 +125,7 @@ public class InputMethodHighlight { * @param variation The style variation for the text range * @see InputMethodHighlight#RAW_TEXT * @see InputMethodHighlight#CONVERTED_TEXT - * @exception IllegalArgumentException if a state other than RAW_TEXT or CONVERTED_TEXT is given + * @throws IllegalArgumentException if a state other than RAW_TEXT or CONVERTED_TEXT is given */ public InputMethodHighlight(boolean selected, int state, int variation) { this(selected, state, variation, null); @@ -140,7 +140,7 @@ public class InputMethodHighlight { * @param style the rendering style attributes for the text range, or null * @see InputMethodHighlight#RAW_TEXT * @see InputMethodHighlight#CONVERTED_TEXT - * @exception IllegalArgumentException if a state other than RAW_TEXT or CONVERTED_TEXT is given + * @throws IllegalArgumentException if a state other than RAW_TEXT or CONVERTED_TEXT is given * @since 1.3 */ public InputMethodHighlight(boolean selected, int state, int variation, diff --git a/src/java.desktop/share/classes/java/awt/im/spi/InputMethod.java b/src/java.desktop/share/classes/java/awt/im/spi/InputMethod.java index 1174493cc58..c01987bbfed 100644 --- a/src/java.desktop/share/classes/java/awt/im/spi/InputMethod.java +++ b/src/java.desktop/share/classes/java/awt/im/spi/InputMethod.java @@ -59,7 +59,7 @@ public interface InputMethod { * method. * * @param context the input method context for this input method - * @exception NullPointerException if {@code context} is null + * @throws NullPointerException if {@code context} is null */ public void setInputMethodContext(InputMethodContext context); @@ -80,7 +80,7 @@ public interface InputMethod { * * @param locale locale to input * @return whether the specified locale is supported - * @exception NullPointerException if {@code locale} is null + * @throws NullPointerException if {@code locale} is null */ public boolean setLocale(Locale locale); @@ -211,7 +211,7 @@ public interface InputMethod { * This method is called by {@link java.awt.im.InputContext#dispatchEvent InputContext.dispatchEvent}. * * @param event the event being dispatched to the input method - * @exception NullPointerException if {@code event} is null + * @throws NullPointerException if {@code event} is null */ public void dispatchEvent(AWTEvent event); diff --git a/src/java.desktop/share/classes/java/awt/im/spi/InputMethodContext.java b/src/java.desktop/share/classes/java/awt/im/spi/InputMethodContext.java index 09d44a5eda4..c17c4e4afef 100644 --- a/src/java.desktop/share/classes/java/awt/im/spi/InputMethodContext.java +++ b/src/java.desktop/share/classes/java/awt/im/spi/InputMethodContext.java @@ -92,7 +92,7 @@ public interface InputMethodContext extends InputMethodRequests { * @param attachToInputContext whether this window should share the input context * that corresponds to this input method context * @return a window with special characteristics for use by input methods - * @exception HeadlessException if {@code GraphicsEnvironment.isHeadless} + * @throws HeadlessException if {@code GraphicsEnvironment.isHeadless} * returns {@code true} */ public Window createInputMethodWindow(String title, boolean attachToInputContext); @@ -124,7 +124,7 @@ public interface InputMethodContext extends InputMethodRequests { * @param attachToInputContext whether this window should share the input context * that corresponds to this input method context * @return a JFrame with special characteristics for use by input methods - * @exception HeadlessException if {@code GraphicsEnvironment.isHeadless} + * @throws HeadlessException if {@code GraphicsEnvironment.isHeadless} * returns {@code true} * * @since 1.4 diff --git a/src/java.desktop/share/classes/java/awt/im/spi/InputMethodDescriptor.java b/src/java.desktop/share/classes/java/awt/im/spi/InputMethodDescriptor.java index 885e7ad4e09..6e3d8f89706 100644 --- a/src/java.desktop/share/classes/java/awt/im/spi/InputMethodDescriptor.java +++ b/src/java.desktop/share/classes/java/awt/im/spi/InputMethodDescriptor.java @@ -63,7 +63,7 @@ public interface InputMethodDescriptor { * unavailable. * * @return the locales supported by the input method - * @exception AWTException if it can be determined that the input method + * @throws AWTException if it can be determined that the input method * is inoperable, for example, because of incomplete installation. */ Locale[] getAvailableLocales() throws AWTException; @@ -122,7 +122,7 @@ public interface InputMethodDescriptor { * Creates a new instance of the corresponding input method. * * @return a new instance of the corresponding input method - * @exception Exception any exception that may occur while creating the + * @throws Exception any exception that may occur while creating the * input method instance */ InputMethod createInputMethod() throws Exception; diff --git a/src/java.desktop/share/classes/java/awt/image/BufferedImage.java b/src/java.desktop/share/classes/java/awt/image/BufferedImage.java index 3c937dd3866..770fec6e8ab 100644 --- a/src/java.desktop/share/classes/java/awt/image/BufferedImage.java +++ b/src/java.desktop/share/classes/java/awt/image/BufferedImage.java @@ -594,12 +594,12 @@ public class BufferedImage extends java.awt.Image * the raster has been premultiplied with alpha. * @param properties {@code Hashtable} of * {@code String}/{@code Object} pairs. - * @exception RasterFormatException if the number and + * @throws RasterFormatException if the number and * types of bands in the {@code SampleModel} of the * {@code Raster} do not match the number and types required by * the {@code ColorModel} to represent its color and alpha * components. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code raster} is incompatible with {@code cm} * @see ColorModel * @see Raster @@ -1195,7 +1195,7 @@ public class BufferedImage extends java.awt.Image * @param h the height of the specified rectangular region * @return a {@code BufferedImage} that is the subimage of this * {@code BufferedImage}. - * @exception RasterFormatException if the specified + * @throws RasterFormatException if the specified * area is not contained within this {@code BufferedImage}. */ public BufferedImage getSubimage (int x, int y, int w, int h) { @@ -1391,7 +1391,7 @@ public class BufferedImage extends java.awt.Image * @param tileY the y index of the requested tile in the tile array * @return a {@code Raster} that is the tile defined by the * arguments {@code tileX} and {@code tileY}. - * @exception ArrayIndexOutOfBoundsException if both + * @throws ArrayIndexOutOfBoundsException if both * {@code tileX} and {@code tileY} are not * equal to 0 */ @@ -1561,7 +1561,7 @@ public class BufferedImage extends java.awt.Image * @return {@code true} if the tile specified by the specified * indices is checked out for writing; {@code false} * otherwise. - * @exception ArrayIndexOutOfBoundsException if both + * @throws ArrayIndexOutOfBoundsException if both * {@code tileX} and {@code tileY} are not equal * to 0 */ diff --git a/src/java.desktop/share/classes/java/awt/image/ByteLookupTable.java b/src/java.desktop/share/classes/java/awt/image/ByteLookupTable.java index 01bebc12ee2..2bb5a1219ef 100644 --- a/src/java.desktop/share/classes/java/awt/image/ByteLookupTable.java +++ b/src/java.desktop/share/classes/java/awt/image/ByteLookupTable.java @@ -117,7 +117,7 @@ public class ByteLookupTable extends LookupTable { * same length as {@code src}. * @return the array {@code dst}, an {@code int} array of * samples. - * @exception ArrayIndexOutOfBoundsException if {@code src} is + * @throws ArrayIndexOutOfBoundsException if {@code src} is * longer than {@code dst} or if for any element * {@code i} of {@code src}, * {@code src[i]-offset} is either less than zero or @@ -168,7 +168,7 @@ public class ByteLookupTable extends LookupTable { * same length as {@code src}. * @return the array {@code dst}, an {@code int} array of * samples. - * @exception ArrayIndexOutOfBoundsException if {@code src} is + * @throws ArrayIndexOutOfBoundsException if {@code src} is * longer than {@code dst} or if for any element * {@code i} of {@code src}, * {@code (src[i]&0xff)-offset} is either less than diff --git a/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java b/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java index 023b376d73d..f5ec86a151a 100644 --- a/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java +++ b/src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java @@ -194,9 +194,9 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp { * @param profiles the array of {@code ICC_Profile} objects * @param hints the {@code RenderingHints} object used to control * the color conversion, or {@code null} - * @exception IllegalArgumentException when the profile sequence does not + * @throws IllegalArgumentException when the profile sequence does not * specify a well-defined color conversion - * @exception NullPointerException if profiles is null + * @throws NullPointerException if profiles is null */ public ColorConvertOp (ICC_Profile[] profiles, RenderingHints hints) { @@ -242,7 +242,7 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp { * @return {@code dest} color converted from {@code src} * or a new, converted {@code BufferedImage} * if {@code dest} is {@code null} - * @exception IllegalArgumentException if dest is null and this op was + * @throws IllegalArgumentException if dest is null and this op was * constructed using the constructor which takes only a * RenderingHints argument, since the operation is ill defined. */ @@ -456,7 +456,7 @@ public class ColorConvertOp implements BufferedImageOp, RasterOp { * @return {@code dest} color converted from {@code src} * or a new, converted {@code WritableRaster} * if {@code dest} is {@code null} - * @exception IllegalArgumentException if the number of source or + * @throws IllegalArgumentException if the number of source or * destination bands is incorrect, the source or destination * color spaces are undefined, or this op was constructed * with one of the constructors that applies only to diff --git a/src/java.desktop/share/classes/java/awt/image/DirectColorModel.java b/src/java.desktop/share/classes/java/awt/image/DirectColorModel.java index bf7ad07a22e..5853f3802a4 100644 --- a/src/java.desktop/share/classes/java/awt/image/DirectColorModel.java +++ b/src/java.desktop/share/classes/java/awt/image/DirectColorModel.java @@ -642,12 +642,12 @@ public class DirectColorModel extends PackedColorModel { * @param inData the specified pixel * @return the alpha component of the specified pixel, scaled from * 0 to 255. - * @exception ClassCastException if {@code inData} + * @throws ClassCastException if {@code inData} * is not a primitive array of type {@code transferType} - * @exception ArrayIndexOutOfBoundsException if + * @throws ArrayIndexOutOfBoundsException if * {@code inData} is not large enough to hold a pixel value * for this {@code ColorModel} - * @exception UnsupportedOperationException if this + * @throws UnsupportedOperationException if this * {@code tranferType} is not supported by this * {@code ColorModel} */ @@ -694,7 +694,7 @@ public class DirectColorModel extends PackedColorModel { * * @param inData the specified pixel * @return the color and alpha components of the specified pixel. - * @exception UnsupportedOperationException if this + * @throws UnsupportedOperationException if this * {@code transferType} is not supported by this * {@code ColorModel} * @see ColorModel#getRGBdefault @@ -744,12 +744,12 @@ public class DirectColorModel extends PackedColorModel { * @param pixel the specified pixel * @return an array representation of the specified pixel in this * {@code ColorModel} - * @exception ClassCastException if {@code pixel} + * @throws ClassCastException if {@code pixel} * is not a primitive array of type {@code transferType} - * @exception ArrayIndexOutOfBoundsException if + * @throws ArrayIndexOutOfBoundsException if * {@code pixel} is not large enough to hold a pixel value * for this {@code ColorModel} - * @exception UnsupportedOperationException if this + * @throws UnsupportedOperationException if this * {@code transferType} is not supported by this * {@code ColorModel} * @see WritableRaster#setDataElements @@ -963,14 +963,14 @@ public class DirectColorModel extends PackedColorModel { * which to start storing the color and alpha components * @return an array containing the color and alpha components of the * specified pixel starting at the specified offset. - * @exception ClassCastException if {@code pixel} + * @throws ClassCastException if {@code pixel} * is not a primitive array of type {@code transferType} - * @exception ArrayIndexOutOfBoundsException if + * @throws ArrayIndexOutOfBoundsException if * {@code pixel} is not large enough to hold a pixel value * for this {@code ColorModel}, or if {@code components} * is not {@code null} and is not large enough to hold all the * color and alpha components, starting at {@code offset} - * @exception UnsupportedOperationException if this + * @throws UnsupportedOperationException if this * {@code transferType} is not supported by this * color model */ @@ -1055,7 +1055,7 @@ public class DirectColorModel extends PackedColorModel { * begin retrieving the color and alpha components * @return an {@code int} pixel value in this * {@code ColorModel} corresponding to the specified components. - * @exception ArrayIndexOutOfBoundsException if + * @throws ArrayIndexOutOfBoundsException if * the {@code components} array is not large enough to * hold all of the color and alpha components starting at * {@code offset} @@ -1097,14 +1097,14 @@ public class DirectColorModel extends PackedColorModel { * and alpha components * @return an {@code Object} representing an array of color and * alpha components. - * @exception ClassCastException if {@code obj} + * @throws ClassCastException if {@code obj} * is not a primitive array of type {@code transferType} - * @exception ArrayIndexOutOfBoundsException if + * @throws ArrayIndexOutOfBoundsException if * {@code obj} is not large enough to hold a pixel value * for this {@code ColorModel} or the {@code components} * array is not large enough to hold all of the color and alpha * components starting at {@code offset} - * @exception UnsupportedOperationException if this + * @throws UnsupportedOperationException if this * {@code transferType} is not supported by this * color model * @see WritableRaster#setDataElements @@ -1169,7 +1169,7 @@ public class DirectColorModel extends PackedColorModel { * premultiplied; {@code false} otherwise * @return a {@code ColorModel} object that represents the * coerced data. - * @exception UnsupportedOperationException if this + * @throws UnsupportedOperationException if this * {@code transferType} is not supported by this * color model */ diff --git a/src/java.desktop/share/classes/java/awt/image/ImageFilter.java b/src/java.desktop/share/classes/java/awt/image/ImageFilter.java index d136e16fc6b..94586b851ae 100644 --- a/src/java.desktop/share/classes/java/awt/image/ImageFilter.java +++ b/src/java.desktop/share/classes/java/awt/image/ImageFilter.java @@ -107,7 +107,7 @@ public class ImageFilter implements ImageConsumer, Cloneable { * with the filtering operation. * * @param props the properties from the source object - * @exception NullPointerException if {@code props} is null + * @throws NullPointerException if {@code props} is null */ public void setProperties(Hashtable props) { @SuppressWarnings("unchecked") @@ -245,7 +245,7 @@ public class ImageFilter implements ImageConsumer, Cloneable { * @param ip the ImageProducer that is feeding this instance of * the filter - also the ImageProducer that the request should be * forwarded to if necessary - * @exception NullPointerException if {@code ip} is null + * @throws NullPointerException if {@code ip} is null */ public void resendTopDownLeftRight(ImageProducer ip) { ip.requestTopDownLeftRightResend(this); diff --git a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java index dcec78fb348..9254d9fa717 100644 --- a/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/MultiPixelPackedSampleModel.java @@ -130,7 +130,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param scanlineStride the line stride of the image data * @param dataBitOffset the data bit offset for the region of image * data described - * @exception RasterFormatException if the number of bits per pixel + * @throws RasterFormatException if the number of bits per pixel * is not a power of 2 or if a power of 2 number of * pixels do not fit in one data element. * @throws IllegalArgumentException if {@code w} or @@ -321,7 +321,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param bands the specified bands * @return a new {@code SampleModel} with a subset of bands of * this {@code MultiPixelPackedSampleModel}. - * @exception RasterFormatException if the number of bands requested + * @throws RasterFormatException if the number of bands requested * is not one. * @throws IllegalArgumentException if {@code w} or * {@code h} is not greater than 0 @@ -348,7 +348,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * data * @return the specified band containing the sample of the specified * pixel. - * @exception ArrayIndexOutOfBoundsException if the specified + * @throws ArrayIndexOutOfBoundsException if the specified * coordinates are not in bounds. * @see #setSample(int, int, int, int, DataBuffer) */ @@ -377,7 +377,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param b the band to return, which is assumed to be 0 * @param s the input sample as an {@code int} * @param data the {@code DataBuffer} where image data is stored - * @exception ArrayIndexOutOfBoundsException if the coordinates are + * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds. * @see #getSample(int, int, int, DataBuffer) */ @@ -442,9 +442,9 @@ public class MultiPixelPackedSampleModel extends SampleModel * @param data the {@code DataBuffer} containing the image data. * @return an {@code Object} containing data for the specified * pixel. - * @exception ClassCastException if {@code obj} is not a + * @throws ClassCastException if {@code obj} is not a * primitive array of type TransferType or is not {@code null} - * @exception ArrayIndexOutOfBoundsException if the coordinates are + * @throws ArrayIndexOutOfBoundsException if the coordinates are * not in bounds, or if {@code obj} is not {@code null} or * not large enough to hold the pixel data * @see #setDataElements(int, int, Object, DataBuffer) @@ -526,7 +526,7 @@ public class MultiPixelPackedSampleModel extends SampleModel * {@code null} * @param data the {@code DataBuffer} where image data is stored * @return an array containing the specified pixel. - * @exception ArrayIndexOutOfBoundsException if the coordinates + * @throws ArrayIndexOutOfBoundsException if the coordinates * are not in bounds * @see #setPixel(int, int, int[], DataBuffer) */ diff --git a/src/java.desktop/share/classes/java/awt/image/PixelGrabber.java b/src/java.desktop/share/classes/java/awt/image/PixelGrabber.java index 3855316d986..fb66a95f539 100644 --- a/src/java.desktop/share/classes/java/awt/image/PixelGrabber.java +++ b/src/java.desktop/share/classes/java/awt/image/PixelGrabber.java @@ -219,7 +219,7 @@ public class PixelGrabber implements ImageConsumer { * delivered. * @return true if the pixels were successfully grabbed, false on * abort, error or timeout - * @exception InterruptedException + * @throws InterruptedException * Another thread has interrupted this thread. */ public boolean grabPixels() throws InterruptedException { @@ -243,7 +243,7 @@ public class PixelGrabber implements ImageConsumer { * to arrive before timing out * @return true if the pixels were successfully grabbed, false on * abort, error or timeout - * @exception InterruptedException + * @throws InterruptedException * Another thread has interrupted this thread. */ public synchronized boolean grabPixels(long ms) diff --git a/src/java.desktop/share/classes/java/awt/image/RGBImageFilter.java b/src/java.desktop/share/classes/java/awt/image/RGBImageFilter.java index 44302923d17..9838fdfe8b6 100644 --- a/src/java.desktop/share/classes/java/awt/image/RGBImageFilter.java +++ b/src/java.desktop/share/classes/java/awt/image/RGBImageFilter.java @@ -146,7 +146,7 @@ public abstract class RGBImageFilter extends ImageFilter { * a color table entry is being filtered rather than an actual * pixel value. * @param icm the IndexColorModel object to be filtered - * @exception NullPointerException if {@code icm} is null + * @throws NullPointerException if {@code icm} is null * @return a new IndexColorModel representing the filtered colors */ public IndexColorModel filterIndexColorModel(IndexColorModel icm) { diff --git a/src/java.desktop/share/classes/java/awt/image/Raster.java b/src/java.desktop/share/classes/java/awt/image/Raster.java index 32d45078b38..d388aa1f79c 100644 --- a/src/java.desktop/share/classes/java/awt/image/Raster.java +++ b/src/java.desktop/share/classes/java/awt/image/Raster.java @@ -1375,7 +1375,7 @@ public class Raster { * @param h the specified height of the new {@code WritableRaster} * @return a compatible {@code WritableRaster} with the specified * size and a new sample model and data buffer. - * @exception RasterFormatException if the width or height is less than + * @throws RasterFormatException if the width or height is less than * or equal to zero. */ public WritableRaster createCompatibleWritableRaster(int w, int h) { @@ -1501,7 +1501,7 @@ public class Raster { * of the returned Raster * @param bandList Array of band indices, or null to use all bands * @return a new {@code Raster}. - * @exception RasterFormatException if the specified subregion is outside + * @throws RasterFormatException if the specified subregion is outside * of the raster bounds. * @throws RasterFormatException if {@code width} or * {@code height} diff --git a/src/java.desktop/share/classes/java/awt/image/ShortLookupTable.java b/src/java.desktop/share/classes/java/awt/image/ShortLookupTable.java index 3f4e236b9bc..e9c97ad864e 100644 --- a/src/java.desktop/share/classes/java/awt/image/ShortLookupTable.java +++ b/src/java.desktop/share/classes/java/awt/image/ShortLookupTable.java @@ -111,7 +111,7 @@ public class ShortLookupTable extends LookupTable { * same length as {@code src}. * @return the array {@code dst}, an {@code int} array of * samples. - * @exception ArrayIndexOutOfBoundsException if {@code src} is + * @throws ArrayIndexOutOfBoundsException if {@code src} is * longer than {@code dst} or if for any element * {@code i} of {@code src}, * {@code (src[i]&0xffff)-offset} is either less than @@ -162,7 +162,7 @@ public class ShortLookupTable extends LookupTable { * same length as {@code src}. * @return the array {@code dst}, an {@code int} array of * samples. - * @exception ArrayIndexOutOfBoundsException if {@code src} is + * @throws ArrayIndexOutOfBoundsException if {@code src} is * longer than {@code dst} or if for any element * {@code i} of {@code src}, * {@code (src[i]&0xffff)-offset} is either less than diff --git a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java index 864ed00cf76..abb669e02c6 100644 --- a/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java +++ b/src/java.desktop/share/classes/java/awt/image/SinglePixelPackedSampleModel.java @@ -302,7 +302,7 @@ public class SinglePixelPackedSampleModel extends SampleModel * SinglePixelPackedSampleModel/DataBuffer combination will represent * an image with a subset of the bands of the original * SinglePixelPackedSampleModel/DataBuffer combination. - * @exception RasterFormatException if the length of the bands argument is + * @throws RasterFormatException if the length of the bands argument is * greater than the number of bands in * the sample model. */ diff --git a/src/java.desktop/share/classes/java/awt/image/WritableRaster.java b/src/java.desktop/share/classes/java/awt/image/WritableRaster.java index 0e345026c2b..729317d85a3 100644 --- a/src/java.desktop/share/classes/java/awt/image/WritableRaster.java +++ b/src/java.desktop/share/classes/java/awt/image/WritableRaster.java @@ -204,7 +204,7 @@ public class WritableRaster extends Raster { * @param bandList Array of band indices, or null to use all bands. * @return a {@code WritableRaster} sharing all or part of the * {@code DataBuffer} of this {@code WritableRaster}. - * @exception RasterFormatException if the subregion is outside of the + * @throws RasterFormatException if the subregion is outside of the * raster bounds. * @throws RasterFormatException if {@code w} or * {@code h} diff --git a/src/java.desktop/share/classes/java/awt/print/PageFormat.java b/src/java.desktop/share/classes/java/awt/print/PageFormat.java index b7709eb581e..019c5d0bdcc 100644 --- a/src/java.desktop/share/classes/java/awt/print/PageFormat.java +++ b/src/java.desktop/share/classes/java/awt/print/PageFormat.java @@ -286,7 +286,7 @@ public class PageFormat implements Cloneable * {@code PageFormat}. * @param paper the {@code Paper} object to which to set * the {@code Paper} object for this {@code PageFormat}. - * @exception NullPointerException + * @throws NullPointerException * a null paper instance was passed as a parameter. * @see #getPaper */ diff --git a/src/java.desktop/share/classes/java/awt/print/Printable.java b/src/java.desktop/share/classes/java/awt/print/Printable.java index 28a01cc9a16..1fbf1f7c616 100644 --- a/src/java.desktop/share/classes/java/awt/print/Printable.java +++ b/src/java.desktop/share/classes/java/awt/print/Printable.java @@ -134,7 +134,7 @@ public interface Printable { * @return PAGE_EXISTS if the page is rendered successfully * or NO_SUCH_PAGE if {@code pageIndex} specifies a * non-existent page. - * @exception java.awt.print.PrinterException + * @throws java.awt.print.PrinterException * thrown when the print job is terminated. */ int print(Graphics graphics, PageFormat pageFormat, int pageIndex) diff --git a/src/java.desktop/share/classes/java/awt/print/PrinterJob.java b/src/java.desktop/share/classes/java/awt/print/PrinterJob.java index 41656367183..ddf565f3ce3 100644 --- a/src/java.desktop/share/classes/java/awt/print/PrinterJob.java +++ b/src/java.desktop/share/classes/java/awt/print/PrinterJob.java @@ -168,7 +168,7 @@ public abstract class PrinterJob { * cannot support the {@code Pageable} and * {@code Printable} interfaces necessary to support 2D printing. * @param service a print service that supports 2D printing - * @exception PrinterException if the specified service does not support + * @throws PrinterException if the specified service does not support * 2D printing, or this PrinterJob class does not support * setting a 2D print service, or the specified service is * otherwise not a valid print service. @@ -212,7 +212,7 @@ public abstract class PrinterJob { * {@code document}. * @param document the pages to be printed. It can not be * {@code null}. - * @exception NullPointerException the {@code Pageable} passed in + * @throws NullPointerException the {@code Pageable} passed in * was {@code null}. * @see PageFormat * @see Printable @@ -235,7 +235,7 @@ public abstract class PrinterJob { * selected by the user. * @return {@code true} if the user does not cancel the dialog; * {@code false} otherwise. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -279,9 +279,9 @@ public abstract class PrinterJob { * This parameter may not be null. * @return {@code true} if the user does not cancel the dialog; * {@code false} otherwise. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. - * @exception NullPointerException if {@code attributes} parameter + * @throws NullPointerException if {@code attributes} parameter * is null. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.4 @@ -313,7 +313,7 @@ public abstract class PrinterJob { * is cancelled; a new {@code PageFormat} object * containing the format indicated by the user if the * dialog is acknowledged. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -342,9 +342,9 @@ public abstract class PrinterJob { * This parameter may not be null. * @return a page format if the user does not cancel the dialog; * {@code null} otherwise. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. - * @exception NullPointerException if {@code attributes} parameter + * @throws NullPointerException if {@code attributes} parameter * is null. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.4 @@ -495,7 +495,7 @@ public abstract class PrinterJob { /** * Prints a set of pages. - * @exception PrinterException an error in the print system + * @throws PrinterException an error in the print system * caused the job to be aborted. * @see Book * @see Pageable @@ -533,7 +533,7 @@ public abstract class PrinterJob { * this print() method. * * @param attributes a set of attributes for the job - * @exception PrinterException an error in the print system + * @throws PrinterException an error in the print system * caused the job to be aborted. * @see Book * @see Pageable -- GitLab From beedae1141b6b650dc4cedf1f038afc1c8b460dd Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 17 Mar 2022 09:20:24 +0000 Subject: [PATCH 066/237] 8281146: Replace StringCoding.hasNegatives with countPositives Co-authored-by: Lutz Schmidt Co-authored-by: Martin Doerr Reviewed-by: kvn, lucy, rriggs --- src/hotspot/cpu/aarch64/aarch64.ad | 8 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 36 ++-- .../cpu/aarch64/macroAssembler_aarch64.hpp | 2 +- .../cpu/aarch64/stubGenerator_aarch64.cpp | 54 +++--- .../cpu/aarch64/stubRoutines_aarch64.cpp | 4 +- .../cpu/aarch64/stubRoutines_aarch64.hpp | 12 +- src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp | 32 ++-- src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp | 2 +- src/hotspot/cpu/ppc/ppc.ad | 14 +- .../cpu/s390/c2_MacroAssembler_s390.cpp | 104 ++++++----- .../cpu/s390/c2_MacroAssembler_s390.hpp | 4 +- src/hotspot/cpu/s390/s390.ad | 11 +- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 155 +++++++++++------ src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp | 9 +- src/hotspot/cpu/x86/x86_32.ad | 28 +-- src/hotspot/cpu/x86/x86_64.ad | 28 +-- src/hotspot/share/adlc/formssel.cpp | 4 +- src/hotspot/share/classfile/vmIntrinsics.cpp | 2 +- src/hotspot/share/classfile/vmIntrinsics.hpp | 9 +- .../gc/shenandoah/c2/shenandoahSupport.cpp | 2 +- src/hotspot/share/jvmci/vmStructs_jvmci.cpp | 4 +- src/hotspot/share/opto/c2compiler.cpp | 4 +- src/hotspot/share/opto/classes.hpp | 2 +- src/hotspot/share/opto/escape.cpp | 9 +- src/hotspot/share/opto/intrinsicnode.hpp | 8 +- src/hotspot/share/opto/lcm.cpp | 2 +- src/hotspot/share/opto/library_call.cpp | 12 +- src/hotspot/share/opto/library_call.hpp | 2 +- src/hotspot/share/opto/loopTransform.cpp | 4 +- src/hotspot/share/opto/loopnode.cpp | 2 +- src/hotspot/share/opto/matcher.cpp | 4 +- .../share/classes/java/lang/String.java | 164 +++++++++--------- .../share/classes/java/lang/StringCoding.java | 23 ++- .../intrinsics/string/TestCountPositives.java | 130 ++++++++++++++ .../patches/java.base/java/lang/Helper.java | 5 + .../openjdk/bench/java/lang/StringDecode.java | 4 +- 36 files changed, 558 insertions(+), 341 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 96075ecd9d5..68fd336aa33 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -17080,13 +17080,13 @@ instruct array_equalsC(iRegP_R1 ary1, iRegP_R2 ary2, iRegI_R0 result, ins_pipe(pipe_class_memory); %} -instruct has_negatives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr) +instruct count_positives(iRegP_R1 ary1, iRegI_R2 len, iRegI_R0 result, rFlagsReg cr) %{ - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(USE_KILL ary1, USE_KILL len, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result" %} + format %{ "count positives byte[] $ary1,$len -> $result" %} ins_encode %{ - address tpc = __ has_negatives($ary1$$Register, $len$$Register, $result$$Register); + address tpc = __ count_positives($ary1$$Register, $len$$Register, $result$$Register); if (tpc == NULL) { ciEnv::current()->record_failure("CodeCache is full"); return; diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 80287fb6949..dae4e22b15b 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -4339,16 +4339,17 @@ void MacroAssembler::remove_frame(int framesize) { } -// This method checks if provided byte array contains byte with highest bit set. -address MacroAssembler::has_negatives(Register ary1, Register len, Register result) { +// This method counts leading positive bytes (highest bit not set) in provided byte array +address MacroAssembler::count_positives(Register ary1, Register len, Register result) { // Simple and most common case of aligned small array which is not at the // end of memory page is placed here. All other cases are in stub. Label LOOP, END, STUB, STUB_LONG, SET_RESULT, DONE; const uint64_t UPPER_BIT_MASK=0x8080808080808080; assert_different_registers(ary1, len, result); + mov(result, len); cmpw(len, 0); - br(LE, SET_RESULT); + br(LE, DONE); cmpw(len, 4 * wordSize); br(GE, STUB_LONG); // size > 32 then go to stub @@ -4367,19 +4368,20 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu subs(len, len, wordSize); br(GE, LOOP); cmpw(len, -wordSize); - br(EQ, SET_RESULT); + br(EQ, DONE); BIND(END); - ldr(result, Address(ary1)); - sub(len, zr, len, LSL, 3); // LSL 3 is to get bits from bytes - lslv(result, result, len); - tst(result, UPPER_BIT_MASK); - b(SET_RESULT); + ldr(rscratch1, Address(ary1)); + sub(rscratch2, zr, len, LSL, 3); // LSL 3 is to get bits from bytes + lslv(rscratch1, rscratch1, rscratch2); + tst(rscratch1, UPPER_BIT_MASK); + br(NE, SET_RESULT); + b(DONE); BIND(STUB); - RuntimeAddress has_neg = RuntimeAddress(StubRoutines::aarch64::has_negatives()); - assert(has_neg.target() != NULL, "has_negatives stub has not been generated"); - address tpc1 = trampoline_call(has_neg); + RuntimeAddress count_pos = RuntimeAddress(StubRoutines::aarch64::count_positives()); + assert(count_pos.target() != NULL, "count_positives stub has not been generated"); + address tpc1 = trampoline_call(count_pos); if (tpc1 == NULL) { DEBUG_ONLY(reset_labels(STUB_LONG, SET_RESULT, DONE)); postcond(pc() == badAddress); @@ -4388,9 +4390,9 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu b(DONE); BIND(STUB_LONG); - RuntimeAddress has_neg_long = RuntimeAddress(StubRoutines::aarch64::has_negatives_long()); - assert(has_neg_long.target() != NULL, "has_negatives stub has not been generated"); - address tpc2 = trampoline_call(has_neg_long); + RuntimeAddress count_pos_long = RuntimeAddress(StubRoutines::aarch64::count_positives_long()); + assert(count_pos_long.target() != NULL, "count_positives_long stub has not been generated"); + address tpc2 = trampoline_call(count_pos_long); if (tpc2 == NULL) { DEBUG_ONLY(reset_labels(SET_RESULT, DONE)); postcond(pc() == badAddress); @@ -4399,7 +4401,9 @@ address MacroAssembler::has_negatives(Register ary1, Register len, Register resu b(DONE); BIND(SET_RESULT); - cset(result, NE); // set true or false + + add(len, len, wordSize); + sub(result, result, len); BIND(DONE); postcond(pc() != badAddress); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 29d4b8ac119..1344250febb 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1234,7 +1234,7 @@ public: Register table0, Register table1, Register table2, Register table3, bool upper = false); - address has_negatives(Register ary1, Register len, Register result); + address count_positives(Register ary1, Register len, Register result); address arrays_equals(Register a1, Register a2, Register result, Register cnt1, Register tmp1, Register tmp2, Register tmp3, int elem_size); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index eef7e6afe71..5a92dcb6b47 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -4657,7 +4657,7 @@ class StubGenerator: public StubCodeGenerator { return start; } - address generate_has_negatives(address &has_negatives_long) { + address generate_count_positives(address &count_positives_long) { const u1 large_loop_size = 64; const uint64_t UPPER_BIT_MASK=0x8080808080808080; int dcache_line = VM_Version::dcache_line_size(); @@ -4666,13 +4666,15 @@ class StubGenerator: public StubCodeGenerator { __ align(CodeEntryAlignment); - StubCodeMark mark(this, "StubRoutines", "has_negatives"); + StubCodeMark mark(this, "StubRoutines", "count_positives"); address entry = __ pc(); __ enter(); + // precondition: a copy of len is already in result + // __ mov(result, len); - Label RET_TRUE, RET_TRUE_NO_POP, RET_FALSE, ALIGNED, LOOP16, CHECK_16, + Label RET_ADJUST, RET_ADJUST_16, RET_ADJUST_LONG, RET_NO_POP, RET_LEN, ALIGNED, LOOP16, CHECK_16, LARGE_LOOP, POST_LOOP16, LEN_OVER_15, LEN_OVER_8, POST_LOOP16_LOAD_TAIL; __ cmp(len, (u1)15); @@ -4686,25 +4688,26 @@ class StubGenerator: public StubCodeGenerator { __ sub(rscratch1, zr, len, __ LSL, 3); // LSL 3 is to get bits from bytes. __ lsrv(rscratch2, rscratch2, rscratch1); __ tst(rscratch2, UPPER_BIT_MASK); - __ cset(result, Assembler::NE); + __ csel(result, zr, result, Assembler::NE); __ leave(); __ ret(lr); __ bind(LEN_OVER_8); __ ldp(rscratch1, rscratch2, Address(ary1, -16)); __ sub(len, len, 8); // no data dep., then sub can be executed while loading __ tst(rscratch2, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE_NO_POP); + __ br(Assembler::NE, RET_NO_POP); __ sub(rscratch2, zr, len, __ LSL, 3); // LSL 3 is to get bits from bytes __ lsrv(rscratch1, rscratch1, rscratch2); __ tst(rscratch1, UPPER_BIT_MASK); - __ cset(result, Assembler::NE); + __ bind(RET_NO_POP); + __ csel(result, zr, result, Assembler::NE); __ leave(); __ ret(lr); Register tmp1 = r3, tmp2 = r4, tmp3 = r5, tmp4 = r6, tmp5 = r7, tmp6 = r10; const RegSet spilled_regs = RegSet::range(tmp1, tmp5) + tmp6; - has_negatives_long = __ pc(); // 2nd entry point + count_positives_long = __ pc(); // 2nd entry point __ enter(); @@ -4716,10 +4719,10 @@ class StubGenerator: public StubCodeGenerator { __ mov(tmp5, 16); __ sub(rscratch1, tmp5, rscratch2); // amount of bytes until aligned address __ add(ary1, ary1, rscratch1); - __ sub(len, len, rscratch1); __ orr(tmp6, tmp6, tmp1); __ tst(tmp6, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST); + __ sub(len, len, rscratch1); __ bind(ALIGNED); __ cmp(len, large_loop_size); @@ -4734,7 +4737,7 @@ class StubGenerator: public StubCodeGenerator { __ sub(len, len, 16); __ orr(tmp6, tmp6, tmp1); __ tst(tmp6, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST_16); __ cmp(len, large_loop_size); __ br(Assembler::LT, CHECK_16); @@ -4766,7 +4769,7 @@ class StubGenerator: public StubCodeGenerator { __ orr(rscratch1, rscratch1, tmp6); __ orr(tmp2, tmp2, rscratch1); __ tst(tmp2, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST_LONG); __ cmp(len, large_loop_size); __ br(Assembler::GE, LARGE_LOOP); @@ -4779,7 +4782,7 @@ class StubGenerator: public StubCodeGenerator { __ sub(len, len, 16); __ orr(tmp2, tmp2, tmp3); __ tst(tmp2, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST_16); __ cmp(len, (u1)16); __ br(Assembler::GE, LOOP16); // 16-byte load loop end @@ -4787,31 +4790,36 @@ class StubGenerator: public StubCodeGenerator { __ cmp(len, (u1)8); __ br(Assembler::LE, POST_LOOP16_LOAD_TAIL); __ ldr(tmp3, Address(__ post(ary1, 8))); - __ sub(len, len, 8); __ tst(tmp3, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST); + __ sub(len, len, 8); __ bind(POST_LOOP16_LOAD_TAIL); - __ cbz(len, RET_FALSE); // Can't shift left by 64 when len==0 + __ cbz(len, RET_LEN); // Can't shift left by 64 when len==0 __ ldr(tmp1, Address(ary1)); __ mov(tmp2, 64); __ sub(tmp4, tmp2, len, __ LSL, 3); __ lslv(tmp1, tmp1, tmp4); __ tst(tmp1, UPPER_BIT_MASK); - __ br(Assembler::NE, RET_TRUE); + __ br(Assembler::NE, RET_ADJUST); // Fallthrough - __ bind(RET_FALSE); + __ bind(RET_LEN); __ pop(spilled_regs, sp); __ leave(); - __ mov(result, zr); __ ret(lr); - __ bind(RET_TRUE); + // difference result - len is the count of guaranteed to be + // positive bytes + + __ bind(RET_ADJUST_LONG); + __ add(len, len, (u1)(large_loop_size - 16)); + __ bind(RET_ADJUST_16); + __ add(len, len, 16); + __ bind(RET_ADJUST); __ pop(spilled_regs, sp); - __ bind(RET_TRUE_NO_POP); __ leave(); - __ mov(result, 1); + __ sub(result, result, len); __ ret(lr); return entry; @@ -7515,8 +7523,8 @@ class StubGenerator: public StubCodeGenerator { // arraycopy stubs used by compilers generate_arraycopy_stubs(); - // has negatives stub for large arrays. - StubRoutines::aarch64::_has_negatives = generate_has_negatives(StubRoutines::aarch64::_has_negatives_long); + // countPositives stub for large arrays. + StubRoutines::aarch64::_count_positives = generate_count_positives(StubRoutines::aarch64::_count_positives_long); // array equals stub for large arrays. if (!UseSimpleArrayEquals) { diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp index 9e16a1f9f88..2e1c4b69542 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.cpp @@ -45,8 +45,8 @@ address StubRoutines::aarch64::_float_sign_flip = NULL; address StubRoutines::aarch64::_double_sign_mask = NULL; address StubRoutines::aarch64::_double_sign_flip = NULL; address StubRoutines::aarch64::_zero_blocks = NULL; -address StubRoutines::aarch64::_has_negatives = NULL; -address StubRoutines::aarch64::_has_negatives_long = NULL; +address StubRoutines::aarch64::_count_positives = NULL; +address StubRoutines::aarch64::_count_positives_long = NULL; address StubRoutines::aarch64::_large_array_equals = NULL; address StubRoutines::aarch64::_compare_long_string_LL = NULL; address StubRoutines::aarch64::_compare_long_string_UU = NULL; diff --git a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp index ae48d8788e1..a17e7540e42 100644 --- a/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/stubRoutines_aarch64.hpp @@ -76,8 +76,8 @@ class aarch64 { public: - static address _has_negatives; - static address _has_negatives_long; + static address _count_positives; + static address _count_positives_long; static address get_previous_sp_entry() { @@ -132,12 +132,12 @@ class aarch64 { return _zero_blocks; } - static address has_negatives() { - return _has_negatives; + static address count_positives() { + return _count_positives; } - static address has_negatives_long() { - return _has_negatives_long; + static address count_positives_long() { + return _count_positives_long; } static address large_array_equals() { diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp index 1ae5c13e62e..30104094983 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp @@ -565,16 +565,16 @@ void C2_MacroAssembler::string_indexof_char(Register result, Register haystack, } // string_indexof_char -void C2_MacroAssembler::has_negatives(Register src, Register cnt, Register result, - Register tmp1, Register tmp2) { +void C2_MacroAssembler::count_positives(Register src, Register cnt, Register result, + Register tmp1, Register tmp2) { const Register tmp0 = R0; assert_different_registers(src, result, cnt, tmp0, tmp1, tmp2); - Label Lfastloop, Lslow, Lloop, Lnoneg, Ldone; + Label Lfastloop, Lslow, Lloop, Ldone; // Check if cnt >= 8 (= 16 bytes) lis(tmp1, (int)(short)0x8080); // tmp1 = 0x8080808080808080 srwi_(tmp2, cnt, 4); - li(result, 1); // Assume there's a negative byte. + mr(result, src); // Use result reg to point to the current position. beq(CCR0, Lslow); ori(tmp1, tmp1, 0x8080); rldimi(tmp1, tmp1, 32, 0); @@ -582,30 +582,28 @@ void C2_MacroAssembler::has_negatives(Register src, Register cnt, Register resul // 2x unrolled loop bind(Lfastloop); - ld(tmp2, 0, src); - ld(tmp0, 8, src); + ld(tmp2, 0, result); + ld(tmp0, 8, result); orr(tmp0, tmp2, tmp0); and_(tmp0, tmp0, tmp1); - bne(CCR0, Ldone); // Found negative byte. - addi(src, src, 16); - + bne(CCR0, Lslow); // Found negative byte. + addi(result, result, 16); bdnz(Lfastloop); - bind(Lslow); // Fallback to slow version - rldicl_(tmp0, cnt, 0, 64-4); - beq(CCR0, Lnoneg); + bind(Lslow); // Fallback to slow version. + subf(tmp0, src, result); // Bytes known positive. + subf_(tmp0, tmp0, cnt); // Remaining Bytes. + beq(CCR0, Ldone); mtctr(tmp0); bind(Lloop); - lbz(tmp0, 0, src); - addi(src, src, 1); + lbz(tmp0, 0, result); andi_(tmp0, tmp0, 0x80); bne(CCR0, Ldone); // Found negative byte. + addi(result, result, 1); bdnz(Lloop); - bind(Lnoneg); - li(result, 0); bind(Ldone); + subf(result, src, result); // Result is offset from src. } - diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp index 9c4576f2eaf..ef4840b08a2 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.hpp @@ -63,6 +63,6 @@ void string_indexof_char(Register result, Register haystack, Register haycnt, Register needle, jchar needleChar, Register tmp1, Register tmp2, bool is_byte); - void has_negatives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); + void count_positives(Register src, Register cnt, Register result, Register tmp1, Register tmp2); #endif // CPU_PPC_C2_MACROASSEMBLER_PPC_HPP diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 832982deb45..b41c72ab449 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -12779,16 +12779,16 @@ instruct string_inflate(Universe dummy, rarg1RegP src, rarg2RegP dst, iRegIsrc l %} // StringCoding.java intrinsics -instruct has_negatives(rarg1RegP ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2, - regCTR ctr, flagsRegCR0 cr0) +instruct count_positives(iRegPsrc ary1, iRegIsrc len, iRegIdst result, iRegLdst tmp1, iRegLdst tmp2, + regCTR ctr, flagsRegCR0 cr0) %{ - match(Set result (HasNegatives ary1 len)); - effect(TEMP_DEF result, USE_KILL ary1, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0); + match(Set result (CountPositives ary1 len)); + effect(TEMP_DEF result, TEMP tmp1, TEMP tmp2, KILL ctr, KILL cr0); ins_cost(300); - format %{ "has negatives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %} + format %{ "count positives byte[] $ary1,$len -> $result \t// KILL $tmp1, $tmp2" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, $result$$Register, - $tmp1$$Register, $tmp2$$Register); + __ count_positives($ary1$$Register, $len$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register); %} ins_pipe(pipe_class_default); %} diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp index 04a6b88052c..6fac285f738 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp @@ -823,52 +823,64 @@ unsigned int C2_MacroAssembler::string_inflate_const(Register src, Register dst, return offset() - block_start; } -// Kills src. -unsigned int C2_MacroAssembler::has_negatives(Register result, Register src, Register cnt, - Register odd_reg, Register even_reg, Register tmp) { - int block_start = offset(); - Label Lloop1, Lloop2, Lslow, Lnotfound, Ldone; - const Register addr = src, mask = tmp; - - BLOCK_COMMENT("has_negatives {"); - - z_llgfr(Z_R1, cnt); // Number of bytes to read. (Must be a positive simm32.) - z_llilf(mask, 0x80808080); - z_lhi(result, 1); // Assume true. - // Last possible addr for fast loop. - z_lay(odd_reg, -16, Z_R1, src); - z_chi(cnt, 16); - z_brl(Lslow); - - // ind1: index, even_reg: index increment, odd_reg: index limit - z_iihf(mask, 0x80808080); - z_lghi(even_reg, 16); - - bind(Lloop1); // 16 bytes per iteration. - z_lg(Z_R0, Address(addr)); - z_lg(Z_R1, Address(addr, 8)); - z_ogr(Z_R0, Z_R1); - z_ngr(Z_R0, mask); - z_brne(Ldone); // If found return 1. - z_brxlg(addr, even_reg, Lloop1); - - bind(Lslow); - z_aghi(odd_reg, 16-1); // Last possible addr for slow loop. - z_lghi(even_reg, 1); - z_cgr(addr, odd_reg); - z_brh(Lnotfound); - - bind(Lloop2); // 1 byte per iteration. - z_cli(Address(addr), 0x80); - z_brnl(Ldone); // If found return 1. - z_brxlg(addr, even_reg, Lloop2); - - bind(Lnotfound); - z_lhi(result, 0); - - bind(Ldone); - - BLOCK_COMMENT("} has_negatives"); +// Returns the number of non-negative bytes (aka US-ASCII characters) found +// before the first negative byte is encountered. +unsigned int C2_MacroAssembler::count_positives(Register result, Register src, Register cnt, Register tmp) { + const unsigned int block_start = offset(); + const unsigned int byte_mask = 0x80; + const unsigned int twobyte_mask = byte_mask<<8 | byte_mask; + const unsigned int unroll_factor = 16; + const unsigned int log_unroll_factor = exact_log2(unroll_factor); + Register pos = src; // current position in src array, restored at end + Register ctr = result; // loop counter, result value + Register mask = tmp; // holds the sign detection mask + Label unrolledLoop, unrolledDone, byteLoop, allDone; + + assert_different_registers(result, src, cnt, tmp); + + BLOCK_COMMENT("count_positives {"); + + lgr_if_needed(pos, src); // current position in src array + z_srak(ctr, cnt, log_unroll_factor); // # iterations of unrolled loop + z_brnh(unrolledDone); // array too short for unrolled loop + + z_iilf(mask, twobyte_mask<<16 | twobyte_mask); + z_iihf(mask, twobyte_mask<<16 | twobyte_mask); + + bind(unrolledLoop); + z_lmg(Z_R0, Z_R1, 0, pos); + z_ogr(Z_R0, Z_R1); + z_ngr(Z_R0, mask); + z_brne(unrolledDone); // There is a negative byte somewhere. + // ctr and pos are not updated yet -> + // delegate finding correct pos to byteLoop. + add2reg(pos, unroll_factor); + z_brct(ctr, unrolledLoop); + + // Once we arrive here, we have to examine at most (unroll_factor - 1) bytes more. + // We then either have reached the end of the array or we hit a negative byte. + bind(unrolledDone); + z_sll(ctr, log_unroll_factor); // calculate # bytes not processed by unrolled loop + // > 0 only if a negative byte was found + z_lr(Z_R0, cnt); // calculate remainder bytes + z_nilf(Z_R0, unroll_factor - 1); + z_ar(ctr, Z_R0); // remaining bytes + z_brnh(allDone); // shortcut if nothing left to do + + bind(byteLoop); + z_cli(0, pos, byte_mask); // unsigned comparison! byte@pos must be smaller that byte_mask + z_brnl(allDone); // negative byte found. + + add2reg(pos, 1); + z_brct(ctr, byteLoop); + + bind(allDone); + + z_srk(ctr, cnt, ctr); // # bytes actually processed (= cnt or index of first negative byte) + z_sgfr(pos, ctr); // restore src + z_lgfr(result, ctr); // unnecessary. Only there to be sure the high word has a defined state. + + BLOCK_COMMENT("} count_positives"); return offset() - block_start; } diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp index a6c98656495..a502e41ee08 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.hpp @@ -57,9 +57,7 @@ // len is signed int. Counts # characters, not bytes. unsigned int string_inflate_const(Register src, Register dst, Register tmp, int len); - // Kills src. - unsigned int has_negatives(Register result, Register src, Register cnt, - Register odd_reg, Register even_reg, Register tmp); + unsigned int count_positives(Register result, Register src, Register cnt, Register tmp); unsigned int string_compare(Register str1, Register str2, Register cnt1, Register cnt2, Register odd_reg, Register even_reg, Register result, int ae); diff --git a/src/hotspot/cpu/s390/s390.ad b/src/hotspot/cpu/s390/s390.ad index 74ad8ef40d3..d13afd1c8b4 100644 --- a/src/hotspot/cpu/s390/s390.ad +++ b/src/hotspot/cpu/s390/s390.ad @@ -10273,14 +10273,13 @@ instruct string_inflate_const(Universe dummy, iRegP src, iRegP dst, iRegI tmp, i %} // StringCoding.java intrinsics -instruct has_negatives(rarg5RegP ary1, iRegI len, iRegI result, roddRegI oddReg, revenRegI evenReg, iRegI tmp, flagsReg cr) %{ - match(Set result (HasNegatives ary1 len)); - effect(TEMP_DEF result, USE_KILL ary1, TEMP oddReg, TEMP evenReg, TEMP tmp, KILL cr); // R0, R1 are killed, too. +instruct count_positives(iRegP ary1, iRegI len, iRegI result, iRegI tmp, flagsReg cr) %{ + match(Set result (CountPositives ary1 len)); + effect(TEMP_DEF result, TEMP tmp, KILL cr); // R0, R1 are killed, too. ins_cost(300); - format %{ "has negatives byte[] $ary1($len) -> $result" %} + format %{ "count positives byte[] $ary1($len) -> $result" %} ins_encode %{ - __ has_negatives($result$$Register, $ary1$$Register, $len$$Register, - $oddReg$$Register, $evenReg$$Register, $tmp$$Register); + __ count_positives($result$$Register, $ary1$$Register, $len$$Register, $tmp$$Register); %} ins_pipe(pipe_class_dummy); %} diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index f3f684b1b25..6d8b9101303 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -3374,18 +3374,19 @@ void C2_MacroAssembler::string_compare(Register str1, Register str2, } // Search for Non-ASCII character (Negative byte value) in a byte array, -// return true if it has any and false otherwise. +// return the index of the first such character, otherwise the length +// of the array segment searched. // ..\jdk\src\java.base\share\classes\java\lang\StringCoding.java // @IntrinsicCandidate -// private static boolean hasNegatives(byte[] ba, int off, int len) { +// public static int countPositives(byte[] ba, int off, int len) { // for (int i = off; i < off + len; i++) { // if (ba[i] < 0) { -// return true; +// return i - off; // } // } -// return false; +// return len; // } -void C2_MacroAssembler::has_negatives(Register ary1, Register len, +void C2_MacroAssembler::count_positives(Register ary1, Register len, Register result, Register tmp1, XMMRegister vec1, XMMRegister vec2, KRegister mask1, KRegister mask2) { // rsi: byte array @@ -3394,17 +3395,18 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, ShortBranchVerifier sbv(this); assert_different_registers(ary1, len, result, tmp1); assert_different_registers(vec1, vec2); - Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_CHAR, COMPARE_VECTORS, COMPARE_BYTE; + Label ADJUST, TAIL_ADJUST, DONE, TAIL_START, CHAR_ADJUST, COMPARE_CHAR, COMPARE_VECTORS, COMPARE_BYTE; + movl(result, len); // copy // len == 0 testl(len, len); - jcc(Assembler::zero, FALSE_LABEL); + jcc(Assembler::zero, DONE); if ((AVX3Threshold == 0) && (UseAVX > 2) && // AVX512 VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()) { - Label test_64_loop, test_tail; + Label test_64_loop, test_tail, BREAK_LOOP; Register tmp3_aliased = len; movl(tmp1, len); @@ -3421,16 +3423,15 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, // Check whether our 64 elements of size byte contain negatives evpcmpgtb(mask1, vec2, Address(ary1, len, Address::times_1), Assembler::AVX_512bit); kortestql(mask1, mask1); - jcc(Assembler::notZero, TRUE_LABEL); + jcc(Assembler::notZero, BREAK_LOOP); addptr(len, 64); jccb(Assembler::notZero, test_64_loop); - bind(test_tail); // bail out when there is nothing to be done testl(tmp1, -1); - jcc(Assembler::zero, FALSE_LABEL); + jcc(Assembler::zero, DONE); // ~(~0 << len) applied up to two times (for 32-bit scenario) #ifdef _LP64 @@ -3467,21 +3468,30 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, #endif evpcmpgtb(mask1, mask2, vec2, Address(ary1, 0), Assembler::AVX_512bit); ktestq(mask1, mask2); - jcc(Assembler::notZero, TRUE_LABEL); + jcc(Assembler::zero, DONE); - jmp(FALSE_LABEL); + bind(BREAK_LOOP); + // At least one byte in the last 64 bytes is negative. + // Set up to look at the last 64 bytes as if they were a tail + lea(ary1, Address(ary1, len, Address::times_1)); + addptr(result, len); + // Ignore the very last byte: if all others are positive, + // it must be negative, so we can skip right to the 2+1 byte + // end comparison at this point + orl(result, 63); + movl(len, 63); + // Fallthru to tail compare } else { - movl(result, len); // copy if (UseAVX >= 2 && UseSSE >= 2) { // With AVX2, use 32-byte vector compare - Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + Label COMPARE_WIDE_VECTORS, BREAK_LOOP; // Compare 32-byte vectors - andl(result, 0x0000001f); // tail count (in bytes) - andl(len, 0xffffffe0); // vector count (in bytes) - jccb(Assembler::zero, COMPARE_TAIL); + testl(len, 0xffffffe0); // vector count (in bytes) + jccb(Assembler::zero, TAIL_START); + andl(len, 0xffffffe0); lea(ary1, Address(ary1, len, Address::times_1)); negptr(len); @@ -3492,30 +3502,42 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, bind(COMPARE_WIDE_VECTORS); vmovdqu(vec1, Address(ary1, len, Address::times_1)); vptest(vec1, vec2); - jccb(Assembler::notZero, TRUE_LABEL); + jccb(Assembler::notZero, BREAK_LOOP); addptr(len, 32); - jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + jccb(Assembler::notZero, COMPARE_WIDE_VECTORS); - testl(result, result); - jccb(Assembler::zero, FALSE_LABEL); + testl(result, 0x0000001f); // any bytes remaining? + jcc(Assembler::zero, DONE); - vmovdqu(vec1, Address(ary1, result, Address::times_1, -32)); + // Quick test using the already prepared vector mask + movl(len, result); + andl(len, 0x0000001f); + vmovdqu(vec1, Address(ary1, len, Address::times_1, -32)); vptest(vec1, vec2); - jccb(Assembler::notZero, TRUE_LABEL); - jmpb(FALSE_LABEL); + jcc(Assembler::zero, DONE); + // There are zeros, jump to the tail to determine exactly where + jmpb(TAIL_START); - bind(COMPARE_TAIL); // len is zero - movl(len, result); + bind(BREAK_LOOP); + // At least one byte in the last 32-byte vector is negative. + // Set up to look at the last 32 bytes as if they were a tail + lea(ary1, Address(ary1, len, Address::times_1)); + addptr(result, len); + // Ignore the very last byte: if all others are positive, + // it must be negative, so we can skip right to the 2+1 byte + // end comparison at this point + orl(result, 31); + movl(len, 31); // Fallthru to tail compare } else if (UseSSE42Intrinsics) { // With SSE4.2, use double quad vector compare - Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; + Label COMPARE_WIDE_VECTORS, BREAK_LOOP; // Compare 16-byte vectors - andl(result, 0x0000000f); // tail count (in bytes) - andl(len, 0xfffffff0); // vector count (in bytes) - jcc(Assembler::zero, COMPARE_TAIL); + testl(len, 0xfffffff0); // vector count (in bytes) + jcc(Assembler::zero, TAIL_START); + andl(len, 0xfffffff0); lea(ary1, Address(ary1, len, Address::times_1)); negptr(len); @@ -3526,23 +3548,36 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, bind(COMPARE_WIDE_VECTORS); movdqu(vec1, Address(ary1, len, Address::times_1)); ptest(vec1, vec2); - jcc(Assembler::notZero, TRUE_LABEL); + jccb(Assembler::notZero, BREAK_LOOP); addptr(len, 16); - jcc(Assembler::notZero, COMPARE_WIDE_VECTORS); + jccb(Assembler::notZero, COMPARE_WIDE_VECTORS); - testl(result, result); - jcc(Assembler::zero, FALSE_LABEL); + testl(result, 0x0000000f); // len is zero, any bytes remaining? + jcc(Assembler::zero, DONE); - movdqu(vec1, Address(ary1, result, Address::times_1, -16)); + // Quick test using the already prepared vector mask + movl(len, result); + andl(len, 0x0000000f); // tail count (in bytes) + movdqu(vec1, Address(ary1, len, Address::times_1, -16)); ptest(vec1, vec2); - jccb(Assembler::notZero, TRUE_LABEL); - jmpb(FALSE_LABEL); + jcc(Assembler::zero, DONE); + jmpb(TAIL_START); - bind(COMPARE_TAIL); // len is zero - movl(len, result); + bind(BREAK_LOOP); + // At least one byte in the last 16-byte vector is negative. + // Set up and look at the last 16 bytes as if they were a tail + lea(ary1, Address(ary1, len, Address::times_1)); + addptr(result, len); + // Ignore the very last byte: if all others are positive, + // it must be negative, so we can skip right to the 2+1 byte + // end comparison at this point + orl(result, 15); + movl(len, 15); // Fallthru to tail compare } } + + bind(TAIL_START); // Compare 4-byte vectors andl(len, 0xfffffffc); // vector count (in bytes) jccb(Assembler::zero, COMPARE_CHAR); @@ -3553,34 +3588,45 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, bind(COMPARE_VECTORS); movl(tmp1, Address(ary1, len, Address::times_1)); andl(tmp1, 0x80808080); - jccb(Assembler::notZero, TRUE_LABEL); + jccb(Assembler::notZero, TAIL_ADJUST); addptr(len, 4); - jcc(Assembler::notZero, COMPARE_VECTORS); + jccb(Assembler::notZero, COMPARE_VECTORS); - // Compare trailing char (final 2 bytes), if any + // Compare trailing char (final 2-3 bytes), if any bind(COMPARE_CHAR); + testl(result, 0x2); // tail char jccb(Assembler::zero, COMPARE_BYTE); load_unsigned_short(tmp1, Address(ary1, 0)); andl(tmp1, 0x00008080); - jccb(Assembler::notZero, TRUE_LABEL); - subptr(result, 2); + jccb(Assembler::notZero, CHAR_ADJUST); lea(ary1, Address(ary1, 2)); bind(COMPARE_BYTE); testl(result, 0x1); // tail byte - jccb(Assembler::zero, FALSE_LABEL); + jccb(Assembler::zero, DONE); load_unsigned_byte(tmp1, Address(ary1, 0)); - andl(tmp1, 0x00000080); - jccb(Assembler::notEqual, TRUE_LABEL); - jmpb(FALSE_LABEL); - - bind(TRUE_LABEL); - movl(result, 1); // return true + testl(tmp1, 0x00000080); + jccb(Assembler::zero, DONE); + subptr(result, 1); jmpb(DONE); - bind(FALSE_LABEL); - xorl(result, result); // return false + bind(TAIL_ADJUST); + // there are negative bits in the last 4 byte block. + // Adjust result and check the next three bytes + addptr(result, len); + orl(result, 3); + lea(ary1, Address(ary1, len, Address::times_1)); + jmpb(COMPARE_CHAR); + + bind(CHAR_ADJUST); + // We are looking at a char + optional byte tail, and found that one + // of the bytes in the char is negative. Adjust the result, check the + // first byte and readjust if needed. + andl(result, 0xfffffffc); + testl(tmp1, 0x00000080); // little-endian, so lowest byte comes first + jccb(Assembler::notZero, DONE); + addptr(result, 1); // That's it bind(DONE); @@ -3590,6 +3636,7 @@ void C2_MacroAssembler::has_negatives(Register ary1, Register len, vpxor(vec2, vec2); } } + // Compare char[] or byte[] arrays aligned to 4 bytes or substrings. void C2_MacroAssembler::arrays_equals(bool is_array_equ, Register ary1, Register ary2, Register limit, Register result, Register chr, diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp index 0464d755ed4..5ecdf20700d 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.hpp @@ -271,11 +271,10 @@ public: XMMRegister vec1, int ae, KRegister mask = knoreg); // Search for Non-ASCII character (Negative byte value) in a byte array, - // return true if it has any and false otherwise. - void has_negatives(Register ary1, Register len, - Register result, Register tmp1, - XMMRegister vec1, XMMRegister vec2, KRegister mask1 = knoreg, KRegister mask2 = knoreg); - + // return index of the first such character, otherwise len. + void count_positives(Register ary1, Register len, + Register result, Register tmp1, + XMMRegister vec1, XMMRegister vec2, KRegister mask1 = knoreg, KRegister mask2 = knoreg); // Compare char[] or byte[] arrays. void arrays_equals(bool is_array_equ, Register ary1, Register ary2, Register limit, Register result, Register chr, diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 3bb01e3eeae..9bba150516e 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -12122,34 +12122,34 @@ instruct array_equalsC_evex(eDIRegP ary1, eSIRegP ary2, eAXRegI result, ins_pipe( pipe_slow ); %} -instruct has_negatives(eSIRegP ary1, eCXRegI len, eAXRegI result, - regD tmp1, regD tmp2, eBXRegI tmp3, eFlagsReg cr) +instruct count_positives(eSIRegP ary1, eCXRegI len, eAXRegI result, + regD tmp1, regD tmp2, eBXRegI tmp3, eFlagsReg cr) %{ predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); %} ins_pipe( pipe_slow ); %} -instruct has_negatives_evex(eSIRegP ary1, eCXRegI len, eAXRegI result, - regD tmp1, regD tmp2, kReg ktmp1, kReg ktmp2, eBXRegI tmp3, eFlagsReg cr) +instruct count_positives_evex(eSIRegP ary1, eCXRegI len, eAXRegI result, + regD tmp1, regD tmp2, kReg ktmp1, kReg ktmp2, eBXRegI tmp3, eFlagsReg cr) %{ predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(TEMP tmp1, TEMP tmp2, TEMP ktmp1, TEMP ktmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); %} ins_pipe( pipe_slow ); %} diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index bc04106f3f2..3eed117ece8 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -11685,34 +11685,34 @@ instruct array_equalsC_evex(rdi_RegP ary1, rsi_RegP ary2, rax_RegI result, ins_pipe( pipe_slow ); %} -instruct has_negatives(rsi_RegP ary1, rcx_RegI len, rax_RegI result, - legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr,) +instruct count_positives(rsi_RegP ary1, rcx_RegI len, rax_RegI result, + legRegD tmp1, legRegD tmp2, rbx_RegI tmp3, rFlagsReg cr,) %{ predicate(!VM_Version::supports_avx512vlbw() || !VM_Version::supports_bmi2()); - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(TEMP tmp1, TEMP tmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, knoreg, knoreg); %} ins_pipe( pipe_slow ); %} -instruct has_negatives_evex(rsi_RegP ary1, rcx_RegI len, rax_RegI result, - legRegD tmp1, legRegD tmp2, kReg ktmp1, kReg ktmp2, rbx_RegI tmp3, rFlagsReg cr,) +instruct count_positives_evex(rsi_RegP ary1, rcx_RegI len, rax_RegI result, + legRegD tmp1, legRegD tmp2, kReg ktmp1, kReg ktmp2, rbx_RegI tmp3, rFlagsReg cr,) %{ predicate(VM_Version::supports_avx512vlbw() && VM_Version::supports_bmi2()); - match(Set result (HasNegatives ary1 len)); + match(Set result (CountPositives ary1 len)); effect(TEMP tmp1, TEMP tmp2, TEMP ktmp1, TEMP ktmp2, USE_KILL ary1, USE_KILL len, KILL tmp3, KILL cr); - format %{ "has negatives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} + format %{ "countPositives byte[] $ary1,$len -> $result // KILL $tmp1, $tmp2, $tmp3" %} ins_encode %{ - __ has_negatives($ary1$$Register, $len$$Register, - $result$$Register, $tmp3$$Register, - $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); + __ count_positives($ary1$$Register, $len$$Register, + $result$$Register, $tmp3$$Register, + $tmp1$$XMMRegister, $tmp2$$XMMRegister, $ktmp1$$KRegister, $ktmp2$$KRegister); %} ins_pipe( pipe_slow ); %} diff --git a/src/hotspot/share/adlc/formssel.cpp b/src/hotspot/share/adlc/formssel.cpp index 274e623ea61..0ae7b075074 100644 --- a/src/hotspot/share/adlc/formssel.cpp +++ b/src/hotspot/share/adlc/formssel.cpp @@ -612,7 +612,7 @@ bool InstructForm::needs_anti_dependence_check(FormDict &globals) const { strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOf" )==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOfChar" )==0 || - strcmp(_matrule->_rChild->_opType,"HasNegatives" )==0 || + strcmp(_matrule->_rChild->_opType,"CountPositives" )==0 || strcmp(_matrule->_rChild->_opType,"AryEq" )==0 )) return true; @@ -902,7 +902,7 @@ uint InstructForm::oper_input_base(FormDict &globals) { strcmp(_matrule->_rChild->_opType,"StrCompressedCopy" )==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 || strcmp(_matrule->_rChild->_opType,"StrIndexOfChar")==0 || - strcmp(_matrule->_rChild->_opType,"HasNegatives")==0 || + strcmp(_matrule->_rChild->_opType,"CountPositives")==0 || strcmp(_matrule->_rChild->_opType,"EncodeISOArray")==0)) { // String.(compareTo/equals/indexOf) and Arrays.equals // and sun.nio.cs.iso8859_1$Encoder.EncodeISOArray diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index cc3dc1ebdcc..a329669bed3 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -229,7 +229,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_loadFence: case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: - case vmIntrinsics::_hasNegatives: + case vmIntrinsics::_countPositives: case vmIntrinsics::_Reference_get: break; default: diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 7c3cb1d3f10..5b2c6a9ce56 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -354,9 +354,9 @@ class methodHandle; do_signature(Preconditions_checkLongIndex_signature, "(JJLjava/util/function/BiFunction;)J") \ \ do_class(java_lang_StringCoding, "java/lang/StringCoding") \ - do_intrinsic(_hasNegatives, java_lang_StringCoding, hasNegatives_name, hasNegatives_signature, F_S) \ - do_name( hasNegatives_name, "hasNegatives") \ - do_signature(hasNegatives_signature, "([BII)Z") \ + do_intrinsic(_countPositives, java_lang_StringCoding, countPositives_name, countPositives_signature, F_S) \ + do_name( countPositives_name, "countPositives") \ + do_signature(countPositives_signature, "([BII)I") \ \ do_class(sun_nio_cs_iso8859_1_Encoder, "sun/nio/cs/ISO_8859_1$Encoder") \ do_intrinsic(_encodeISOArray, sun_nio_cs_iso8859_1_Encoder, encodeISOArray_name, encodeISOArray_signature, F_S) \ @@ -459,9 +459,8 @@ class methodHandle; \ /* support for sun.security.provider.DigestBase */ \ do_class(sun_security_provider_digestbase, "sun/security/provider/DigestBase") \ - do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, implCompressMB_signature, F_R) \ + do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, countPositives_signature, F_R) \ do_name( implCompressMB_name, "implCompressMultiBlock0") \ - do_signature(implCompressMB_signature, "([BII)I") \ \ /* support for java.util.Base64.Encoder*/ \ do_class(java_util_Base64_Encoder, "java/util/Base64$Encoder") \ diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 849b40f3d79..667808f4efd 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -567,7 +567,7 @@ void ShenandoahBarrierC2Support::verify(RootNode* root) { { { 2, ShenandoahLoad }, { 3, ShenandoahLoad } }, Op_EncodeISOArray, { { 2, ShenandoahLoad }, { 3, ShenandoahStore } }, - Op_HasNegatives, + Op_CountPositives, { { 2, ShenandoahLoad }, { -1, ShenandoahNone} }, Op_CastP2X, { { 1, ShenandoahLoad }, { -1, ShenandoahNone} }, diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 998f1d1ad4f..7ed48a79eeb 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -742,8 +742,8 @@ #define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ static_field(VM_Version, _zva_length, int) \ - static_field(StubRoutines::aarch64, _has_negatives, address) \ - static_field(StubRoutines::aarch64, _has_negatives_long, address) \ + static_field(StubRoutines::aarch64, _count_positives, address) \ + static_field(StubRoutines::aarch64, _count_positives_long, address) \ static_field(VM_Version, _rop_protection, bool) \ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index af2b8e5456c..94e7fb4f4a0 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -234,8 +234,8 @@ bool C2Compiler::is_intrinsic_supported(const methodHandle& method, bool is_virt case vmIntrinsics::_encodeByteISOArray: if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return false; break; - case vmIntrinsics::_hasNegatives: - if (!Matcher::match_rule_supported(Op_HasNegatives)) return false; + case vmIntrinsics::_countPositives: + if (!Matcher::match_rule_supported(Op_CountPositives)) return false; break; case vmIntrinsics::_bitCount_i: if (!Matcher::match_rule_supported(Op_PopCountI)) return false; diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index 4abb3fef3b4..35dd640b4ee 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -174,7 +174,7 @@ macro(FmaD) macro(FmaF) macro(Goto) macro(Halt) -macro(HasNegatives) +macro(CountPositives) macro(If) macro(RangeCheck) macro(IfFalse) diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index d9df238aff4..3e02b18f50f 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -635,7 +635,7 @@ void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *de break; } case Op_AryEq: - case Op_HasNegatives: + case Op_CountPositives: case Op_StrComp: case Op_StrEquals: case Op_StrIndexOf: @@ -773,7 +773,7 @@ void ConnectionGraph::add_final_edges(Node *n) { break; } case Op_AryEq: - case Op_HasNegatives: + case Op_CountPositives: case Op_StrComp: case Op_StrEquals: case Op_StrIndexOf: @@ -3344,7 +3344,8 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, memnode_worklist.append_if_missing(use); } else if (!(op == Op_CmpP || op == Op_Conv2B || op == Op_CastP2X || op == Op_StoreCM || - op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives || + op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || + op == Op_CountPositives || op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar || op == Op_SubTypeCheck || @@ -3475,7 +3476,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, // They overwrite memory edge corresponding to destination array, memnode_worklist.append_if_missing(use); } else if (!(BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use) || - op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives || + op == Op_AryEq || op == Op_StrComp || op == Op_CountPositives || op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar)) { n->dump(); diff --git a/src/hotspot/share/opto/intrinsicnode.hpp b/src/hotspot/share/opto/intrinsicnode.hpp index ab8a834bb28..477842869c3 100644 --- a/src/hotspot/share/opto/intrinsicnode.hpp +++ b/src/hotspot/share/opto/intrinsicnode.hpp @@ -157,13 +157,13 @@ class AryEqNode: public StrIntrinsicNode { virtual const Type* bottom_type() const { return TypeInt::BOOL; } }; -//------------------------------HasNegatives--------------------------------- -class HasNegativesNode: public StrIntrinsicNode { +//------------------------------CountPositives------------------------------ +class CountPositivesNode: public StrIntrinsicNode { public: - HasNegativesNode(Node* control, Node* char_array_mem, Node* s1, Node* c1): + CountPositivesNode(Node* control, Node* char_array_mem, Node* s1, Node* c1): StrIntrinsicNode(control, char_array_mem, s1, c1, none) {}; virtual int Opcode() const; - virtual const Type* bottom_type() const { return TypeInt::BOOL; } + virtual const Type* bottom_type() const { return TypeInt::POS; } }; diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index fe799dd9847..97740e90a29 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -203,7 +203,7 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo case Op_StrInflatedCopy: case Op_StrCompressedCopy: case Op_EncodeISOArray: - case Op_HasNegatives: + case Op_CountPositives: // Not a legit memory op for implicit null check regardless of // embedded loads continue; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index f5c19d8123c..2f7c7fdc84c 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -617,8 +617,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_isCompileConstant: return inline_isCompileConstant(); - case vmIntrinsics::_hasNegatives: - return inline_hasNegatives(); + case vmIntrinsics::_countPositives: + return inline_countPositives(); case vmIntrinsics::_fmaD: case vmIntrinsics::_fmaF: @@ -1011,13 +1011,13 @@ bool LibraryCallKit::inline_array_equals(StrIntrinsicNode::ArgEnc ae) { return true; } -//------------------------------inline_hasNegatives------------------------------ -bool LibraryCallKit::inline_hasNegatives() { +//------------------------------inline_countPositives------------------------------ +bool LibraryCallKit::inline_countPositives() { if (too_many_traps(Deoptimization::Reason_intrinsic)) { return false; } - assert(callee()->signature()->size() == 3, "hasNegatives has 3 parameters"); + assert(callee()->signature()->size() == 3, "countPositives has 3 parameters"); // no receiver since it is static method Node* ba = argument(0); Node* offset = argument(1); @@ -1031,7 +1031,7 @@ bool LibraryCallKit::inline_hasNegatives() { return true; } Node* ba_start = array_element_address(ba, offset, T_BYTE); - Node* result = new HasNegativesNode(control(), memory(TypeAryPtr::BYTES), ba_start, len); + Node* result = new CountPositivesNode(control(), memory(TypeAryPtr::BYTES), ba_start, len); set_result(_gvn.transform(result)); return true; } diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index eca3e70bb5a..d8f86233d6b 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -296,7 +296,7 @@ class LibraryCallKit : public GraphKit { bool inline_updateBytesAdler32(); bool inline_updateByteBufferAdler32(); bool inline_multiplyToLen(); - bool inline_hasNegatives(); + bool inline_countPositives(); bool inline_squareToLen(); bool inline_mulAdd(); bool inline_montgomeryMultiply(); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index dccf75c0022..4257b0fd6e5 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -828,7 +828,7 @@ bool IdealLoopTree::policy_maximally_unroll(PhaseIdealLoop* phase) const { case Op_StrIndexOfChar: case Op_EncodeISOArray: case Op_AryEq: - case Op_HasNegatives: { + case Op_CountPositives: { return false; } #if INCLUDE_RTM_OPT @@ -981,7 +981,7 @@ bool IdealLoopTree::policy_unroll(PhaseIdealLoop *phase) { case Op_StrIndexOfChar: case Op_EncodeISOArray: case Op_AryEq: - case Op_HasNegatives: { + case Op_CountPositives: { // Do not unroll a loop with String intrinsics code. // String intrinsics are large and have loops. return false; diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 39c6ad49563..f08b1d46b1c 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -5775,7 +5775,7 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) { case Op_StrIndexOf: case Op_StrIndexOfChar: case Op_AryEq: - case Op_HasNegatives: + case Op_CountPositives: pinned = false; } if (n->is_CMove() || n->is_ConstraintCast()) { diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index 35ccf26e7cb..20a08e0cb4b 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -1066,7 +1066,7 @@ static void match_alias_type(Compile* C, Node* n, Node* m) { case Op_StrIndexOf: case Op_StrIndexOfChar: case Op_AryEq: - case Op_HasNegatives: + case Op_CountPositives: case Op_MemBarVolatile: case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type? case Op_StrInflatedCopy: @@ -2252,7 +2252,7 @@ bool Matcher::find_shared_visit(MStack& mstack, Node* n, uint opcode, bool& mem_ case Op_StrIndexOf: case Op_StrIndexOfChar: case Op_AryEq: - case Op_HasNegatives: + case Op_CountPositives: case Op_StrInflatedCopy: case Op_StrCompressedCopy: case Op_EncodeISOArray: diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index e79884bd4cc..3c3a2ba28f0 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -525,56 +525,63 @@ public final class String this.value = "".value; this.coder = "".coder; } else if (charset == UTF_8.INSTANCE) { - if (COMPACT_STRINGS && !StringCoding.hasNegatives(bytes, offset, length)) { - this.value = Arrays.copyOfRange(bytes, offset, offset + length); - this.coder = LATIN1; - } else { + if (COMPACT_STRINGS) { + int dp = StringCoding.countPositives(bytes, offset, length); + if (dp == length) { + this.value = Arrays.copyOfRange(bytes, offset, offset + length); + this.coder = LATIN1; + return; + } int sl = offset + length; - int dp = 0; - byte[] dst = null; - if (COMPACT_STRINGS) { - dst = new byte[length]; - while (offset < sl) { - int b1 = bytes[offset]; - if (b1 >= 0) { - dst[dp++] = (byte)b1; + byte[] dst = new byte[length]; + if (dp > 0) { + System.arraycopy(bytes, offset, dst, 0, dp); + offset += dp; + } + while (offset < sl) { + int b1 = bytes[offset++]; + if (b1 >= 0) { + dst[dp++] = (byte)b1; + continue; + } + if ((b1 & 0xfe) == 0xc2 && offset < sl) { // b1 either 0xc2 or 0xc3 + int b2 = bytes[offset]; + if (b2 < -64) { // continuation bytes are always negative values in the range -128 to -65 + dst[dp++] = (byte)decode2(b1, b2); offset++; continue; } - if ((b1 & 0xfe) == 0xc2 && offset + 1 < sl) { // b1 either 0xc2 or 0xc3 - int b2 = bytes[offset + 1]; - if (!isNotContinuation(b2)) { - dst[dp++] = (byte)decode2(b1, b2); - offset += 2; - continue; - } - } - // anything not a latin1, including the repl - // we have to go with the utf16 - break; - } - if (offset == sl) { - if (dp != dst.length) { - dst = Arrays.copyOf(dst, dp); - } - this.value = dst; - this.coder = LATIN1; - return; } + // anything not a latin1, including the REPL + // we have to go with the utf16 + offset--; + break; } - if (dp == 0 || dst == null) { - dst = new byte[length << 1]; - } else { - byte[] buf = new byte[length << 1]; - StringLatin1.inflate(dst, 0, buf, 0, dp); - dst = buf; + if (offset == sl) { + if (dp != dst.length) { + dst = Arrays.copyOf(dst, dp); + } + this.value = dst; + this.coder = LATIN1; + return; } + byte[] buf = new byte[length << 1]; + StringLatin1.inflate(dst, 0, buf, 0, dp); + dst = buf; dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, true); if (dp != length) { dst = Arrays.copyOf(dst, dp << 1); } this.value = dst; this.coder = UTF16; + } else { // !COMPACT_STRINGS + byte[] dst = new byte[length << 1]; + int dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, true); + if (dp != length) { + dst = Arrays.copyOf(dst, dp << 1); + } + this.value = dst; + this.coder = UTF16; } } else if (charset == ISO_8859_1.INSTANCE) { if (COMPACT_STRINGS) { @@ -682,41 +689,43 @@ public final class String if (length == 0) { return ""; } - if (COMPACT_STRINGS && !StringCoding.hasNegatives(bytes, offset, length)) { - return new String(Arrays.copyOfRange(bytes, offset, offset + length), LATIN1); - } else { + int dp; + byte[] dst; + if (COMPACT_STRINGS) { + dp = StringCoding.countPositives(bytes, offset, length); int sl = offset + length; - int dp = 0; - byte[] dst = null; - if (COMPACT_STRINGS) { - dst = new byte[length]; - while (offset < sl) { - int b1 = bytes[offset]; - if (b1 >= 0) { - dst[dp++] = (byte) b1; + if (dp == length) { + return new String(Arrays.copyOfRange(bytes, offset, offset + length), LATIN1); + } + dst = new byte[length]; + System.arraycopy(bytes, offset, dst, 0, dp); + offset += dp; + while (offset < sl) { + int b1 = bytes[offset++]; + if (b1 >= 0) { + dst[dp++] = (byte)b1; + continue; + } + if ((b1 & 0xfe) == 0xc2 && offset < sl) { // b1 either 0xc2 or 0xc3 + int b2 = bytes[offset]; + if (b2 < -64) { // continuation bytes are always negative values in the range -128 to -65 + dst[dp++] = (byte)decode2(b1, b2); offset++; continue; } - if ((b1 & 0xfe) == 0xc2 && offset + 1 < sl) { // b1 either 0xc2 or 0xc3 - int b2 = bytes[offset + 1]; - if (!isNotContinuation(b2)) { - dst[dp++] = (byte) decode2(b1, b2); - offset += 2; - continue; - } - } - // anything not a latin1, including the REPL - // we have to go with the utf16 - break; } - if (offset == sl) { - if (dp != dst.length) { - dst = Arrays.copyOf(dst, dp); - } - return new String(dst, LATIN1); + // anything not a latin1, including the REPL + // we have to go with the utf16 + offset--; + break; + } + if (offset == sl) { + if (dp != dst.length) { + dst = Arrays.copyOf(dst, dp); } + return new String(dst, LATIN1); } - if (dp == 0 || dst == null) { + if (dp == 0) { dst = new byte[length << 1]; } else { byte[] buf = new byte[length << 1]; @@ -724,11 +733,14 @@ public final class String dst = buf; } dp = decodeUTF8_UTF16(bytes, offset, sl, dst, dp, false); - if (dp != length) { - dst = Arrays.copyOf(dst, dp << 1); - } - return new String(dst, UTF16); + } else { // !COMPACT_STRINGS + dst = new byte[length << 1]; + dp = decodeUTF8_UTF16(bytes, offset, offset + length, dst, 0, false); } + if (dp != length) { + dst = Arrays.copyOf(dst, dp << 1); + } + return new String(dst, UTF16); } static String newStringNoRepl(byte[] src, Charset cs) throws CharacterCodingException { @@ -1019,17 +1031,9 @@ public final class String */ /* package-private */ static int decodeASCII(byte[] sa, int sp, char[] da, int dp, int len) { - if (!StringCoding.hasNegatives(sa, sp, len)) { - StringLatin1.inflate(sa, sp, da, dp, len); - return len; - } else { - int start = sp; - int end = sp + len; - while (sp < end && sa[sp] >= 0) { - da[dp++] = (char) sa[sp++]; - } - return sp - start; - } + int count = StringCoding.countPositives(sa, sp, len); + StringLatin1.inflate(sa, sp, da, dp, count); + return count; } private static boolean isNotContinuation(int b) { diff --git a/src/java.base/share/classes/java/lang/StringCoding.java b/src/java.base/share/classes/java/lang/StringCoding.java index ec81c379579..293fbdb78dc 100644 --- a/src/java.base/share/classes/java/lang/StringCoding.java +++ b/src/java.base/share/classes/java/lang/StringCoding.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -34,14 +34,27 @@ class StringCoding { private StringCoding() { } - @IntrinsicCandidate public static boolean hasNegatives(byte[] ba, int off, int len) { - for (int i = off; i < off + len; i++) { + return countPositives(ba, off, len) != len; + } + + /** + * Count the number of leading positive bytes in the range. + * + * @implSpec the implementation must return len if there are no negative + * bytes in the range. If there are negative bytes, the implementation must return + * a value that is less than or equal to the index of the first negative byte + * in the range. + */ + @IntrinsicCandidate + public static int countPositives(byte[] ba, int off, int len) { + int limit = off + len; + for (int i = off; i < limit; i++) { if (ba[i] < 0) { - return true; + return i - off; } } - return false; + return len; } @IntrinsicCandidate diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java new file mode 100644 index 00000000000..afc308c37dd --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2022, 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. + */ + +package compiler.intrinsics.string; + +/* + * @test + * @bug 8999999 + * @summary Validates StringCoding.countPositives intrinsic with a small range of tests. + * @library /compiler/patches + * + * @build java.base/java.lang.Helper + * @run main compiler.intrinsics.string.TestCountPositives + */ + +public class TestCountPositives { + + private static byte[] tBa = new byte[4096 + 16]; + + /** + * Completely initialize the test array, preparing it for tests of the + * StringCoding.hasNegatives method with a given array segment offset, + * length, and number of negative bytes. + */ + public static void initialize(int off, int len, int neg) { + assert (len + off <= tBa.length); + // insert "canary" (negative) values before offset + for (int i = 0; i < off; ++i) { + tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80); + } + // fill the array segment + for (int i = off; i < len + off; ++i) { + tBa[i] = (byte) (((i - off + 15) & 0x7F)); + } + if (neg != 0) { + // modify a number (neg) disparate array bytes inside + // segment to be negative. + int div = (neg > 1) ? (len - 1) / (neg - 1) : 0; + int idx; + for (int i = 0; i < neg; ++i) { + idx = off + (len - 1) - div * i; + tBa[idx] = (byte) (0x80 | tBa[idx]); + } + } + // insert "canary" negative values after array segment + for (int i = len + off; i < tBa.length; ++i) { + tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80); + } + } + + /** Sizes of array segments to test. */ + private static int sizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 13, 17, 19, 23, 37, 61, 131, + 4099 }; + + /** + * Test different array segment sizes, offsets, and number of negative + * bytes. + */ + public static void test_countPositives() throws Exception { + int len, off; + int ng; + + for (ng = 0; ng < 57; ++ng) { // number of negatives in array segment + for (off = 0; off < 8; ++off) { // starting offset of array segment + for (int i = 0; i < sizes.length; ++i) { // array segment size + // choice + len = sizes[i]; + if (len + off > tBa.length) + continue; + initialize(off, len, ng); + int calculated = Helper.StringCodingCountPositives(tBa, off, len); + int expected = countPositives(tBa, off, len); + if (calculated != expected) { + if (expected != len && calculated >= 0 && calculated < expected) { + // allow intrinsics to return early with a lower value, + // but only if we're not expecting the full length (no + // negative bytes) + continue; + } + throw new Exception("Failed test countPositives " + "offset: " + off + " " + + "length: " + len + " " + "return: " + calculated + " expected: " + expected + " negatives: " + + ng); + } + } + } + } + } + + private static int countPositives(byte[] ba, int off, int len) { + int limit = off + len; + for (int i = off; i < limit; i++) { + if (ba[i] < 0) { + return i - off; + } + } + return len; + } + + public void run() throws Exception { + // iterate to eventually get intrinsic inlined + for (int j = 0; j < 1000; ++j) { + test_countPositives(); + } + } + + public static void main(String[] args) throws Exception { + (new TestCountPositives()).run(); + System.out.println("countPositives validated"); + } +} diff --git a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java index ded4a58945d..6d8b5be79bf 100644 --- a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java +++ b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java @@ -32,6 +32,11 @@ public class Helper { return StringCoding.hasNegatives(ba, off, len); } + @jdk.internal.vm.annotation.ForceInline + public static int StringCodingCountPositives(byte[] ba, int off, int len) { + return StringCoding.countPositives(ba, off, len); + } + @jdk.internal.vm.annotation.ForceInline public static byte[] compressByte(byte[] src, int srcOff, int dstSize, int dstOff, int len) { byte[] dst = new byte[dstSize]; diff --git a/test/micro/org/openjdk/bench/java/lang/StringDecode.java b/test/micro/org/openjdk/bench/java/lang/StringDecode.java index c5609ce4e51..ee4f8df7c73 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringDecode.java +++ b/test/micro/org/openjdk/bench/java/lang/StringDecode.java @@ -87,7 +87,7 @@ public class StringDecode { bh.consume(new String(asciiString, charset)); bh.consume(new String(longAsciiString, 0, 15, charset)); bh.consume(new String(asciiString, 0, 3, charset)); - bh.consume(new String(longAsciiString, 512, 512 + 7, charset)); + bh.consume(new String(longAsciiString, 512, 7, charset)); } @Benchmark @@ -103,7 +103,7 @@ public class StringDecode { bh.consume(new String(latin1String, charset)); bh.consume(new String(latin1String, 0, 15, charset)); bh.consume(new String(latin1String, 0, 3, charset)); - bh.consume(new String(longLatin1OnlyString, 512, 512 + 7, charset)); + bh.consume(new String(longLatin1OnlyString, 512, 7, charset)); } @Benchmark -- GitLab From bad658e8e93c831631d41b6dbf66a0a102cd0462 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 17 Mar 2022 09:47:51 +0000 Subject: [PATCH 067/237] 8282727: Parallel: Remove PSPromotionManager::_totally_drain Reviewed-by: tschatzl, kbarrett --- src/hotspot/share/gc/parallel/psPromotionManager.cpp | 5 ++--- src/hotspot/share/gc/parallel/psPromotionManager.hpp | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.cpp b/src/hotspot/share/gc/parallel/psPromotionManager.cpp index 9c6b8acf624..652342ae31f 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.cpp @@ -180,8 +180,7 @@ PSPromotionManager::PSPromotionManager() { uint queue_size; queue_size = claimed_stack_depth()->max_elems(); - _totally_drain = (ParallelGCThreads == 1) || (GCDrainStackTargetSize == 0); - if (_totally_drain) { + if (ParallelGCThreads == 1) { _target_stack_size = 0; } else { // don't let the target stack size to be more than 1/4 of the entries @@ -227,7 +226,7 @@ void PSPromotionManager::restore_preserved_marks() { } void PSPromotionManager::drain_stacks_depth(bool totally_drain) { - totally_drain = totally_drain || _totally_drain; + totally_drain = totally_drain || (_target_stack_size == 0); PSScannerTasksQueue* const tq = claimed_stack_depth(); do { diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index bd48135f134..a1d2b38db31 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -83,7 +83,6 @@ class PSPromotionManager { PSScannerTasksQueue _claimed_stack_depth; - bool _totally_drain; uint _target_stack_size; uint _array_chunk_size; -- GitLab From 69e4e338b19c0ffd2f0881be1bbb19a5642bc4d4 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Thu, 17 Mar 2022 12:51:10 +0000 Subject: [PATCH 068/237] 8283056: show abstract machine code in hs-err for all VM crashes Reviewed-by: thartmann, dholmes --- src/hotspot/share/utilities/vmError.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 1d72092f8ae..89b4645fa45 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -910,7 +910,7 @@ void VMError::report(outputStream* st, bool _verbose) { STEP("printing code blobs if possible") - if (_verbose && _context) { + if (_verbose) { const int printed_capacity = max_error_log_print_code; address printed[printed_capacity]; printed[0] = nullptr; @@ -929,7 +929,8 @@ void VMError::report(outputStream* st, bool _verbose) { printed_len++; } } else { - frame fr = os::fetch_frame_from_context(_context); + frame fr = _context ? os::fetch_frame_from_context(_context) + : os::current_frame(); while (printed_len < limit && fr.pc() != nullptr) { if (print_code(st, _thread, fr.pc(), fr.pc() == _pc, printed, printed_capacity)) { printed_len++; -- GitLab From 0f1766dff633e55532d94069d7266a7fe625286c Mon Sep 17 00:00:00 2001 From: Julian Waters Date: Thu, 17 Mar 2022 15:30:17 +0000 Subject: [PATCH 069/237] 8283320: Error message for Windows libraries always points to --with-msvcr-dll no matter the actual file name Reviewed-by: erikj, ihse --- make/autoconf/toolchain_microsoft.m4 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/make/autoconf/toolchain_microsoft.m4 b/make/autoconf/toolchain_microsoft.m4 index 2e02c531da7..03d4ae50dfb 100644 --- a/make/autoconf/toolchain_microsoft.m4 +++ b/make/autoconf/toolchain_microsoft.m4 @@ -481,6 +481,7 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_MSVC_DLL], AC_DEFUN([TOOLCHAIN_SETUP_MSVC_DLL], [ DLL_NAME="$1" + DLL_HELP="$2" MSVC_DLL= if test "x$OPENJDK_TARGET_CPU" = xx86; then @@ -565,7 +566,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_MSVC_DLL], if test "x$MSVC_DLL" = x; then AC_MSG_CHECKING([for $DLL_NAME]) AC_MSG_RESULT([no]) - AC_MSG_ERROR([Could not find $DLL_NAME. Please specify using --with-msvcr-dll.]) + AC_MSG_ERROR([Could not find $DLL_NAME. Please specify using ${DLL_HELP}.]) fi ]) @@ -588,7 +589,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VS_RUNTIME_DLLS], fi MSVCR_DLL="$MSVC_DLL" else - TOOLCHAIN_SETUP_MSVC_DLL([${MSVCR_NAME}]) + TOOLCHAIN_SETUP_MSVC_DLL([${MSVCR_NAME}], [--with-msvcr-dll]) MSVCR_DLL="$MSVC_DLL" fi AC_SUBST(MSVCR_DLL) @@ -611,7 +612,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VS_RUNTIME_DLLS], fi MSVCP_DLL="$MSVC_DLL" else - TOOLCHAIN_SETUP_MSVC_DLL([${MSVCP_NAME}]) + TOOLCHAIN_SETUP_MSVC_DLL([${MSVCP_NAME}], [--with-msvcp-dll]) MSVCP_DLL="$MSVC_DLL" fi AC_SUBST(MSVCP_DLL) @@ -636,7 +637,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VS_RUNTIME_DLLS], fi VCRUNTIME_1_DLL="$MSVC_DLL" else - TOOLCHAIN_SETUP_MSVC_DLL([${VCRUNTIME_1_NAME}]) + TOOLCHAIN_SETUP_MSVC_DLL([${VCRUNTIME_1_NAME}], [--with-vcruntime-1-dll]) VCRUNTIME_1_DLL="$MSVC_DLL" fi fi -- GitLab From 31df6a60a8853be224d8c8b8c8ca6aea1bae2167 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Thu, 17 Mar 2022 16:17:18 +0000 Subject: [PATCH 070/237] 8283188: Build time regression caused by JDK-8278917 Reviewed-by: kbarrett, tschatzl --- src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 7 +++++++ src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 2 +- src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp | 8 -------- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index cbd13a7f282..3b6458b9f82 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -3313,6 +3313,13 @@ HeapRegion* G1CollectedHeap::alloc_highest_free_region() { return NULL; } +void G1CollectedHeap::mark_evac_failure_object(const oop obj, uint worker_id) const { + // All objects failing evacuation are live. What we'll do is + // that we'll update the prev marking info so that they are + // all under PTAMS and explicitly marked. + _cm->par_mark_in_prev_bitmap(obj); +} + // Optimized nmethod scanning class RegisterNMethodOopClosure: public OopClosure { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 6c1b60a3faa..de2442c7ce5 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1249,7 +1249,7 @@ public: inline bool is_obj_dead_full(const oop obj) const; // Mark the live object that failed evacuation in the prev bitmap. - inline void mark_evac_failure_object(const oop obj, uint worker_id) const; + void mark_evac_failure_object(const oop obj, uint worker_id) const; G1ConcurrentMark* concurrent_mark() const { return _cm; } diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 13231603533..0cd8de23e56 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -29,7 +29,6 @@ #include "gc/g1/g1BarrierSet.hpp" #include "gc/g1/g1CollectorState.hpp" -#include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1EvacFailureRegions.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1RemSet.hpp" @@ -234,13 +233,6 @@ inline bool G1CollectedHeap::is_obj_dead_full(const oop obj) const { return is_obj_dead_full(obj, heap_region_containing(obj)); } -inline void G1CollectedHeap::mark_evac_failure_object(const oop obj, uint worker_id) const { - // All objects failing evacuation are live. What we'll do is - // that we'll update the prev marking info so that they are - // all under PTAMS and explicitly marked. - _cm->par_mark_in_prev_bitmap(obj); -} - inline void G1CollectedHeap::set_humongous_reclaim_candidate(uint region, bool value) { assert(_hrm.at(region)->is_starts_humongous(), "Must start a humongous object"); _humongous_reclaim_candidates.set_candidate(region, value); -- GitLab From 5ef1990d6ce35a85c86689badba465b6c8f9f4a1 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 17 Mar 2022 16:37:20 +0000 Subject: [PATCH 071/237] 8283274: Improve @jvms usage in java.base Reviewed-by: iris --- .../share/classes/java/lang/constant/ClassDesc.java | 2 +- .../share/classes/java/lang/constant/Constable.java | 6 +++--- .../share/classes/java/lang/constant/ConstantDesc.java | 6 +++--- .../share/classes/java/lang/constant/package-info.java | 4 ++-- .../share/classes/java/lang/invoke/ConstantBootstraps.java | 4 ++-- .../share/classes/java/lang/invoke/MethodHandles.java | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java index c992bfb4380..6742b622a40 100644 --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java @@ -116,7 +116,7 @@ public sealed interface ClassDesc * followed by the field descriptor for the component type. Examples of * valid type descriptor strings include {@code "Ljava/lang/String;"}, {@code "I"}, * {@code "[I"}, {@code "V"}, {@code "[Ljava/lang/String;"}, etc. - * See JVMS 4.3.2 ("Field Descriptors") for more detail. + * See JVMS {@jvms 4.3.2 }("Field Descriptors") for more detail. * * @param descriptor a field descriptor string * @return a {@linkplain ClassDesc} describing the desired class diff --git a/src/java.base/share/classes/java/lang/constant/Constable.java b/src/java.base/share/classes/java/lang/constant/Constable.java index 33875654c05..e404dff6e4b 100644 --- a/src/java.base/share/classes/java/lang/constant/Constable.java +++ b/src/java.base/share/classes/java/lang/constant/Constable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -32,7 +32,7 @@ import java.util.Optional; /** * Represents a type which is constable. A constable type is one whose * values are constants that can be represented in the constant pool of a Java - * classfile as described in JVMS 4.4, and whose instances can describe themselves + * classfile as described in JVMS {@jvms 4.4}, and whose instances can describe themselves * nominally as a {@link ConstantDesc}. * *

    Some constable types have a native representation in the constant pool: @@ -48,7 +48,7 @@ import java.util.Optional; * Platform API are types that support Java language features such as {@link Enum}, * and runtime support classes such as {@link VarHandle}. These are typically * described with a {@link DynamicConstantDesc}, which describes dynamically - * generated constants (JVMS 4.4.10). + * generated constants (JVMS {@jvms 4.4.10}). * *

    The nominal form of an instance of a constable type is obtained via * {@link #describeConstable()}. A {@linkplain Constable} need diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java index 70c5f8fcb55..401119989a9 100644 --- a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java +++ b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -32,7 +32,7 @@ import java.lang.invoke.VarHandle.VarHandleDesc; /** * A nominal descriptor for a loadable - * constant value, as defined in JVMS 4.4. Such a descriptor can be resolved via + * constant value, as defined in JVMS {@jvms 4.4}. Such a descriptor can be resolved via * {@link ConstantDesc#resolveConstantDesc(MethodHandles.Lookup)} to yield the * constant value itself. * @@ -87,7 +87,7 @@ public sealed interface ConstantDesc String { /** * Resolves this descriptor reflectively, emulating the resolution behavior - * of JVMS 5.4.3 and the access control behavior of JVMS 5.4.4. The resolution + * of JVMS {@jvms 5.4.3} and the access control behavior of JVMS {@jvms 5.4.4}. The resolution * and access control context is provided by the {@link MethodHandles.Lookup} * parameter. No caching of the resulting value is performed. * diff --git a/src/java.base/share/classes/java/lang/constant/package-info.java b/src/java.base/share/classes/java/lang/constant/package-info.java index 9bc978e44a1..fd85dfb93d7 100644 --- a/src/java.base/share/classes/java/lang/constant/package-info.java +++ b/src/java.base/share/classes/java/lang/constant/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -55,7 +55,7 @@ * referenced in their nominal description are present and accessible. * *

    The subtypes of {@link java.lang.constant.ConstantDesc} describe various kinds - * of constant values. For each type of loadable constant pool entry defined in JVMS 4.4, + * of constant values. For each type of loadable constant pool entry defined in JVMS {@jvms 4.4}, * there is a corresponding subtype of {@link java.lang.constant.ConstantDesc}: * {@link java.lang.constant.ClassDesc}, {@link java.lang.constant.MethodTypeDesc}, * {@link java.lang.constant.DirectMethodHandleDesc}, {@link java.lang.String}, diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java index 27d74284dc6..b3858104e21 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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 @@ -96,7 +96,7 @@ public final class ConstantBootstraps { * descriptor is specified by {@code name}. * * @param lookup unused - * @param name the descriptor (JVMS 4.3) of the desired primitive type + * @param name the descriptor (JVMS {@jvms 4.3}) of the desired primitive type * @param type the required result type (must be {@code Class.class}) * @return the {@link Class} mirror * @throws IllegalArgumentException if the name is not a descriptor for a diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index dd8b01c73bc..7488db060d2 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -2759,7 +2759,7 @@ assertEquals("[x, y, z]", pb.command().toString()); /** * Looks up a class by name from the lookup context defined by this {@code Lookup} object, * as if resolved by an {@code ldc} instruction. - * Such a resolution, as specified in JVMS 5.4.3.1 section, attempts to locate and load the class, + * Such a resolution, as specified in JVMS {@jvms 5.4.3.1}, attempts to locate and load the class, * and then determines whether the class is accessible to this lookup object. *

    * The lookup context here is determined by the {@linkplain #lookupClass() lookup class}, -- GitLab From b004fb0550d8fc94e3f6412975c23c0a2ac2a42f Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 17 Mar 2022 17:50:20 +0000 Subject: [PATCH 072/237] 8282773: Refactor parsing of integer VM options Reviewed-by: dholmes, kbarrett --- src/hotspot/share/runtime/arguments.cpp | 235 ++++++----- .../share/runtime/flags/debug_globals.hpp | 25 +- test/hotspot/gtest/runtime/test_arguments.cpp | 366 +++++++++++++++++- .../gtest/runtime/test_largeOptions.cpp | 108 ------ 4 files changed, 529 insertions(+), 205 deletions(-) delete mode 100644 test/hotspot/gtest/runtime/test_largeOptions.cpp diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index a38e70b0b26..1d7fb5f983a 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -40,6 +40,7 @@ #include "logging/logStream.hpp" #include "logging/logTag.hpp" #include "memory/allocation.inline.hpp" +#include "metaprogramming/enableIf.hpp" #include "oops/instanceKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/jvmtiExport.hpp" @@ -56,6 +57,7 @@ #include "services/management.hpp" #include "services/nmtCommon.hpp" #include "utilities/align.hpp" +#include "utilities/debug.hpp" #include "utilities/defaultStream.hpp" #include "utilities/macros.hpp" #include "utilities/powerOfTwo.hpp" @@ -63,6 +65,7 @@ #if INCLUDE_JFR #include "jfr/jfr.hpp" #endif +#include #define DEFAULT_JAVA_LAUNCHER "generic" @@ -744,20 +747,84 @@ bool Arguments::verify_special_jvm_flags(bool check_globals) { } #endif -// Parses a size specification string. -bool Arguments::atojulong(const char *s, julong* result) { - julong n = 0; +template ::value), ENABLE_IF(sizeof(T) == 4)> // signed 32-bit +static bool parse_integer_impl(const char *s, char **endptr, int base, T* result) { + // Don't use strtol -- on 64-bit builds, "long" could be either 32- or 64-bits + // so the range tests could be tautological and might cause compiler warnings. + STATIC_ASSERT(sizeof(long long) >= 8); // C++ specification + errno = 0; // errno is thread safe + long long v = strtoll(s, endptr, base); + if (errno != 0 || v < min_jint || v > max_jint) { + return false; + } + *result = static_cast(v); + return true; +} - // First char must be a digit. Don't allow negative numbers or leading spaces. - if (!isdigit(*s)) { +template ::value), ENABLE_IF(sizeof(T) == 4)> // unsigned 32-bit +static bool parse_integer_impl(const char *s, char **endptr, int base, T* result) { + if (s[0] == '-') { return false; } + // Don't use strtoul -- same reason as above. + STATIC_ASSERT(sizeof(unsigned long long) >= 8); // C++ specification + errno = 0; // errno is thread safe + unsigned long long v = strtoull(s, endptr, base); + if (errno != 0 || v > max_juint) { + return false; + } + *result = static_cast(v); + return true; +} - bool is_hex = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')); +template ::value), ENABLE_IF(sizeof(T) == 8)> // signed 64-bit +static bool parse_integer_impl(const char *s, char **endptr, int base, T* result) { + errno = 0; // errno is thread safe + *result = strtoll(s, endptr, base); + return errno == 0; +} + +template ::value), ENABLE_IF(sizeof(T) == 8)> // unsigned 64-bit +static bool parse_integer_impl(const char *s, char **endptr, int base, T* result) { + if (s[0] == '-') { + return false; + } + errno = 0; // errno is thread safe + *result = strtoull(s, endptr, base); + return errno == 0; +} + +template +static bool multiply_by_1k(T& n) { + if (n >= std::numeric_limits::min() / 1024 && + n <= std::numeric_limits::max() / 1024) { + n *= 1024; + return true; + } else { + return false; + } +} + +// All of the integral types that can be used for command line options: +// int, uint, intx, uintx, uint64_t, size_t +// +// In all supported platforms, these types can be mapped to only 4 native types: +// {signed, unsigned} x {32-bit, 64-bit} +// +// We use SFINAE to pick the correct parse_integer_impl() function +template +static bool parse_integer(const char *s, T* result) { + if (!isdigit(s[0]) && s[0] != '-') { + // strtoll/strtoull may allow leading spaces. Forbid it. + return false; + } + + T n = 0; + bool is_hex = (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) || + (s[0] == '-' && s[1] == '0' && (s[2] == 'x' || s[3] == 'X')); char* remainder; - errno = 0; - n = strtoull(s, &remainder, (is_hex ? 16 : 10)); - if (errno != 0) { + + if (!parse_integer_impl(s, &remainder, (is_hex ? 16 : 10), &n)) { return false; } @@ -768,28 +835,29 @@ bool Arguments::atojulong(const char *s, julong* result) { switch (*remainder) { case 'T': case 't': - *result = n * G * K; - // Check for overflow. - if (*result/((julong)G * K) != n) return false; - return true; + if (!multiply_by_1k(n)) return false; + // fall-through case 'G': case 'g': - *result = n * G; - if (*result/G != n) return false; - return true; + if (!multiply_by_1k(n)) return false; + // fall-through case 'M': case 'm': - *result = n * M; - if (*result/M != n) return false; - return true; + if (!multiply_by_1k(n)) return false; + // fall-through case 'K': case 'k': - *result = n * K; - if (*result/K != n) return false; - return true; + if (!multiply_by_1k(n)) return false; + break; case '\0': - *result = n; - return true; + break; default: return false; } + + *result = n; + return true; +} + +bool Arguments::atojulong(const char *s, julong* result) { + return parse_integer(s, result); } Arguments::ArgsRange Arguments::check_memory_size(julong size, julong min_size, julong max_size) { @@ -838,72 +906,57 @@ static bool set_fp_numeric_flag(JVMFlag* flag, char* value, JVMFlagOrigin origin return false; } -static bool set_numeric_flag(JVMFlag* flag, char* value, JVMFlagOrigin origin) { - julong v; - int int_v; - intx intx_v; - bool is_neg = false; - +static JVMFlag::Error set_numeric_flag(JVMFlag* flag, char* value, JVMFlagOrigin origin) { if (flag == NULL) { - return false; + return JVMFlag::INVALID_FLAG; } - // Check the sign first since atojulong() parses only unsigned values. - if (*value == '-') { - if (!flag->is_intx() && !flag->is_int()) { - return false; - } - value++; - is_neg = true; - } - if (!Arguments::atojulong(value, &v)) { - return false; - } if (flag->is_int()) { - int_v = (int) v; - if (is_neg) { - int_v = -int_v; + int v; + if (parse_integer(value, &v)) { + return JVMFlagAccess::set_int(flag, &v, origin); } - if ((!is_neg && v > max_jint) || (is_neg && -(intx)v < min_jint)) { - return false; - } - return JVMFlagAccess::set_int(flag, &int_v, origin) == JVMFlag::SUCCESS; } else if (flag->is_uint()) { - if (v > max_juint) { - return false; + uint v; + if (parse_integer(value, &v)) { + return JVMFlagAccess::set_uint(flag, &v, origin); } - uint uint_v = (uint) v; - return JVMFlagAccess::set_uint(flag, &uint_v, origin) == JVMFlag::SUCCESS; } else if (flag->is_intx()) { - intx_v = (intx) v; - if (is_neg) { - if (intx_v != min_intx) { - intx_v = - intx_v; - if (intx_v > 0) { - return false; // underflow - } - } - } else { - if (intx_v < 0) { - return false; // overflow - } + intx v; + if (parse_integer(value, &v)) { + return JVMFlagAccess::set_intx(flag, &v, origin); } - return JVMFlagAccess::set_intx(flag, &intx_v, origin) == JVMFlag::SUCCESS; } else if (flag->is_uintx()) { - uintx uintx_v = (uintx) v; - return JVMFlagAccess::set_uintx(flag, &uintx_v, origin) == JVMFlag::SUCCESS; + uintx v; + if (parse_integer(value, &v)) { + return JVMFlagAccess::set_uintx(flag, &v, origin); + } } else if (flag->is_uint64_t()) { - uint64_t uint64_t_v = (uint64_t) v; - return JVMFlagAccess::set_uint64_t(flag, &uint64_t_v, origin) == JVMFlag::SUCCESS; + uint64_t v; + if (parse_integer(value, &v)) { + return JVMFlagAccess::set_uint64_t(flag, &v, origin); + } } else if (flag->is_size_t()) { - size_t size_t_v = (size_t) v; - return JVMFlagAccess::set_size_t(flag, &size_t_v, origin) == JVMFlag::SUCCESS; + size_t v; + if (parse_integer(value, &v)) { + return JVMFlagAccess::set_size_t(flag, &v, origin); + } } else if (flag->is_double()) { - double double_v = (double) v; - return JVMFlagAccess::set_double(flag, &double_v, origin) == JVMFlag::SUCCESS; - } else { - return false; + // This function parses only input strings without a decimal + // point character (.) + // If a string looks like a FP number, it would be parsed by + // set_fp_numeric_flag(). See Arguments::parse_argument(). + jlong v; + if (parse_integer(value, &v)) { + double double_v = (double) v; + if (value[0] == '-' && v == 0) { // special case: 0.0 is different than -0.0. + double_v = -0.0; + } + return JVMFlagAccess::set_double(flag, &double_v, origin); + } } + + return JVMFlag::WRONG_FORMAT; } static bool set_string_flag(JVMFlag* flag, const char* value, JVMFlagOrigin origin) { @@ -1065,7 +1118,7 @@ bool Arguments::parse_argument(const char* arg, JVMFlagOrigin origin) { return false; } JVMFlag* flag = JVMFlag::find_flag(real_name); - return set_numeric_flag(flag, value, origin); + return set_numeric_flag(flag, value, origin) == JVMFlag::SUCCESS; } return false; @@ -2082,24 +2135,16 @@ static const char* system_assertion_options[] = { bool Arguments::parse_uintx(const char* value, uintx* uintx_arg, uintx min_size) { - - // Check the sign first since atojulong() parses only unsigned values. - bool value_is_positive = !(*value == '-'); - - if (value_is_positive) { - julong n; - bool good_return = atojulong(value, &n); - if (good_return) { - bool above_minimum = n >= min_size; - bool value_is_too_large = n > max_uintx; - - if (above_minimum && !value_is_too_large) { - *uintx_arg = n; - return true; - } - } + uintx n; + if (!parse_integer(value, &n)) { + return false; + } + if (n >= min_size) { + *uintx_arg = n; + return true; + } else { + return false; } - return false; } bool Arguments::create_module_property(const char* prop_name, const char* prop_value, PropertyInternal internal) { @@ -2150,7 +2195,7 @@ Arguments::ArgsRange Arguments::parse_memory_size(const char* s, julong* long_arg, julong min_size, julong max_size) { - if (!atojulong(s, long_arg)) return arg_unreadable; + if (!parse_integer(s, long_arg)) return arg_unreadable; return check_memory_size(*long_arg, min_size, max_size); } diff --git a/src/hotspot/share/runtime/flags/debug_globals.hpp b/src/hotspot/share/runtime/flags/debug_globals.hpp index 11ea2f60104..177a4ae074b 100644 --- a/src/hotspot/share/runtime/flags/debug_globals.hpp +++ b/src/hotspot/share/runtime/flags/debug_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -62,6 +62,29 @@ product(ccstr, DummyManageableStringFlag, NULL, MANAGEABLE, \ "Dummy flag for testing string handling in WriteableFlags") \ \ + product(bool, TestFlagFor_bool, false, \ + "Used by VM internal regression tests only") \ + \ + product(int, TestFlagFor_int, 0, \ + "Used by VM internal regression tests only") \ + \ + product(uint, TestFlagFor_uint, 0, \ + "Used by VM internal regression tests only") \ + \ + product(intx, TestFlagFor_intx, 0, \ + "Used by VM internal regression tests only") \ + \ + product(uintx, TestFlagFor_uintx, 0, \ + "Used by VM internal regression tests only") \ + \ + product(uint64_t, TestFlagFor_uint64_t, 0, \ + "Used by VM internal regression tests only") \ + \ + product(size_t, TestFlagFor_size_t, 0, \ + "Used by VM internal regression tests only") \ + \ + product(double, TestFlagFor_double, 0.0, \ + "Used by VM internal regression tests only") \ // end of DEBUG_RUNTIME_FLAGS diff --git a/test/hotspot/gtest/runtime/test_arguments.cpp b/test/hotspot/gtest/runtime/test_arguments.cpp index 81bae6c468a..234bb2a015b 100644 --- a/test/hotspot/gtest/runtime/test_arguments.cpp +++ b/test/hotspot/gtest/runtime/test_arguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, 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 @@ -25,6 +25,7 @@ #include "jvm.h" #include "unittest.hpp" #include "runtime/arguments.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "utilities/align.hpp" #include "utilities/globalDefinitions.hpp" @@ -41,6 +42,16 @@ public: static jint parse_xss(const JavaVMOption* option, const char* tail, intx* out_ThreadStackSize) { return Arguments::parse_xss(option, tail, out_ThreadStackSize); } + + static bool parse_argument(const char* name, const char* value) { + char buf[1024]; + int ret = jio_snprintf(buf, sizeof(buf), "%s=%s", name, value); + if (ret > 0) { + return Arguments::parse_argument(buf, JVMFlagOrigin::COMMAND_LINE); + } else { + return false; + } + } }; TEST_F(ArgumentsTest, atojulong) { @@ -201,3 +212,356 @@ TEST_VM_F(ArgumentsTest, parse_xss) { EXPECT_EQ(parse_xss_inner(to_string(K + 1), JNI_OK), calc_expected(K + 1)); } } + +struct Dummy {}; +static Dummy BAD; + +template +struct NumericArgument { + bool bad; + const char* str; + T expected_value; + + NumericArgument(const char* s, T v) : bad(false), str(s), expected_value(v) {} + NumericArgument(const char* s, Dummy & dummy) : bad(true), str(s), expected_value(0) {} +}; + +static void check_invalid_numeric_string(JVMFlag* flag, const char** invalid_strings) { + for (uint i = 0; ; i++) { + const char* str = invalid_strings[i]; + if (str == NULL) { + return; + } + ASSERT_FALSE(ArgumentsTest::parse_argument(flag->name(), str)) + << "Invalid string '" << str + << "' parsed without error for type " << flag->type_string() << "."; + } +} + +template +void check_numeric_flag(JVMFlag* flag, T getvalue(JVMFlag* flag), + NumericArgument* valid_args, size_t n, + bool is_double = false) { + for (size_t i = 0; i < n; i++) { + NumericArgument* info = &valid_args[i]; + const char* str = info->str; + if (info->bad) { + ASSERT_FALSE(ArgumentsTest::parse_argument(flag->name(), str)) + << "Invalid string '" << str + << "' parsed without error for type " << flag->type_string() << "."; + } else { + ASSERT_TRUE(ArgumentsTest::parse_argument(flag->name(), str)) + << "Valid string '" << + str << "' did not parse for type " << flag->type_string() << "."; + ASSERT_EQ(getvalue(flag), info->expected_value) + << "Valid string '" << str + << "' did not parse to the correct value for type " + << flag->type_string() << "."; + } + } + + { + // Invalid strings for *any* type of integer VM arguments + const char* invalid_strings[] = { + "", " 1", "2 ", "3 2", + "0x", "0x0x1" "e" + "K", "M", "G", "1MB", "1KM", "AA", "0B", + "18446744073709551615K", "17179869184G", + "999999999999999999999999999999", + "0x10000000000000000", "18446744073709551616", + "-0x10000000000000000", "-18446744073709551616", + "-0x8000000000000001", "-9223372036854775809", + "0x8000000t", "0x800000000g", + "0x800000000000m", "0x800000000000000k", + "-0x8000000t", "-0x800000000g", + "-0x800000000000m", "-0x800000000000000k", + NULL, + }; + check_invalid_numeric_string(flag, invalid_strings); + } + + if (!is_double) { + const char* invalid_strings_for_integers[] = { + "1.0", "0x4.5", "0.001", "4e10", + NULL, + }; + check_invalid_numeric_string(flag, invalid_strings_for_integers); + } +} + +#define INTEGER_TEST_TABLE(f) \ + /*input i32 u32 i64 u64 */ \ + f("0", 0, 0, 0, 0 ) \ + f("-0", 0, BAD, 0, BAD ) \ + f("-1", -1, BAD, -1, BAD ) \ + f("0x1", 1, 1, 1, 1 ) \ + f("-0x1", -1, BAD, -1, BAD ) \ + f("4711", 4711, 4711, 4711, 4711 ) \ + f("1K", 1024, 1024, 1024, 1024 ) \ + f("1k", 1024, 1024, 1024, 1024 ) \ + f("2M", 2097152, 2097152, 2097152, 2097152 ) \ + f("2m", 2097152, 2097152, 2097152, 2097152 ) \ + f("1G", 1073741824, 1073741824, 1073741824, 1073741824 ) \ + f("2G", BAD, 0x80000000, 2147483648LL, 2147483648ULL ) \ + f("1T", BAD, BAD, 1099511627776LL, 1099511627776ULL ) \ + f("1t", BAD, BAD, 1099511627776LL, 1099511627776ULL ) \ + f("-1K", -1024, BAD, -1024, BAD ) \ + f("0x1K", 1024, 1024, 1024, 1024 ) \ + f("-0x1K", -1024, BAD, -1024, BAD ) \ + f("0K", 0, 0, 0, 0 ) \ + f("0x1000000k", BAD, BAD, 17179869184LL, 17179869184ULL ) \ + f("0x800000m", BAD, BAD, 0x80000000000LL, 0x80000000000ULL ) \ + f("0x8000g", BAD, BAD, 0x200000000000LL, 0x200000000000ULL ) \ + f("0x8000t", BAD, BAD, 0x80000000000000LL, 0x80000000000000ULL ) \ + f("-0x1000000k", BAD, BAD, -17179869184LL, BAD ) \ + f("-0x800000m", BAD, BAD, -0x80000000000LL, BAD ) \ + f("-0x8000g", BAD, BAD, -0x200000000000LL, BAD ) \ + f("-0x8000t", BAD, BAD, -0x80000000000000LL, BAD ) \ + f("0x7fffffff", 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff ) \ + f("0xffffffff", BAD, 0xffffffff, 0xffffffff, 0xffffffff ) \ + f("0x80000000", BAD, 0x80000000, 0x80000000, 0x80000000 ) \ + f("-0x7fffffff", -2147483647, BAD, -2147483647LL, BAD ) \ + f("-0x80000000", -2147483648, BAD, -2147483648LL, BAD ) \ + f("-0x80000001", BAD, BAD, -2147483649LL, BAD ) \ + f("0x100000000", BAD, BAD, 0x100000000LL, 0x100000000ULL ) \ + f("0xcafebabe", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0XCAFEBABE", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0XCAFEbabe", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0xcafebabe1", BAD, BAD, 0xcafebabe1, 0xcafebabe1 ) \ + f("0x7fffffffffffffff", BAD, BAD, max_jlong, 9223372036854775807ULL ) \ + f("0x8000000000000000", BAD, BAD, BAD, 9223372036854775808ULL ) \ + f("0xffffffffffffffff", BAD, BAD, BAD, max_julong ) \ + f("9223372036854775807", BAD, BAD, 9223372036854775807LL, 9223372036854775807ULL ) \ + f("9223372036854775808", BAD, BAD, BAD, 9223372036854775808ULL ) \ + f("-9223372036854775808", BAD, BAD, min_jlong, BAD ) \ + f("18446744073709551615", BAD, BAD, BAD, max_julong ) \ + \ + /* All edge cases without a k/m/g/t suffix */ \ + f("0x7ffffffe", max_jint-1, 0x7ffffffe, 0x7ffffffeLL, 0x7ffffffeULL ) \ + f("0x7fffffff", max_jint, 0x7fffffff, 0x7fffffffLL, 0x7fffffffULL ) \ + f("0x80000000", BAD, 0x80000000, 0x80000000LL, 0x80000000ULL ) \ + f("0xfffffffe", BAD, max_juint-1, 0xfffffffeLL, 0xfffffffeULL ) \ + f("0xffffffff", BAD, max_juint, 0xffffffffLL, 0xffffffffULL ) \ + f("0x100000000", BAD, BAD, 0x100000000LL, 0x100000000ULL ) \ + f("-0x7fffffff", min_jint+1, BAD, -0x7fffffffLL, BAD ) \ + f("-0x80000000", min_jint, BAD, -0x80000000LL, BAD ) \ + f("-0x80000001", BAD, BAD, -0x80000001LL, BAD ) \ + \ + f("0x7ffffffffffffffe", BAD, BAD, max_jlong-1, 0x7ffffffffffffffeULL ) \ + f("0x7fffffffffffffff", BAD, BAD, max_jlong, 0x7fffffffffffffffULL ) \ + f("0x8000000000000000", BAD, BAD, BAD, 0x8000000000000000ULL ) \ + f("0xfffffffffffffffe", BAD, BAD, BAD, max_julong-1 ) \ + f("0xffffffffffffffff", BAD, BAD, BAD, max_julong ) \ + f("0x10000000000000000", BAD, BAD, BAD, BAD ) \ + f("-0x7fffffffffffffff", BAD, BAD, min_jlong+1, BAD ) \ + f("-0x8000000000000000", BAD, BAD, min_jlong, BAD ) \ + f("-0x8000000000000001", BAD, BAD, BAD, BAD ) \ + \ + /* edge cases for suffix: K */ \ + f("0x1ffffek", 0x1ffffe * k, 0x1ffffeU * k,0x1ffffeLL * k, 0x1ffffeULL * k ) \ + f("0x1fffffk", 0x1fffff * k, 0x1fffffU * k,0x1fffffLL * k, 0x1fffffULL * k ) \ + f("0x200000k", BAD, 0x200000U * k,0x200000LL * k, 0x200000ULL * k ) \ + f("0x3ffffek", BAD, 0x3ffffeU * k,0x3ffffeLL * k, 0x3ffffeULL * k ) \ + f("0x3fffffk", BAD, 0x3fffffU * k,0x3fffffLL * k, 0x3fffffULL * k ) \ + f("0x400000k", BAD, BAD, 0x400000LL * k, 0x400000ULL * k ) \ + f("-0x1fffffk", -0x1fffff * k, BAD, -0x1fffffLL * k, BAD ) \ + f("-0x200000k", -0x200000 * k, BAD, -0x200000LL * k, BAD ) \ + f("-0x200001k", BAD, BAD, -0x200001LL * k, BAD ) \ + \ + f("0x1ffffffffffffek", BAD, BAD, 0x1ffffffffffffeLL * k, 0x1ffffffffffffeULL * k ) \ + f("0x1fffffffffffffk", BAD, BAD, 0x1fffffffffffffLL * k, 0x1fffffffffffffULL * k ) \ + f("0x20000000000000k", BAD, BAD, BAD, 0x20000000000000ULL * k ) \ + f("0x3ffffffffffffek", BAD, BAD, BAD, 0x3ffffffffffffeULL * k ) \ + f("0x3fffffffffffffk", BAD, BAD, BAD, 0x3fffffffffffffULL * k ) \ + f("0x40000000000000k", BAD, BAD, BAD, BAD ) \ + f("-0x1fffffffffffffk", BAD, BAD, -0x1fffffffffffffLL * k, BAD ) \ + f("-0x20000000000000k", BAD, BAD, -0x20000000000000LL * k, BAD ) \ + f("-0x20000000000001k", BAD, BAD, BAD, BAD ) \ + \ + /* edge cases for suffix: M */ \ + f("0x7fem", 0x7fe * m, 0x7feU * m, 0x7feLL * m, 0x7feULL * m ) \ + f("0x7ffm", 0x7ff * m, 0x7ffU * m, 0x7ffLL * m, 0x7ffULL * m ) \ + f("0x800m", BAD, 0x800U * m, 0x800LL * m, 0x800ULL * m ) \ + f("0xffem", BAD, 0xffeU * m, 0xffeLL * m, 0xffeULL * m ) \ + f("0xfffm", BAD, 0xfffU * m, 0xfffLL * m, 0xfffULL * m ) \ + f("0x1000m", BAD, BAD, 0x1000LL * m, 0x1000ULL * m ) \ + f("-0x7ffm", -0x7ff * m, BAD, -0x7ffLL * m, BAD ) \ + f("-0x800m", -0x800 * m, BAD, -0x800LL * m, BAD ) \ + f("-0x801m", BAD, BAD, -0x801LL * m, BAD ) \ + \ + f("0x7fffffffffem", BAD, BAD, 0x7fffffffffeLL * m, 0x7fffffffffeULL * m ) \ + f("0x7ffffffffffm", BAD, BAD, 0x7ffffffffffLL * m, 0x7ffffffffffULL * m ) \ + f("0x80000000000m", BAD, BAD, BAD, 0x80000000000ULL * m ) \ + f("0xffffffffffem", BAD, BAD, BAD, 0xffffffffffeULL * m ) \ + f("0xfffffffffffm", BAD, BAD, BAD, 0xfffffffffffULL * m ) \ + f("0x100000000000m", BAD, BAD, BAD, BAD ) \ + f("-0x7ffffffffffm", BAD, BAD, -0x7ffffffffffLL * m, BAD ) \ + f("-0x80000000000m", BAD, BAD, -0x80000000000LL * m, BAD ) \ + f("-0x80000000001m", BAD, BAD, BAD, BAD ) \ + \ + /* edge cases for suffix: G */ \ + f("0x0g", 0x0 * g, 0x0U * g, 0x0LL * g, 0x0ULL * g ) \ + f("0x1g", 0x1 * g, 0x1U * g, 0x1LL * g, 0x1ULL * g ) \ + f("0x2g", BAD, 0x2U * g, 0x2LL * g, 0x2ULL * g ) \ + f("0x3g", BAD, 0x3U * g, 0x3LL * g, 0x3ULL * g ) \ + f("0x4g", BAD, BAD, 0x4LL * g, 0x4ULL * g ) \ + f("-0x1g", -0x1 * g, BAD, -0x1LL * g, BAD ) \ + f("-0x2g", -0x2 * g, BAD, -0x2LL * g, BAD ) \ + f("-0x3g", BAD, BAD, -0x3LL * g, BAD ) \ + \ + f("0x1fffffffeg", BAD, BAD, 0x1fffffffeLL * g, 0x1fffffffeULL * g ) \ + f("0x1ffffffffg", BAD, BAD, 0x1ffffffffLL * g, 0x1ffffffffULL * g ) \ + f("0x200000000g", BAD, BAD, BAD, 0x200000000ULL * g ) \ + f("0x3fffffffeg", BAD, BAD, BAD, 0x3fffffffeULL * g ) \ + f("0x3ffffffffg", BAD, BAD, BAD, 0x3ffffffffULL * g ) \ + f("0x400000000g", BAD, BAD, BAD, BAD ) \ + f("-0x1ffffffffg", BAD, BAD, -0x1ffffffffLL * g, BAD ) \ + f("-0x200000000g", BAD, BAD, -0x200000000LL * g, BAD ) \ + f("-0x200000001g", BAD, BAD, BAD, BAD ) \ + \ + /* edge cases for suffix: T */ \ + f("0x7ffffet", BAD, BAD, 0x7ffffeLL * t, 0x7ffffeULL * t ) \ + f("0x7ffffft", BAD, BAD, 0x7fffffLL * t, 0x7fffffULL * t ) \ + f("0x800000t", BAD, BAD, BAD, 0x800000ULL * t ) \ + f("0xfffffet", BAD, BAD, BAD, 0xfffffeULL * t ) \ + f("0xfffffft", BAD, BAD, BAD, 0xffffffULL * t ) \ + f("0x1000000t", BAD, BAD, BAD, BAD ) \ + f("-0x7ffffft", BAD, BAD, -0x7fffffLL * t, BAD ) \ + f("-0x800000t", BAD, BAD, -0x800000LL * t, BAD ) \ + f("-0x800001t", BAD, BAD, BAD, BAD ) + +#define INTEGER_TEST_i32(s, i32, u32, i64, u64) NumericArgument(s, i32), +#define INTEGER_TEST_u32(s, i32, u32, i64, u64) NumericArgument(s, u32), +#define INTEGER_TEST_i64(s, i32, u32, i64, u64) NumericArgument(s, i64), +#define INTEGER_TEST_u64(s, i32, u32, i64, u64) NumericArgument(s, u64), + +// signed 32-bit +template ::value), ENABLE_IF(sizeof(T) == 4)> +void check_flag(const char* f, T getvalue(JVMFlag* flag)) { + JVMFlag* flag = JVMFlag::find_flag(f); + if (flag == NULL) { // not available in product builds + return; + } + + T k = static_cast(K); + T m = static_cast(M); + T g = static_cast(G); + NumericArgument valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_i32) }; + check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings)); +} + +// unsigned 32-bit +template ::value), ENABLE_IF(sizeof(T) == 4)> +void check_flag(const char* f, T getvalue(JVMFlag* flag)) { + JVMFlag* flag = JVMFlag::find_flag(f); + if (flag == NULL) { // not available in product builds + return; + } + + T k = static_cast(K); + T m = static_cast(M); + T g = static_cast(G); + NumericArgument valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_u32) }; + check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings)); +} + +// signed 64-bit +template ::value), ENABLE_IF(sizeof(T) == 8)> +void check_flag(const char* f, T getvalue(JVMFlag* flag)) { + JVMFlag* flag = JVMFlag::find_flag(f); + if (flag == NULL) { // not available in product builds + return; + } + + T k = static_cast(K); + T m = static_cast(M); + T g = static_cast(G); + T t = static_cast(G) * k; + NumericArgument valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_i64) }; + check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings)); +} + +// unsigned 64-bit +template ::value), ENABLE_IF(sizeof(T) == 8)> +void check_flag(const char* f, T getvalue(JVMFlag* flag)) { + JVMFlag* flag = JVMFlag::find_flag(f); + if (flag == NULL) { // not available in product builds + return; + } + + T k = static_cast(K); + T m = static_cast(M); + T g = static_cast(G); + T t = static_cast(G) * k; + NumericArgument valid_strings[] = { INTEGER_TEST_TABLE(INTEGER_TEST_u64) }; + check_numeric_flag(flag, getvalue, valid_strings, ARRAY_SIZE(valid_strings)); +} + +// Testing the parsing of -XX:= +// +// All of the integral types that can be used for command line options: +// int, uint, intx, uintx, uint64_t, size_t +// +// In all supported platforms, these types can be mapped to only 4 native types: +// {signed, unsigned} x {32-bit, 64-bit} +// +// We use SFINAE to pick the correct column in the INTEGER_TEST_TABLE for each type. + +TEST_VM_F(ArgumentsTest, set_numeric_flag_int) { + check_flag("TestFlagFor_int", [] (JVMFlag* flag) { + return flag->get_int(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_uint) { + check_flag("TestFlagFor_uint", [] (JVMFlag* flag) { + return flag->get_uint(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_intx) { + check_flag("TestFlagFor_intx", [] (JVMFlag* flag) { + return flag->get_intx(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_uintx) { + check_flag("TestFlagFor_uintx", [] (JVMFlag* flag) { + return flag->get_uintx(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_uint64_t) { + check_flag("TestFlagFor_uint64_t", [] (JVMFlag* flag) { + return flag->get_uint64_t(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_size_t) { + check_flag("TestFlagFor_size_t", [] (JVMFlag* flag) { + return flag->get_size_t(); + }); +} + +TEST_VM_F(ArgumentsTest, set_numeric_flag_double) { + JVMFlag* flag = JVMFlag::find_flag("TestFlagFor_double"); + if (flag == NULL) { // not available in product builds + return; + } + + // TODO -- JDK-8282774 + // Need to add more test input that have a fractional part like "4.2". + NumericArgument valid_strings[] = { + NumericArgument("0", 0.0), + NumericArgument("1", 1.0), + NumericArgument("-0", -0.0), + NumericArgument("-1", -1.0), + }; + + auto getvalue = [] (JVMFlag* flag) { + return flag->get_double(); + }; + + check_numeric_flag(flag, getvalue, valid_strings, + ARRAY_SIZE(valid_strings), /*is_double=*/true); +} diff --git a/test/hotspot/gtest/runtime/test_largeOptions.cpp b/test/hotspot/gtest/runtime/test_largeOptions.cpp deleted file mode 100644 index a8d5af24915..00000000000 --- a/test/hotspot/gtest/runtime/test_largeOptions.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2022, 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. - */ - -#include "precompiled.hpp" -#include "compiler/compiler_globals.hpp" -#include "runtime/arguments.hpp" -#include "runtime/flags/jvmFlag.hpp" -#include "runtime/globals.hpp" -#include "unittest.hpp" - -class LargeOptionsTest : public ::testing::Test { -public: - static bool test_option_value(const char* option, intx value) { - char buffer[100]; - UnlockDiagnosticVMOptions = true; - os::snprintf(buffer, 100, "%s=" INTX_FORMAT, option, value); - return Arguments::parse_argument(buffer, JVMFlagOrigin::COMMAND_LINE); - } - - static bool test_option_value(const char* option) { - UnlockDiagnosticVMOptions = true; - return Arguments::parse_argument(option, JVMFlagOrigin::COMMAND_LINE); - } -}; - -#ifdef _LP64 -// CompilerDirectivesLimit is a diagnostic int option. -TEST_VM(LARGE_OPTION, large_ints) { - for (intx x = max_jint - 1; x <= (intx)max_jint + 1; x++) { - bool result = LargeOptionsTest::test_option_value("CompilerDirectivesLimit", x); - if (x > max_jint) { - ASSERT_FALSE(result); - } else { - ASSERT_TRUE(result); - ASSERT_EQ(CompilerDirectivesLimit, x); - } - } -} - -TEST_VM(LARGE_OPTION, small_ints) { - for (intx x = min_jint + 1; x >= (intx)min_jint - 1; x--) { - bool result = LargeOptionsTest::test_option_value("CompilerDirectivesLimit", x); - if (x < min_jint) { - ASSERT_FALSE(result); - } else { - ASSERT_TRUE(result); - ASSERT_EQ(CompilerDirectivesLimit, x); - } - } -} - -TEST_VM(LARGE_OPTION, large_int_overflow) { // Test 0x100000000 - ASSERT_FALSE(LargeOptionsTest::test_option_value("CompilerDirectivesLimit", 4294967296)); -} -#endif - -// HandshakeTimeout is a diagnostic uint option. -TEST_VM(LARGE_OPTION, large_uints) { - for (uintx x = max_juint - 1; x <= (uintx)max_juint + 1; x++) { - bool result = LargeOptionsTest::test_option_value("HandshakeTimeout", x); - if (x <= max_juint) { - ASSERT_TRUE(result); - ASSERT_EQ(HandshakeTimeout, x); - } else { - ASSERT_FALSE(result); - } - } -} - -#ifdef _LP64 -// MaxJNILocalCapacity is an intx option. -TEST_VM(LARGE_OPTION, large_intxs) { - // max_intx + 1 equals min_intx! - for (julong x = max_intx - 1; x <= (julong)max_intx + 1; x++) { - ASSERT_TRUE(LargeOptionsTest::test_option_value("MaxJNILocalCapacity", x)); - ASSERT_EQ((julong)MaxJNILocalCapacity, x); - } -} - -TEST_VM(LARGE_OPTION, small_intxs) { - ASSERT_TRUE(LargeOptionsTest::test_option_value("MaxJNILocalCapacity", min_intx + 1)); - ASSERT_EQ(MaxJNILocalCapacity, -9223372036854775807); - ASSERT_TRUE(LargeOptionsTest::test_option_value("MaxJNILocalCapacity", min_intx)); - ASSERT_EQ(MaxJNILocalCapacity, min_intx); - // Test value that's less than min_intx (-0x8000000000000001). - ASSERT_FALSE(LargeOptionsTest::test_option_value("MaxJNILocalCapacity=-9223372036854775809")); -} -#endif -- GitLab From 002e3667443d94e2303c875daf72cf1ccbbb0099 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Thu, 17 Mar 2022 21:15:36 +0000 Subject: [PATCH 073/237] 8283325: US_ASCII decoder relies on String.decodeASCII being exhaustive Reviewed-by: rriggs, dcubed --- .../share/classes/java/lang/String.java | 6 ++ .../charset/CharsetDecoder/ASCIIDecode.java | 55 +++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 test/jdk/java/nio/charset/CharsetDecoder/ASCIIDecode.java diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 3c3a2ba28f0..009a61a9ba3 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -1032,6 +1032,12 @@ public final class String /* package-private */ static int decodeASCII(byte[] sa, int sp, char[] da, int dp, int len) { int count = StringCoding.countPositives(sa, sp, len); + while (count < len) { + if (sa[sp + count] < 0) { + break; + } + count++; + } StringLatin1.inflate(sa, sp, da, dp, count); return count; } diff --git a/test/jdk/java/nio/charset/CharsetDecoder/ASCIIDecode.java b/test/jdk/java/nio/charset/CharsetDecoder/ASCIIDecode.java new file mode 100644 index 00000000000..330c2c49a07 --- /dev/null +++ b/test/jdk/java/nio/charset/CharsetDecoder/ASCIIDecode.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022, 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 8283325 + * @summary Ensure that decoding to ASCII from a stream with a non-ASCII + * character correctly decodes up until the byte in error. + */ + +import java.nio.*; +import java.nio.charset.*; +import java.util.Arrays; + +public class ASCIIDecode { + + public static void main(String[] args) throws Exception { + final Charset ascii = Charset.forName("US-ASCII"); + final CharsetDecoder decoder = ascii.newDecoder(); + + byte[] ba = new byte[] { 0x60, 0x60, 0x60, (byte)0xFF }; + + // Repeat enough times to test that interpreter and JIT:ed versions + // behave the same (without the patch for 8283325 this fails within + // 50 000 iterations on the system used for verification) + for (int i = 0; i < 100_000; i++) { + ByteBuffer bb = ByteBuffer.wrap(ba); + char[] ca = new char[4]; + CharBuffer cb = CharBuffer.wrap(ca); + CoderResult buf = decoder.decode(bb, cb, true); + if (ca[0] != 0x60 || ca[1] != 0x60 || ca[2] != 0x60) { + throw new RuntimeException("Unexpected output on iteration " + i); + } + } + } +} -- GitLab From d83cee98b5e6628f19f1b5dea11038079dd0c758 Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Fri, 18 Mar 2022 03:14:32 +0000 Subject: [PATCH 074/237] 8282407: Missing ')' in MacResources.properties Reviewed-by: naoto --- .../jdk/jpackage/internal/resources/MacResources.properties | 4 ++-- .../jpackage/internal/resources/MacResources_ja.properties | 4 ++-- .../jpackage/internal/resources/MacResources_zh_CN.properties | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index 23a4f9d0437..25a9facea5f 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2022, 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 @@ -80,7 +80,7 @@ message.building-dmg=Building DMG package for {0}. message.running-script=Running shell script on application image [{0}]. message.preparing-dmg-setup=Preparing dmg setup: {0}. message.creating-dmg-file=Creating DMG file: {0}. -message.dmg-cannot-be-overwritten=Dmg file exists ({0} and can not be removed. +message.dmg-cannot-be-overwritten=Dmg file exists [{0}] and can not be removed. message.output-to-location=Result DMG installer for {0}: {1}. message.building-pkg=Building PKG package for {0}. message.preparing-scripts=Preparing package scripts. diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties index d9da226ec92..291130fb237 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2022, 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 @@ -79,7 +79,7 @@ message.building-dmg={0}\u306EDMG\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u4F5C\u621 message.running-script=\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u30FB\u30A4\u30E1\u30FC\u30B8[{0}]\u3067\u30B7\u30A7\u30EB\u30FB\u30B9\u30AF\u30EA\u30D7\u30C8\u3092\u5B9F\u884C\u3057\u3066\u3044\u307E\u3059\u3002 message.preparing-dmg-setup=dmg\u306E\u8A2D\u5B9A\u3092\u6E96\u5099\u3057\u3066\u3044\u307E\u3059: {0} message.creating-dmg-file=DMG\u30D5\u30A1\u30A4\u30EB\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059: {0} -message.dmg-cannot-be-overwritten=Dmg\u30D5\u30A1\u30A4\u30EB\u306F\u5B58\u5728\u3057({0}\u3001\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002 +message.dmg-cannot-be-overwritten=Dmg\u30D5\u30A1\u30A4\u30EB\u306F\u5B58\u5728\u3057[{0}]\u3001\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002 message.output-to-location={0}\u306E\u7D50\u679C\u306EDMG\u30A4\u30F3\u30B9\u30C8\u30FC\u30E9: {1} message.building-pkg={0}\u306EPKG\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u4F5C\u6210\u3057\u3066\u3044\u307E\u3059 message.preparing-scripts=\u30D1\u30C3\u30B1\u30FC\u30B8\u30FB\u30B9\u30AF\u30EA\u30D7\u30C8\u3092\u6E96\u5099\u3057\u3066\u3044\u307E\u3059 diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties index d6f47a7bc85..ecf9e8796d5 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2022, 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 @@ -79,7 +79,7 @@ message.building-dmg=\u6B63\u5728\u4E3A {0} \u6784\u5EFA DMG \u7A0B\u5E8F\u5305\ message.running-script=\u6B63\u5728\u5E94\u7528\u7A0B\u5E8F\u6620\u50CF [{0}] \u4E0A\u8FD0\u884C shell \u811A\u672C\u3002 message.preparing-dmg-setup=\u6B63\u5728\u51C6\u5907 dmg \u8BBE\u7F6E: {0}\u3002 message.creating-dmg-file=\u6B63\u5728\u521B\u5EFA DMG \u6587\u4EF6: {0}\u3002 -message.dmg-cannot-be-overwritten=Dmg \u6587\u4EF6\u5DF2\u5B58\u5728 ({0}) \u4E14\u65E0\u6CD5\u5220\u9664\u3002 +message.dmg-cannot-be-overwritten=Dmg \u6587\u4EF6\u5DF2\u5B58\u5728 [{0}] \u4E14\u65E0\u6CD5\u5220\u9664\u3002 message.output-to-location=\u4E3A {0} \u751F\u6210\u7684 DMG \u5B89\u88C5\u7A0B\u5E8F: {1}\u3002 message.building-pkg=\u6B63\u5728\u4E3A {0} \u6784\u5EFA PKG \u7A0B\u5E8F\u5305\u3002 message.preparing-scripts=\u6B63\u5728\u51C6\u5907\u7A0B\u5E8F\u5305\u811A\u672C\u3002 -- GitLab From cab4ff64541393a974ea91e35167668ef0036804 Mon Sep 17 00:00:00 2001 From: Tyler Steele Date: Fri, 18 Mar 2022 07:02:26 +0000 Subject: [PATCH 075/237] 8283225: ClassLoader.c produces incorrect OutOfMemory Exception when length is 0 (aix) Reviewed-by: stuefe, rriggs, dholmes --- src/java.base/share/native/libjava/ClassLoader.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/java.base/share/native/libjava/ClassLoader.c b/src/java.base/share/native/libjava/ClassLoader.c index bbdff87b0b3..da34a7b438b 100644 --- a/src/java.base/share/native/libjava/ClassLoader.c +++ b/src/java.base/share/native/libjava/ClassLoader.c @@ -99,7 +99,12 @@ Java_java_lang_ClassLoader_defineClass1(JNIEnv *env, return 0; } + // On AIX malloc(0) returns NULL which looks like an out-of-memory condition; so adjust it to malloc(1) + #ifdef _AIX + body = (jbyte *)malloc(length == 0 ? 1 : length); + #else body = (jbyte *)malloc(length); + #endif if (body == 0) { JNU_ThrowOutOfMemoryError(env, 0); @@ -239,7 +244,13 @@ Java_java_lang_ClassLoader_defineClass0(JNIEnv *env, return 0; } + // On AIX malloc(0) returns NULL which looks like an out-of-memory condition; so adjust it to malloc(1) + #ifdef _AIX + body = (jbyte *)malloc(length == 0 ? 1 : length); + #else body = (jbyte *)malloc(length); + #endif + if (body == 0) { JNU_ThrowOutOfMemoryError(env, 0); return 0; -- GitLab From b96cb048f1a7f3ae6e745b245f2b04c64ebb911e Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Fri, 18 Mar 2022 07:58:58 +0000 Subject: [PATCH 076/237] 8283353: compiler/c2/cr6865031/Test.java and compiler/runtime/Test6826736.java fails on x86_32 Reviewed-by: chagedorn --- test/hotspot/jtreg/compiler/c2/cr6865031/Test.java | 2 ++ test/hotspot/jtreg/compiler/runtime/Test6826736.java | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java b/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java index 71689eaca18..af23628577b 100644 --- a/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java +++ b/test/hotspot/jtreg/compiler/c2/cr6865031/Test.java @@ -1,5 +1,6 @@ /* * Copyright 2009 Goldman Sachs International. All Rights Reserved. + * Copyright (C) 2022 THL A29 Limited, a Tencent company. 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 @@ -27,6 +28,7 @@ * @bug 6865031 * @summary Application gives bad result (throws bad exception) with compressed oops * + * @requires vm.bits == 64 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+UseCompressedOops * -XX:HeapBaseMinAddress=32g -XX:-LoopUnswitching * -XX:CompileCommand=inline,compiler.c2.cr6865031.AbstractMemoryEfficientList::equals diff --git a/test/hotspot/jtreg/compiler/runtime/Test6826736.java b/test/hotspot/jtreg/compiler/runtime/Test6826736.java index 2f078506e55..0b028947f77 100644 --- a/test/hotspot/jtreg/compiler/runtime/Test6826736.java +++ b/test/hotspot/jtreg/compiler/runtime/Test6826736.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2022, 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 @@ -26,6 +26,7 @@ * @bug 6826736 * @summary CMS: core dump with -XX:+UseCompressedOops * + * @requires vm.bits == 64 * @run main/othervm/timeout=600 -XX:+IgnoreUnrecognizedVMOptions -Xbatch * -XX:+ScavengeALot -XX:+UseCompressedOops -XX:HeapBaseMinAddress=32g * -XX:CompileThreshold=100 -XX:-BlockLayoutRotateLoops -- GitLab From 4b5079b9836c1cc881f571d060b310f58c8a860c Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 18 Mar 2022 13:18:38 +0000 Subject: [PATCH 077/237] 8283202: Potential off-read when checking JFR's status in awaitFinished Reviewed-by: mgronlun --- .../jfr/internal/consumer/ChunkHeader.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java index 54687725b74..550878888cd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java @@ -109,14 +109,19 @@ public final class ChunkHeader { input.position(absoluteEventStart); } + private byte readFileState() throws IOException { + byte fs; + input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); + while ((fs = input.readPhysicalByte()) == UPDATING_CHUNK_HEADER) { + Utils.takeNap(1); + input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); + } + return fs; + } + public void refresh() throws IOException { while (true) { - byte fileState1; - input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); - while ((fileState1 = input.readPhysicalByte()) == UPDATING_CHUNK_HEADER) { - Utils.takeNap(1); - input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); - } + byte fileState1 = readFileState(); input.positionPhysical(absoluteChunkStart + CHUNK_SIZE_POSITION); long chunkSize = input.readPhysicalLong(); long constantPoolPosition = input.readPhysicalLong(); @@ -169,10 +174,9 @@ public final class ChunkHeader { } long pos = input.position(); try { - input.positionPhysical(absoluteChunkStart + FILE_STATE_POSITION); while (true) { - byte filestate = input.readPhysicalByte(); - if (filestate == 0) { + byte fileState = readFileState(); + if (fileState == 0) { finished = true; return; } -- GitLab From c72bcfc1b230d22137ac7f683cf46dc70b6e3d16 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 18 Mar 2022 13:27:49 +0000 Subject: [PATCH 078/237] 8283289: JFR: Rename CheckPoint Reviewed-by: mgronlun --- .../jfr/internal/consumer/ChunkParser.java | 12 ++++---- .../consumer/filter/CheckPointEvent.java | 14 ++++----- .../consumer/filter/CheckPointPool.java | 4 +-- .../internal/consumer/filter/ChunkWriter.java | 30 +++++++++---------- .../jdk/jfr/internal/tool/Summary.java | 2 +- .../jdk/management/jfr/DiskRepository.java | 8 ++--- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java index 8a392d985c5..9d88adcf478 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java @@ -41,7 +41,7 @@ import jdk.jfr.internal.LongMap; import jdk.jfr.internal.MetadataDescriptor; import jdk.jfr.internal.Type; import jdk.jfr.internal.Utils; -import jdk.jfr.internal.consumer.filter.CheckPointEvent; +import jdk.jfr.internal.consumer.filter.CheckpointEvent; import jdk.jfr.internal.consumer.filter.ChunkWriter; /** @@ -77,7 +77,7 @@ public final class ChunkParser { } } - private enum CheckPointType { + private enum CheckpointType { // Checkpoint that finishes a flush segment FLUSH(1), // Checkpoint contains chunk header information in the first pool @@ -87,7 +87,7 @@ public final class ChunkParser { // Checkpoint contains thread related information THREAD(8); private final int mask; - private CheckPointType(int mask) { + private CheckpointType(int mask) { this.mask = mask; } @@ -267,7 +267,7 @@ public final class ChunkParser { // Not accepted by filter } else { if (typeId == 1) { // checkpoint event - if (CheckPointType.FLUSH.is(parseCheckpointType())) { + if (CheckpointType.FLUSH.is(parseCheckpointType())) { input.position(pos + size); return FLUSH_MARKER; } @@ -317,9 +317,9 @@ public final class ChunkParser { long delta = -1; boolean logTrace = Logger.shouldLog(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE); while (thisCP != abortCP && delta != 0) { - CheckPointEvent cp = null; + CheckpointEvent cp = null; if (configuration.chunkWriter != null) { - cp = configuration.chunkWriter.newCheckPointEvent(thisCP); + cp = configuration.chunkWriter.newCheckpointEvent(thisCP); } input.position(thisCP); lastCP = thisCP; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointEvent.java index a2c1723a1e3..72f40c0e7a7 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointEvent.java @@ -35,12 +35,12 @@ import jdk.jfr.internal.Type; *

    * All positional values are relative to file start, not the chunk. */ -public final class CheckPointEvent { +public final class CheckpointEvent { private final ChunkWriter chunkWriter; - private final LinkedHashMap pools = new LinkedHashMap<>(); + private final LinkedHashMap pools = new LinkedHashMap<>(); private final long startPosition; - public CheckPointEvent(ChunkWriter chunkWriter, long startPosition) { + public CheckpointEvent(ChunkWriter chunkWriter, long startPosition) { this.chunkWriter = chunkWriter; this.startPosition = startPosition; } @@ -48,7 +48,7 @@ public final class CheckPointEvent { public PoolEntry addEntry(Type type, long id, long startPosition, long endPosition, Object references) { long typeId = type.getId(); PoolEntry pe = new PoolEntry(startPosition, endPosition, type, id, references); - var cpp = pools.computeIfAbsent(typeId, k -> new CheckPointPool(typeId)); + var cpp = pools.computeIfAbsent(typeId, k -> new CheckpointPool(typeId)); cpp.add(pe); chunkWriter.getPool(type).add(id, pe); return pe; @@ -56,7 +56,7 @@ public final class CheckPointEvent { public long touchedPools() { int count = 0; - for (CheckPointPool cpp : pools.values()) { + for (CheckpointPool cpp : pools.values()) { if (cpp.isTouched()) { count++; } @@ -64,7 +64,7 @@ public final class CheckPointEvent { return count; } - public Collection getPools() { + public Collection getPools() { return pools.values(); } @@ -74,7 +74,7 @@ public final class CheckPointEvent { public String toString() { StringBuilder sb = new StringBuilder(); - for (CheckPointPool p : pools.values()) { + for (CheckpointPool p : pools.values()) { for (var e : p.getEntries()) { if (e.isTouched()) { sb.append(e.getType().getName() + " " + e.getId() + "\n"); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointPool.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointPool.java index 3b0ca0f58eb..d4b1ce926be 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointPool.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointPool.java @@ -29,11 +29,11 @@ import java.util.List; /** * Represents a constant pool in a checkpoint, both entries and type id */ -final class CheckPointPool { +final class CheckpointPool { private final List entries = new ArrayList<>(); private final long typeId; - public CheckPointPool(long typeId) { + public CheckpointPool(long typeId) { this.typeId = typeId; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java index 1a1cc236359..8c22432512a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/ChunkWriter.java @@ -51,7 +51,7 @@ import jdk.jfr.internal.consumer.Reference; */ public final class ChunkWriter implements Closeable { private LongMap pools = new LongMap<>(); - private final Deque checkPoints = new ArrayDeque<>(); + private final Deque checkpoints = new ArrayDeque<>(); private final Path destination; private final RecordingInput input; private final RecordingOutput output; @@ -59,7 +59,7 @@ public final class ChunkWriter implements Closeable { private long chunkStartPosition; private boolean chunkComplete; - private long lastCheckPoint; + private long lastCheckpoint; public ChunkWriter(Path source, Path destination, Predicate filter) throws IOException { this.destination = destination; @@ -78,9 +78,9 @@ public final class ChunkWriter implements Closeable { return pool; } - public CheckPointEvent newCheckPointEvent(long startPosition) { - CheckPointEvent event = new CheckPointEvent(this, startPosition); - checkPoints.add(event); + public CheckpointEvent newCheckpointEvent(long startPosition) { + CheckpointEvent event = new CheckpointEvent(this, startPosition); + checkpoints.add(event); return event; } @@ -120,16 +120,16 @@ public final class ChunkWriter implements Closeable { // Write check point events before a position private void writeCheckpointEvents(long before) throws IOException { - CheckPointEvent cp = checkPoints.peek(); + CheckpointEvent cp = checkpoints.peek(); while (cp != null && cp.getStartPosition() < before) { - checkPoints.poll(); + checkpoints.poll(); long delta = 0; - if (lastCheckPoint != 0) { - delta = lastCheckPoint - output.position(); + if (lastCheckpoint != 0) { + delta = lastCheckpoint - output.position(); } - lastCheckPoint = output.position(); + lastCheckpoint = output.position(); write(cp, delta); - cp = checkPoints.peek(); + cp = checkpoints.peek(); } } @@ -174,10 +174,10 @@ public final class ChunkWriter implements Closeable { writeCheckpointEvents(Long.MAX_VALUE); long metadata = output.position(); writeMetadataEvent(header); - updateHeader(output.position(), lastCheckPoint, metadata); + updateHeader(output.position(), lastCheckpoint, metadata); pools = new LongMap<>(); chunkComplete = true; - lastCheckPoint = 0; + lastCheckpoint = 0; } private void writeMetadataEvent(ChunkHeader header) throws IOException { @@ -190,7 +190,7 @@ public final class ChunkWriter implements Closeable { } } - private void write(CheckPointEvent event, long delta) throws IOException { + private void write(CheckpointEvent event, long delta) throws IOException { input.position(event.getStartPosition()); long startPosition = output.position(); @@ -205,7 +205,7 @@ public final class ChunkWriter implements Closeable { // Write even if touched pools are zero, checkpoint works as sync point output.writeLong(event.touchedPools()); // Pool count - for (CheckPointPool pool : event.getPools()) { + for (CheckpointPool pool : event.getPools()) { if (pool.isTouched()) { output.writeLong(pool.getTypeId()); output.writeLong(pool.getTouchedCount()); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java index 767ccf63507..850e995acf3 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Summary.java @@ -100,7 +100,7 @@ final class Summary extends Command { } HashMap stats = new HashMap<>(); stats.put(0L, new Statistics(eventPrefix + "Metadata")); - stats.put(1L, new Statistics(eventPrefix + "CheckPoint")); + stats.put(1L, new Statistics(eventPrefix + "Checkpoint")); int minWidth = 0; while (true) { long chunkEnd = ch.getEnd(); diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java index 7ce5f9c9360..d8ff2debe9e 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java @@ -179,7 +179,7 @@ final class DiskRepository implements Closeable { bufferIndex = 0; break; case CHECKPOINT_EVENT_HEADER_BYTE_ARRAY_CONTENT: - processCheckPointHeader(); + processCheckpointHeader(); break; case CHECKPOINT_EVENT_FLUSH_TYPE: processFlush(); @@ -286,10 +286,10 @@ final class DiskRepository implements Closeable { } } - private void processCheckPointHeader() throws IOException { + private void processCheckpointHeader() throws IOException { buffer.put(bufferIndex, nextByte(true)); if (bufferIndex == HEADER_SIZE) { - writeCheckPointHeader(); + writeCheckpointHeader(); state = State.EVENT_PAYLOAD; bufferIndex = 0; } @@ -321,7 +321,7 @@ final class DiskRepository implements Closeable { } } - private void writeCheckPointHeader() throws IOException { + private void writeCheckpointHeader() throws IOException { Objects.requireNonNull(raf); byte state = buffer.get(HEADER_FILE_STATE_POSITION); boolean complete = state == COMPLETE_STATE; -- GitLab From 85cc6f1440aa7e073cab894cb9a72d9eed4e8369 Mon Sep 17 00:00:00 2001 From: Andrew Leonard Date: Fri, 18 Mar 2022 13:40:35 +0000 Subject: [PATCH 079/237] 8283315: jrt-fs.jar not always deterministically built Reviewed-by: ihse --- make/common/JarArchive.gmk | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/make/common/JarArchive.gmk b/make/common/JarArchive.gmk index 5a87e471428..26b08fc1509 100644 --- a/make/common/JarArchive.gmk +++ b/make/common/JarArchive.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -193,7 +193,8 @@ define SetupJarArchiveBody $1_UPDATE_CONTENTS=\ if [ "`$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'`" -gt "0" ]; then \ $(ECHO) " updating" `$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'` files && \ - $$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents; \ + $(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \ + $$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted; \ fi $$(NEWLINE) # The s-variants of the above macros are used when the jar is created from scratch. # NOTICE: please leave the parentheses space separated otherwise the AIX build will break! @@ -212,7 +213,9 @@ define SetupJarArchiveBody | $(SED) 's|$$(src)/|-C $$(src) |g' >> \ $$($1_BIN)/_the.$$($1_JARNAME)_contents) $$(NEWLINE) ) endif - $1_SUPDATE_CONTENTS=$$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE) + $1_SUPDATE_CONTENTS=\ + $(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \ + $$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted $$(NEWLINE) # Use a slightly shorter name for logging, but with enough path to identify this jar. $1_NAME:=$$(subst $$(OUTPUTDIR)/,,$$($1_JAR)) -- GitLab From b2aa085e67711a32e1679b68aabb092058dca044 Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Fri, 18 Mar 2022 14:54:56 +0000 Subject: [PATCH 080/237] 8283378: JFR: Checkpoint classes not renamed properly Reviewed-by: dcubed --- .../filter/{CheckPointEvent.java => CheckpointEvent.java} | 0 .../consumer/filter/{CheckPointPool.java => CheckpointPool.java} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/{CheckPointEvent.java => CheckpointEvent.java} (100%) rename src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/{CheckPointPool.java => CheckpointPool.java} (100%) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointEvent.java similarity index 100% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointEvent.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointEvent.java diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointPool.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointPool.java similarity index 100% rename from src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckPointPool.java rename to src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/filter/CheckpointPool.java -- GitLab From ff0b0927a2df8b36f8fd6ed41bd4e20e71a5b653 Mon Sep 17 00:00:00 2001 From: Ravi Reddy Date: Fri, 18 Mar 2022 15:31:30 +0000 Subject: [PATCH 081/237] 8278794: Infinite loop in DeflaterOutputStream.finish() Reviewed-by: coffeys, lancea --- .../share/classes/java/util/zip/Deflater.java | 12 +- .../java/util/zip/DeflaterOutputStream.java | 14 +- .../java/util/zip/ZipOutputStream.java | 4 +- test/jdk/java/util/zip/CloseDeflaterTest.java | 147 ------------- .../util/zip/CloseInflaterDeflaterTest.java | 208 ++++++++++++++++++ 5 files changed, 231 insertions(+), 154 deletions(-) delete mode 100644 test/jdk/java/util/zip/CloseDeflaterTest.java create mode 100644 test/jdk/java/util/zip/CloseInflaterDeflaterTest.java diff --git a/src/java.base/share/classes/java/util/zip/Deflater.java b/src/java.base/share/classes/java/util/zip/Deflater.java index d41b8a7e126..155264e4afe 100644 --- a/src/java.base/share/classes/java/util/zip/Deflater.java +++ b/src/java.base/share/classes/java/util/zip/Deflater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -895,6 +895,16 @@ public class Deflater { throw new NullPointerException("Deflater has been closed"); } + /** + * Returns the value of 'finish' flag. + * 'finish' will be set to true if def.finish() method is called. + */ + boolean shouldFinish() { + synchronized (zsRef) { + return finish; + } + } + private static native long init(int level, int strategy, boolean nowrap); private static native void setDictionary(long addr, byte[] b, int off, int len); diff --git a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java index 7dfbd7f9edb..c856d8999b3 100644 --- a/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/DeflaterOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -220,9 +220,15 @@ public class DeflaterOutputStream extends FilterOutputStream { */ public void finish() throws IOException { if (!def.finished()) { - def.finish(); - while (!def.finished()) { - deflate(); + try{ + def.finish(); + while (!def.finished()) { + deflate(); + } + } catch(IOException e) { + if (usesDefaultDeflater) + def.end(); + throw e; } } } diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java index 1b8ed562d9f..d11eb4d4aae 100644 --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -314,7 +314,7 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant crc.reset(); current = null; } catch (IOException e) { - if (usesDefaultDeflater && !(e instanceof ZipException)) + if (def.shouldFinish() && usesDefaultDeflater && !(e instanceof ZipException)) def.end(); throw e; } diff --git a/test/jdk/java/util/zip/CloseDeflaterTest.java b/test/jdk/java/util/zip/CloseDeflaterTest.java deleted file mode 100644 index 8aa4960f543..00000000000 --- a/test/jdk/java/util/zip/CloseDeflaterTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2021, 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 8193682 - * @summary Test Infinite loop while writing on closed GZipOutputStream , ZipOutputStream and JarOutputStream. - * @run testng CloseDeflaterTest - */ -import java.io.*; -import java.util.Random; -import java.util.jar.JarOutputStream; -import java.util.zip.GZIPOutputStream; -import java.util.zip.ZipOutputStream; -import java.util.zip.ZipEntry; - -import org.testng.annotations.BeforeTest; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.fail; - - -public class CloseDeflaterTest { - - //number of bytes to write - private static final int INPUT_LENGTH= 512; - //OutputStream that will throw an exception during a write operation - private static OutputStream outStream = new OutputStream() { - @Override - public void write(byte[] b, int off, int len) throws IOException { - //throw exception during write - throw new IOException(); - } - @Override - public void write(byte b[]) throws IOException {} - @Override - public void write(int b) throws IOException {} - }; - private static byte[] inputBytes = new byte[INPUT_LENGTH]; - private static Random rand = new Random(); - - @DataProvider(name = "testgzipinput") - public Object[][] testGZipInput() { - //testGZip will close the GZipOutputStream using close() method when the boolean - //useCloseMethod is set to true and finish() method if the value is set to false - return new Object[][] { - { GZIPOutputStream.class, true }, - { GZIPOutputStream.class, false }, - }; - } - - @DataProvider(name = "testzipjarinput") - public Object[][] testZipAndJarInput() { - //testZipAndJarInput will perfrom write/closeEntry operations on JarOutputStream when the boolean - //useJar is set to true and on ZipOutputStream if the value is set to false - return new Object[][] { - { JarOutputStream.class, true }, - { ZipOutputStream.class, false }, - }; - } - - @BeforeTest - public void before_test() - { - //add inputBytes array with random bytes to write into Zip - rand.nextBytes(inputBytes); - } - - //Test for infinite loop by writing bytes to closed GZIPOutputStream - @Test(dataProvider = "testgzipinput") - public void testGZip(Class type, boolean useCloseMethod) throws IOException { - GZIPOutputStream zip = new GZIPOutputStream(outStream); - try { - zip.write(inputBytes, 0, INPUT_LENGTH); - //close zip - if(useCloseMethod) { - zip.close(); - } else { - zip.finish(); - } - } catch (IOException e) { - //expected - } - for (int i = 0; i < 3; i++) { - try { - //write on a closed GZIPOutputStream - zip.write(inputBytes, 0, INPUT_LENGTH); - fail("Deflater closed exception not thrown"); - } catch (NullPointerException e) { - //expected , Deflater has been closed exception - } - } - } - - //Test for infinite loop by writing bytes to closed ZipOutputStream/JarOutputStream - @Test(dataProvider = "testzipjarinput") - public void testZipCloseEntry(Class type,boolean useJar) throws IOException { - ZipOutputStream zip = null; - if(useJar) { - zip = new JarOutputStream(outStream); - } else { - zip = new ZipOutputStream(outStream); - } - try { - zip.putNextEntry(new ZipEntry("")); - } catch (IOException e) { - //expected to throw IOException since putNextEntry calls write method - } - try { - zip.write(inputBytes, 0, INPUT_LENGTH); - //close zip entry - zip.closeEntry(); - } catch (IOException e) { - //expected - } - for (int i = 0; i < 3; i++) { - try { - //write on a closed ZipOutputStream - zip.write(inputBytes, 0, INPUT_LENGTH); - fail("Deflater closed exception not thrown"); - } catch (NullPointerException e) { - //expected , Deflater has been closed exception - } - } - } - -} diff --git a/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java b/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java new file mode 100644 index 00000000000..4f0fafc8dbe --- /dev/null +++ b/test/jdk/java/util/zip/CloseInflaterDeflaterTest.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2021, 2022, 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 8193682 8278794 + * @summary Test Infinite loop while writing on closed Deflater and Inflater. + * @run testng CloseInflaterDeflaterTest + */ +import java.io.*; +import java.util.Random; +import java.util.jar.JarOutputStream; +import java.util.zip.DeflaterInputStream; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPOutputStream; +import java.util.zip.InflaterOutputStream; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.assertThrows; + + +public class CloseInflaterDeflaterTest { + + // Number of bytes to write/read from Deflater/Inflater + private static final int INPUT_LENGTH= 512; + // OutputStream that will throw an exception during a write operation + private static OutputStream outStream = new OutputStream() { + @Override + public void write(byte[] b, int off, int len) throws IOException { + throw new IOException(); + } + @Override + public void write(byte[] b) throws IOException {} + @Override + public void write(int b) throws IOException {} + }; + // InputStream that will throw an exception during a read operation + private static InputStream inStream = new InputStream() { + @Override + public int read(byte[] b, int off, int len) throws IOException { + throw new IOException(); + } + @Override + public int read(byte[] b) throws IOException { throw new IOException();} + @Override + public int read() throws IOException { throw new IOException();} + }; + // Input bytes for read/write operation + private static byte[] inputBytes = new byte[INPUT_LENGTH]; + // Random function to add bytes to inputBytes + private static Random rand = new Random(); + + /** + * DataProvider to specify whether to use close() or finish() of OutputStream + * + * @return Entry object indicating which method to use for closing OutputStream + */ + @DataProvider + public Object[][] testOutputStreams() { + return new Object[][] { + { true }, + { false }, + }; + } + + /** + * DataProvider to specify on which outputstream closeEntry() has to be called + * + * @return Entry object returning either JarOutputStream or ZipOutputStream + */ + @DataProvider + public Object[][] testZipAndJar() throws IOException{ + return new Object[][] { + { new JarOutputStream(outStream)}, + { new ZipOutputStream(outStream)}, + }; + } + + /** + * Add inputBytes array with random bytes to write into OutputStream + */ + @BeforeTest + public void before_test() + { + rand.nextBytes(inputBytes); + } + + /** + * Test for infinite loop by writing bytes to closed GZIPOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testGZip(boolean useCloseMethod) throws IOException { + GZIPOutputStream gzip = new GZIPOutputStream(outStream); + gzip.write(inputBytes, 0, INPUT_LENGTH); + assertThrows(IOException.class, () -> { + // Close GZIPOutputStream + if (useCloseMethod) { + gzip.close(); + } else { + gzip.finish(); + } + }); + // Write on a closed GZIPOutputStream, closed Deflater IOException expected + assertThrows(NullPointerException.class , () -> gzip.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed DeflaterOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testDeflaterOutputStream(boolean useCloseMethod) throws IOException { + DeflaterOutputStream def = new DeflaterOutputStream(outStream); + assertThrows(IOException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH)); + assertThrows(IOException.class, () -> { + // Close DeflaterOutputStream + if (useCloseMethod) { + def.close(); + } else { + def.finish(); + } + }); + // Write on a closed DeflaterOutputStream, 'Deflater has been closed' NPE is expected + assertThrows(NullPointerException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by reading bytes from closed DeflaterInputStream + * + * @throws IOException if an error occurs + */ + @Test + public void testDeflaterInputStream() throws IOException { + DeflaterInputStream def = new DeflaterInputStream(inStream); + assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH)); + // Close DeflaterInputStream + def.close(); + // Read from a closed DeflaterInputStream, closed Deflater IOException expected + assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed InflaterOutputStream + * + * @param useCloseMethod indicates whether to use Close() or finish() method + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testOutputStreams") + public void testInflaterOutputStream(boolean useCloseMethod) throws IOException { + InflaterOutputStream inf = new InflaterOutputStream(outStream); + assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH)); + assertThrows(IOException.class , () -> { + // Close InflaterOutputStream + if (useCloseMethod) { + inf.close(); + } else { + inf.finish(); + } + }); + // Write on a closed InflaterOutputStream , closed Inflater IOException expected + assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH)); + } + + /** + * Test for infinite loop by writing bytes to closed ZipOutputStream/JarOutputStream + * + * @param zip will be the instance of either JarOutputStream or ZipOutputStream + * @throws IOException if an error occurs + */ + @Test(dataProvider = "testZipAndJar") + public void testZipCloseEntry(ZipOutputStream zip) throws IOException { + assertThrows(IOException.class , () -> zip.putNextEntry(new ZipEntry(""))); + zip.write(inputBytes, 0, INPUT_LENGTH); + assertThrows(IOException.class , () -> zip.closeEntry()); + // Write on a closed ZipOutputStream , 'Deflater has been closed' NPE is expected + assertThrows(NullPointerException.class , () -> zip.write(inputBytes, 0, INPUT_LENGTH)); + } + +} -- GitLab From d8893fad23d1ee6841336b96c34599643edb81ce Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Fri, 18 Mar 2022 20:28:39 +0000 Subject: [PATCH 082/237] 8283059: Uninitialized warning in check_code.c with GCC 11.2 Reviewed-by: dholmes --- .../share/native/libverify/check_code.c | 51 +++++++++++-------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c index fca549cfc9b..55d6fbcf42a 100644 --- a/src/java.base/share/native/libverify/check_code.c +++ b/src/java.base/share/native/libverify/check_code.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2022, 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 @@ -468,7 +468,8 @@ static void CCout_of_memory (context_type *); /* Because we can longjmp any time, we need to be very careful about * remembering what needs to be freed. */ -static void check_and_push(context_type *context, const void *ptr, int kind); +static void check_and_push_malloc_block(context_type *context, void *ptr); +static void check_and_push_string_utf(context_type *context, const char *ptr); static void pop_and_free(context_type *context); static int signature_to_args_size(const char *method_signature); @@ -604,7 +605,7 @@ class_to_ID(context_type *context, jclass cb, jboolean loadable) unsigned short *pID; const char *name = JVM_GetClassNameUTF(env, cb); - check_and_push(context, name, VM_STRING_UTF); + check_and_push_string_utf(context, name); hash = class_hash_fun(name); pID = &(class_hash->table[hash % HASH_TABLE_SIZE]); while (*pID) { @@ -939,10 +940,10 @@ read_all_code(context_type* context, jclass cb, int num_methods, int i; lengths = malloc(sizeof(int) * num_methods); - check_and_push(context, lengths, VM_MALLOC_BLK); + check_and_push_malloc_block(context, lengths); code = malloc(sizeof(unsigned char*) * num_methods); - check_and_push(context, code, VM_MALLOC_BLK); + check_and_push_malloc_block(context, code); *(lengths_addr) = lengths; *(code_addr) = code; @@ -951,7 +952,7 @@ read_all_code(context_type* context, jclass cb, int num_methods, lengths[i] = JVM_GetMethodIxByteCodeLength(context->env, cb, i); if (lengths[i] > 0) { code[i] = malloc(sizeof(unsigned char) * (lengths[i] + 1)); - check_and_push(context, code[i], VM_MALLOC_BLK); + check_and_push_malloc_block(context, code[i]); JVM_GetMethodIxByteCode(context->env, cb, i, code[i]); } else { code[i] = NULL; @@ -1305,7 +1306,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) /* Make sure the constant pool item is the right type. */ verify_constant_pool_type(context, key, kind); methodname = JVM_GetCPMethodNameUTF(env, cb, key); - check_and_push(context, methodname, VM_STRING_UTF); + check_and_push_string_utf(context, methodname); is_constructor = !strcmp(methodname, ""); is_internal = methodname[0] == '<'; pop_and_free(context); @@ -1354,7 +1355,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset) unsigned int args2; const char *signature = JVM_GetCPMethodSignatureUTF(env, context->class, key); - check_and_push(context, signature, VM_STRING_UTF); + check_and_push_string_utf(context, signature); args1 = signature_to_args_size(signature) + 1; args2 = code[offset + 3]; if (args1 != args2) { @@ -1652,7 +1653,7 @@ initialize_exception_table(context_type *context) classname = JVM_GetCPClassNameUTF(env, context->class, einfo.catchType); - check_and_push(context, classname, VM_STRING_UTF); + check_and_push_string_utf(context, classname); stack_item->item = make_class_info_from_name(context, classname); if (!isAssignableTo(context, stack_item->item, @@ -1807,7 +1808,7 @@ initialize_dataflow(context_type *context) } } signature = JVM_GetMethodIxSignatureUTF(env, cb, mi); - check_and_push(context, signature, VM_STRING_UTF); + check_and_push_string_utf(context, signature); /* Fill in each of the arguments into the registers. */ for (p = signature + 1; *p != JVM_SIGNATURE_ENDFUNC; ) { char fieldchar = signature_to_fieldtype(context, &p, &full_info); @@ -2050,7 +2051,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac context->class, operand); char *ip = buffer; - check_and_push(context, signature, VM_STRING_UTF); + check_and_push_string_utf(context, signature); #ifdef DEBUG if (verify_verbose) { print_formatted_fieldname(context, operand); @@ -2076,7 +2077,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac operand); char *ip = buffer; const char *p; - check_and_push(context, signature, VM_STRING_UTF); + check_and_push_string_utf(context, signature); #ifdef DEBUG if (verify_verbose) { print_formatted_methodname(context, operand); @@ -2376,7 +2377,7 @@ pop_stack(context_type *context, unsigned int inumber, stack_info_type *new_stac operand); int item; const char *p; - check_and_push(context, signature, VM_STRING_UTF); + check_and_push_string_utf(context, signature); if (opcode == JVM_OPC_invokestatic) { item = 0; } else if (opcode == JVM_OPC_invokeinit) { @@ -2758,7 +2759,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta const char *signature = JVM_GetCPFieldSignatureUTF(context->env, context->class, operand); - check_and_push(context, signature, VM_STRING_UTF); + check_and_push_string_utf(context, signature); #ifdef DEBUG if (verify_verbose) { print_formatted_fieldname(context, operand); @@ -2780,7 +2781,7 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta context->class, operand); const char *result_signature; - check_and_push(context, signature, VM_STRING_UTF); + check_and_push_string_utf(context, signature); result_signature = get_result_signature(signature); if (result_signature++ == NULL) { CCerror(context, "Illegal signature %s", signature); @@ -3621,7 +3622,7 @@ cp_index_to_class_fullinfo(context_type *context, int cp_index, int kind) CCerror(context, "Internal error #5"); } - check_and_push(context, classname, VM_STRING_UTF); + check_and_push_string_utf(context, classname); if (classname[0] == JVM_SIGNATURE_ARRAY) { /* This make recursively call us, in case of a class array */ signature_to_fieldtype(context, &classname, &result); @@ -3822,8 +3823,8 @@ signature_to_fieldtype(context_type *context, assert(finish >= p); length = (int)(finish - p); if (length + 1 > (int)sizeof(buffer_space)) { - buffer = calloc(length + 1, sizeof(char)); - check_and_push(context, buffer, VM_MALLOC_BLK); + buffer = malloc(length + 1); + check_and_push_malloc_block(context, buffer); } memcpy(buffer, p, length); buffer[length] = '\0'; @@ -4142,7 +4143,7 @@ static void free_block(void *ptr, int kind) } } -static void check_and_push(context_type *context, const void *ptr, int kind) +static void check_and_push_common(context_type *context, void *ptr, int kind) { alloc_stack_type *p; if (ptr == 0) @@ -4154,16 +4155,24 @@ static void check_and_push(context_type *context, const void *ptr, int kind) p = malloc(sizeof(alloc_stack_type)); if (p == 0) { /* Make sure we clean up. */ - free_block((void *)ptr, kind); + free_block(ptr, kind); CCout_of_memory(context); } } p->kind = kind; - p->ptr = (void *)ptr; + p->ptr = ptr; p->next = context->allocated_memory; context->allocated_memory = p; } +static void check_and_push_malloc_block(context_type *context, void *ptr) { + check_and_push_common(context, ptr, VM_MALLOC_BLK); +} + +static void check_and_push_string_utf(context_type *context, const char *ptr) { + check_and_push_common(context, (void *)ptr, VM_STRING_UTF); +} + static void pop_and_free(context_type *context) { alloc_stack_type *p = context->allocated_memory; -- GitLab From 8384ac4ed3eaaa18998ab88e1ca36358c212e699 Mon Sep 17 00:00:00 2001 From: Mikael Vidstedt Date: Fri, 18 Mar 2022 22:01:27 +0000 Subject: [PATCH 083/237] 8283057: Update GCC to version 11.2 for Oracle builds on Linux Reviewed-by: erikj --- doc/building.html | 4 ++-- doc/building.md | 4 ++-- make/conf/jib-profiles.js | 4 ++-- make/devkit/Tools.gmk | 13 +++++++++++-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/doc/building.html b/doc/building.html index 09ea7dc7f72..66e07f07b9d 100644 --- a/doc/building.html +++ b/doc/building.html @@ -273,7 +273,7 @@ Linux -gcc 10.2.0 +gcc 11.2.0 macOS @@ -288,7 +288,7 @@

    All compilers are expected to be able to compile to the C99 language standard, as some C99 features are used in the source code. Microsoft Visual Studio doesn't fully support C99 so in practice shared code is limited to using C99 features that it does support.

    gcc

    The minimum accepted version of gcc is 5.0. Older versions will generate a warning by configure and are unlikely to work.

    -

    The JDK is currently known to be able to compile with at least version 10.2 of gcc.

    +

    The JDK is currently known to be able to compile with at least version 11.2 of gcc.

    In general, any version between these two should be usable.

    clang

    The minimum accepted version of clang is 3.5. Older versions will not be accepted by configure.

    diff --git a/doc/building.md b/doc/building.md index e83c2bada21..6bc5857811e 100644 --- a/doc/building.md +++ b/doc/building.md @@ -329,7 +329,7 @@ issues. Operating system Toolchain version ------------------ ------------------------------------------------------- - Linux gcc 10.2.0 + Linux gcc 11.2.0 macOS Apple Xcode 10.1 (using clang 10.0.0) Windows Microsoft Visual Studio 2019 update 16.7.2 @@ -343,7 +343,7 @@ features that it does support. The minimum accepted version of gcc is 5.0. Older versions will generate a warning by `configure` and are unlikely to work. -The JDK is currently known to be able to compile with at least version 10.2 of +The JDK is currently known to be able to compile with at least version 11.2 of gcc. In general, any version between these two should be usable. diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 137d7cc7bb2..f16d7fd12e7 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -1052,10 +1052,10 @@ var getJibProfilesProfiles = function (input, common, data) { var getJibProfilesDependencies = function (input, common) { var devkit_platform_revisions = { - linux_x64: "gcc10.3.0-OL6.4+1.0", + linux_x64: "gcc11.2.0-OL6.4+1.0", macosx: "Xcode12.4+1.0", windows_x64: "VS2019-16.9.3+1.0", - linux_aarch64: "gcc10.3.0-OL7.6+1.0", + linux_aarch64: "gcc11.2.0-OL7.6+1.0", linux_arm: "gcc8.2.0-Fedora27+1.0", linux_ppc64le: "gcc8.2.0-Fedora27+1.0", linux_s390x: "gcc8.2.0-Fedora27+1.0" diff --git a/make/devkit/Tools.gmk b/make/devkit/Tools.gmk index 19eccf89be2..e94a74d0063 100644 --- a/make/devkit/Tools.gmk +++ b/make/devkit/Tools.gmk @@ -87,8 +87,17 @@ endif # Define external dependencies # Latest that could be made to work. -GCC_VER := 10.3.0 -ifeq ($(GCC_VER), 10.3.0) +GCC_VER := 11.2.0 +ifeq ($(GCC_VER), 11.2.0) + gcc_ver := gcc-11.2.0 + binutils_ver := binutils-2.37 + ccache_ver := ccache-3.7.12 + mpfr_ver := mpfr-4.1.0 + gmp_ver := gmp-6.2.1 + mpc_ver := mpc-1.2.1 + gdb_ver := gdb-11.1 + REQUIRED_MIN_MAKE_MAJOR_VERSION := 4 +else ifeq ($(GCC_VER), 10.3.0) gcc_ver := gcc-10.3.0 binutils_ver := binutils-2.36.1 ccache_ver := ccache-3.7.11 -- GitLab From 0c3094c8186b4d53e8bad80e2369fc7b9ae9e201 Mon Sep 17 00:00:00 2001 From: Ichiroh Takiguchi Date: Sat, 19 Mar 2022 04:43:20 +0000 Subject: [PATCH 084/237] 8204541: Correctly support AIX xlC 16.1 symbol visibility flags Reviewed-by: ihse, stuefe --- make/autoconf/flags-ldflags.m4 | 2 +- make/common/modules/LauncherCommon.gmk | 5 +++-- make/common/modules/LibCommon.gmk | 7 +++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 index 8f77734c93c..457690ac391 100644 --- a/make/autoconf/flags-ldflags.m4 +++ b/make/autoconf/flags-ldflags.m4 @@ -77,7 +77,7 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], -fPIC" elif test "x$TOOLCHAIN_TYPE" = xxlc; then - BASIC_LDFLAGS="-b64 -brtl -bnorwexec -bnolibpath -bexpall -bernotok -btextpsize:64K \ + BASIC_LDFLAGS="-b64 -brtl -bnorwexec -bnolibpath -bnoexpall -bernotok -btextpsize:64K \ -bdatapsize:64K -bstackpsize:64K" # libjvm.so has gotten too large for normal TOC size; compile with qpic=large and link with bigtoc BASIC_LDFLAGS_JVM_ONLY="-Wl,-lC_r -bbigtoc" diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk index 7ad0375e2e3..85056bbe40f 100644 --- a/make/common/modules/LauncherCommon.gmk +++ b/make/common/modules/LauncherCommon.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -33,13 +33,14 @@ include ToolsJdk.gmk # On Mac, we have always exported all symbols, probably due to oversight # and/or misunderstanding. To emulate this, don't hide any symbols # by default. -# On AIX/xlc we need at least xlc 13.1 for the symbol hiding (see JDK-8214063) # Also provide an override for non-conformant libraries. ifeq ($(TOOLCHAIN_TYPE), gcc) LAUNCHER_CFLAGS += -fvisibility=hidden LDFLAGS_JDKEXE += -Wl,--exclude-libs,ALL else ifeq ($(TOOLCHAIN_TYPE), clang) LAUNCHER_CFLAGS += -fvisibility=hidden +else ifeq ($(TOOLCHAIN_TYPE), xlc) + LAUNCHER_CFLAGS += -qvisibility=hidden endif LAUNCHER_SRC := $(TOPDIR)/src/java.base/share/native/launcher diff --git a/make/common/modules/LibCommon.gmk b/make/common/modules/LibCommon.gmk index 8ca3ddfffe9..aa5c9f0a5c6 100644 --- a/make/common/modules/LibCommon.gmk +++ b/make/common/modules/LibCommon.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -36,7 +36,6 @@ WIN_JAVA_LIB := $(SUPPORT_OUTPUTDIR)/native/java.base/libjava/java.lib # On Mac, we have always exported all symbols, probably due to oversight # and/or misunderstanding. To emulate this, don't hide any symbols # by default. -# On AIX/xlc we need at least xlc 13.1 for the symbol hiding (see JDK-8214063) # Also provide an override for non-conformant libraries. ifeq ($(TOOLCHAIN_TYPE), gcc) CFLAGS_JDKLIB += -fvisibility=hidden @@ -47,6 +46,10 @@ else ifeq ($(TOOLCHAIN_TYPE), clang) CFLAGS_JDKLIB += -fvisibility=hidden CXXFLAGS_JDKLIB += -fvisibility=hidden EXPORT_ALL_SYMBOLS := -fvisibility=default +else ifeq ($(TOOLCHAIN_TYPE), xlc) + CFLAGS_JDKLIB += -qvisibility=hidden + CXXFLAGS_JDKLIB += -qvisibility=hidden + EXPORT_ALL_SYMBOLS := -qvisibility=default endif # Put the libraries here. -- GitLab From 3e58a438e9051d4c976273eea35e36d37d5428c3 Mon Sep 17 00:00:00 2001 From: Tyler Steele Date: Sat, 19 Mar 2022 07:06:47 +0000 Subject: [PATCH 085/237] 8283287: ClassLoader.c cleanups Reviewed-by: stuefe, alanb, rriggs --- .../share/native/libjava/ClassLoader.c | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/native/libjava/ClassLoader.c b/src/java.base/share/native/libjava/ClassLoader.c index da34a7b438b..301f068070b 100644 --- a/src/java.base/share/native/libjava/ClassLoader.c +++ b/src/java.base/share/native/libjava/ClassLoader.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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,16 +23,16 @@ * questions. */ -#include #include +#include +#include +#include "check_classname.h" +#include "java_lang_ClassLoader.h" +#include "jlong.h" #include "jni.h" #include "jni_util.h" -#include "jlong.h" #include "jvm.h" -#include "check_classname.h" -#include "java_lang_ClassLoader.h" -#include static JNINativeMethod methods[] = { {"retrieveDirectives", "()Ljava/lang/AssertionStatusDirectives;", (void *)&JVM_AssertionStatusDirectives} @@ -88,7 +88,7 @@ Java_java_lang_ClassLoader_defineClass1(JNIEnv *env, if (data == NULL) { JNU_ThrowNullPointerException(env, 0); - return 0; + return NULL; } /* Work around 4153825. malloc crashes on Solaris when passed a @@ -96,25 +96,27 @@ Java_java_lang_ClassLoader_defineClass1(JNIEnv *env, */ if (length < 0) { JNU_ThrowArrayIndexOutOfBoundsException(env, 0); - return 0; + return NULL; } - // On AIX malloc(0) returns NULL which looks like an out-of-memory condition; so adjust it to malloc(1) + // On AIX malloc(0) returns NULL which looks like an out-of-memory + // condition; so adjust it to malloc(1) #ifdef _AIX - body = (jbyte *)malloc(length == 0 ? 1 : length); + body = (jbyte *)malloc(length == 0 ? 1 : length); #else - body = (jbyte *)malloc(length); + body = (jbyte *)malloc(length); #endif - if (body == 0) { + if (body == NULL) { JNU_ThrowOutOfMemoryError(env, 0); - return 0; + return NULL; } (*env)->GetByteArrayRegion(env, data, offset, length, body); - if ((*env)->ExceptionOccurred(env)) + if ((*env)->ExceptionOccurred(env)) { goto free_body; + } if (name != NULL) { utfName = getUTF(env, name, buf, sizeof(buf)); @@ -173,9 +175,9 @@ Java_java_lang_ClassLoader_defineClass2(JNIEnv *env, body = (*env)->GetDirectBufferAddress(env, data); - if (body == 0) { + if (body == NULL) { JNU_ThrowNullPointerException(env, 0); - return 0; + return NULL; } body += offset; @@ -233,7 +235,7 @@ Java_java_lang_ClassLoader_defineClass0(JNIEnv *env, if (data == NULL) { JNU_ThrowNullPointerException(env, 0); - return 0; + return NULL; } /* Work around 4153825. malloc crashes on Solaris when passed a @@ -241,19 +243,20 @@ Java_java_lang_ClassLoader_defineClass0(JNIEnv *env, */ if (length < 0) { JNU_ThrowArrayIndexOutOfBoundsException(env, 0); - return 0; + return NULL; } - // On AIX malloc(0) returns NULL which looks like an out-of-memory condition; so adjust it to malloc(1) + // On AIX malloc(0) returns NULL which looks like an out-of-memory + // condition; so adjust it to malloc(1) #ifdef _AIX - body = (jbyte *)malloc(length == 0 ? 1 : length); + body = (jbyte *)malloc(length == 0 ? 1 : length); #else - body = (jbyte *)malloc(length); + body = (jbyte *)malloc(length); #endif - if (body == 0) { + if (body == NULL) { JNU_ThrowOutOfMemoryError(env, 0); - return 0; + return NULL; } (*env)->GetByteArrayRegion(env, data, offset, length, body); @@ -293,7 +296,7 @@ Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jclass dummy, char buf[128]; if (classname == NULL) { - return 0; + return NULL; } clname = getUTF(env, classname, buf, sizeof(buf)); @@ -322,7 +325,7 @@ Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader, jstring name) { if (name == NULL) { - return 0; + return NULL; } else { return JVM_FindLoadedClass(env, loader, name); } -- GitLab From 10ccfffae1f18dd1a3d2f3dca53ad547d3d3ecb5 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Sat, 19 Mar 2022 07:08:47 +0000 Subject: [PATCH 086/237] 8283352: [CDS] SharedBaseAddress.java fails on x86_32 Reviewed-by: dholmes, iklam, stuefe --- .../jtreg/runtime/cds/SharedBaseAddress.java | 32 +++++++++++++------ .../runtime/cds/appcds/SharedBaseAddress.java | 26 +++++++++++---- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java b/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java index 761b5a05d29..a7f31cf1a08 100644 --- a/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java +++ b/test/hotspot/jtreg/runtime/cds/SharedBaseAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -70,26 +70,31 @@ import jdk.test.lib.process.OutputAnalyzer; public class SharedBaseAddress { - // shared base address test table - private static final String[] testTable = { - "1g", "8g", "64g","512g", "4t", - "32t", "128t", "0", + // shared base address test table for {32, 64}bit VM + private static final String[] testTableShared = { + "1g", "0", "1", "64k", "64M", + "0xfff80000", // archive top wraps around 32-bit address space + "0xffffffff", // archive bottom wraps around 32-bit address space -- due to align_up() + "0" // always let OS pick the base address at runtime (ASLR for CDS archive) + }; + + // shared base address test table for 64bit VM only + private static final String[] testTable64 = { + "8g", "64g","512g", "4t", + "32t", "128t", "0x800001000", // Default base address + 1 page - probably valid but unaligned to metaspace alignment, see JDK 8247522 "0xfffffffffff00000", // archive top wraps around 64-bit address space - "0xfff80000", // archive top wraps around 32-bit address space "0xffffffffffffffff", // archive bottom wraps around 64-bit address space -- due to align_up() - "0xffffffff", // archive bottom wraps around 32-bit address space -- due to align_up() "0x00007ffffff00000", // end of archive will go past the end of user space on linux/x64 - "0x500000000", // (20g) below 32g at a 4g aligned address, but cannot be expressed with a logical + "0x500000000" // (20g) below 32g at a 4g aligned address, but cannot be expressed with a logical // immediate on aarch64 (0x5_0000_0000) (see JDK-8265705) - "0", // always let OS pick the base address at runtime (ASLR for CDS archive) }; // failed pattern private static String failedPattern = "os::release_memory\\(0x[0-9a-fA-F]*,\\s[0-9]*\\)\\sfailed"; - public static void main(String[] args) throws Exception { + public static void test(String[] args, String[] testTable) throws Exception { int mid = testTable.length / 2; int start = args[0].equals("0") ? 0 : mid; int end = args[0].equals("0") ? mid : testTable.length; @@ -134,4 +139,11 @@ public class SharedBaseAddress { } } } + + public static void main(String[] args) throws Exception { + test(args, testTableShared); + if (Platform.is64bit()) { + test(args, testTable64); + } + } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java b/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java index 5d981c01794..2220fc52baa 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/SharedBaseAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -33,19 +33,24 @@ * @run main/timeout=240 SharedBaseAddress */ +import jdk.test.lib.Platform; import jdk.test.lib.process.OutputAnalyzer; public class SharedBaseAddress { - // shared base address test table - private static final String[] testTable = { - "1g", "8g", "64g","512g", "4t", - "32t", "128t", "0", - "1", "64k", "64M", "320g", + // shared base address test table for {32, 64}bit VM + private static final String[] testTableShared = { + "1g", "0", "1", "64k", "64M" + }; + + // shared base address test table for 64bit VM only + private static final String[] testTable64 = { + "8g", "64g","512g", "4t", + "32t", "128t", "320g", "0x800001000" // Default base address + 1 page - probably valid but unaligned to metaspace alignment, see JDK 8247522 }; - public static void main(String[] args) throws Exception { + public static void test(String[] testTable) throws Exception { String appJar = JarBuilder.getOrCreateHelloJar(); for (String testEntry : testTable) { @@ -62,4 +67,11 @@ public class SharedBaseAddress { TestCommon.checkExec(execOutput, "Hello World"); } } + + public static void main(String[] args) throws Exception { + test(testTableShared); + if (Platform.is64bit()) { + test(testTable64); + } + } } -- GitLab From e8caf84fb9dfcbb59da6459972724b6780b0871a Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Sat, 19 Mar 2022 13:29:49 +0000 Subject: [PATCH 087/237] 8282574: Cleanup unnecessary calls to Throwable.initCause() in jdk.compiler Reviewed-by: darcy --- .../tools/javac/processing/JavacProcessingEnvironment.java | 7 ++----- .../share/classes/com/sun/tools/javac/tree/Pretty.java | 6 ++---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index 9dd94f74252..9174f0b7385 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -300,10 +300,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea try { processorIterator = List.of(new PrintingProcessor()).iterator(); } catch (Throwable t) { - AssertionError assertError = - new AssertionError("Problem instantiating PrintingProcessor."); - assertError.initCause(t); - throw assertError; + throw new AssertionError("Problem instantiating PrintingProcessor.", t); } } else if (processors != null) { processorIterator = processors.iterator(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index acccd4d574c..bdfef06fd7c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, 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 @@ -194,9 +194,7 @@ public class Pretty extends JCTree.Visitor { tree.accept(this); } } catch (UncheckedIOException ex) { - IOException e = new IOException(ex.getMessage()); - e.initCause(ex); - throw e; + throw new IOException(ex.getMessage(), ex); } finally { this.prec = prevPrec; } -- GitLab From 80415e04c5fd6709e7e5b5ffb7a3d9431b672d99 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Sat, 19 Mar 2022 13:31:50 +0000 Subject: [PATCH 088/237] 8282534: Remove redundant null check in ChaCha20Cipher.engineInit Reviewed-by: xuelei --- .../com/sun/crypto/provider/ChaCha20Cipher.java | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java index 8cb200876ac..917921801cb 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/ChaCha20Cipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -159,7 +159,7 @@ abstract class ChaCha20Cipher extends CipherSpi { * ciphers, but allow {@code NoPadding}. See JCE spec. * * @param padding The padding type. The only allowed value is - * {@code NoPadding} case insensitive). + * {@code NoPadding} case insensitive. * * @throws NoSuchPaddingException if a padding scheme besides * {@code NoPadding} is provided. @@ -393,7 +393,7 @@ abstract class ChaCha20Cipher extends CipherSpi { return; } - byte[] newNonce = null; + byte[] newNonce; switch (mode) { case MODE_NONE: throw new InvalidAlgorithmParameterException( @@ -420,12 +420,6 @@ abstract class ChaCha20Cipher extends CipherSpi { throw new RuntimeException("Invalid mode: " + mode); } - // If after all the above processing we still don't have a nonce value - // then supply a random one provided a random source has been given. - if (newNonce == null) { - newNonce = createRandomNonce(random); - } - // Continue with initialization init(opmode, key, newNonce); } -- GitLab From 3f923b82c31325504430b50dee262fd460004e7b Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Sat, 19 Mar 2022 13:43:06 +0000 Subject: [PATCH 089/237] 8282704: runtime/Thread/StopAtExit.java may leak memory Reviewed-by: dholmes, alanb --- .../jtreg/runtime/Thread/StopAtExit.java | 69 ++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/runtime/Thread/StopAtExit.java b/test/hotspot/jtreg/runtime/Thread/StopAtExit.java index 22550093202..b997890e347 100644 --- a/test/hotspot/jtreg/runtime/Thread/StopAtExit.java +++ b/test/hotspot/jtreg/runtime/Thread/StopAtExit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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,11 +23,13 @@ /** * @test - * @bug 8167108 8266130 + * @bug 8167108 8266130 8282704 * @summary Stress test java.lang.Thread.stop() at thread exit. + * @modules java.base/java.lang:open * @run main/othervm StopAtExit */ +import java.lang.reflect.Method; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -38,6 +40,10 @@ public class StopAtExit extends Thread { public CountDownLatch exitSyncObj = new CountDownLatch(1); public CountDownLatch startSyncObj = new CountDownLatch(1); + public StopAtExit(ThreadGroup group, Runnable target) { + super(group, target); + } + @Override public void run() { try { @@ -72,11 +78,18 @@ public class StopAtExit extends Thread { System.out.println("About to execute for " + timeMax + " seconds."); long count = 0; + long manualDestroyCnt = 0; + long manualTerminateCnt = 0; long start_time = System.currentTimeMillis(); while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { count++; - StopAtExit thread = new StopAtExit(); + // Use my own ThreadGroup so the thread count is known and make + // it a daemon ThreadGroup so it is automatically destroyed when + // the thread is terminated. + ThreadGroup myTG = new ThreadGroup("myTG-" + count); + myTG.setDaemon(true); + StopAtExit thread = new StopAtExit(myTG, null); thread.start(); try { // Wait for the worker thread to get going. @@ -107,9 +120,52 @@ public class StopAtExit extends Thread { } catch (InterruptedException e) { throw new Error("Unexpected: " + e); } + // This stop() call happens after the join() so it should do + // nothing, but let's make sure. thread.stop(); + + if (myTG.activeCount() != 0) { + // If the ThreadGroup still has a count, then the thread + // received the async exception while in exit() so we need + // to do a manual terminate. + manualTerminateCnt++; + try { + threadTerminated(myTG, thread); + } catch (Exception e) { + throw new Error("threadTerminated() threw unexpected: " + e); + } + int activeCount = myTG.activeCount(); + if (activeCount != 0) { + throw new Error("threadTerminated() did not clean up " + + "worker thread: count=" + activeCount); + } + if (!myTG.isDestroyed()) { + throw new Error("threadTerminated() did not destroy " + + myTG.getName()); + } + } else if (!myTG.isDestroyed()) { + // If the ThreadGroup does not have a count, but is not + // yet destroyed, then the thread received the async + // exception while the thread was in the later stages of + // its threadTerminated() call so we need to do a manual + // destroy. + manualDestroyCnt++; + try { + myTG.destroy(); + } catch (Exception e) { + throw new Error("myTG.destroy() threw unexpected: " + e); + } + } } + if (manualDestroyCnt != 0) { + System.out.println("Manually destroyed ThreadGroup " + + manualDestroyCnt + " times."); + } + if (manualTerminateCnt != 0) { + System.out.println("Manually terminated Thread " + + manualTerminateCnt + " times."); + } System.out.println("Executed " + count + " loops in " + timeMax + " seconds."); @@ -120,6 +176,13 @@ public class StopAtExit extends Thread { } } + static void threadTerminated(ThreadGroup group, Thread thread) throws Exception { + // ThreadGroup.threadTerminated() is package private: + Method method = ThreadGroup.class.getDeclaredMethod("threadTerminated", Thread.class); + method.setAccessible(true); + method.invoke(group, thread); + } + public static void usage() { System.err.println("Usage: " + PROG_NAME + " [time_max]"); System.err.println("where:"); -- GitLab From 4df67426ed02f18af0757897acb28b636a317a91 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Sun, 20 Mar 2022 06:46:13 +0000 Subject: [PATCH 090/237] 8282723: Add constructors taking a cause to JSSE exceptions Reviewed-by: wetmore, iris --- .../classes/javax/net/ssl/SSLException.java | 15 ++---- .../javax/net/ssl/SSLHandshakeException.java | 27 +++++++--- .../javax/net/ssl/SSLKeyException.java | 25 +++++++--- .../net/ssl/SSLPeerUnverifiedException.java | 25 +++++++--- .../javax/net/ssl/SSLProtocolException.java | 25 +++++++--- .../share/classes/sun/security/ssl/Alert.java | 17 ++----- .../sun/security/ssl/DHClientKeyExchange.java | 6 +-- .../sun/security/ssl/ECDHKeyExchange.java | 12 ++--- .../sun/security/ssl/KAKeyDerivation.java | 8 ++- .../sun/security/ssl/NewSessionTicket.java | 5 +- .../security/ssl/SSLBasicKeyDerivation.java | 5 +- .../sun/security/ssl/SSLEngineImpl.java | 14 ++---- .../security/ssl/SSLEngineInputRecord.java | 5 +- .../sun/security/ssl/SSLSecretDerivation.java | 5 +- .../sun/security/ssl/SSLSocketImpl.java | 16 ++---- .../security/ssl/SSLSocketInputRecord.java | 5 +- .../security/ssl/SSLTrafficKeyDerivation.java | 6 +-- .../classes/sun/security/ssl/ServerHello.java | 5 +- .../sun/security/ssl/ServerNameExtension.java | 12 ++--- .../jndi/ldap/ext/StartTlsResponseImpl.java | 7 ++- .../jdk/internal/net/http/HttpClientImpl.java | 6 +-- .../jdk/internal/net/http/common/SSLTube.java | 6 +-- .../net/ssl/ALPN/SSLServerSocketAlpnTest.java | 4 +- .../javax/net/ssl/ALPN/SSLSocketAlpnTest.java | 4 +- .../CheckSSLHandshakeException.java | 50 +++++++++++++++++++ .../SSLException/CheckSSLKeyException.java | 50 +++++++++++++++++++ .../CheckSSLPeerUnverifiedException.java | 50 +++++++++++++++++++ .../CheckSSLProtocolException.java | 50 +++++++++++++++++++ .../templates/SSLSocketSSLEngineTemplate.java | 6 +-- .../net/ssl/templates/SSLSocketTemplate.java | 4 +- 30 files changed, 343 insertions(+), 132 deletions(-) create mode 100644 test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java create mode 100644 test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java create mode 100644 test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java create mode 100644 test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java diff --git a/src/java.base/share/classes/javax/net/ssl/SSLException.java b/src/java.base/share/classes/javax/net/ssl/SSLException.java index c77992db301..b2e96afa7d6 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -36,9 +36,7 @@ import java.io.IOException; * @since 1.4 * @author David Brownell */ -public -class SSLException extends IOException -{ +public class SSLException extends IOException { @java.io.Serial private static final long serialVersionUID = 4511006460650708967L; @@ -48,8 +46,7 @@ class SSLException extends IOException * * @param reason describes the problem. */ - public SSLException(String reason) - { + public SSLException(String reason) { super(reason); } @@ -66,8 +63,7 @@ class SSLException extends IOException * @since 1.5 */ public SSLException(String message, Throwable cause) { - super(message); - initCause(cause); + super(message, cause); } /** @@ -83,7 +79,6 @@ class SSLException extends IOException * @since 1.5 */ public SSLException(Throwable cause) { - super(cause == null ? null : cause.toString()); - initCause(cause); + super(cause); } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLHandshakeException.java b/src/java.base/share/classes/javax/net/ssl/SSLHandshakeException.java index 5f342b074db..e6fa239bdcb 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLHandshakeException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLHandshakeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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,10 +23,8 @@ * questions. */ - package javax.net.ssl; - /** * Indicates that the client and server could not negotiate the * desired level of security. The connection is no longer usable. @@ -34,9 +32,7 @@ package javax.net.ssl; * @since 1.4 * @author David Brownell */ -public -class SSLHandshakeException extends SSLException -{ +public class SSLHandshakeException extends SSLException { @java.io.Serial private static final long serialVersionUID = -5045881315018326890L; @@ -46,8 +42,23 @@ class SSLHandshakeException extends SSLException * * @param reason describes the problem. */ - public SSLHandshakeException(String reason) - { + public SSLHandshakeException(String reason) { super(reason); } + + /** + * Creates a {@code SSLHandshakeException} with the specified detail + * message and cause. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 19 + */ + public SSLHandshakeException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLKeyException.java b/src/java.base/share/classes/javax/net/ssl/SSLKeyException.java index 49fe57c369d..f27c9ee554c 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLKeyException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLKeyException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -33,9 +33,7 @@ package javax.net.ssl; * @since 1.4 * @author David Brownell */ -public -class SSLKeyException extends SSLException -{ +public class SSLKeyException extends SSLException { @java.io.Serial private static final long serialVersionUID = -8071664081941937874L; @@ -45,8 +43,23 @@ class SSLKeyException extends SSLException * * @param reason describes the problem. */ - public SSLKeyException(String reason) - { + public SSLKeyException(String reason) { super(reason); } + + /** + * Creates a {@code SSLKeyException} with the specified detail + * message and cause. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 19 + */ + public SSLKeyException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLPeerUnverifiedException.java b/src/java.base/share/classes/javax/net/ssl/SSLPeerUnverifiedException.java index e98e2b4b7f4..3fbec6c0434 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLPeerUnverifiedException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLPeerUnverifiedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -39,9 +39,7 @@ package javax.net.ssl; * @since 1.4 * @author David Brownell */ -public -class SSLPeerUnverifiedException extends SSLException -{ +public class SSLPeerUnverifiedException extends SSLException { @java.io.Serial private static final long serialVersionUID = -8919512675000600547L; @@ -51,8 +49,23 @@ class SSLPeerUnverifiedException extends SSLException * * @param reason describes the problem. */ - public SSLPeerUnverifiedException(String reason) - { + public SSLPeerUnverifiedException(String reason) { super(reason); } + + /** + * Creates a {@code SSLPeerUnverifiedException} with the specified detail + * message and cause. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 19 + */ + public SSLPeerUnverifiedException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLProtocolException.java b/src/java.base/share/classes/javax/net/ssl/SSLProtocolException.java index a39b2048924..bf590430b3f 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLProtocolException.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLProtocolException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -33,9 +33,7 @@ package javax.net.ssl; * @since 1.4 * @author David Brownell */ -public -class SSLProtocolException extends SSLException -{ +public class SSLProtocolException extends SSLException { @java.io.Serial private static final long serialVersionUID = 5445067063799134928L; @@ -45,8 +43,23 @@ class SSLProtocolException extends SSLException * * @param reason describes the problem. */ - public SSLProtocolException(String reason) - { + public SSLProtocolException(String reason) { super(reason); } + + /** + * Creates a {@code SSLProtocolException} with the specified detail + * message and cause. + * + * @param message the detail message (which is saved for later retrieval + * by the {@link #getMessage()} method). + * @param cause the cause (which is saved for later retrieval by the + * {@link #getCause()} method). (A {@code null} value is + * permitted, and indicates that the cause is nonexistent or + * unknown.) + * @since 19 + */ + public SSLProtocolException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/java.base/share/classes/sun/security/ssl/Alert.java b/src/java.base/share/classes/sun/security/ssl/Alert.java index bc034dc8c3b..922937887aa 100644 --- a/src/java.base/share/classes/sun/security/ssl/Alert.java +++ b/src/java.base/share/classes/sun/security/ssl/Alert.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -122,22 +122,15 @@ enum Alert { reason = (cause != null) ? cause.getMessage() : ""; } - SSLException ssle; if (cause instanceof IOException) { - ssle = new SSLException(reason); + return new SSLException(reason, cause); } else if ((this == UNEXPECTED_MESSAGE)) { - ssle = new SSLProtocolException(reason); + return new SSLProtocolException(reason, cause); } else if (handshakeOnly) { - ssle = new SSLHandshakeException(reason); + return new SSLHandshakeException(reason, cause); } else { - ssle = new SSLException(reason); + return new SSLException(reason, cause); } - - if (cause != null) { - ssle.initCause(cause); - } - - return ssle; } /** diff --git a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java index f9753ffe078..996e3f78ec1 100644 --- a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -295,8 +295,8 @@ final class DHClientKeyExchange { shc.handshakeCredentials.add( new DHECredentials(peerPublicKey, namedGroup)); } catch (GeneralSecurityException | java.io.IOException e) { - throw (SSLHandshakeException)(new SSLHandshakeException( - "Could not generate DHPublicKey").initCause(e)); + throw new SSLHandshakeException( + "Could not generate DHPublicKey", e); } // update the states diff --git a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java index 59bc40411ce..9833ea94e8d 100644 --- a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java +++ b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -160,8 +160,7 @@ final class ECDHKeyExchange { ka.doPhase(peerPublicKey, true); return ka.generateSecret("TlsPremasterSecret"); } catch (GeneralSecurityException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(e); + throw new SSLHandshakeException("Could not generate secret", e); } } @@ -177,8 +176,7 @@ final class ECDHKeyExchange { PublicKey peerPublicKey = kf.generatePublic(spec); return getAgreedSecret(peerPublicKey); } catch (GeneralSecurityException | java.io.IOException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(e); + throw new SSLHandshakeException("Could not generate secret", e); } } @@ -202,8 +200,8 @@ final class ECDHKeyExchange { "ECPublicKey does not comply to algorithm constraints"); } } catch (GeneralSecurityException | java.io.IOException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate ECPublicKey").initCause(e); + throw new SSLHandshakeException( + "Could not generate ECPublicKey", e); } } diff --git a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java index 7c791e85f77..b76da75c763 100644 --- a/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -88,8 +88,7 @@ public class KAKeyDerivation implements SSLKeyDerivation { context, preMasterSecret); return kd.deriveKey("MasterSecret", params); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } @@ -125,8 +124,7 @@ public class KAKeyDerivation implements SSLKeyDerivation { // derive handshake secret return hkdf.extract(saltSecret, sharedSecret, algorithm); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } } diff --git a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java index 50f19dbf715..337c8384991 100644 --- a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java +++ b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -302,8 +302,7 @@ final class NewSessionTicket { return hkdf.expand(resumptionMasterSecret, hkdfInfo, hashAlg.hashLength, "TlsPreSharedKey"); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not derive PSK").initCause(gse); + throw new SSLHandshakeException("Could not derive PSK", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLBasicKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLBasicKeyDerivation.java index 7f693400637..20fc7112593 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLBasicKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLBasicKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -52,8 +52,7 @@ final class SSLBasicKeyDerivation implements SSLKeyDerivation { return hkdf.expand(secret, hkdfInfo, ((SecretSizeSpec)keySpec).length, algorithm); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java index ca4a80c5a5c..1db9ba8d86b 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -1167,17 +1167,13 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { if (taskThrown instanceof RuntimeException) { throw new RuntimeException(msg, taskThrown); } else if (taskThrown instanceof SSLHandshakeException) { - return (SSLHandshakeException) - new SSLHandshakeException(msg).initCause(taskThrown); + return new SSLHandshakeException(msg, taskThrown); } else if (taskThrown instanceof SSLKeyException) { - return (SSLKeyException) - new SSLKeyException(msg).initCause(taskThrown); + return new SSLKeyException(msg, taskThrown); } else if (taskThrown instanceof SSLPeerUnverifiedException) { - return (SSLPeerUnverifiedException) - new SSLPeerUnverifiedException(msg).initCause(taskThrown); + return new SSLPeerUnverifiedException(msg, taskThrown); } else if (taskThrown instanceof SSLProtocolException) { - return (SSLProtocolException) - new SSLProtocolException(msg).initCause(taskThrown); + return new SSLProtocolException(msg, taskThrown); } else if (taskThrown instanceof SSLException) { return (SSLException)taskThrown; } else { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java index 938768aaf76..dc957ca1419 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -242,8 +242,7 @@ final class SSLEngineInputRecord extends InputRecord implements SSLRecord { } catch (BadPaddingException bpe) { throw bpe; } catch (GeneralSecurityException gse) { - throw (SSLProtocolException)(new SSLProtocolException( - "Unexpected exception")).initCause(gse); + throw new SSLProtocolException("Unexpected exception", gse); } finally { // consume a complete record packet.limit(srcLim); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java index a7ba9a5e566..ff13948a67c 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSecretDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -113,8 +113,7 @@ final class SSLSecretDerivation implements SSLKeyDerivation { HKDF hkdf = new HKDF(hashAlg.name); return hkdf.expand(secret, hkdfInfo, hashAlg.hashLength, algorithm); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 842cef11911..68fb3860203 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -1709,19 +1709,13 @@ public final class SSLSocketImpl private Plaintext handleEOF(EOFException eofe) throws IOException { if (requireCloseNotify || conContext.handshakeContext != null) { - SSLException ssle; if (conContext.handshakeContext != null) { - ssle = new SSLHandshakeException( - "Remote host terminated the handshake"); + throw new SSLHandshakeException( + "Remote host terminated the handshake", eofe); } else { - ssle = new SSLProtocolException( - "Remote host terminated the connection"); - } - - if (eofe != null) { - ssle.initCause(eofe); + throw new SSLProtocolException( + "Remote host terminated the connection", eofe); } - throw ssle; } else { // treat as if we had received a close_notify conContext.isInputCloseNotified = true; diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java index da189f4f3ff..7afacb0f3d7 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -263,8 +263,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord { } catch (BadPaddingException bpe) { throw bpe; } catch (GeneralSecurityException gse) { - throw (SSLProtocolException)(new SSLProtocolException( - "Unexpected exception")).initCause(gse); + throw new SSLProtocolException("Unexpected exception", gse); } if (contentType != ContentType.HANDSHAKE.id && diff --git a/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java b/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java index ac39cbb16fb..6e890c8818d 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLTrafficKeyDerivation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -154,8 +154,8 @@ enum SSLTrafficKeyDerivation implements SSLKeyDerivationGenerator { ks.getKeyLength(cs), ks.getAlgorithm(cs, algorithm)); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException)(new SSLHandshakeException( - "Could not generate secret").initCause(gse)); + throw new SSLHandshakeException( + "Could not generate secret", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java index 193a71cde86..efbe860bfd6 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -1205,8 +1205,7 @@ final class ServerHello { hc.handshakeKeyDerivation = new SSLSecretDerivation(hc, earlySecret); } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); + throw new SSLHandshakeException("Could not generate secret", gse); } } diff --git a/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java b/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java index 74f38bf5b56..eaf154af3bb 100644 --- a/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/ServerNameExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -135,9 +135,8 @@ final class ServerNameExtension { nameType + "), name=" + (new String(encoded, StandardCharsets.UTF_8)) + ", value={" + - Utilities.toHexString(encoded) + "}"); - throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER, - (SSLProtocolException)spe.initCause(iae)); + Utilities.toHexString(encoded) + "}", iae); + throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER, spe); } } else { try { @@ -146,9 +145,8 @@ final class ServerNameExtension { SSLProtocolException spe = new SSLProtocolException( "Illegal server name, type=(" + nameType + "), value={" + - Utilities.toHexString(encoded) + "}"); - throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER, - (SSLProtocolException)spe.initCause(iae)); + Utilities.toHexString(encoded) + "}", iae); + throw hc.conContext.fatal(Alert.ILLEGAL_PARAMETER, spe); } } diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java b/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java index 3c75f75519a..41144b132c0 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -435,11 +435,10 @@ public final class StartTlsResponseImpl extends StartTlsResponse { /* * Pass up the cause of the failure */ - throw(SSLPeerUnverifiedException) - new SSLPeerUnverifiedException("hostname of the server '" + + throw new SSLPeerUnverifiedException("hostname of the server '" + hostname + "' does not match the hostname in the " + - "server's certificate.").initCause(e); + "server's certificate.", e); } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java index 6394b7b3cfa..fc2596e0aa4 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -573,9 +573,7 @@ final class HttpClientImpl extends HttpClient implements Trackable { throw ce; } else if (throwable instanceof SSLHandshakeException) { // special case for SSLHandshakeException - SSLHandshakeException he = new SSLHandshakeException(msg); - he.initCause(throwable); - throw he; + throw new SSLHandshakeException(msg, throwable); } else if (throwable instanceof SSLException) { // any other SSLException is wrapped in a plain // SSLException diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLTube.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLTube.java index 42174ef9c44..e72ba9d33dc 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLTube.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLTube.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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 @@ -592,9 +592,7 @@ public class SSLTube implements FlowTube { engine.isOutboundDone(), handshakeFailed); - SSLHandshakeException e = new SSLHandshakeException(handshakeFailed); - if (t != null) e.initCause(t); - return e; + return new SSLHandshakeException(handshakeFailed, t); } @Override diff --git a/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java b/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java index a9373ed09f9..2752649dc74 100644 --- a/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java +++ b/test/jdk/javax/net/ssl/ALPN/SSLServerSocketAlpnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -484,7 +484,7 @@ public class SSLServerSocketAlpnTest { */ if ((local != null) && (remote != null)) { // If both failed, return the curthread's exception. - local.initCause(remote); + local.addSuppressed(remote); exception = local; } else if (local != null) { exception = local; diff --git a/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java b/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java index ef72474f417..172eecd4608 100644 --- a/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java +++ b/test/jdk/javax/net/ssl/ALPN/SSLSocketAlpnTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -480,7 +480,7 @@ public class SSLSocketAlpnTest { */ if ((local != null) && (remote != null)) { // If both failed, return the curthread's exception. - local.initCause(remote); + local.addSuppressed(remote); exception = local; } else if (local != null) { exception = local; diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java new file mode 100644 index 00000000000..4c8aba3de44 --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLHandshakeException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. 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 8282723 + * @summary Add constructors taking a cause to JSSE exceptions + */ +import javax.net.ssl.SSLHandshakeException; +import java.util.Objects; + +public class CheckSSLHandshakeException { + private static String exceptionMessage = "message"; + private static Throwable exceptionCause = new RuntimeException(); + + public static void main(String[] args) throws Exception { + testException( + new SSLHandshakeException(exceptionMessage, exceptionCause)); + } + + private static void testException(Exception ex) { + if (!Objects.equals(ex.getMessage(), exceptionMessage)) { + throw new RuntimeException("Unexpected exception message"); + } + + if (ex.getCause() != exceptionCause) { + throw new RuntimeException("Unexpected exception cause"); + } + } +} diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java new file mode 100644 index 00000000000..dcd62fcf8e7 --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLKeyException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. 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 8282723 + * @summary Add constructors taking a cause to JSSE exceptions + */ +import javax.net.ssl.SSLKeyException; +import java.util.Objects; + +public class CheckSSLKeyException { + private static String exceptionMessage = "message"; + private static Throwable exceptionCause = new RuntimeException(); + + public static void main(String[] args) throws Exception { + testException( + new SSLKeyException(exceptionMessage, exceptionCause)); + } + + private static void testException(Exception ex) { + if (!Objects.equals(ex.getMessage(), exceptionMessage)) { + throw new RuntimeException("Unexpected exception message"); + } + + if (ex.getCause() != exceptionCause) { + throw new RuntimeException("Unexpected exception cause"); + } + } +} diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java new file mode 100644 index 00000000000..04184e99306 --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLPeerUnverifiedException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. 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 8282723 + * @summary Add constructors taking a cause to JSSE exceptions + */ +import javax.net.ssl.SSLPeerUnverifiedException; +import java.util.Objects; + +public class CheckSSLPeerUnverifiedException { + private static String exceptionMessage = "message"; + private static Throwable exceptionCause = new RuntimeException(); + + public static void main(String[] args) throws Exception { + testException( + new SSLPeerUnverifiedException(exceptionMessage, exceptionCause)); + } + + private static void testException(Exception ex) { + if (!Objects.equals(ex.getMessage(), exceptionMessage)) { + throw new RuntimeException("Unexpected exception message"); + } + + if (ex.getCause() != exceptionCause) { + throw new RuntimeException("Unexpected exception cause"); + } + } +} diff --git a/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java b/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java new file mode 100644 index 00000000000..3f62fac8f77 --- /dev/null +++ b/test/jdk/javax/net/ssl/SSLException/CheckSSLProtocolException.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2022 THL A29 Limited, a Tencent company. 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 8282723 + * @summary Add constructors taking a cause to JSSE exceptions + */ +import javax.net.ssl.SSLProtocolException; +import java.util.Objects; + +public class CheckSSLProtocolException { + private static String exceptionMessage = "message"; + private static Throwable exceptionCause = new RuntimeException(); + + public static void main(String[] args) throws Exception { + testException( + new SSLProtocolException(exceptionMessage, exceptionCause)); + } + + private static void testException(Exception ex) { + if (!Objects.equals(ex.getMessage(), exceptionMessage)) { + throw new RuntimeException("Unexpected exception message"); + } + + if (ex.getCause() != exceptionCause) { + throw new RuntimeException("Unexpected exception cause"); + } + } +} diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java index 54b4e3c6840..cbb42ee1a69 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, 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 @@ -349,13 +349,13 @@ public class SSLSocketSSLEngineTemplate { } finally { if (serverException != null) { if (clientException != null) { - serverException.initCause(clientException); + serverException.addSuppressed(clientException); } throw serverException; } if (clientException != null) { if (serverException != null) { - clientException.initCause(serverException); + clientException.addSuppressed(serverException); } throw clientException; } diff --git a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java index ce2e3ee121b..f200752d2a7 100644 --- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java +++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, 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 @@ -544,7 +544,7 @@ public class SSLSocketTemplate { */ if ((local != null) && (remote != null)) { // If both failed, return the curthread's exception. - local.initCause(remote); + local.addSuppressed(remote); exception = local; } else if (local != null) { exception = local; -- GitLab From 8a2d5ab07e6a1668f3e3918bdc8a30bd28a8f93b Mon Sep 17 00:00:00 2001 From: Maxim Kartashev Date: Mon, 21 Mar 2022 07:21:00 +0000 Subject: [PATCH 091/237] 8282270: java/awt/Robot Screen Capture tests fail after 8280861 Reviewed-by: aivanov --- test/jdk/ProblemList.txt | 2 - .../HiDPIRobotScreenCaptureTest.java | 6 +- .../ScreenCaptureGtkTest.java | 61 ++++++++++++++----- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 0bafc13a252..25858d1cb71 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -739,8 +739,6 @@ javax/swing/plaf/metal/MetalGradient/8163193/ButtonGradientTest.java 8277816 ma javax/swing/JInternalFrame/8160248/JInternalFrameDraggingTest.java 8277816 macosx-aarch64 javax/swing/JInternalFrame/8069348/bug8069348.java 8277816 macosx-aarch64 java/awt/Robot/HiDPIScreenCapture/ScreenCaptureTest.java 8277816 macosx-aarch64 -java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java 8282270 linux-all -java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java 8282270 windows-all java/awt/Robot/CheckCommonColors/CheckCommonColors.java 8277816 macosx-aarch64 java/awt/ColorClass/AlphaColorTest.java 8277816 macosx-aarch64 java/awt/AlphaComposite/WindowAlphaCompositeTest.java 8277816 macosx-aarch64 diff --git a/test/jdk/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java b/test/jdk/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java index 835a52c7719..db34b1714b5 100644 --- a/test/jdk/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java +++ b/test/jdk/java/awt/Robot/HiDPIScreenCapture/HiDPIRobotScreenCaptureTest.java @@ -66,14 +66,14 @@ public class HiDPIRobotScreenCaptureTest { } Frame frame = new Frame(); - // Position the frame on prime number coordinates to avoid - // them being multiple of the desktop scale; this tests Linux + // Position the frame on prime number coordinates (mind OFFSET) + // to avoid them being multiple of the desktop scale; this tests Linux // color picker better. // Also, the position should be far enough from the top left // corner of the screen to reduce the chance of being repositioned // by the system because that area's occupied by the global // menu bar and such. - frame.setBounds(83, 97, 400, 300); + frame.setBounds(78, 92, 100, 100); frame.setUndecorated(true); Panel panel = new Panel(new BorderLayout()); diff --git a/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java b/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java index ef45c08988a..6ba5ec18e0a 100644 --- a/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java +++ b/test/jdk/java/awt/Robot/HiDPIScreenCapture/ScreenCaptureGtkTest.java @@ -31,6 +31,12 @@ import java.awt.Panel; import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; +import java.awt.image.BufferedImage; +import javax.swing.UIManager; +import javax.imageio.ImageIO; +import java.io.File; +import java.io.IOException; + /** * @test @@ -40,11 +46,7 @@ import java.awt.Robot; * Gtk backends and presence of UI scaling * @requires os.family == "linux" * @run main/othervm -Djdk.gtk.version=2 -Dsun.java2d.uiScale=1 ScreenCaptureGtkTest - * @run main/othervm -Djdk.gtk.version=2 -Dsun.java2d.uiScale=2 ScreenCaptureGtkTest - * @run main/othervm -Djdk.gtk.version=2 -Dsun.java2d.uiScale=3 ScreenCaptureGtkTest * @run main/othervm -Djdk.gtk.version=3 -Dsun.java2d.uiScale=1 ScreenCaptureGtkTest - * @run main/othervm -Djdk.gtk.version=3 -Dsun.java2d.uiScale=2 ScreenCaptureGtkTest - * @run main/othervm -Djdk.gtk.version=3 -Dsun.java2d.uiScale=3 ScreenCaptureGtkTest */ public class ScreenCaptureGtkTest { @@ -52,15 +54,18 @@ public class ScreenCaptureGtkTest { Color.GREEN, Color.BLUE, Color.ORANGE, Color.RED}; public static void main(String[] args) throws Exception { + final int topOffset = 50; + final int leftOffset = 50; + Frame frame = new Frame(); - // Position the frame on prime number coordinates to avoid - // them being multiple of the desktop scale; this tests Linux - // color picker better. + // Position the frame such that color picker will work with + // prime number coordinates (mind the offset) to avoid them being + // multiple of the desktop scale; this tests Linux color picker better. // Also, the position should be far enough from the top left // corner of the screen to reduce the chance of being repositioned // by the system because that area's occupied by the global // menu bar and such. - frame.setBounds(83, 97, 400, 300); + frame.setBounds(89, 99, 100, 100); frame.setUndecorated(true); Panel panel = new Panel(new BorderLayout()); @@ -74,9 +79,9 @@ public class ScreenCaptureGtkTest { g.fillRect(0, 0, w, h); // Paint several distinct pixels next to one another // in order to test color picker's precision. - for (int i = 1; i < 4; i++) { + for (int i = 1; i < COLORS.length; i++) { g.setColor(COLORS[i]); - g.fillRect(i, 0, 1, 1); + g.fillRect(leftOffset + i, topOffset, 1, 1); } } }; @@ -88,19 +93,25 @@ public class ScreenCaptureGtkTest { robot.waitForIdle(); robot.delay(500); - final Point screenLocation = frame.getLocationOnScreen(); - checkPixelColors(robot, screenLocation.x, screenLocation.y); + captureImageOf(frame, robot); - robot.delay(100); - frame.dispose(); + final Point screenLocation = frame.getLocationOnScreen(); + try { + checkPixelColors(robot, screenLocation.x + leftOffset, + screenLocation.y + topOffset); + } finally { + robot.delay(100); + frame.dispose(); + } } static void checkPixelColors(Robot robot, int x, int y) { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < COLORS.length; i++) { final Color actualColor = robot.getPixelColor(x + i, y); System.out.print("Checking color at " + (x + i) + ", " + y + " to be equal to " + COLORS[i]); if (!actualColor.equals(COLORS[i])) { System.out.println("... Mismatch: found " + actualColor + " instead"); + saveImage(); throw new RuntimeException("Wrong screen pixel color"); } else { @@ -108,4 +119,24 @@ public class ScreenCaptureGtkTest { } } } + + private static BufferedImage image; + + static void captureImageOf(Frame frame, Robot robot) { + Rectangle rect = frame.getBounds(); + rect.setLocation(frame.getLocationOnScreen()); + + System.out.println("Creating screen capture of " + rect); + image = robot.createScreenCapture(rect); + } + + static void saveImage() { + System.out.println("Check image.png"); + try { + ImageIO.write(image, "png", new File("image.png")); + } catch(IOException e) { + System.out.println("failed to save image.png."); + e.printStackTrace(); + } + } } -- GitLab From b451273d209d9dfce3d7c4464defe0df523dfc7c Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Mon, 21 Mar 2022 07:33:20 +0000 Subject: [PATCH 092/237] 8282548: Create a regression test for JDK-4330998 Reviewed-by: aivanov --- .../4330998/JEditorPaneSetTextNullTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 test/jdk/javax/swing/JEditorPane/4330998/JEditorPaneSetTextNullTest.java diff --git a/test/jdk/javax/swing/JEditorPane/4330998/JEditorPaneSetTextNullTest.java b/test/jdk/javax/swing/JEditorPane/4330998/JEditorPaneSetTextNullTest.java new file mode 100644 index 00000000000..5b543894ef6 --- /dev/null +++ b/test/jdk/javax/swing/JEditorPane/4330998/JEditorPaneSetTextNullTest.java @@ -0,0 +1,45 @@ + /* + * Copyright (c) 2013, 2022, 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. + */ + + import javax.swing.JEditorPane; + import javax.swing.SwingUtilities; + + /* + * @test + * @bug 4330998 + * @summary Verifies that JEditorPane.setText(null) doesn't throw NullPointerException. + * @run main JEditorPaneSetTextNullTest + */ + public class JEditorPaneSetTextNullTest { + + public static void main(String[] args) throws Exception { + try { + SwingUtilities.invokeAndWait(() -> new JEditorPane().setText(null)); + System.out.println("Test passed"); + } catch (Exception e) { + throw new RuntimeException("Test failed, caught Exception " + e + + " when calling JEditorPane.setText(null)"); + } + } + + } -- GitLab From 83a1c90433343107eaa2a7fa41b9b07f86b6ce19 Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Mon, 21 Mar 2022 07:36:21 +0000 Subject: [PATCH 093/237] 8282789: Create a regression test for the JTree usecase of JDK-4618767 Reviewed-by: aivanov --- .../4618767/JTreeSelectedElementTest.java | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 test/jdk/javax/swing/JTree/4618767/JTreeSelectedElementTest.java diff --git a/test/jdk/javax/swing/JTree/4618767/JTreeSelectedElementTest.java b/test/jdk/javax/swing/JTree/4618767/JTreeSelectedElementTest.java new file mode 100644 index 00000000000..19b00c05d37 --- /dev/null +++ b/test/jdk/javax/swing/JTree/4618767/JTreeSelectedElementTest.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2002, 2022, 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. + */ + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.event.MenuEvent; +import javax.swing.event.MenuListener; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4618767 + * @summary This test confirms that typing a letter while a JTree has focus now makes the selection + * not jump to the item whose text starts with that letter if that typed letter is accompanied + * by modifier keys such as ALT or CTRL(eg: ALT+F). + * @run main JTreeSelectedElementTest + */ +public class JTreeSelectedElementTest { + + private static final int FILE_MENU = KeyEvent.VK_F; + private static JFrame frame; + private static JTree tree; + private static Robot robot; + private static CountDownLatch menuSelectedEventLatch; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + + final boolean isMac = System.getProperty("os.name") + .toLowerCase() + .contains("os x"); + + List lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + menuSelectedEventLatch = new CountDownLatch(1); + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + // Select the node named as 'colors' + Point pt = getNodeLocation(1); + robot.mouseMove(pt.x, pt.y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + // Assertion check to verify that the selected node is 'colors' + final String elementSelBefore = getCurrentNodeName(); + if (!"colors".equals(elementSelBefore)) { + throw new RuntimeException("Test failed for " + laf + + " as the tree node selected: " + elementSelBefore + + " is not the expected one 'colors'" + ); + } + + // Now operate Menu using Mnemonics, different key combinations for different OSes. + // For most OSes it's ALT+F; on macOS it's ALT+CNTRL+F except for Nimbus LaF. + if (isMac && !laf.contains("Nimbus")) { + hitKeys(KeyEvent.VK_ALT, KeyEvent.VK_CONTROL, FILE_MENU); + } else { + hitKeys(KeyEvent.VK_ALT, FILE_MENU); + } + + // Wait until the menu got selected. + if (!menuSelectedEventLatch.await(3, TimeUnit.SECONDS)) { + throw new RuntimeException("Waited too long, but can't select menu using mnemonics for " + laf); + } + + hitKeys(KeyEvent.VK_ENTER); + + String elementSelAfter = getCurrentNodeName(); + + // As per the fix of BugID 4618767, the tree element selection should not change + if (!elementSelBefore.equals(elementSelAfter)) { + throw new RuntimeException("Test failed for " + laf + + " as tree.getLastSelectedPathComponent() before: " + elementSelBefore + + " not same as tree.getLastSelectedPathComponent() after pressing Enter: " + + elementSelAfter + ); + } + + System.out.println("Test passed for laf: " + laf); + + } finally { + SwingUtilities.invokeAndWait(JTreeSelectedElementTest::disposeFrame); + } + } + } + + private static void hitKeys(int... keys) { + for (int key : keys) { + robot.keyPress(key); + } + + for (int i = keys.length - 1; i >= 0; i--) { + robot.keyRelease(keys[i]); + } + } + + private static String getCurrentNodeName() throws Exception { + AtomicReference nodeName = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + nodeName.set(tree.getLastSelectedPathComponent().toString().trim()); + }); + return nodeName.get(); + } + + private static Point getNodeLocation(int rowCount) throws Exception { + AtomicReference treeNodeLoc = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + final Point locationOnScreen = tree.getLocationOnScreen(); + Rectangle rt = tree.getPathBounds(tree.getPathForRow(rowCount)); + locationOnScreen.translate(rt.x + rt.width / 2, rt.y + rt.height / 2); + treeNodeLoc.set(locationOnScreen); + }); + return treeNodeLoc.get(); + } + + private static void createUI() { + frame = new JFrame(); + tree = new JTree(); + JMenu menu = new JMenu("File"); + menu.setMnemonic(FILE_MENU); + JMenuItem menuItem = new JMenuItem("Dummy"); + menu.add(menuItem); + menu.addMenuListener(new MenuListener() { + @Override + public void menuSelected(MenuEvent e) { + menuSelectedEventLatch.countDown(); + } + + @Override + public void menuDeselected(MenuEvent e) { + } + + @Override + public void menuCanceled(MenuEvent e) { + } + }); + + JMenuBar menuBar = new JMenuBar(); + menuBar.add(menu); + + frame.setJMenuBar(menuBar); + frame.setContentPane(tree); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} -- GitLab From e709cb05dcf67462f266c1f3dae30976b562676d Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 21 Mar 2022 08:25:33 +0000 Subject: [PATCH 094/237] 8283186: Explicitly pass a third temp register to MacroAssembler::store_heap_oop Reviewed-by: eosterlund --- .../x86/gc/g1/g1BarrierSetAssembler_x86.cpp | 7 ++- .../x86/gc/g1/g1BarrierSetAssembler_x86.hpp | 2 +- .../x86/gc/shared/barrierSetAssembler_x86.cpp | 2 +- .../x86/gc/shared/barrierSetAssembler_x86.hpp | 2 +- .../cardTableBarrierSetAssembler_x86.cpp | 4 +- .../cardTableBarrierSetAssembler_x86.hpp | 2 +- .../shared/modRefBarrierSetAssembler_x86.cpp | 6 +-- .../shared/modRefBarrierSetAssembler_x86.hpp | 4 +- .../shenandoahBarrierSetAssembler_x86.cpp | 9 ++-- .../shenandoahBarrierSetAssembler_x86.hpp | 2 +- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp | 5 +- .../cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp | 3 +- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 12 ++--- src/hotspot/cpu/x86/macroAssembler_x86.hpp | 4 +- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 2 +- src/hotspot/cpu/x86/templateTable_x86.cpp | 46 +++++++++---------- 16 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index 6525b13c5c2..0fb005ce06f 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -342,7 +342,7 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, } void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool in_heap = (decorators & IN_HEAP) != 0; bool as_normal = (decorators & AS_NORMAL) != 0; assert((decorators & IS_DEST_UNINITIALIZED) == 0, "unsupported"); @@ -350,7 +350,6 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco bool needs_pre_barrier = as_normal; bool needs_post_barrier = val != noreg && in_heap; - Register tmp3 = LP64_ONLY(r8) NOT_LP64(rsi); Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); // flatten object address if needed // We do it regardless of precise because we need the registers @@ -379,7 +378,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco false /* expand_call */); } if (val == noreg) { - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); } else { Register new_val = val; if (needs_post_barrier) { @@ -389,7 +388,7 @@ void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet deco __ movptr(new_val, val); } } - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); if (needs_post_barrier) { g1_write_barrier_post(masm /*masm*/, tmp1 /* store_adr */, diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp index 94bbadc7b2b..a5695f5657a 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.hpp @@ -54,7 +54,7 @@ class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { Register tmp2); virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); public: void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp index 55823bdf217..930926bbb17 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp @@ -103,7 +103,7 @@ void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, } void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool in_heap = (decorators & IN_HEAP) != 0; bool in_native = (decorators & IN_NATIVE) != 0; bool is_not_null = (decorators & IS_NOT_NULL) != 0; diff --git a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp index 3c63c00e4db..085238d60b5 100644 --- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp @@ -47,7 +47,7 @@ public: virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); // Support for jniFastGetField to try resolving a jobject/jweak in native virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp index 7fc36ffae8f..f314cac5980 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.cpp @@ -128,7 +128,7 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob } void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool in_heap = (decorators & IN_HEAP) != 0; bool is_array = (decorators & IS_ARRAY) != 0; @@ -137,7 +137,7 @@ void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorS bool needs_post_barrier = val != noreg && in_heap; - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, noreg, noreg, noreg); if (needs_post_barrier) { // flatten object address if needed if (!precise || (dst.index() == noreg && dst.disp() == 0)) { diff --git a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp index a65286bd599..4760b222977 100644 --- a/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/cardTableBarrierSetAssembler_x86.hpp @@ -35,7 +35,7 @@ protected: virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp); virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); }; #endif // CPU_X86_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp index 9325ab7ecf9..618095bdfa6 100644 --- a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.cpp @@ -84,10 +84,10 @@ void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Decorat } void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { if (is_reference_type(type)) { - oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2); + oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); } else { - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); } } diff --git a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp index 39950225bfe..c8b5043256a 100644 --- a/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shared/modRefBarrierSetAssembler_x86.hpp @@ -39,7 +39,7 @@ protected: virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) {} virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) = 0; + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) = 0; public: virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register src, Register dst, Register count); @@ -47,7 +47,7 @@ public: Register src, Register dst, Register count); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); }; #endif // CPU_X86_GC_SHARED_MODREFBARRIERSETASSEMBLER_X86_HPP diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 64169b01529..d213e6fda39 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -591,7 +591,7 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d } void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2) { + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3) { bool on_oop = is_reference_type(type); bool in_heap = (decorators & IN_HEAP) != 0; @@ -599,7 +599,6 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet if (on_oop && in_heap) { bool needs_pre_barrier = as_normal; - Register tmp3 = LP64_ONLY(r8) NOT_LP64(rsi); Register rthread = LP64_ONLY(r15_thread) NOT_LP64(rcx); // flatten object address if needed // We do it regardless of precise because we need the registers @@ -629,14 +628,14 @@ void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet false /* expand_call */); } if (val == noreg) { - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); } else { iu_barrier(masm, val, tmp3); - BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg); + BarrierSetAssembler::store_at(masm, decorators, type, Address(tmp1, 0), val, noreg, noreg, noreg); } NOT_LP64(imasm->restore_bcp()); } else { - BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3); } } diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp index 2a8c0862b9e..47dfe144928 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp @@ -77,7 +77,7 @@ public: virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, Register dst, Address src, Register tmp1, Register tmp_thread); virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, - Address dst, Register val, Register tmp1, Register tmp2); + Address dst, Register val, Register tmp1, Register tmp2, Register tmp3); virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, Register obj, Register tmp, Label& slowpath); }; diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index 8c74db952e8..00071d66da3 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -193,7 +193,8 @@ void ZBarrierSetAssembler::store_at(MacroAssembler* masm, Address dst, Register src, Register tmp1, - Register tmp2) { + Register tmp2, + Register tmp3) { BLOCK_COMMENT("ZBarrierSetAssembler::store_at {"); // Verify oop store @@ -211,7 +212,7 @@ void ZBarrierSetAssembler::store_at(MacroAssembler* masm, } // Store value - BarrierSetAssembler::store_at(masm, decorators, type, dst, src, tmp1, tmp2); + BarrierSetAssembler::store_at(masm, decorators, type, dst, src, tmp1, tmp2, tmp3); BLOCK_COMMENT("} ZBarrierSetAssembler::store_at"); } diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp index 134f7e6c9e2..2446bd1e46a 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp @@ -61,7 +61,8 @@ public: Address dst, Register src, Register tmp1, - Register tmp2); + Register tmp2, + Register tmp3); #endif // ASSERT virtual void arraycopy_prologue(MacroAssembler* masm, diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 7659598fcb7..944e7b9b816 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -4590,14 +4590,14 @@ void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, Reg } void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register src, - Register tmp1, Register tmp2) { + Register tmp1, Register tmp2, Register tmp3) { BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); decorators = AccessInternal::decorator_fixup(decorators); bool as_raw = (decorators & AS_RAW) != 0; if (as_raw) { - bs->BarrierSetAssembler::store_at(this, decorators, type, dst, src, tmp1, tmp2); + bs->BarrierSetAssembler::store_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3); } else { - bs->store_at(this, decorators, type, dst, src, tmp1, tmp2); + bs->store_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3); } } @@ -4613,13 +4613,13 @@ void MacroAssembler::load_heap_oop_not_null(Register dst, Address src, Register } void MacroAssembler::store_heap_oop(Address dst, Register src, Register tmp1, - Register tmp2, DecoratorSet decorators) { - access_store_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, tmp2); + Register tmp2, Register tmp3, DecoratorSet decorators) { + access_store_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, tmp2, tmp3); } // Used for storing NULLs. void MacroAssembler::store_heap_oop_null(Address dst) { - access_store_at(T_OBJECT, IN_HEAP, dst, noreg, noreg, noreg); + access_store_at(T_OBJECT, IN_HEAP, dst, noreg, noreg, noreg, noreg); } #ifdef _LP64 diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 3bffad9940b..918019d015c 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -345,14 +345,14 @@ class MacroAssembler: public Assembler { void access_load_at(BasicType type, DecoratorSet decorators, Register dst, Address src, Register tmp1, Register thread_tmp); void access_store_at(BasicType type, DecoratorSet decorators, Address dst, Register src, - Register tmp1, Register tmp2); + Register tmp1, Register tmp2, Register tmp3); void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, Register thread_tmp = noreg, DecoratorSet decorators = 0); void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg, Register thread_tmp = noreg, DecoratorSet decorators = 0); void store_heap_oop(Address dst, Register src, Register tmp1 = noreg, - Register tmp2 = noreg, DecoratorSet decorators = 0); + Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0); // Used for storing NULL. All other oop constants should be // stored using routines that take a jobject. diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 6bdff24bddd..39d5cbe2fb4 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -2848,7 +2848,7 @@ class StubGenerator: public StubCodeGenerator { __ align(OptoLoopAlignment); __ BIND(L_store_element); - __ store_heap_oop(to_element_addr, rax_oop, noreg, noreg, AS_RAW); // store the oop + __ store_heap_oop(to_element_addr, rax_oop, noreg, noreg, noreg, AS_RAW); // store the oop __ increment(count); // increment the count toward zero __ jcc(Assembler::zero, L_do_card_marks); diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index 0532fb17785..cadc71916db 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -152,7 +152,7 @@ static void do_oop_store(InterpreterMacroAssembler* _masm, Register val, DecoratorSet decorators = 0) { assert(val == noreg || val == rax, "parameter is just for looks"); - __ store_heap_oop(dst, val, rdx, rbx, decorators); + __ store_heap_oop(dst, val, rdx, rbx, LP64_ONLY(r8) NOT_LP64(rsi), decorators); } static void do_oop_load(InterpreterMacroAssembler* _masm, @@ -1067,7 +1067,7 @@ void TemplateTable::iastore() { __ access_store_at(T_INT, IN_HEAP | IS_ARRAY, Address(rdx, rbx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_INT)), - rax, noreg, noreg); + rax, noreg, noreg, noreg); } void TemplateTable::lastore() { @@ -1081,7 +1081,7 @@ void TemplateTable::lastore() { __ access_store_at(T_LONG, IN_HEAP | IS_ARRAY, Address(rcx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_LONG)), - noreg /* ltos */, noreg, noreg); + noreg /* ltos */, noreg, noreg, noreg); } @@ -1095,7 +1095,7 @@ void TemplateTable::fastore() { __ access_store_at(T_FLOAT, IN_HEAP | IS_ARRAY, Address(rdx, rbx, Address::times_4, arrayOopDesc::base_offset_in_bytes(T_FLOAT)), - noreg /* ftos */, noreg, noreg); + noreg /* ftos */, noreg, noreg, noreg); } void TemplateTable::dastore() { @@ -1108,7 +1108,7 @@ void TemplateTable::dastore() { __ access_store_at(T_DOUBLE, IN_HEAP | IS_ARRAY, Address(rdx, rbx, Address::times_8, arrayOopDesc::base_offset_in_bytes(T_DOUBLE)), - noreg /* dtos */, noreg, noreg); + noreg /* dtos */, noreg, noreg, noreg); } void TemplateTable::aastore() { @@ -1186,7 +1186,7 @@ void TemplateTable::bastore() { __ access_store_at(T_BYTE, IN_HEAP | IS_ARRAY, Address(rdx, rbx,Address::times_1, arrayOopDesc::base_offset_in_bytes(T_BYTE)), - rax, noreg, noreg); + rax, noreg, noreg, noreg); } void TemplateTable::castore() { @@ -1199,7 +1199,7 @@ void TemplateTable::castore() { __ access_store_at(T_CHAR, IN_HEAP | IS_ARRAY, Address(rdx, rbx, Address::times_2, arrayOopDesc::base_offset_in_bytes(T_CHAR)), - rax, noreg, noreg); + rax, noreg, noreg, noreg); } @@ -3102,7 +3102,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(btos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_BYTE, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_BYTE, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_bputfield, bc, rbx, true, byte_no); } @@ -3117,7 +3117,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(ztos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_BOOLEAN, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_BOOLEAN, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_zputfield, bc, rbx, true, byte_no); } @@ -3148,7 +3148,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(itos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_INT, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_INT, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_iputfield, bc, rbx, true, byte_no); } @@ -3163,7 +3163,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(ctos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_CHAR, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_CHAR, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_cputfield, bc, rbx, true, byte_no); } @@ -3178,7 +3178,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(stos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_SHORT, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_SHORT, IN_HEAP, field, rax, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_sputfield, bc, rbx, true, byte_no); } @@ -3194,7 +3194,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri __ pop(ltos); if (!is_static) pop_and_check_object(obj); // MO_RELAXED: generate atomic store for the case of volatile field (important for x86_32) - __ access_store_at(T_LONG, IN_HEAP | MO_RELAXED, field, noreg /* ltos*/, noreg, noreg); + __ access_store_at(T_LONG, IN_HEAP | MO_RELAXED, field, noreg /* ltos*/, noreg, noreg, noreg); #ifdef _LP64 if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_lputfield, bc, rbx, true, byte_no); @@ -3211,7 +3211,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri { __ pop(ftos); if (!is_static) pop_and_check_object(obj); - __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos */, noreg, noreg); + __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos */, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_fputfield, bc, rbx, true, byte_no); } @@ -3230,7 +3230,7 @@ void TemplateTable::putfield_or_static_helper(int byte_no, bool is_static, Rewri __ pop(dtos); if (!is_static) pop_and_check_object(obj); // MO_RELAXED: for the case of volatile field, in fact it adds no extra work for the underlying implementation - __ access_store_at(T_DOUBLE, IN_HEAP | MO_RELAXED, field, noreg /* dtos */, noreg, noreg); + __ access_store_at(T_DOUBLE, IN_HEAP | MO_RELAXED, field, noreg /* dtos */, noreg, noreg, noreg); if (!is_static && rc == may_rewrite) { patch_bytecode(Bytecodes::_fast_dputfield, bc, rbx, true, byte_no); } @@ -3373,31 +3373,31 @@ void TemplateTable::fast_storefield_helper(Address field, Register rax) { break; case Bytecodes::_fast_lputfield: #ifdef _LP64 - __ access_store_at(T_LONG, IN_HEAP, field, noreg /* ltos */, noreg, noreg); + __ access_store_at(T_LONG, IN_HEAP, field, noreg /* ltos */, noreg, noreg, noreg); #else __ stop("should not be rewritten"); #endif break; case Bytecodes::_fast_iputfield: - __ access_store_at(T_INT, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_INT, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_zputfield: - __ access_store_at(T_BOOLEAN, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_BOOLEAN, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_bputfield: - __ access_store_at(T_BYTE, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_BYTE, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_sputfield: - __ access_store_at(T_SHORT, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_SHORT, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_cputfield: - __ access_store_at(T_CHAR, IN_HEAP, field, rax, noreg, noreg); + __ access_store_at(T_CHAR, IN_HEAP, field, rax, noreg, noreg, noreg); break; case Bytecodes::_fast_fputfield: - __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos*/, noreg, noreg); + __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos*/, noreg, noreg, noreg); break; case Bytecodes::_fast_dputfield: - __ access_store_at(T_DOUBLE, IN_HEAP, field, noreg /* dtos*/, noreg, noreg); + __ access_store_at(T_DOUBLE, IN_HEAP, field, noreg /* dtos*/, noreg, noreg, noreg); break; default: ShouldNotReachHere(); -- GitLab From ec62d90db2428d0da6ed0f338858f5bc2a76e991 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 21 Mar 2022 08:39:17 +0000 Subject: [PATCH 095/237] 8283365: G1: Remove duplicate assertions in HeapRegion::oops_on_memregion_seq_iterate_careful Reviewed-by: kbarrett, tschatzl --- src/hotspot/share/gc/g1/heapRegion.inline.hpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/hotspot/share/gc/g1/heapRegion.inline.hpp b/src/hotspot/share/gc/g1/heapRegion.inline.hpp index 3d61cc1620a..e94320fbdb4 100644 --- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp @@ -329,16 +329,6 @@ HeapWord* HeapRegion::oops_on_memregion_seq_iterate_careful(MemRegion mr, // Find the obj that extends onto mr.start(). HeapWord* cur = block_start(start); -#ifdef ASSERT - { - assert(cur <= start, - "cur: " PTR_FORMAT ", start: " PTR_FORMAT, p2i(cur), p2i(start)); - HeapWord* next = cur + block_size(cur); - assert(start < next, - "start: " PTR_FORMAT ", next: " PTR_FORMAT, p2i(start), p2i(next)); - } -#endif - const G1CMBitMap* const bitmap = g1h->concurrent_mark()->prev_mark_bitmap(); while (true) { oop obj = cast_to_oop(cur); -- GitLab From fd9301514e2093d9dcd7bcd9e4b812146b20dd03 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 21 Mar 2022 08:40:14 +0000 Subject: [PATCH 096/237] 8283332: G1: Stricter assertion in G1BlockOffsetTablePart::forward_to_block_containing_addr Reviewed-by: kbarrett, iwalulya --- src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp index f70cb118627..058a9f58785 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp @@ -140,7 +140,7 @@ inline HeapWord* G1BlockOffsetTablePart::forward_to_block_containing_addr(HeapWo "start of block must be an initialized object"); n += block_size(q); } - assert(q <= n, "wrong order for q and addr"); + assert(q <= addr, "wrong order for q and addr"); assert(addr < n, "wrong order for addr and n"); return q; } -- GitLab From eb4849e5615dd307a5abc435a0204a6d26610fcb Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 21 Mar 2022 10:42:38 +0000 Subject: [PATCH 097/237] 8283327: Add methods to save/restore registers when calling into the VM from C1/interpreter barrier code Reviewed-by: eosterlund, dlong --- .../cpu/aarch64/macroAssembler_aarch64.cpp | 6 +- .../cpu/aarch64/macroAssembler_aarch64.hpp | 2 +- src/hotspot/cpu/aarch64/register_aarch64.hpp | 105 ---------- .../cpu/aarch64/stubGenerator_aarch64.cpp | 7 +- .../x86/gc/g1/g1BarrierSetAssembler_x86.cpp | 58 ++---- src/hotspot/cpu/x86/macroAssembler_x86.cpp | 185 ++++++++++++++++++ src/hotspot/cpu/x86/macroAssembler_x86.hpp | 30 +++ src/hotspot/cpu/x86/register_x86.hpp | 31 +++ src/hotspot/share/asm/register.hpp | 144 ++++++++++++++ 9 files changed, 417 insertions(+), 151 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index dae4e22b15b..ad1a6d58596 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2543,7 +2543,7 @@ void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) fatal("DEBUG MESSAGE: %s", msg); } -RegSet MacroAssembler::call_clobbered_registers() { +RegSet MacroAssembler::call_clobbered_gp_registers() { RegSet regs = RegSet::range(r0, r17) - RegSet::of(rscratch1, rscratch2); #ifndef R18_RESERVED regs += r18_tls; @@ -2553,7 +2553,7 @@ RegSet MacroAssembler::call_clobbered_registers() { void MacroAssembler::push_call_clobbered_registers_except(RegSet exclude) { int step = 4 * wordSize; - push(call_clobbered_registers() - exclude, sp); + push(call_clobbered_gp_registers() - exclude, sp); sub(sp, sp, step); mov(rscratch1, -step); // Push v0-v7, v16-v31. @@ -2575,7 +2575,7 @@ void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude) { reinitialize_ptrue(); - pop(call_clobbered_registers() - exclude, sp); + pop(call_clobbered_gp_registers() - exclude, sp); } void MacroAssembler::push_CPU_state(bool save_vectors, bool use_sve, diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 1344250febb..d5bfc42e784 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -468,7 +468,7 @@ public: void push_fp(FloatRegSet regs, Register stack) { if (regs.bits()) push_fp(regs.bits(), stack); } void pop_fp(FloatRegSet regs, Register stack) { if (regs.bits()) pop_fp(regs.bits(), stack); } - static RegSet call_clobbered_registers(); + static RegSet call_clobbered_gp_registers(); void push_p(PRegSet regs, Register stack) { if (regs.bits()) push_p(regs.bits(), stack); } void pop_p(PRegSet regs, Register stack) { if (regs.bits()) pop_p(regs.bits(), stack); } diff --git a/src/hotspot/cpu/aarch64/register_aarch64.hpp b/src/hotspot/cpu/aarch64/register_aarch64.hpp index 400eaeb90f2..3fe2fae42a1 100644 --- a/src/hotspot/cpu/aarch64/register_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/register_aarch64.hpp @@ -314,115 +314,10 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { static const int max_pr; }; -template class RegSetIterator; - -// A set of registers -template -class AbstractRegSet { - uint32_t _bitset; - - AbstractRegSet(uint32_t bitset) : _bitset(bitset) { } - -public: - - AbstractRegSet() : _bitset(0) { } - - AbstractRegSet(RegImpl r1) : _bitset(1 << r1->encoding()) { } - - AbstractRegSet operator+(const AbstractRegSet aSet) const { - AbstractRegSet result(_bitset | aSet._bitset); - return result; - } - - AbstractRegSet operator-(const AbstractRegSet aSet) const { - AbstractRegSet result(_bitset & ~aSet._bitset); - return result; - } - - AbstractRegSet &operator+=(const AbstractRegSet aSet) { - *this = *this + aSet; - return *this; - } - - AbstractRegSet &operator-=(const AbstractRegSet aSet) { - *this = *this - aSet; - return *this; - } - - static AbstractRegSet of(RegImpl r1) { - return AbstractRegSet(r1); - } - - static AbstractRegSet of(RegImpl r1, RegImpl r2) { - return of(r1) + r2; - } - - static AbstractRegSet of(RegImpl r1, RegImpl r2, RegImpl r3) { - return of(r1, r2) + r3; - } - - static AbstractRegSet of(RegImpl r1, RegImpl r2, RegImpl r3, RegImpl r4) { - return of(r1, r2, r3) + r4; - } - - static AbstractRegSet range(RegImpl start, RegImpl end) { - uint32_t bits = ~0; - bits <<= start->encoding(); - bits <<= 31 - end->encoding(); - bits >>= 31 - end->encoding(); - - return AbstractRegSet(bits); - } - - uint32_t bits() const { return _bitset; } - -private: - - RegImpl first(); - -public: - - friend class RegSetIterator; - - RegSetIterator begin(); -}; - typedef AbstractRegSet RegSet; typedef AbstractRegSet FloatRegSet; typedef AbstractRegSet PRegSet; -template -class RegSetIterator { - AbstractRegSet _regs; - -public: - RegSetIterator(AbstractRegSet x): _regs(x) {} - RegSetIterator(const RegSetIterator& mit) : _regs(mit._regs) {} - - RegSetIterator& operator++() { - RegImpl r = _regs.first(); - if (r->is_valid()) - _regs -= r; - return *this; - } - - bool operator==(const RegSetIterator& rhs) const { - return _regs.bits() == rhs._regs.bits(); - } - bool operator!=(const RegSetIterator& rhs) const { - return ! (rhs == *this); - } - - RegImpl operator*() { - return _regs.first(); - } -}; - -template -inline RegSetIterator AbstractRegSet::begin() { - return RegSetIterator(*this); -} - template <> inline Register AbstractRegSet::first() { uint32_t first = _bitset & -_bitset; diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 5a92dcb6b47..1b41f09d972 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -26,6 +26,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "asm/register.hpp" #include "atomic_aarch64.hpp" #include "compiler/oopMap.hpp" #include "gc/shared/barrierSet.hpp" @@ -1320,10 +1321,10 @@ class StubGenerator: public StubCodeGenerator { void clobber_registers() { #ifdef ASSERT RegSet clobbered - = MacroAssembler::call_clobbered_registers() - rscratch1; + = MacroAssembler::call_clobbered_gp_registers() - rscratch1; __ mov(rscratch1, (uint64_t)0xdeadbeef); __ orr(rscratch1, rscratch1, rscratch1, Assembler::LSL, 32); - for (RegSetIterator<> it = clobbered.begin(); *it != noreg; ++it) { + for (RegSetIterator it = clobbered.begin(); *it != noreg; ++it) { __ mov(*it, rscratch1); } #endif @@ -6629,7 +6630,7 @@ class StubGenerator: public StubCodeGenerator { // Register allocation - RegSetIterator<> regs = (RegSet::range(r0, r26) - r18_tls).begin(); + RegSetIterator regs = (RegSet::range(r0, r26) - r18_tls).begin(); Pa_base = *regs; // Argument registers if (squaring) Pb_base = Pa_base; diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index 0fb005ce06f..475a92d0f43 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -67,7 +67,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm __ jcc(Assembler::equal, filtered); - __ pusha(); // push registers + __ push_call_clobbered_registers(false /* save_fpu */); #ifdef _LP64 if (count == c_rarg0) { if (addr == c_rarg1) { @@ -90,7 +90,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), addr, count); #endif - __ popa(); + __ pop_call_clobbered_registers(false /* save_fpu */); __ bind(filtered); } @@ -98,7 +98,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count, Register tmp) { - __ pusha(); // push registers (overkill) + __ push_call_clobbered_registers(false /* save_fpu */); #ifdef _LP64 if (c_rarg0 == count) { // On win64 c_rarg0 == rcx assert_different_registers(c_rarg1, addr); @@ -114,7 +114,7 @@ void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* mas __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), addr, count); #endif - __ popa(); + __ pop_call_clobbered_registers(false /* save_fpu */); } void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, @@ -204,14 +204,15 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, __ jmp(done); __ bind(runtime); - // save the live input values - if(tosca_live) __ push(rax); - if (obj != noreg && obj != rax) - __ push(obj); + // Determine and save the live input values + RegSet saved; + if (tosca_live) saved += RegSet::of(rax); + if (obj != noreg && obj != rax) saved += RegSet::of(obj); + if (pre_val != rax) saved += RegSet::of(pre_val); + NOT_LP64( saved += RegSet::of(thread); ) - if (pre_val != rax) - __ push(pre_val); + __ push_set(saved); // Calling the runtime using the regular call_VM_leaf mechanism generates // code (generated by InterpreterMacroAssember::call_VM_leaf_base) @@ -225,8 +226,6 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, // So when we do not have have a full interpreter frame on the stack // expand_call should be passed true. - NOT_LP64( __ push(thread); ) - if (expand_call) { LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); ) #ifdef _LP64 @@ -244,17 +243,7 @@ void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, } else { __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); } - - NOT_LP64( __ pop(thread); ) - - // save the live input values - if (pre_val != rax) - __ pop(pre_val); - - if (obj != noreg && obj != rax) - __ pop(obj); - - if(tosca_live) __ pop(rax); + __ pop_set(saved); __ bind(done); } @@ -328,15 +317,10 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, __ bind(runtime); // save the live input values - __ push(store_addr); -#ifdef _LP64 - __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, r15_thread); -#else - __ push(thread); + RegSet saved = RegSet::of(store_addr NOT_LP64(COMMA thread)); + __ push_set(saved); __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ pop(thread); -#endif - __ pop(store_addr); + __ pop_set(saved); __ bind(done); } @@ -495,13 +479,13 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* __ bind(runtime); - __ save_live_registers_no_oop_map(true); + __ push_call_clobbered_registers(); // load the pre-value __ load_parameter(0, rcx); __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), rcx, thread); - __ restore_live_registers(true); + __ pop_call_clobbered_registers(); __ bind(done); @@ -514,9 +498,6 @@ void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { __ prologue("g1_post_barrier", false); - // arg0: store_address - Address store_addr(rbp, 2*BytesPerWord); - CardTableBarrierSet* ct = barrier_set_cast(BarrierSet::barrier_set()); @@ -572,12 +553,11 @@ void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* __ jmp(enqueued); __ bind(runtime); - - __ save_live_registers_no_oop_map(true); + __ push_call_clobbered_registers(); __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); - __ restore_live_registers(true); + __ pop_call_clobbered_registers(); __ bind(enqueued); __ pop(rdx); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 944e7b9b816..e9285b11e42 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -26,6 +26,7 @@ #include "jvm.h" #include "asm/assembler.hpp" #include "asm/assembler.inline.hpp" +#include "c1/c1_FrameMap.hpp" #include "compiler/compiler_globals.hpp" #include "compiler/disassembler.hpp" #include "gc/shared/barrierSet.hpp" @@ -3578,6 +3579,190 @@ void MacroAssembler::tlab_allocate(Register thread, Register obj, bs->tlab_allocate(this, thread, obj, var_size_in_bytes, con_size_in_bytes, t1, t2, slow_case); } +RegSet MacroAssembler::call_clobbered_gp_registers() { + RegSet regs; +#ifdef _LP64 + regs += RegSet::of(rax, rcx, rdx); +#ifndef WINDOWS + regs += RegSet::of(rsi, rdi); +#endif + regs += RegSet::range(r8, r11); +#else + regs += RegSet::of(rax, rcx, rdx); +#endif + return regs; +} + +XMMRegSet MacroAssembler::call_clobbered_xmm_registers() { +#if defined(WINDOWS) && defined(_LP64) + XMMRegSet result = XMMRegSet::range(xmm0, xmm5); + if (FrameMap::get_num_caller_save_xmms() > 16) { + result += XMMRegSet::range(xmm16, as_XMMRegister(FrameMap::get_num_caller_save_xmms() - 1)); + } + return result; +#else + return XMMRegSet::range(xmm0, as_XMMRegister(FrameMap::get_num_caller_save_xmms() - 1)); +#endif +} + +static int FPUSaveAreaSize = align_up(108, StackAlignmentInBytes); // 108 bytes needed for FPU state by fsave/frstor + +#ifndef _LP64 +static bool use_x87_registers() { return UseSSE < 2; } +#endif +static bool use_xmm_registers() { return UseSSE >= 1; } + +// C1 only ever uses the first double/float of the XMM register. +static int xmm_save_size() { return UseSSE >= 2 ? sizeof(double) : sizeof(float); } + +static void save_xmm_register(MacroAssembler* masm, int offset, XMMRegister reg) { + if (UseSSE == 1) { + masm->movflt(Address(rsp, offset), reg); + } else { + masm->movdbl(Address(rsp, offset), reg); + } +} + +static void restore_xmm_register(MacroAssembler* masm, int offset, XMMRegister reg) { + if (UseSSE == 1) { + masm->movflt(reg, Address(rsp, offset)); + } else { + masm->movdbl(reg, Address(rsp, offset)); + } +} + +int register_section_sizes(RegSet gp_registers, XMMRegSet xmm_registers, bool save_fpu, + int& gp_area_size, int& fp_area_size, int& xmm_area_size) { + + gp_area_size = align_up(gp_registers.size() * RegisterImpl::max_slots_per_register * VMRegImpl::stack_slot_size, + StackAlignmentInBytes); +#ifdef _LP64 + fp_area_size = 0; +#else + fp_area_size = (save_fpu && use_x87_registers()) ? FPUSaveAreaSize : 0; +#endif + xmm_area_size = (save_fpu && use_xmm_registers()) ? xmm_registers.size() * xmm_save_size() : 0; + + return gp_area_size + fp_area_size + xmm_area_size; +} + +void MacroAssembler::push_call_clobbered_registers_except(RegSet exclude, bool save_fpu) { + block_comment("push_call_clobbered_registers start"); + // Regular registers + RegSet gp_registers_to_push = call_clobbered_gp_registers() - exclude; + + int gp_area_size; + int fp_area_size; + int xmm_area_size; + int total_save_size = register_section_sizes(gp_registers_to_push, call_clobbered_xmm_registers(), save_fpu, + gp_area_size, fp_area_size, xmm_area_size); + subptr(rsp, total_save_size); + + push_set(gp_registers_to_push, 0); + +#ifndef _LP64 + if (save_fpu && use_x87_registers()) { + fnsave(Address(rsp, gp_area_size)); + fwait(); + } +#endif + if (save_fpu && use_xmm_registers()) { + push_set(call_clobbered_xmm_registers(), gp_area_size + fp_area_size); + } + + block_comment("push_call_clobbered_registers end"); +} + +void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude, bool restore_fpu) { + block_comment("pop_call_clobbered_registers start"); + + RegSet gp_registers_to_pop = call_clobbered_gp_registers() - exclude; + + int gp_area_size; + int fp_area_size; + int xmm_area_size; + int total_save_size = register_section_sizes(gp_registers_to_pop, call_clobbered_xmm_registers(), restore_fpu, + gp_area_size, fp_area_size, xmm_area_size); + + if (restore_fpu && use_xmm_registers()) { + pop_set(call_clobbered_xmm_registers(), gp_area_size + fp_area_size); + } +#ifndef _LP64 + if (restore_fpu && use_x87_registers()) { + frstor(Address(rsp, gp_area_size)); + } +#endif + + pop_set(gp_registers_to_pop, 0); + + addptr(rsp, total_save_size); + + vzeroupper(); + + block_comment("pop_call_clobbered_registers end"); +} + +void MacroAssembler::push_set(XMMRegSet set, int offset) { + assert(is_aligned(set.size() * xmm_save_size(), StackAlignmentInBytes), "must be"); + int spill_offset = offset; + + for (RegSetIterator it = set.begin(); *it != xnoreg; ++it) { + save_xmm_register(this, spill_offset, *it); + spill_offset += xmm_save_size(); + } +} + +void MacroAssembler::pop_set(XMMRegSet set, int offset) { + int restore_size = set.size() * xmm_save_size(); + assert(is_aligned(restore_size, StackAlignmentInBytes), "must be"); + + int restore_offset = offset + restore_size - xmm_save_size(); + + for (ReverseRegSetIterator it = set.rbegin(); *it != xnoreg; ++it) { + restore_xmm_register(this, restore_offset, *it); + restore_offset -= xmm_save_size(); + } +} + +void MacroAssembler::push_set(RegSet set, int offset) { + int spill_offset; + if (offset == -1) { + int register_push_size = set.size() * RegisterImpl::max_slots_per_register * VMRegImpl::stack_slot_size; + int aligned_size = align_up(register_push_size, StackAlignmentInBytes); + subptr(rsp, aligned_size); + spill_offset = 0; + } else { + spill_offset = offset; + } + + for (RegSetIterator it = set.begin(); *it != noreg; ++it) { + movptr(Address(rsp, spill_offset), *it); + spill_offset += RegisterImpl::max_slots_per_register * VMRegImpl::stack_slot_size; + } +} + +void MacroAssembler::pop_set(RegSet set, int offset) { + + int gp_reg_size = RegisterImpl::max_slots_per_register * VMRegImpl::stack_slot_size; + int restore_size = set.size() * gp_reg_size; + int aligned_size = align_up(restore_size, StackAlignmentInBytes); + + int restore_offset; + if (offset == -1) { + restore_offset = restore_size - gp_reg_size; + } else { + restore_offset = offset + restore_size - gp_reg_size; + } + for (ReverseRegSetIterator it = set.rbegin(); *it != noreg; ++it) { + movptr(*it, Address(rsp, restore_offset)); + restore_offset -= gp_reg_size; + } + + if (offset == -1) { + addptr(rsp, aligned_size); + } +} + // Defines obj, preserves var_size_in_bytes void MacroAssembler::eden_allocate(Register thread, Register obj, Register var_size_in_bytes, diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 918019d015c..9b3da9d5de1 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -26,6 +26,7 @@ #define CPU_X86_MACROASSEMBLER_X86_HPP #include "asm/assembler.hpp" +#include "asm/register.hpp" #include "code/vmreg.inline.hpp" #include "compiler/oopMap.hpp" #include "utilities/macros.hpp" @@ -521,6 +522,35 @@ class MacroAssembler: public Assembler { // Round up to a power of two void round_to(Register reg, int modulus); +private: + // General purpose and XMM registers potentially clobbered by native code; there + // is no need for FPU or AVX opmask related methods because C1/interpreter + // - we save/restore FPU state as a whole always + // - do not care about AVX-512 opmask + static RegSet call_clobbered_gp_registers(); + static XMMRegSet call_clobbered_xmm_registers(); + + void push_set(XMMRegSet set, int offset); + void pop_set(XMMRegSet set, int offset); + +public: + void push_set(RegSet set, int offset = -1); + void pop_set(RegSet set, int offset = -1); + + // Push and pop everything that might be clobbered by a native + // runtime call. + // Only save the lower 64 bits of each vector register. + // Additonal registers can be excluded in a passed RegSet. + void push_call_clobbered_registers_except(RegSet exclude, bool save_fpu = true); + void pop_call_clobbered_registers_except(RegSet exclude, bool restore_fpu = true); + + void push_call_clobbered_registers(bool save_fpu = true) { + push_call_clobbered_registers_except(RegSet(), save_fpu); + } + void pop_call_clobbered_registers(bool restore_fpu = true) { + pop_call_clobbered_registers_except(RegSet(), restore_fpu); + } + // allocation void eden_allocate( Register thread, // Current thread diff --git a/src/hotspot/cpu/x86/register_x86.hpp b/src/hotspot/cpu/x86/register_x86.hpp index 38ca95c0126..f57b1db48c8 100644 --- a/src/hotspot/cpu/x86/register_x86.hpp +++ b/src/hotspot/cpu/x86/register_x86.hpp @@ -26,6 +26,8 @@ #define CPU_X86_REGISTER_X86_HPP #include "asm/register.hpp" +#include "utilities/count_leading_zeros.hpp" +#include "utilities/powerOfTwo.hpp" class VMRegImpl; typedef VMRegImpl* VMReg; @@ -272,4 +274,33 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl { }; +template <> +inline Register AbstractRegSet::first() { + uint32_t first = _bitset & -_bitset; + return first ? as_Register(exact_log2(first)) : noreg; +} + +template <> +inline Register AbstractRegSet::last() { + if (_bitset == 0) { return noreg; } + uint32_t last = 31 - count_leading_zeros(_bitset); + return as_Register(last); +} + +template <> +inline XMMRegister AbstractRegSet::first() { + uint32_t first = _bitset & -_bitset; + return first ? as_XMMRegister(exact_log2(first)) : xnoreg; +} + +template <> +inline XMMRegister AbstractRegSet::last() { + if (_bitset == 0) { return xnoreg; } + uint32_t last = 31 - count_leading_zeros(_bitset); + return as_XMMRegister(last); +} + +typedef AbstractRegSet RegSet; +typedef AbstractRegSet XMMRegSet; + #endif // CPU_X86_REGISTER_X86_HPP diff --git a/src/hotspot/share/asm/register.hpp b/src/hotspot/share/asm/register.hpp index 4207267ebab..b8538e4df68 100644 --- a/src/hotspot/share/asm/register.hpp +++ b/src/hotspot/share/asm/register.hpp @@ -28,6 +28,7 @@ #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" +#include "utilities/population_count.hpp" // Use AbstractRegister as shortcut class AbstractRegisterImpl; @@ -86,6 +87,149 @@ const type name = ((type)value) #define INTERNAL_VISIBILITY #endif +template class RegSetIterator; +template class ReverseRegSetIterator; + +// A set of registers +template +class AbstractRegSet { + uint32_t _bitset; + + AbstractRegSet(uint32_t bitset) : _bitset(bitset) { } + +public: + + AbstractRegSet() : _bitset(0) { } + + AbstractRegSet(RegImpl r1) : _bitset(1 << r1->encoding()) { } + + AbstractRegSet operator+(const AbstractRegSet aSet) const { + AbstractRegSet result(_bitset | aSet._bitset); + return result; + } + + AbstractRegSet operator-(const AbstractRegSet aSet) const { + AbstractRegSet result(_bitset & ~aSet._bitset); + return result; + } + + AbstractRegSet &operator+=(const AbstractRegSet aSet) { + *this = *this + aSet; + return *this; + } + + AbstractRegSet &operator-=(const AbstractRegSet aSet) { + *this = *this - aSet; + return *this; + } + + static AbstractRegSet of(RegImpl r1) { + return AbstractRegSet(r1); + } + + static AbstractRegSet of(RegImpl r1, RegImpl r2) { + return of(r1) + r2; + } + + static AbstractRegSet of(RegImpl r1, RegImpl r2, RegImpl r3) { + return of(r1, r2) + r3; + } + + static AbstractRegSet of(RegImpl r1, RegImpl r2, RegImpl r3, RegImpl r4) { + return of(r1, r2, r3) + r4; + } + + static AbstractRegSet range(RegImpl start, RegImpl end) { + assert(start <= end, "must be"); + uint32_t bits = ~0; + bits <<= start->encoding(); + bits <<= 31 - end->encoding(); + bits >>= 31 - end->encoding(); + + return AbstractRegSet(bits); + } + + uint size() const { return population_count(_bitset); } + + uint32_t bits() const { return _bitset; } + +private: + + RegImpl first(); + RegImpl last(); + +public: + + friend class RegSetIterator; + friend class ReverseRegSetIterator; + + RegSetIterator begin(); + ReverseRegSetIterator rbegin(); +}; + +template +class RegSetIterator { + AbstractRegSet _regs; + +public: + RegSetIterator(AbstractRegSet x): _regs(x) {} + RegSetIterator(const RegSetIterator& mit) : _regs(mit._regs) {} + + RegSetIterator& operator++() { + RegImpl r = _regs.first(); + if (r->is_valid()) + _regs -= r; + return *this; + } + + bool operator==(const RegSetIterator& rhs) const { + return _regs.bits() == rhs._regs.bits(); + } + bool operator!=(const RegSetIterator& rhs) const { + return ! (rhs == *this); + } + + RegImpl operator*() { + return _regs.first(); + } +}; + +template +inline RegSetIterator AbstractRegSet::begin() { + return RegSetIterator(*this); +} + +template +class ReverseRegSetIterator { + AbstractRegSet _regs; + +public: + ReverseRegSetIterator(AbstractRegSet x): _regs(x) {} + ReverseRegSetIterator(const ReverseRegSetIterator& mit) : _regs(mit._regs) {} + + ReverseRegSetIterator& operator++() { + RegImpl r = _regs.last(); + if (r->is_valid()) + _regs -= r; + return *this; + } + + bool operator==(const ReverseRegSetIterator& rhs) const { + return _regs.bits() == rhs._regs.bits(); + } + bool operator!=(const ReverseRegSetIterator& rhs) const { + return ! (rhs == *this); + } + + RegImpl operator*() { + return _regs.last(); + } +}; + +template +inline ReverseRegSetIterator AbstractRegSet::rbegin() { + return ReverseRegSetIterator(*this); +} #include CPU_HEADER(register) -- GitLab From b617f1db4ec5d54b1ea541fb885e296da928f166 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 21 Mar 2022 11:30:26 +0000 Subject: [PATCH 098/237] 8283447: Remove unused LIR_Assembler::_bs Reviewed-by: redestad --- src/hotspot/share/c1/c1_LIRAssembler.cpp | 4 +--- src/hotspot/share/c1/c1_LIRAssembler.hpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index be0a6abc2ca..1c4e0d09306 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -32,7 +32,6 @@ #include "c1/c1_ValueStack.hpp" #include "ci/ciInstance.hpp" #include "compiler/oopMap.hpp" -#include "gc/shared/barrierSet.hpp" #include "runtime/os.hpp" #include "runtime/vm_version.hpp" @@ -104,7 +103,6 @@ PatchingStub::PatchID LIR_Assembler::patching_id(CodeEmitInfo* info) { LIR_Assembler::LIR_Assembler(Compilation* c): _masm(c->masm()) - , _bs(BarrierSet::barrier_set()) , _compilation(c) , _frame_map(c->frame_map()) , _current_block(NULL) diff --git a/src/hotspot/share/c1/c1_LIRAssembler.hpp b/src/hotspot/share/c1/c1_LIRAssembler.hpp index f27ade60bae..1d873b9638d 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.hpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -32,13 +32,11 @@ class Compilation; class ScopeValue; -class BarrierSet; class LIR_Assembler: public CompilationResourceObj { private: C1_MacroAssembler* _masm; CodeStubList* _slow_case_stubs; - BarrierSet* _bs; Compilation* _compilation; FrameMap* _frame_map; -- GitLab From 909986c7e110c8ac3ba16750be7707b1ec344ee5 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Mon, 21 Mar 2022 12:26:58 +0000 Subject: [PATCH 099/237] 8283217: Leak FcObjectSet in getFontConfigLocations() in fontpath.c Reviewed-by: prr, aivanov --- src/java.desktop/unix/native/common/awt/fontpath.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/java.desktop/unix/native/common/awt/fontpath.c b/src/java.desktop/unix/native/common/awt/fontpath.c index 051c9de88fa..fd28f5c0ea6 100644 --- a/src/java.desktop/unix/native/common/awt/fontpath.c +++ b/src/java.desktop/unix/native/common/awt/fontpath.c @@ -496,6 +496,7 @@ typedef FcResult (*FcPatternGetStringFuncType)(const FcPattern *p, FcChar8 ** s); typedef FcChar8* (*FcStrDirnameFuncType)(const FcChar8 *file); typedef void (*FcPatternDestroyFuncType)(FcPattern *p); +typedef void (*FcObjectSetDestroyFuncType)(FcObjectSet *os); typedef void (*FcFontSetDestroyFuncType)(FcFontSet *s); typedef FcPattern* (*FcNameParseFuncType)(const FcChar8 *name); typedef FcBool (*FcPatternAddStringFuncType)(FcPattern *p, @@ -542,6 +543,7 @@ static char **getFontConfigLocations() { FcPatternGetStringFuncType FcPatternGetString; FcStrDirnameFuncType FcStrDirname; FcPatternDestroyFuncType FcPatternDestroy; + FcObjectSetDestroyFuncType FcObjectSetDestroy; FcFontSetDestroyFuncType FcFontSetDestroy; FcConfig *fontconfig; @@ -571,6 +573,8 @@ static char **getFontConfigLocations() { (FcStrDirnameFuncType)dlsym(libfontconfig, "FcStrDirname"); FcPatternDestroy = (FcPatternDestroyFuncType)dlsym(libfontconfig, "FcPatternDestroy"); + FcObjectSetDestroy = + (FcObjectSetDestroyFuncType)dlsym(libfontconfig, "FcObjectSetDestroy"); FcFontSetDestroy = (FcFontSetDestroyFuncType)dlsym(libfontconfig, "FcFontSetDestroy"); @@ -580,6 +584,7 @@ static char **getFontConfigLocations() { FcFontList == NULL || FcStrDirname == NULL || FcPatternDestroy == NULL || + FcObjectSetDestroy == NULL || FcFontSetDestroy == NULL) { /* problem with the library: return. */ closeFontConfig(libfontconfig, JNI_FALSE); return NULL; @@ -636,6 +641,7 @@ static char **getFontConfigLocations() { cleanup: /* Free memory and close the ".so" */ + (*FcObjectSetDestroy)(objset); (*FcPatternDestroy)(pattern); closeFontConfig(libfontconfig, JNI_TRUE); return fontdirs; -- GitLab From cb576da575ea3c8f14087dd312313843764ca2f4 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Mon, 21 Mar 2022 12:28:17 +0000 Subject: [PATCH 100/237] 8283379: Memory leak in FileHeaderHelper Reviewed-by: dholmes, iklam, stuefe --- src/hotspot/share/cds/filemap.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 7901ab855ce..b8e28f30b72 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1108,6 +1108,9 @@ public: } ~FileHeaderHelper() { + if (_header != nullptr) { + FREE_C_HEAP_ARRAY(char, _header); + } if (_fd != -1) { ::close(_fd); } -- GitLab From c4dc58e12e197562dce90c0027aa74c29047cea6 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Mon, 21 Mar 2022 15:33:09 +0000 Subject: [PATCH 101/237] 8283277: ISO 4217 Amendment 171 Update Reviewed-by: iris, joehw --- make/data/currency/CurrencyData.properties | 8 ++++---- .../classes/sun/util/resources/CurrencyNames.properties | 4 +++- test/jdk/java/util/Currency/ValidateISO4217.java | 6 +++--- test/jdk/java/util/Currency/tablea1.txt | 8 ++++---- test/jdk/sun/text/resources/LocaleData | 1 + test/jdk/sun/text/resources/LocaleDataTest.java | 4 ++-- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/make/data/currency/CurrencyData.properties b/make/data/currency/CurrencyData.properties index 236e544feaf..d86fc6ddfd4 100644 --- a/make/data/currency/CurrencyData.properties +++ b/make/data/currency/CurrencyData.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2000, 2022, 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 @@ -32,7 +32,7 @@ formatVersion=3 # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=170 +dataVersion=171 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -51,7 +51,7 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 MTL470-MUR480-MVR462-MWK454-MXN484-MXV979-MYR458-MZM508-MZN943-NAD516-NGN566-\ NIO558-NLG528-NOK578-NPR524-NZD554-OMR512-PAB590-PEN604-PGK598-PHP608-\ PKR586-PLN985-PTE620-PYG600-QAR634-ROL642-RON946-RSD941-RUB643-RUR810-RWF646-SAR682-\ - SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLL694-SOS706-\ + SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLE925-SLL694-SOS706-\ SRD968-SRG740-SSP728-STD678-STN930-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TMT934-TND788-TOP776-\ TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-UYI940-\ UYU858-UZS860-VEB862-VED926-VEF937-VES928-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\ @@ -484,7 +484,7 @@ CS=CSD # SEYCHELLES SC=SCR # SIERRA LEONE -SL=SLL +SL=SLE # SINGAPORE SG=SGD # SLOVAKIA diff --git a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties index 9f1867d2cd1..53bf1d837ff 100644 --- a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties +++ b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2022, 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 @@ -221,6 +221,7 @@ SGD=SGD SHP=SHP SIT=SIT SKK=SKK +SLE=SLE SLL=SLL SOS=SOS SRD=SRD @@ -445,6 +446,7 @@ sgd=Singapore Dollar shp=Saint Helena Pound sit=Slovenian Tolar skk=Slovak Koruna +sle=Sierra Leonean Leone sll=Sierra Leonean Leone sos=Somali Shilling srd=Surinamese Dollar diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index 40bb55cfd1f..a0f09842ffe 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, 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 @@ -24,7 +24,7 @@ * @test * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 - * 8208746 8209775 8264792 8274658 + * 8208746 8209775 8264792 8274658 8283277 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -101,7 +101,7 @@ public class ValidateISO4217 { static final String otherCodes = "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-" + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" - + "PTE-ROL-RUR-SDD-SIT-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + + "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" + "YUM-ZMK-ZWD-ZWN-ZWR"; diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/tablea1.txt index 7716863419f..62d71c8c94b 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/tablea1.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 170 -# (As of 1 Oct 2021) +# Amendments up until ISO 4217 AMENDMENT NUMBER 171 +# (As of 16 Mar 2022) # # Version FILEVERSION=3 -DATAVERSION=170 +DATAVERSION=171 # ISO 4217 currency data AF AFN 971 2 @@ -218,7 +218,7 @@ RS RSD 941 2 CS CSD 891 2 #CS EUR 978 2 SC SCR 690 2 -SL SLL 694 2 +SL SLE 925 2 SG SGD 702 2 SK EUR 978 2 # MA 131 diff --git a/test/jdk/sun/text/resources/LocaleData b/test/jdk/sun/text/resources/LocaleData index ba176097825..50fa417ae6d 100644 --- a/test/jdk/sun/text/resources/LocaleData +++ b/test/jdk/sun/text/resources/LocaleData @@ -6448,6 +6448,7 @@ CurrencyNames//rsd=Serbian Dinar CurrencyNames//scr=Seychellois Rupee CurrencyNames//sdd=Sudanese Dinar (1992-2007) CurrencyNames//sit=Slovenian Tolar +CurrencyNames//sle=Sierra Leonean Leone CurrencyNames//sll=Sierra Leonean Leone CurrencyNames//srd=Surinamese Dollar CurrencyNames//srg=Surinamese Guilder diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index 1d2ddd03a82..51e88d72a2b 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, 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 @@ -40,7 +40,7 @@ * 8145136 8145952 8164784 8037111 8081643 7037368 8178872 8185841 8190918 * 8187946 8195478 8181157 8179071 8193552 8202026 8204269 8202537 8208746 * 8209775 8221432 8227127 8230284 8231273 8233579 8234288 8250665 8255086 - * 8251317 8274658 + * 8251317 8274658 8283277 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata -- GitLab From 999da9bfc5be703141cdc07af455b4b6b2cc1aae Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Mon, 21 Mar 2022 15:49:59 +0000 Subject: [PATCH 102/237] 8282306: os::is_first_C_frame(frame*) crashes on invalid link access Reviewed-by: stuefe, mdoerr --- .../cpu/aarch64/frame_aarch64.inline.hpp | 6 +++-- src/hotspot/cpu/arm/frame_arm.inline.hpp | 6 ++++- src/hotspot/cpu/ppc/frame_ppc.inline.hpp | 4 +++ src/hotspot/cpu/s390/frame_s390.inline.hpp | 4 +++ src/hotspot/cpu/x86/frame_x86.inline.hpp | 7 ++++-- src/hotspot/cpu/zero/frame_zero.inline.hpp | 5 ++++ src/hotspot/share/runtime/frame.hpp | 4 +++ src/hotspot/share/runtime/os.cpp | 25 +++++++++---------- .../share/runtime/safefetch.inline.hpp | 10 ++++++++ src/hotspot/share/runtime/thread.cpp | 4 +-- test/hotspot/gtest/runtime/test_os.cpp | 11 ++++++++ 11 files changed, 66 insertions(+), 20 deletions(-) diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index b0fe436ca59..20b5b8e8662 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -148,10 +148,12 @@ inline intptr_t* frame::id(void) const { return unextended_sp(); } inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id"); return this->id() > id ; } - - inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } +inline intptr_t* frame::link_or_null() const { + intptr_t** ptr = (intptr_t **)addr_at(link_offset); + return os::is_readable_pointer(ptr) ? *ptr : NULL; +} inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp index 835edd68493..773b6d06f7b 100644 --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp @@ -124,9 +124,13 @@ inline intptr_t* frame::id(void) const { return unextended_sp(); } inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id"); return this->id() > id ; } - inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } +inline intptr_t* frame::link_or_null() const { + intptr_t** ptr = (intptr_t **)addr_at(link_offset); + return os::is_readable_pointer(ptr) ? *ptr : NULL; +} + inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } // Return address: diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index 705b4abefdb..239db8224c0 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -117,6 +117,10 @@ inline intptr_t* frame::link() const { return (intptr_t*)callers_abi()->callers_sp; } +inline intptr_t* frame::link_or_null() const { + return link(); +} + inline intptr_t* frame::real_fp() const { return fp(); } diff --git a/src/hotspot/cpu/s390/frame_s390.inline.hpp b/src/hotspot/cpu/s390/frame_s390.inline.hpp index d8a4395d8ca..5574e6384e2 100644 --- a/src/hotspot/cpu/s390/frame_s390.inline.hpp +++ b/src/hotspot/cpu/s390/frame_s390.inline.hpp @@ -155,6 +155,10 @@ inline intptr_t* frame::link() const { return (intptr_t*) callers_abi()->callers_sp; } +inline intptr_t* frame::link_or_null() const { + return link(); +} + inline intptr_t** frame::interpreter_frame_locals_addr() const { return (intptr_t**) &(ijava_state()->locals); } diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index 733a357d5fe..23072238e16 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -138,10 +138,13 @@ inline intptr_t* frame::id(void) const { return unextended_sp(); } inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id"); return this->id() > id ; } - - inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } +inline intptr_t* frame::link_or_null() const { + intptr_t** ptr = (intptr_t **)addr_at(link_offset); + return os::is_readable_pointer(ptr) ? *ptr : NULL; +} + inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } // Return address: diff --git a/src/hotspot/cpu/zero/frame_zero.inline.hpp b/src/hotspot/cpu/zero/frame_zero.inline.hpp index 396e189a5db..dfca0e4bcb1 100644 --- a/src/hotspot/cpu/zero/frame_zero.inline.hpp +++ b/src/hotspot/cpu/zero/frame_zero.inline.hpp @@ -82,6 +82,11 @@ inline intptr_t* frame::link() const { return NULL; } +inline intptr_t* frame::link_or_null() const { + ShouldNotCallThis(); + return NULL; +} + inline interpreterState frame::get_interpreterState() const { return zero_interpreterframe()->interpreter_state(); } diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index e4eed4a1198..bc7d3d4775e 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -207,8 +207,12 @@ class frame { public: // Link (i.e., the pointer to the previous frame) + // might crash if the frame has no parent intptr_t* link() const; + // Link (i.e., the pointer to the previous frame) or null if the link cannot be accessed + intptr_t* link_or_null() const; + // Return address address sender_pc() const; diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 6e2ee7654ea..9ac8a993556 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1173,34 +1173,34 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { st->print_cr(INTPTR_FORMAT " is an unknown value", p2i(addr)); } +bool is_pointer_bad(intptr_t* ptr) { + return !is_aligned(ptr, sizeof(uintptr_t)) || !os::is_readable_pointer(ptr); +} + // Looks like all platforms can use the same function to check if C // stack is walkable beyond current frame. +// Returns true if this is not the case, i.e. the frame is possibly +// the first C frame on the stack. bool os::is_first_C_frame(frame* fr) { #ifdef _WINDOWS return true; // native stack isn't walkable on windows this way. #endif - // Load up sp, fp, sender sp and sender fp, check for reasonable values. // Check usp first, because if that's bad the other accessors may fault // on some architectures. Ditto ufp second, etc. - uintptr_t fp_align_mask = (uintptr_t)(sizeof(address)-1); - // sp on amd can be 32 bit aligned. - uintptr_t sp_align_mask = (uintptr_t)(sizeof(int)-1); - uintptr_t usp = (uintptr_t)fr->sp(); - if ((usp & sp_align_mask) != 0) return true; + if (is_pointer_bad(fr->sp())) return true; uintptr_t ufp = (uintptr_t)fr->fp(); - if ((ufp & fp_align_mask) != 0) return true; + if (is_pointer_bad(fr->fp())) return true; uintptr_t old_sp = (uintptr_t)fr->sender_sp(); - if ((old_sp & sp_align_mask) != 0) return true; - if (old_sp == 0 || old_sp == (uintptr_t)-1) return true; + if ((uintptr_t)fr->sender_sp() == (uintptr_t)-1 || is_pointer_bad(fr->sender_sp())) return true; - uintptr_t old_fp = (uintptr_t)fr->link(); - if ((old_fp & fp_align_mask) != 0) return true; - if (old_fp == 0 || old_fp == (uintptr_t)-1 || old_fp == ufp) return true; + uintptr_t old_fp = (uintptr_t)fr->link_or_null(); + if (old_fp == 0 || old_fp == (uintptr_t)-1 || old_fp == ufp || + is_pointer_bad(fr->link_or_null())) return true; // stack grows downwards; if old_fp is below current fp or if the stack // frame is too large, either the stack is corrupted or fp is not saved @@ -1212,7 +1212,6 @@ bool os::is_first_C_frame(frame* fr) { return false; } - // Set up the boot classpath. char* os::format_boot_path(const char* format_string, diff --git a/src/hotspot/share/runtime/safefetch.inline.hpp b/src/hotspot/share/runtime/safefetch.inline.hpp index 79c833e4db6..cee0853573c 100644 --- a/src/hotspot/share/runtime/safefetch.inline.hpp +++ b/src/hotspot/share/runtime/safefetch.inline.hpp @@ -54,10 +54,20 @@ inline intptr_t SafeFetchN(intptr_t* adr, intptr_t errValue) { // returns true if SafeFetch32 and SafeFetchN can be used safely (stubroutines are already generated) inline bool CanUseSafeFetch32() { +#if defined (__APPLE__) && defined(AARCH64) + if (Thread::current_or_null_safe() == NULL) { // workaround for JDK-8282475 + return false; + } +#endif // __APPLE__ && AARCH64 return StubRoutines::SafeFetch32_stub() ? true : false; } inline bool CanUseSafeFetchN() { +#if defined (__APPLE__) && defined(AARCH64) + if (Thread::current_or_null_safe() == NULL) { + return false; + } +#endif // __APPLE__ && AARCH64 return StubRoutines::SafeFetchN_stub() ? true : false; } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 0ec50849f5a..eb6bce1fdbb 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -336,10 +336,10 @@ void Thread::call_run() { // Perform common initialization actions - register_thread_stack_with_NMT(); - MACOS_AARCH64_ONLY(this->init_wx()); + register_thread_stack_with_NMT(); + JFR_ONLY(Jfr::on_thread_start(this);) log_debug(os, thread)("Thread " UINTX_FORMAT " stack dimensions: " diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 60bd02a42ee..0f78630d460 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -32,6 +32,7 @@ #include "utilities/ostream.hpp" #include "utilities/align.hpp" #include "unittest.hpp" +#include "runtime/frame.inline.hpp" static size_t small_page_size() { return os::vm_page_size(); @@ -865,3 +866,13 @@ TEST_VM(os, iso8601_time) { // Canary should still be intact EXPECT_EQ(buffer[os::iso8601_timestamp_size], 'X'); } + +TEST_VM(os, is_first_C_frame) { +#ifndef _WIN32 + frame invalid_frame; + EXPECT_TRUE(os::is_first_C_frame(&invalid_frame)); // the frame has zeroes for all values + + frame cur_frame = os::current_frame(); // this frame has to have a sender + EXPECT_FALSE(os::is_first_C_frame(&cur_frame)); +#endif // _WIN32 +} -- GitLab From 19d34bdf99e98a9ef614cb7f93c141e6c82bedcb Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 21 Mar 2022 16:20:20 +0000 Subject: [PATCH 103/237] 8281879: Serial: Merge CardGeneration into TenuredGeneration Reviewed-by: tschatzl, iwalulya --- .../share/gc/serial/tenuredGeneration.cpp | 283 +++++++++++++++- .../share/gc/serial/tenuredGeneration.hpp | 67 +++- .../gc/serial/tenuredGeneration.inline.hpp | 24 ++ .../share/gc/serial/vmStructs_serial.hpp | 2 +- .../share/gc/shared/cardGeneration.cpp | 318 ------------------ .../share/gc/shared/cardGeneration.hpp | 95 ------ .../share/gc/shared/cardGeneration.inline.hpp | 56 --- src/hotspot/share/gc/shared/generation.hpp | 3 +- src/hotspot/share/gc/shared/vmStructs_gc.hpp | 12 +- .../hotspot/gc/serial/TenuredGeneration.java | 2 +- .../jvm/hotspot/gc/shared/CardGeneration.java | 40 --- .../sun/jvm/hotspot/gc/shared/Generation.java | 5 +- .../sa/ClhsdbVmStructsDump.java | 2 +- .../jtreg/serviceability/sa/TestType.java | 1 - 14 files changed, 367 insertions(+), 543 deletions(-) delete mode 100644 src/hotspot/share/gc/shared/cardGeneration.cpp delete mode 100644 src/hotspot/share/gc/shared/cardGeneration.hpp delete mode 100644 src/hotspot/share/gc/shared/cardGeneration.inline.hpp delete mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index acf19426a95..08aede2880f 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -26,8 +26,8 @@ #include "gc/serial/genMarkSweep.hpp" #include "gc/serial/tenuredGeneration.inline.hpp" #include "gc/shared/blockOffsetTable.inline.hpp" -#include "gc/shared/cardGeneration.inline.hpp" #include "gc/shared/collectorCounters.hpp" +#include "gc/shared/gcLocker.hpp" #include "gc/shared/gcTimer.hpp" #include "gc/shared/gcTrace.hpp" #include "gc/shared/genCollectedHeap.hpp" @@ -40,13 +40,286 @@ #include "runtime/java.hpp" #include "utilities/macros.hpp" +bool TenuredGeneration::grow_by(size_t bytes) { + assert_correct_size_change_locking(); + bool result = _virtual_space.expand_by(bytes); + if (result) { + size_t new_word_size = + heap_word_size(_virtual_space.committed_size()); + MemRegion mr(space()->bottom(), new_word_size); + // Expand card table + GenCollectedHeap::heap()->rem_set()->resize_covered_region(mr); + // Expand shared block offset array + _bts->resize(new_word_size); + + // Fix for bug #4668531 + if (ZapUnusedHeapArea) { + MemRegion mangle_region(space()->end(), + (HeapWord*)_virtual_space.high()); + SpaceMangler::mangle_region(mangle_region); + } + + // Expand space -- also expands space's BOT + // (which uses (part of) shared array above) + space()->set_end((HeapWord*)_virtual_space.high()); + + // update the space and generation capacity counters + update_counters(); + + size_t new_mem_size = _virtual_space.committed_size(); + size_t old_mem_size = new_mem_size - bytes; + log_trace(gc, heap)("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, bytes/K, new_mem_size/K); + } + return result; +} + +bool TenuredGeneration::expand(size_t bytes, size_t expand_bytes) { + assert_locked_or_safepoint(Heap_lock); + if (bytes == 0) { + return true; // That's what grow_by(0) would return + } + size_t aligned_bytes = ReservedSpace::page_align_size_up(bytes); + if (aligned_bytes == 0){ + // The alignment caused the number of bytes to wrap. An expand_by(0) will + // return true with the implication that an expansion was done when it + // was not. A call to expand implies a best effort to expand by "bytes" + // but not a guarantee. Align down to give a best effort. This is likely + // the most that the generation can expand since it has some capacity to + // start with. + aligned_bytes = ReservedSpace::page_align_size_down(bytes); + } + size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); + bool success = false; + if (aligned_expand_bytes > aligned_bytes) { + success = grow_by(aligned_expand_bytes); + } + if (!success) { + success = grow_by(aligned_bytes); + } + if (!success) { + success = grow_to_reserved(); + } + if (success && GCLocker::is_active_and_needs_gc()) { + log_trace(gc, heap)("Garbage collection disabled, expanded heap instead"); + } + + return success; +} + +bool TenuredGeneration::grow_to_reserved() { + assert_correct_size_change_locking(); + bool success = true; + const size_t remaining_bytes = _virtual_space.uncommitted_size(); + if (remaining_bytes > 0) { + success = grow_by(remaining_bytes); + DEBUG_ONLY(if (!success) log_warning(gc)("grow to reserved failed");) + } + return success; +} + +void TenuredGeneration::shrink(size_t bytes) { + assert_correct_size_change_locking(); + + size_t size = ReservedSpace::page_align_size_down(bytes); + if (size == 0) { + return; + } + + // Shrink committed space + _virtual_space.shrink_by(size); + // Shrink space; this also shrinks the space's BOT + space()->set_end((HeapWord*) _virtual_space.high()); + size_t new_word_size = heap_word_size(space()->capacity()); + // Shrink the shared block offset array + _bts->resize(new_word_size); + MemRegion mr(space()->bottom(), new_word_size); + // Shrink the card table + GenCollectedHeap::heap()->rem_set()->resize_covered_region(mr); + + size_t new_mem_size = _virtual_space.committed_size(); + size_t old_mem_size = new_mem_size + size; + log_trace(gc, heap)("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K", + name(), old_mem_size/K, new_mem_size/K); +} + +// Objects in this generation may have moved, invalidate this +// generation's cards. +void TenuredGeneration::invalidate_remembered_set() { + _rs->invalidate(used_region()); +} + +void TenuredGeneration::compute_new_size_inner() { + assert(_shrink_factor <= 100, "invalid shrink factor"); + size_t current_shrink_factor = _shrink_factor; + if (ShrinkHeapInSteps) { + // Always reset '_shrink_factor' if the heap is shrunk in steps. + // If we shrink the heap in this iteration, '_shrink_factor' will + // be recomputed based on the old value further down in this fuction. + _shrink_factor = 0; + } + + // We don't have floating point command-line arguments + // Note: argument processing ensures that MinHeapFreeRatio < 100. + const double minimum_free_percentage = MinHeapFreeRatio / 100.0; + const double maximum_used_percentage = 1.0 - minimum_free_percentage; + + // Compute some numbers about the state of the heap. + const size_t used_after_gc = used(); + const size_t capacity_after_gc = capacity(); + + const double min_tmp = used_after_gc / maximum_used_percentage; + size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx)); + // Don't shrink less than the initial generation size + minimum_desired_capacity = MAX2(minimum_desired_capacity, initial_size()); + assert(used_after_gc <= minimum_desired_capacity, "sanity check"); + + const size_t free_after_gc = free(); + const double free_percentage = ((double)free_after_gc) / capacity_after_gc; + log_trace(gc, heap)("TenuredGeneration::compute_new_size:"); + log_trace(gc, heap)(" minimum_free_percentage: %6.2f maximum_used_percentage: %6.2f", + minimum_free_percentage, + maximum_used_percentage); + log_trace(gc, heap)(" free_after_gc : %6.1fK used_after_gc : %6.1fK capacity_after_gc : %6.1fK", + free_after_gc / (double) K, + used_after_gc / (double) K, + capacity_after_gc / (double) K); + log_trace(gc, heap)(" free_percentage: %6.2f", free_percentage); + + if (capacity_after_gc < minimum_desired_capacity) { + // If we have less free space than we want then expand + size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; + // Don't expand unless it's significant + if (expand_bytes >= _min_heap_delta_bytes) { + expand(expand_bytes, 0); // safe if expansion fails + } + log_trace(gc, heap)(" expanding: minimum_desired_capacity: %6.1fK expand_bytes: %6.1fK _min_heap_delta_bytes: %6.1fK", + minimum_desired_capacity / (double) K, + expand_bytes / (double) K, + _min_heap_delta_bytes / (double) K); + return; + } + + // No expansion, now see if we want to shrink + size_t shrink_bytes = 0; + // We would never want to shrink more than this + size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity; + + if (MaxHeapFreeRatio < 100) { + const double maximum_free_percentage = MaxHeapFreeRatio / 100.0; + const double minimum_used_percentage = 1.0 - maximum_free_percentage; + const double max_tmp = used_after_gc / minimum_used_percentage; + size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); + maximum_desired_capacity = MAX2(maximum_desired_capacity, initial_size()); + log_trace(gc, heap)(" maximum_free_percentage: %6.2f minimum_used_percentage: %6.2f", + maximum_free_percentage, minimum_used_percentage); + log_trace(gc, heap)(" _capacity_at_prologue: %6.1fK minimum_desired_capacity: %6.1fK maximum_desired_capacity: %6.1fK", + _capacity_at_prologue / (double) K, + minimum_desired_capacity / (double) K, + maximum_desired_capacity / (double) K); + assert(minimum_desired_capacity <= maximum_desired_capacity, + "sanity check"); + + if (capacity_after_gc > maximum_desired_capacity) { + // Capacity too large, compute shrinking size + shrink_bytes = capacity_after_gc - maximum_desired_capacity; + if (ShrinkHeapInSteps) { + // If ShrinkHeapInSteps is true (the default), + // we don't want to shrink all the way back to initSize if people call + // System.gc(), because some programs do that between "phases" and then + // we'd just have to grow the heap up again for the next phase. So we + // damp the shrinking: 0% on the first call, 10% on the second call, 40% + // on the third call, and 100% by the fourth call. But if we recompute + // size without shrinking, it goes back to 0%. + shrink_bytes = shrink_bytes / 100 * current_shrink_factor; + if (current_shrink_factor == 0) { + _shrink_factor = 10; + } else { + _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); + } + } + assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); + log_trace(gc, heap)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK", + initial_size() / (double) K, maximum_desired_capacity / (double) K); + log_trace(gc, heap)(" shrink_bytes: %.1fK current_shrink_factor: " SIZE_FORMAT " new shrink factor: " SIZE_FORMAT " _min_heap_delta_bytes: %.1fK", + shrink_bytes / (double) K, + current_shrink_factor, + _shrink_factor, + _min_heap_delta_bytes / (double) K); + } + } + + if (capacity_after_gc > _capacity_at_prologue) { + // We might have expanded for promotions, in which case we might want to + // take back that expansion if there's room after GC. That keeps us from + // stretching the heap with promotions when there's plenty of room. + size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue; + expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes); + // We have two shrinking computations, take the largest + shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion); + assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); + log_trace(gc, heap)(" aggressive shrinking: _capacity_at_prologue: %.1fK capacity_after_gc: %.1fK expansion_for_promotion: %.1fK shrink_bytes: %.1fK", + capacity_after_gc / (double) K, + _capacity_at_prologue / (double) K, + expansion_for_promotion / (double) K, + shrink_bytes / (double) K); + } + // Don't shrink unless it's significant + if (shrink_bytes >= _min_heap_delta_bytes) { + shrink(shrink_bytes); + } +} + +void TenuredGeneration::space_iterate(SpaceClosure* blk, + bool usedOnly) { + blk->do_space(space()); +} + +void TenuredGeneration::younger_refs_iterate(OopIterateClosure* blk) { + // Apply "cl->do_oop" to (the address of) (exactly) all the ref fields in + // "sp" that point into the young generation. + // The iteration is only over objects allocated at the start of the + // iterations; objects allocated as a result of applying the closure are + // not included. + + HeapWord* gen_boundary = reserved().start(); + _rs->younger_refs_in_space_iterate(space(), gen_boundary, blk); +} + TenuredGeneration::TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, size_t min_byte_size, size_t max_byte_size, CardTableRS* remset) : - CardGeneration(rs, initial_byte_size, remset) + Generation(rs, initial_byte_size), _rs(remset), + _min_heap_delta_bytes(), _capacity_at_prologue(), + _used_at_prologue() { + // If we don't shrink the heap in steps, '_shrink_factor' is always 100%. + _shrink_factor = ShrinkHeapInSteps ? 0 : 100; + HeapWord* start = (HeapWord*)rs.base(); + size_t reserved_byte_size = rs.size(); + assert((uintptr_t(start) & 3) == 0, "bad alignment"); + assert((reserved_byte_size & 3) == 0, "bad alignment"); + MemRegion reserved_mr(start, heap_word_size(reserved_byte_size)); + _bts = new BlockOffsetSharedArray(reserved_mr, + heap_word_size(initial_byte_size)); + MemRegion committed_mr(start, heap_word_size(initial_byte_size)); + _rs->resize_covered_region(committed_mr); + + // Verify that the start and end of this generation is the start of a card. + // If this wasn't true, a single card could span more than on generation, + // which would cause problems when we commit/uncommit memory, and when we + // clear and dirty cards. + guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned"); + if (reserved_mr.end() != GenCollectedHeap::heap()->reserved_region().end()) { + // Don't check at the very end of the heap as we'll assert that we're probing off + // the end if we try. + guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned"); + } + _min_heap_delta_bytes = MinHeapDeltaBytes; + _capacity_at_prologue = initial_byte_size; + _used_at_prologue = 0; HeapWord* bottom = (HeapWord*) _virtual_space.low(); HeapWord* end = (HeapWord*) _virtual_space.high(); _the_space = new TenuredSpace(_bts, MemRegion(bottom, end)); @@ -114,7 +387,7 @@ void TenuredGeneration::compute_new_size() { const size_t used_after_gc = used(); const size_t capacity_after_gc = capacity(); - CardGeneration::compute_new_size(); + compute_new_size_inner(); assert(used() == used_after_gc && used_after_gc <= capacity(), "used: " SIZE_FORMAT " used_after_gc: " SIZE_FORMAT @@ -195,10 +468,6 @@ TenuredGeneration::expand_and_allocate(size_t word_size, bool is_tlab) { return _the_space->allocate(word_size); } -bool TenuredGeneration::expand(size_t bytes, size_t expand_bytes) { - return CardGeneration::expand(bytes, expand_bytes); -} - size_t TenuredGeneration::unsafe_max_alloc_nogc() const { return _the_space->free(); } diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index 410981de758..6f364a38f44 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -26,36 +26,85 @@ #define SHARE_GC_SERIAL_TENUREDGENERATION_HPP #include "gc/serial/cSpaceCounters.hpp" -#include "gc/shared/cardGeneration.hpp" +#include "gc/shared/generation.hpp" #include "gc/shared/gcStats.hpp" #include "gc/shared/generationCounters.hpp" #include "utilities/macros.hpp" +class BlockOffsetSharedArray; +class CardTableRS; +class CompactibleSpace; + // TenuredGeneration models the heap containing old (promoted/tenured) objects -// contained in a single contiguous space. -// +// contained in a single contiguous space. This generation is covered by a card +// table, and uses a card-size block-offset array to implement block_start. // Garbage collection is performed using mark-compact. -class TenuredGeneration: public CardGeneration { +class TenuredGeneration: public Generation { friend class VMStructs; // Abstractly, this is a subtype that gets access to protected fields. friend class VM_PopulateDumpSharedSpace; protected: + + // This is shared with other generations. + CardTableRS* _rs; + // This is local to this generation. + BlockOffsetSharedArray* _bts; + + // Current shrinking effect: this damps shrinking when the heap gets empty. + size_t _shrink_factor; + + size_t _min_heap_delta_bytes; // Minimum amount to expand. + + // Some statistics from before gc started. + // These are gathered in the gc_prologue (and should_collect) + // to control growing/shrinking policy in spite of promotions. + size_t _capacity_at_prologue; + size_t _used_at_prologue; + + void assert_correct_size_change_locking(); + ContiguousSpace* _the_space; // Actual space holding objects GenerationCounters* _gen_counters; CSpaceCounters* _space_counters; - // Allocation failure - virtual bool expand(size_t bytes, size_t expand_bytes); - // Accessing spaces ContiguousSpace* space() const { return _the_space; } - void assert_correct_size_change_locking(); + // Attempt to expand the generation by "bytes". Expand by at a + // minimum "expand_bytes". Return true if some amount (not + // necessarily the full "bytes") was done. + bool expand(size_t bytes, size_t expand_bytes); + + // Shrink generation with specified size + void shrink(size_t bytes); + void compute_new_size_inner(); public: + virtual void compute_new_size(); + + virtual void invalidate_remembered_set(); + + // Grow generation with specified size (returns false if unable to grow) + bool grow_by(size_t bytes); + // Grow generation to reserved size. + bool grow_to_reserved(); + + size_t capacity() const; + size_t used() const; + size_t free() const; + MemRegion used_region() const; + + void space_iterate(SpaceClosure* blk, bool usedOnly = false); + + void younger_refs_iterate(OopIterateClosure* blk); + + bool is_in(const void* p) const; + + CompactibleSpace* first_compaction_space() const; + TenuredGeneration(ReservedSpace rs, size_t initial_byte_size, size_t min_byte_size, @@ -104,8 +153,6 @@ class TenuredGeneration: public CardGeneration { size_t word_size, bool is_tlab); - virtual void compute_new_size(); - // Performance Counter support void update_counters(); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp index f79d31786e2..2e6a4ca56df 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp @@ -29,6 +29,30 @@ #include "gc/shared/space.inline.hpp" +inline size_t TenuredGeneration::capacity() const { + return space()->capacity(); +} + +inline size_t TenuredGeneration::used() const { + return space()->used(); +} + +inline size_t TenuredGeneration::free() const { + return space()->free(); +} + +inline MemRegion TenuredGeneration::used_region() const { + return space()->used_region(); +} + +inline bool TenuredGeneration::is_in(const void* p) const { + return space()->is_in(p); +} + +inline CompactibleSpace* TenuredGeneration::first_compaction_space() const { + return space(); +} + HeapWord* TenuredGeneration::allocate(size_t word_size, bool is_tlab) { assert(!is_tlab, "TenuredGeneration does not support TLAB allocation"); diff --git a/src/hotspot/share/gc/serial/vmStructs_serial.hpp b/src/hotspot/share/gc/serial/vmStructs_serial.hpp index 39905458d4c..0ba676706ab 100644 --- a/src/hotspot/share/gc/serial/vmStructs_serial.hpp +++ b/src/hotspot/share/gc/serial/vmStructs_serial.hpp @@ -45,7 +45,7 @@ declare_toplevel_type, \ declare_integer_type) \ declare_type(SerialHeap, GenCollectedHeap) \ - declare_type(TenuredGeneration, CardGeneration) \ + declare_type(TenuredGeneration, Generation) \ declare_type(TenuredSpace, OffsetTableContigSpace) \ \ declare_type(DefNewGeneration, Generation) \ diff --git a/src/hotspot/share/gc/shared/cardGeneration.cpp b/src/hotspot/share/gc/shared/cardGeneration.cpp deleted file mode 100644 index 523f65c8cc3..00000000000 --- a/src/hotspot/share/gc/shared/cardGeneration.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (c) 2014, 2021, 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. - * - */ - -#include "precompiled.hpp" - -#include "gc/shared/blockOffsetTable.inline.hpp" -#include "gc/shared/cardGeneration.inline.hpp" -#include "gc/shared/cardTableRS.hpp" -#include "gc/shared/gcLocker.hpp" -#include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/genOopClosures.inline.hpp" -#include "gc/shared/generationSpec.hpp" -#include "gc/shared/space.inline.hpp" -#include "memory/iterator.hpp" -#include "memory/memRegion.hpp" -#include "logging/log.hpp" -#include "runtime/java.hpp" - -CardGeneration::CardGeneration(ReservedSpace rs, - size_t initial_byte_size, - CardTableRS* remset) : - Generation(rs, initial_byte_size), _rs(remset), - _min_heap_delta_bytes(), _capacity_at_prologue(), - _used_at_prologue() -{ - // If we don't shrink the heap in steps, '_shrink_factor' is always 100%. - _shrink_factor = ShrinkHeapInSteps ? 0 : 100; - HeapWord* start = (HeapWord*)rs.base(); - size_t reserved_byte_size = rs.size(); - assert((uintptr_t(start) & 3) == 0, "bad alignment"); - assert((reserved_byte_size & 3) == 0, "bad alignment"); - MemRegion reserved_mr(start, heap_word_size(reserved_byte_size)); - _bts = new BlockOffsetSharedArray(reserved_mr, - heap_word_size(initial_byte_size)); - MemRegion committed_mr(start, heap_word_size(initial_byte_size)); - _rs->resize_covered_region(committed_mr); - - // Verify that the start and end of this generation is the start of a card. - // If this wasn't true, a single card could span more than on generation, - // which would cause problems when we commit/uncommit memory, and when we - // clear and dirty cards. - guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned"); - if (reserved_mr.end() != GenCollectedHeap::heap()->reserved_region().end()) { - // Don't check at the very end of the heap as we'll assert that we're probing off - // the end if we try. - guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned"); - } - _min_heap_delta_bytes = MinHeapDeltaBytes; - _capacity_at_prologue = initial_byte_size; - _used_at_prologue = 0; -} - -bool CardGeneration::grow_by(size_t bytes) { - assert_correct_size_change_locking(); - bool result = _virtual_space.expand_by(bytes); - if (result) { - size_t new_word_size = - heap_word_size(_virtual_space.committed_size()); - MemRegion mr(space()->bottom(), new_word_size); - // Expand card table - GenCollectedHeap::heap()->rem_set()->resize_covered_region(mr); - // Expand shared block offset array - _bts->resize(new_word_size); - - // Fix for bug #4668531 - if (ZapUnusedHeapArea) { - MemRegion mangle_region(space()->end(), - (HeapWord*)_virtual_space.high()); - SpaceMangler::mangle_region(mangle_region); - } - - // Expand space -- also expands space's BOT - // (which uses (part of) shared array above) - space()->set_end((HeapWord*)_virtual_space.high()); - - // update the space and generation capacity counters - update_counters(); - - size_t new_mem_size = _virtual_space.committed_size(); - size_t old_mem_size = new_mem_size - bytes; - log_trace(gc, heap)("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K", - name(), old_mem_size/K, bytes/K, new_mem_size/K); - } - return result; -} - -bool CardGeneration::expand(size_t bytes, size_t expand_bytes) { - assert_locked_or_safepoint(Heap_lock); - if (bytes == 0) { - return true; // That's what grow_by(0) would return - } - size_t aligned_bytes = ReservedSpace::page_align_size_up(bytes); - if (aligned_bytes == 0){ - // The alignment caused the number of bytes to wrap. An expand_by(0) will - // return true with the implication that an expansion was done when it - // was not. A call to expand implies a best effort to expand by "bytes" - // but not a guarantee. Align down to give a best effort. This is likely - // the most that the generation can expand since it has some capacity to - // start with. - aligned_bytes = ReservedSpace::page_align_size_down(bytes); - } - size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes); - bool success = false; - if (aligned_expand_bytes > aligned_bytes) { - success = grow_by(aligned_expand_bytes); - } - if (!success) { - success = grow_by(aligned_bytes); - } - if (!success) { - success = grow_to_reserved(); - } - if (success && GCLocker::is_active_and_needs_gc()) { - log_trace(gc, heap)("Garbage collection disabled, expanded heap instead"); - } - - return success; -} - -bool CardGeneration::grow_to_reserved() { - assert_correct_size_change_locking(); - bool success = true; - const size_t remaining_bytes = _virtual_space.uncommitted_size(); - if (remaining_bytes > 0) { - success = grow_by(remaining_bytes); - DEBUG_ONLY(if (!success) log_warning(gc)("grow to reserved failed");) - } - return success; -} - -void CardGeneration::shrink(size_t bytes) { - assert_correct_size_change_locking(); - - size_t size = ReservedSpace::page_align_size_down(bytes); - if (size == 0) { - return; - } - - // Shrink committed space - _virtual_space.shrink_by(size); - // Shrink space; this also shrinks the space's BOT - space()->set_end((HeapWord*) _virtual_space.high()); - size_t new_word_size = heap_word_size(space()->capacity()); - // Shrink the shared block offset array - _bts->resize(new_word_size); - MemRegion mr(space()->bottom(), new_word_size); - // Shrink the card table - GenCollectedHeap::heap()->rem_set()->resize_covered_region(mr); - - size_t new_mem_size = _virtual_space.committed_size(); - size_t old_mem_size = new_mem_size + size; - log_trace(gc, heap)("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K", - name(), old_mem_size/K, new_mem_size/K); -} - -// Objects in this generation may have moved, invalidate this -// generation's cards. -void CardGeneration::invalidate_remembered_set() { - _rs->invalidate(used_region()); -} - -void CardGeneration::compute_new_size() { - assert(_shrink_factor <= 100, "invalid shrink factor"); - size_t current_shrink_factor = _shrink_factor; - if (ShrinkHeapInSteps) { - // Always reset '_shrink_factor' if the heap is shrunk in steps. - // If we shrink the heap in this iteration, '_shrink_factor' will - // be recomputed based on the old value further down in this fuction. - _shrink_factor = 0; - } - - // We don't have floating point command-line arguments - // Note: argument processing ensures that MinHeapFreeRatio < 100. - const double minimum_free_percentage = MinHeapFreeRatio / 100.0; - const double maximum_used_percentage = 1.0 - minimum_free_percentage; - - // Compute some numbers about the state of the heap. - const size_t used_after_gc = used(); - const size_t capacity_after_gc = capacity(); - - const double min_tmp = used_after_gc / maximum_used_percentage; - size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx)); - // Don't shrink less than the initial generation size - minimum_desired_capacity = MAX2(minimum_desired_capacity, initial_size()); - assert(used_after_gc <= minimum_desired_capacity, "sanity check"); - - const size_t free_after_gc = free(); - const double free_percentage = ((double)free_after_gc) / capacity_after_gc; - log_trace(gc, heap)("CardGeneration::compute_new_size:"); - log_trace(gc, heap)(" minimum_free_percentage: %6.2f maximum_used_percentage: %6.2f", - minimum_free_percentage, - maximum_used_percentage); - log_trace(gc, heap)(" free_after_gc : %6.1fK used_after_gc : %6.1fK capacity_after_gc : %6.1fK", - free_after_gc / (double) K, - used_after_gc / (double) K, - capacity_after_gc / (double) K); - log_trace(gc, heap)(" free_percentage: %6.2f", free_percentage); - - if (capacity_after_gc < minimum_desired_capacity) { - // If we have less free space than we want then expand - size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; - // Don't expand unless it's significant - if (expand_bytes >= _min_heap_delta_bytes) { - expand(expand_bytes, 0); // safe if expansion fails - } - log_trace(gc, heap)(" expanding: minimum_desired_capacity: %6.1fK expand_bytes: %6.1fK _min_heap_delta_bytes: %6.1fK", - minimum_desired_capacity / (double) K, - expand_bytes / (double) K, - _min_heap_delta_bytes / (double) K); - return; - } - - // No expansion, now see if we want to shrink - size_t shrink_bytes = 0; - // We would never want to shrink more than this - size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity; - - if (MaxHeapFreeRatio < 100) { - const double maximum_free_percentage = MaxHeapFreeRatio / 100.0; - const double minimum_used_percentage = 1.0 - maximum_free_percentage; - const double max_tmp = used_after_gc / minimum_used_percentage; - size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx)); - maximum_desired_capacity = MAX2(maximum_desired_capacity, initial_size()); - log_trace(gc, heap)(" maximum_free_percentage: %6.2f minimum_used_percentage: %6.2f", - maximum_free_percentage, minimum_used_percentage); - log_trace(gc, heap)(" _capacity_at_prologue: %6.1fK minimum_desired_capacity: %6.1fK maximum_desired_capacity: %6.1fK", - _capacity_at_prologue / (double) K, - minimum_desired_capacity / (double) K, - maximum_desired_capacity / (double) K); - assert(minimum_desired_capacity <= maximum_desired_capacity, - "sanity check"); - - if (capacity_after_gc > maximum_desired_capacity) { - // Capacity too large, compute shrinking size - shrink_bytes = capacity_after_gc - maximum_desired_capacity; - if (ShrinkHeapInSteps) { - // If ShrinkHeapInSteps is true (the default), - // we don't want to shrink all the way back to initSize if people call - // System.gc(), because some programs do that between "phases" and then - // we'd just have to grow the heap up again for the next phase. So we - // damp the shrinking: 0% on the first call, 10% on the second call, 40% - // on the third call, and 100% by the fourth call. But if we recompute - // size without shrinking, it goes back to 0%. - shrink_bytes = shrink_bytes / 100 * current_shrink_factor; - if (current_shrink_factor == 0) { - _shrink_factor = 10; - } else { - _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100); - } - } - assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); - log_trace(gc, heap)(" shrinking: initSize: %.1fK maximum_desired_capacity: %.1fK", - initial_size() / (double) K, maximum_desired_capacity / (double) K); - log_trace(gc, heap)(" shrink_bytes: %.1fK current_shrink_factor: " SIZE_FORMAT " new shrink factor: " SIZE_FORMAT " _min_heap_delta_bytes: %.1fK", - shrink_bytes / (double) K, - current_shrink_factor, - _shrink_factor, - _min_heap_delta_bytes / (double) K); - } - } - - if (capacity_after_gc > _capacity_at_prologue) { - // We might have expanded for promotions, in which case we might want to - // take back that expansion if there's room after GC. That keeps us from - // stretching the heap with promotions when there's plenty of room. - size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue; - expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes); - // We have two shrinking computations, take the largest - shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion); - assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size"); - log_trace(gc, heap)(" aggressive shrinking: _capacity_at_prologue: %.1fK capacity_after_gc: %.1fK expansion_for_promotion: %.1fK shrink_bytes: %.1fK", - capacity_after_gc / (double) K, - _capacity_at_prologue / (double) K, - expansion_for_promotion / (double) K, - shrink_bytes / (double) K); - } - // Don't shrink unless it's significant - if (shrink_bytes >= _min_heap_delta_bytes) { - shrink(shrink_bytes); - } -} - -void CardGeneration::space_iterate(SpaceClosure* blk, - bool usedOnly) { - blk->do_space(space()); -} - -void CardGeneration::younger_refs_iterate(OopIterateClosure* blk) { - // Apply "cl->do_oop" to (the address of) (exactly) all the ref fields in - // "sp" that point into the young generation. - // The iteration is only over objects allocated at the start of the - // iterations; objects allocated as a result of applying the closure are - // not included. - - HeapWord* gen_boundary = reserved().start(); - _rs->younger_refs_in_space_iterate(space(), gen_boundary, blk); -} diff --git a/src/hotspot/share/gc/shared/cardGeneration.hpp b/src/hotspot/share/gc/shared/cardGeneration.hpp deleted file mode 100644 index 084737a6146..00000000000 --- a/src/hotspot/share/gc/shared/cardGeneration.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2014, 2019, 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. - * - */ - -#ifndef SHARE_GC_SHARED_CARDGENERATION_HPP -#define SHARE_GC_SHARED_CARDGENERATION_HPP - -// Class CardGeneration is a generation that is covered by a card table, -// and uses a card-size block-offset array to implement block_start. - -#include "gc/shared/generation.hpp" - -class BlockOffsetSharedArray; -class CardTableRS; -class CompactibleSpace; - -class CardGeneration: public Generation { - friend class VMStructs; - protected: - // This is shared with other generations. - CardTableRS* _rs; - // This is local to this generation. - BlockOffsetSharedArray* _bts; - - // Current shrinking effect: this damps shrinking when the heap gets empty. - size_t _shrink_factor; - - size_t _min_heap_delta_bytes; // Minimum amount to expand. - - // Some statistics from before gc started. - // These are gathered in the gc_prologue (and should_collect) - // to control growing/shrinking policy in spite of promotions. - size_t _capacity_at_prologue; - size_t _used_at_prologue; - - CardGeneration(ReservedSpace rs, size_t initial_byte_size, CardTableRS* remset); - - virtual void assert_correct_size_change_locking() = 0; - - virtual CompactibleSpace* space() const = 0; - - public: - - // Attempt to expand the generation by "bytes". Expand by at a - // minimum "expand_bytes". Return true if some amount (not - // necessarily the full "bytes") was done. - virtual bool expand(size_t bytes, size_t expand_bytes); - - // Shrink generation with specified size - virtual void shrink(size_t bytes); - - virtual void compute_new_size(); - - virtual void invalidate_remembered_set(); - - // Grow generation with specified size (returns false if unable to grow) - bool grow_by(size_t bytes); - // Grow generation to reserved size. - bool grow_to_reserved(); - - size_t capacity() const; - size_t used() const; - size_t free() const; - MemRegion used_region() const; - - void space_iterate(SpaceClosure* blk, bool usedOnly = false); - - void younger_refs_iterate(OopIterateClosure* blk); - - bool is_in(const void* p) const; - - CompactibleSpace* first_compaction_space() const; -}; - -#endif // SHARE_GC_SHARED_CARDGENERATION_HPP diff --git a/src/hotspot/share/gc/shared/cardGeneration.inline.hpp b/src/hotspot/share/gc/shared/cardGeneration.inline.hpp deleted file mode 100644 index bd8285af679..00000000000 --- a/src/hotspot/share/gc/shared/cardGeneration.inline.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2014, 2019, 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. - * - */ - -#ifndef SHARE_GC_SHARED_CARDGENERATION_INLINE_HPP -#define SHARE_GC_SHARED_CARDGENERATION_INLINE_HPP - -#include "gc/shared/cardGeneration.hpp" - -#include "gc/shared/space.hpp" - -inline size_t CardGeneration::capacity() const { - return space()->capacity(); -} - -inline size_t CardGeneration::used() const { - return space()->used(); -} - -inline size_t CardGeneration::free() const { - return space()->free(); -} - -inline MemRegion CardGeneration::used_region() const { - return space()->used_region(); -} - -inline bool CardGeneration::is_in(const void* p) const { - return space()->is_in(p); -} - -inline CompactibleSpace* CardGeneration::first_compaction_space() const { - return space(); -} - -#endif // SHARE_GC_SHARED_CARDGENERATION_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/generation.hpp b/src/hotspot/share/gc/shared/generation.hpp index b9183ec2898..36740cc4039 100644 --- a/src/hotspot/share/gc/shared/generation.hpp +++ b/src/hotspot/share/gc/shared/generation.hpp @@ -41,8 +41,7 @@ // // Generation - abstract base class // - DefNewGeneration - allocation area (copy collected) -// - CardGeneration - abstract class adding offset array behavior -// - TenuredGeneration - tenured (old object) space (markSweepCompact) +// - TenuredGeneration - tenured (old object) space (markSweepCompact) // // The system configuration currently allowed is: // diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index f9b1c631123..d5cf2c15373 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -26,7 +26,6 @@ #define SHARE_GC_SHARED_VMSTRUCTS_GC_HPP #include "gc/shared/ageTable.hpp" -#include "gc/shared/cardGeneration.hpp" #include "gc/shared/cardTable.hpp" #include "gc/shared/cardTableRS.hpp" #include "gc/shared/collectedHeap.hpp" @@ -101,11 +100,11 @@ nonstatic_field(BlockOffsetArrayContigSpace, _next_offset_threshold, HeapWord*) \ nonstatic_field(BlockOffsetArrayContigSpace, _next_offset_index, size_t) \ \ - nonstatic_field(CardGeneration, _rs, CardTableRS*) \ - nonstatic_field(CardGeneration, _bts, BlockOffsetSharedArray*) \ - nonstatic_field(CardGeneration, _shrink_factor, size_t) \ - nonstatic_field(CardGeneration, _capacity_at_prologue, size_t) \ - nonstatic_field(CardGeneration, _used_at_prologue, size_t) \ + nonstatic_field(TenuredGeneration, _rs, CardTableRS*) \ + nonstatic_field(TenuredGeneration, _bts, BlockOffsetSharedArray*) \ + nonstatic_field(TenuredGeneration, _shrink_factor, size_t) \ + nonstatic_field(TenuredGeneration, _capacity_at_prologue, size_t) \ + nonstatic_field(TenuredGeneration, _used_at_prologue, size_t) \ \ nonstatic_field(CardTable, _whole_heap, const MemRegion) \ nonstatic_field(CardTable, _guard_index, const size_t) \ @@ -186,7 +185,6 @@ declare_toplevel_type(CollectedHeap) \ declare_type(GenCollectedHeap, CollectedHeap) \ declare_toplevel_type(Generation) \ - declare_type(CardGeneration, Generation) \ declare_toplevel_type(Space) \ declare_type(CompactibleSpace, Space) \ declare_type(ContiguousSpace, CompactibleSpace) \ diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/TenuredGeneration.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/TenuredGeneration.java index 6f121f963af..cc4f216efc2 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/TenuredGeneration.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/serial/TenuredGeneration.java @@ -39,7 +39,7 @@ import sun.jvm.hotspot.utilities.Observer;

    Garbage collection is performed using mark-compact.

    */ -public class TenuredGeneration extends CardGeneration { +public class TenuredGeneration extends Generation { private static AddressField theSpaceField; static { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java deleted file mode 100644 index 3d96d33d81e..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/CardGeneration.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2000, 2015, 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. - * - */ - -package sun.jvm.hotspot.gc.shared; - -import sun.jvm.hotspot.debugger.*; - -/** Class CardGeneration is a generation that is covered by a card - table, and uses a card-size block-offset array to implement - block_start. */ - -public abstract class CardGeneration extends Generation { - public CardGeneration(Address addr) { - super(addr); - } - - // FIXME: not sure what I need to expose from here in order to have - // verification similar to that of the old RememberedSet -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/Generation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/Generation.java index eeb099a11dc..5323d9cee4e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/Generation.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/Generation.java @@ -38,10 +38,7 @@ import sun.jvm.hotspot.utilities.Observer;
    • Generation
        -
      • CardGeneration -
          -
        • TenuredGeneration -
        +
      • TenuredGeneration
      • DefNewGeneration
    diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java index 680d9078d3b..050ec9c05d6 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbVmStructsDump.java @@ -57,7 +57,7 @@ public class ClhsdbVmStructsDump { "field Klass _name Symbol*", "type ClassLoaderData* null", "field JavaThread _osthread OSThread*", - "type TenuredGeneration CardGeneration", + "type TenuredGeneration Generation", "type Universe null", "type ConstantPoolCache MetaspaceObj")); test.run(theApp.getPid(), cmds, expStrMap, null); diff --git a/test/hotspot/jtreg/serviceability/sa/TestType.java b/test/hotspot/jtreg/serviceability/sa/TestType.java index 1e4a9e56e57..4f71e42cd4e 100644 --- a/test/hotspot/jtreg/serviceability/sa/TestType.java +++ b/test/hotspot/jtreg/serviceability/sa/TestType.java @@ -62,7 +62,6 @@ public class TestType { "type ConstantPoolCache MetaspaceObj", "type ConstantPool Metadata", "type CompilerThread JavaThread", - "type CardGeneration Generation", "type ArrayKlass Klass", "type InstanceKlass Klass")); // String to check for in the output of "type InstanceKlass" -- GitLab From f4f87284cbbe95958d8c7d8adc0f5c5e260892ca Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 21 Mar 2022 16:21:30 +0000 Subject: [PATCH 104/237] 8283097: Parallel: Move filler object logic inside PSPromotionLAB::unallocate_object Reviewed-by: tschatzl, iwalulya --- src/hotspot/share/gc/parallel/psPromotionLAB.cpp | 9 +++++---- src/hotspot/share/gc/parallel/psPromotionLAB.hpp | 2 +- .../share/gc/parallel/psPromotionManager.inline.hpp | 11 +++-------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psPromotionLAB.cpp b/src/hotspot/share/gc/parallel/psPromotionLAB.cpp index 312db67606a..bab79b25a13 100644 --- a/src/hotspot/share/gc/parallel/psPromotionLAB.cpp +++ b/src/hotspot/share/gc/parallel/psPromotionLAB.cpp @@ -85,18 +85,19 @@ void PSPromotionLAB::flush() { _state = flushed; } -bool PSPromotionLAB::unallocate_object(HeapWord* obj, size_t obj_size) { +void PSPromotionLAB::unallocate_object(HeapWord* obj, size_t obj_size) { assert(ParallelScavengeHeap::heap()->is_in(obj), "Object outside heap"); + // If the object is inside this LAB, we just bump-down the `top` pointer. + // Otherwise, we overwrite it with a filler object. if (contains(obj)) { HeapWord* object_end = obj + obj_size; assert(object_end == top(), "Not matching last allocation"); set_top(obj); - return true; + } else { + CollectedHeap::fill_with_object(obj, obj_size); } - - return false; } // Fill all remaining lab space with an unreachable object. diff --git a/src/hotspot/share/gc/parallel/psPromotionLAB.hpp b/src/hotspot/share/gc/parallel/psPromotionLAB.hpp index 239a1140a8a..7e8f8857dcd 100644 --- a/src/hotspot/share/gc/parallel/psPromotionLAB.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionLAB.hpp @@ -72,7 +72,7 @@ class PSPromotionLAB : public CHeapObj { bool is_flushed() { return _state == flushed; } - bool unallocate_object(HeapWord* obj, size_t obj_size); + void unallocate_object(HeapWord* obj, size_t obj_size); // Returns a subregion containing all objects in this space. MemRegion used_region() { return MemRegion(bottom(), top()); } diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index b3f1c7297f4..1b7b00d9fba 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -290,15 +290,10 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, assert(o->is_forwarded(), "Object must be forwarded if the cas failed."); assert(o->forwardee() == forwardee, "invariant"); - // Try to deallocate the space. If it was directly allocated we cannot - // deallocate it, so we have to test. If the deallocation fails, - // overwrite with a filler object. if (new_obj_is_tenured) { - if (!_old_lab.unallocate_object(cast_from_oop(new_obj), new_obj_size)) { - CollectedHeap::fill_with_object(cast_from_oop(new_obj), new_obj_size); - } - } else if (!_young_lab.unallocate_object(cast_from_oop(new_obj), new_obj_size)) { - CollectedHeap::fill_with_object(cast_from_oop(new_obj), new_obj_size); + _old_lab.unallocate_object(cast_from_oop(new_obj), new_obj_size); + } else { + _young_lab.unallocate_object(cast_from_oop(new_obj), new_obj_size); } return forwardee; } -- GitLab From 14b9e80b8adcc0ab0634357f5a7c25f24fd6808c Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 21 Mar 2022 16:57:17 +0000 Subject: [PATCH 105/237] 8283415: Update java.lang.ref to use sealed classes Reviewed-by: kbarrett, alanb --- .../share/classes/java/lang/ref/FinalReference.java | 4 ++-- .../share/classes/java/lang/ref/PhantomReference.java | 4 ++-- src/java.base/share/classes/java/lang/ref/Reference.java | 5 +++-- src/java.base/share/classes/java/lang/ref/SoftReference.java | 4 ++-- src/java.base/share/classes/java/lang/ref/WeakReference.java | 4 ++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/lang/ref/FinalReference.java b/src/java.base/share/classes/java/lang/ref/FinalReference.java index 9175516d4d0..06af37df67c 100644 --- a/src/java.base/share/classes/java/lang/ref/FinalReference.java +++ b/src/java.base/share/classes/java/lang/ref/FinalReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -28,7 +28,7 @@ package java.lang.ref; /** * Final references, used to implement finalization */ -class FinalReference extends Reference { +sealed class FinalReference extends Reference permits Finalizer { public FinalReference(T referent, ReferenceQueue q) { super(referent, q); diff --git a/src/java.base/share/classes/java/lang/ref/PhantomReference.java b/src/java.base/share/classes/java/lang/ref/PhantomReference.java index 2c1532b8eb2..fef3bc7c508 100644 --- a/src/java.base/share/classes/java/lang/ref/PhantomReference.java +++ b/src/java.base/share/classes/java/lang/ref/PhantomReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -50,7 +50,7 @@ import jdk.internal.vm.annotation.IntrinsicCandidate; * @since 1.2 */ -public class PhantomReference extends Reference { +public non-sealed class PhantomReference extends Reference { /** * Returns this reference object's referent. Because the referent of a diff --git a/src/java.base/share/classes/java/lang/ref/Reference.java b/src/java.base/share/classes/java/lang/ref/Reference.java index 17d8c7b669c..777567085eb 100644 --- a/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/src/java.base/share/classes/java/lang/ref/Reference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -41,7 +41,8 @@ import jdk.internal.ref.Cleaner; * @since 1.2 */ -public abstract class Reference { +public abstract sealed class Reference + permits PhantomReference, SoftReference, WeakReference, FinalReference { /* The state of a Reference object is characterized by two attributes. It * may be either "active", "pending", or "inactive". It may also be diff --git a/src/java.base/share/classes/java/lang/ref/SoftReference.java b/src/java.base/share/classes/java/lang/ref/SoftReference.java index 8ce74a67d0a..a0cb75dcf50 100644 --- a/src/java.base/share/classes/java/lang/ref/SoftReference.java +++ b/src/java.base/share/classes/java/lang/ref/SoftReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -61,7 +61,7 @@ package java.lang.ref; * @since 1.2 */ -public class SoftReference extends Reference { +public non-sealed class SoftReference extends Reference { /** * Timestamp clock, updated by the garbage collector diff --git a/src/java.base/share/classes/java/lang/ref/WeakReference.java b/src/java.base/share/classes/java/lang/ref/WeakReference.java index fdf2b5c9f02..1d1a01f3acd 100644 --- a/src/java.base/share/classes/java/lang/ref/WeakReference.java +++ b/src/java.base/share/classes/java/lang/ref/WeakReference.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -45,7 +45,7 @@ package java.lang.ref; * @since 1.2 */ -public class WeakReference extends Reference { +public non-sealed class WeakReference extends Reference { /** * Creates a new weak reference that refers to the given object. The new -- GitLab From f8878cb0cc436993ef1222bc13b00b923d91aad1 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 21 Mar 2022 21:34:09 +0000 Subject: [PATCH 106/237] 8257733: Move module-specific data from make to respective module Reviewed-by: jjg, weijun, naoto, erikj, prr, alanb, mchung --- make/ModuleWrapper.gmk | 4 +- make/ToolsJdk.gmk | 4 +- make/UpdateX11Wrappers.gmk | 4 +- .../tools/symbolgenerator/CreateSymbols.java | 9 ++-- make/modules/java.base/Gendata.gmk | 10 ++--- make/modules/java.base/Gensrc.gmk | 12 +++--- .../java.base/gendata/GendataBlockedCerts.gmk | 4 +- .../gendata/GendataBreakIterator.gmk | 4 +- .../gendata/GendataPublicSuffixList.gmk | 4 +- .../modules/java.base/gendata/GendataTZDB.gmk | 4 +- .../modules/java.base/gensrc/GensrcBuffer.gmk | 4 +- .../java.base/gensrc/GensrcCharacterData.gmk | 10 ++--- .../java.base/gensrc/GensrcCharsetCoder.gmk | 4 +- .../java.base/gensrc/GensrcEmojiData.gmk | 6 +-- .../java.base/gensrc/GensrcExceptions.gmk | 4 +- .../java.base/gensrc/GensrcLocaleData.gmk | 6 +-- .../gensrc/GensrcScopedMemoryAccess.gmk | 6 +-- .../java.base/gensrc/GensrcVarHandles.gmk | 4 +- .../gendata/GendataFontConfig.gmk | 39 ++++++++++-------- .../java.desktop/gensrc/GensrcIcons.gmk | 8 ++-- .../java.desktop/gensrc/GensrcSwing.gmk | 4 +- .../java.desktop/gensrc/GensrcX11Wrappers.gmk | 6 +-- make/modules/jdk.charsets/Gensrc.gmk | 6 +-- make/modules/jdk.compiler/Gendata.gmk | 6 +-- make/modules/jdk.javadoc/Gendata.gmk | 6 +-- make/modules/jdk.jdi/Gensrc.gmk | 9 ++-- make/modules/jdk.localedata/Gensrc.gmk | 4 +- make/scripts/generate-symbol-data.sh | 18 ++++---- .../java/lang}/CharacterData00.java.template | 0 .../java/lang}/CharacterData01.java.template | 0 .../java/lang}/CharacterData02.java.template | 0 .../java/lang}/CharacterData03.java.template | 0 .../java/lang}/CharacterData0E.java.template | 0 .../lang}/CharacterDataLatin1.java.template | 0 .../blockedcertsconverter/blocked.certs.pem | 0 .../java.base/share}/data/cacerts/README | 0 .../data/cacerts/actalisauthenticationrootca | 0 .../share}/data/cacerts/addtrustexternalca | 0 .../share}/data/cacerts/addtrustqualifiedca | 0 .../data/cacerts/affirmtrustcommercialca | 0 .../data/cacerts/affirmtrustnetworkingca | 0 .../share}/data/cacerts/affirmtrustpremiumca | 0 .../data/cacerts/affirmtrustpremiumeccca | 0 .../share}/data/cacerts/amazonrootca1 | 0 .../share}/data/cacerts/amazonrootca2 | 0 .../share}/data/cacerts/amazonrootca3 | 0 .../share}/data/cacerts/amazonrootca4 | 0 .../share}/data/cacerts/baltimorecybertrustca | 0 .../share}/data/cacerts/buypassclass2ca | 0 .../share}/data/cacerts/buypassclass3ca | 0 .../share}/data/cacerts/camerfirmachambersca | 0 .../data/cacerts/camerfirmachamberscommerceca | 0 .../data/cacerts/camerfirmachambersignca | 0 .../java.base/share}/data/cacerts/certumca | 0 .../data/cacerts/certumtrustednetworkca | 0 .../share}/data/cacerts/chunghwaepkirootca | 0 .../java.base/share}/data/cacerts/comodoaaaca | 0 .../java.base/share}/data/cacerts/comodoeccca | 0 .../java.base/share}/data/cacerts/comodorsaca | 0 .../share}/data/cacerts/digicertassuredidg2 | 0 .../share}/data/cacerts/digicertassuredidg3 | 0 .../data/cacerts/digicertassuredidrootca | 0 .../share}/data/cacerts/digicertglobalrootca | 0 .../share}/data/cacerts/digicertglobalrootg2 | 0 .../share}/data/cacerts/digicertglobalrootg3 | 0 .../cacerts/digicerthighassuranceevrootca | 0 .../share}/data/cacerts/digicerttrustedrootg4 | 0 .../share}/data/cacerts/dtrustclass3ca2 | 0 .../share}/data/cacerts/dtrustclass3ca2ev | 0 .../share}/data/cacerts/entrust2048ca | 0 .../java.base/share}/data/cacerts/entrustevca | 0 .../share}/data/cacerts/entrustrootcaec1 | 0 .../share}/data/cacerts/entrustrootcag2 | 0 .../share}/data/cacerts/entrustrootcag4 | 0 .../share}/data/cacerts/geotrustglobalca | 0 .../share}/data/cacerts/geotrustprimaryca | 0 .../share}/data/cacerts/geotrustprimarycag2 | 0 .../share}/data/cacerts/geotrustprimarycag3 | 0 .../share}/data/cacerts/geotrustuniversalca | 0 .../share}/data/cacerts/globalsignca | 0 .../share}/data/cacerts/globalsigneccrootcar4 | 0 .../share}/data/cacerts/globalsigneccrootcar5 | 0 .../share}/data/cacerts/globalsignr3ca | 0 .../share}/data/cacerts/globalsignrootcar6 | 0 .../share}/data/cacerts/godaddyclass2ca | 0 .../share}/data/cacerts/godaddyrootg2ca | 0 .../share}/data/cacerts/haricaeccrootca2015 | 0 .../share}/data/cacerts/haricarootca2015 | 0 .../share}/data/cacerts/identrustcommercial | 0 .../share}/data/cacerts/identrustpublicca | 0 .../share}/data/cacerts/letsencryptisrgx1 | 0 .../share}/data/cacerts/luxtrustglobalroot2ca | 0 .../share}/data/cacerts/luxtrustglobalrootca | 0 .../share}/data/cacerts/quovadisrootca | 0 .../share}/data/cacerts/quovadisrootca1g3 | 0 .../share}/data/cacerts/quovadisrootca2 | 0 .../share}/data/cacerts/quovadisrootca2g3 | 0 .../share}/data/cacerts/quovadisrootca3 | 0 .../share}/data/cacerts/quovadisrootca3g3 | 0 .../share}/data/cacerts/secomscrootca1 | 0 .../share}/data/cacerts/secomscrootca2 | 0 .../share}/data/cacerts/securetrustca | 0 .../share}/data/cacerts/sslrooteccca | 0 .../share}/data/cacerts/sslrootevrsaca | 0 .../share}/data/cacerts/sslrootrsaca | 0 .../share}/data/cacerts/starfieldclass2ca | 0 .../share}/data/cacerts/starfieldrootg2ca | 0 .../data/cacerts/starfieldservicesrootg2ca | 0 .../share}/data/cacerts/swisssigngoldg2ca | 0 .../share}/data/cacerts/swisssignplatinumg2ca | 0 .../share}/data/cacerts/swisssignsilverg2ca | 0 .../share}/data/cacerts/teliasonerarootcav1 | 0 .../share}/data/cacerts/thawteprimaryrootca | 0 .../share}/data/cacerts/thawteprimaryrootcag2 | 0 .../share}/data/cacerts/thawteprimaryrootcag3 | 0 .../data/cacerts/ttelesecglobalrootclass2ca | 0 .../data/cacerts/ttelesecglobalrootclass3ca | 0 .../share}/data/cacerts/usertrusteccca | 0 .../share}/data/cacerts/usertrustrsaca | 0 .../share}/data/cacerts/utnuserfirstobjectca | 0 .../share}/data/cacerts/verisignclass3g3ca | 0 .../share}/data/cacerts/verisignclass3g4ca | 0 .../share}/data/cacerts/verisignclass3g5ca | 0 .../data/cacerts/verisignuniversalrootca | 0 .../share}/data/cacerts/xrampglobalca | 0 .../data/currency/CurrencyData.properties | 0 .../data/lsrdata/language-subtag-registry.txt | 0 .../share}/data/publicsuffixlist/VERSION | 0 .../publicsuffixlist/public_suffix_list.dat | 0 .../java.base/share}/data/tzdata/VERSION | 0 .../java.base/share}/data/tzdata/africa | 0 .../java.base/share}/data/tzdata/antarctica | 0 .../java.base/share}/data/tzdata/asia | 0 .../java.base/share}/data/tzdata/australasia | 0 .../java.base/share}/data/tzdata/backward | 0 .../java.base/share}/data/tzdata/etcetera | 0 .../java.base/share}/data/tzdata/europe | 0 .../java.base/share}/data/tzdata/factory | 0 {make => src/java.base/share}/data/tzdata/gmt | 0 .../java.base/share}/data/tzdata/iso3166.tab | 0 .../share}/data/tzdata/jdk11_backward | 0 .../java.base/share}/data/tzdata/leapseconds | 0 .../java.base/share}/data/tzdata/northamerica | 0 .../java.base/share}/data/tzdata/solar87 | 0 .../java.base/share}/data/tzdata/solar88 | 0 .../java.base/share}/data/tzdata/solar89 | 0 .../java.base/share}/data/tzdata/southamerica | 0 .../java.base/share}/data/tzdata/zone.tab | 0 .../share}/data/unicodedata/Blocks.txt | 0 .../unicodedata/DerivedCoreProperties.txt | 0 .../data/unicodedata/NormalizationTest.txt | 0 .../share}/data/unicodedata/PropList.txt | 0 .../data/unicodedata/PropertyValueAliases.txt | 0 .../share}/data/unicodedata/ReadMe.txt | 0 .../share}/data/unicodedata/Scripts.txt | 0 .../share}/data/unicodedata/SpecialCasing.txt | 0 .../share}/data/unicodedata/UnicodeData.txt | 0 .../auxiliary/GraphemeBreakProperty.txt | 0 .../auxiliary/GraphemeBreakTest.txt | 0 .../data/unicodedata/emoji/emoji-data.txt | 0 .../aix/data/fontconfig/fontconfig.properties | 0 .../bsd/data/fontconfig/fontconfig.properties | 0 .../data/fontconfig/fontconfig.properties | 0 .../macosx}/data/macosxicons/JavaApp.icns | Bin .../share}/data/dtdbuilder/HTMLlat1.sgml | 0 .../share}/data/dtdbuilder/HTMLspecial.sgml | 0 .../share}/data/dtdbuilder/HTMLsymbol.sgml | 0 .../share}/data/dtdbuilder/html32.dtd | 0 .../share}/data/dtdbuilder/public.map | 0 .../unix}/data/x11wrappergen/sizes-32.txt | 0 .../unix}/data/x11wrappergen/sizes-64.txt | 0 .../unix}/data/x11wrappergen/xlibtypes.txt | 0 .../data/fontconfig/fontconfig.properties | 0 .../java.se/share}/data/jdwp/jdwp.spec | 0 .../jdk.compiler/share}/data/symbols/README | 0 .../share}/data/symbols/include.list | 0 .../data/symbols/java.activation-8.sym.txt | 0 .../data/symbols/java.activation-9.sym.txt | 0 .../data/symbols/java.activation-A.sym.txt | 0 .../data/symbols/java.activation-B.sym.txt | 0 .../share}/data/symbols/java.base-7.sym.txt | 0 .../share}/data/symbols/java.base-8.sym.txt | 0 .../share}/data/symbols/java.base-9.sym.txt | 0 .../share}/data/symbols/java.base-A.sym.txt | 0 .../share}/data/symbols/java.base-B.sym.txt | 0 .../share}/data/symbols/java.base-C.sym.txt | 0 .../share}/data/symbols/java.base-D.sym.txt | 0 .../share}/data/symbols/java.base-E.sym.txt | 0 .../share}/data/symbols/java.base-F.sym.txt | 0 .../share}/data/symbols/java.base-G.sym.txt | 0 .../share}/data/symbols/java.base-H.sym.txt | 0 .../share}/data/symbols/java.base-I.sym.txt | 0 .../data/symbols/java.compiler-7.sym.txt | 0 .../data/symbols/java.compiler-8.sym.txt | 0 .../data/symbols/java.compiler-9.sym.txt | 0 .../data/symbols/java.compiler-A.sym.txt | 0 .../data/symbols/java.compiler-B.sym.txt | 0 .../data/symbols/java.compiler-C.sym.txt | 0 .../data/symbols/java.compiler-D.sym.txt | 0 .../data/symbols/java.compiler-E.sym.txt | 0 .../data/symbols/java.compiler-F.sym.txt | 0 .../data/symbols/java.compiler-G.sym.txt | 0 .../data/symbols/java.compiler-H.sym.txt | 0 .../data/symbols/java.compiler-I.sym.txt | 0 .../share}/data/symbols/java.corba-8.sym.txt | 0 .../share}/data/symbols/java.corba-9.sym.txt | 0 .../share}/data/symbols/java.corba-A.sym.txt | 0 .../share}/data/symbols/java.corba-B.sym.txt | 0 .../data/symbols/java.datatransfer-7.sym.txt | 0 .../data/symbols/java.datatransfer-8.sym.txt | 0 .../data/symbols/java.datatransfer-9.sym.txt | 0 .../data/symbols/java.datatransfer-A.sym.txt | 0 .../data/symbols/java.datatransfer-B.sym.txt | 0 .../data/symbols/java.datatransfer-G.sym.txt | 0 .../data/symbols/java.datatransfer-H.sym.txt | 0 .../data/symbols/java.datatransfer-I.sym.txt | 0 .../data/symbols/java.desktop-7.sym.txt | 0 .../data/symbols/java.desktop-8.sym.txt | 0 .../data/symbols/java.desktop-9.sym.txt | 0 .../data/symbols/java.desktop-A.sym.txt | 0 .../data/symbols/java.desktop-B.sym.txt | 0 .../data/symbols/java.desktop-C.sym.txt | 0 .../data/symbols/java.desktop-D.sym.txt | 0 .../data/symbols/java.desktop-E.sym.txt | 0 .../data/symbols/java.desktop-F.sym.txt | 0 .../data/symbols/java.desktop-G.sym.txt | 0 .../data/symbols/java.desktop-H.sym.txt | 0 .../data/symbols/java.desktop-I.sym.txt | 0 .../data/symbols/java.instrument-8.sym.txt | 0 .../data/symbols/java.instrument-9.sym.txt | 0 .../data/symbols/java.instrument-A.sym.txt | 0 .../data/symbols/java.instrument-B.sym.txt | 0 .../data/symbols/java.instrument-G.sym.txt | 0 .../data/symbols/java.instrument-H.sym.txt | 0 .../data/symbols/java.instrument-I.sym.txt | 0 .../data/symbols/java.logging-7.sym.txt | 0 .../data/symbols/java.logging-8.sym.txt | 0 .../data/symbols/java.logging-9.sym.txt | 0 .../data/symbols/java.logging-A.sym.txt | 0 .../data/symbols/java.logging-B.sym.txt | 0 .../data/symbols/java.logging-G.sym.txt | 0 .../data/symbols/java.logging-H.sym.txt | 0 .../data/symbols/java.logging-I.sym.txt | 0 .../data/symbols/java.management-7.sym.txt | 0 .../data/symbols/java.management-8.sym.txt | 0 .../data/symbols/java.management-9.sym.txt | 0 .../data/symbols/java.management-A.sym.txt | 0 .../data/symbols/java.management-B.sym.txt | 0 .../data/symbols/java.management-D.sym.txt | 0 .../data/symbols/java.management-G.sym.txt | 0 .../data/symbols/java.management-H.sym.txt | 0 .../data/symbols/java.management-I.sym.txt | 0 .../symbols/java.management.rmi-8.sym.txt | 0 .../symbols/java.management.rmi-9.sym.txt | 0 .../symbols/java.management.rmi-A.sym.txt | 0 .../symbols/java.management.rmi-B.sym.txt | 0 .../symbols/java.management.rmi-D.sym.txt | 0 .../symbols/java.management.rmi-F.sym.txt | 0 .../symbols/java.management.rmi-G.sym.txt | 0 .../symbols/java.management.rmi-H.sym.txt | 0 .../symbols/java.management.rmi-I.sym.txt | 0 .../share}/data/symbols/java.naming-7.sym.txt | 0 .../share}/data/symbols/java.naming-8.sym.txt | 0 .../share}/data/symbols/java.naming-9.sym.txt | 0 .../share}/data/symbols/java.naming-A.sym.txt | 0 .../share}/data/symbols/java.naming-B.sym.txt | 0 .../share}/data/symbols/java.naming-C.sym.txt | 0 .../share}/data/symbols/java.naming-F.sym.txt | 0 .../share}/data/symbols/java.naming-G.sym.txt | 0 .../share}/data/symbols/java.naming-H.sym.txt | 0 .../share}/data/symbols/java.naming-I.sym.txt | 0 .../data/symbols/java.net.http-B.sym.txt | 0 .../data/symbols/java.net.http-D.sym.txt | 0 .../data/symbols/java.net.http-G.sym.txt | 0 .../data/symbols/java.net.http-I.sym.txt | 0 .../share}/data/symbols/java.prefs-7.sym.txt | 0 .../share}/data/symbols/java.prefs-8.sym.txt | 0 .../share}/data/symbols/java.prefs-9.sym.txt | 0 .../share}/data/symbols/java.prefs-A.sym.txt | 0 .../share}/data/symbols/java.prefs-B.sym.txt | 0 .../share}/data/symbols/java.rmi-7.sym.txt | 0 .../share}/data/symbols/java.rmi-8.sym.txt | 0 .../share}/data/symbols/java.rmi-9.sym.txt | 0 .../share}/data/symbols/java.rmi-A.sym.txt | 0 .../share}/data/symbols/java.rmi-B.sym.txt | 0 .../share}/data/symbols/java.rmi-C.sym.txt | 0 .../share}/data/symbols/java.rmi-F.sym.txt | 0 .../share}/data/symbols/java.rmi-G.sym.txt | 0 .../share}/data/symbols/java.rmi-H.sym.txt | 0 .../share}/data/symbols/java.rmi-I.sym.txt | 0 .../data/symbols/java.scripting-7.sym.txt | 0 .../data/symbols/java.scripting-8.sym.txt | 0 .../data/symbols/java.scripting-9.sym.txt | 0 .../data/symbols/java.scripting-A.sym.txt | 0 .../data/symbols/java.scripting-B.sym.txt | 0 .../data/symbols/java.scripting-G.sym.txt | 0 .../data/symbols/java.scripting-H.sym.txt | 0 .../data/symbols/java.scripting-I.sym.txt | 0 .../share}/data/symbols/java.se-9.sym.txt | 0 .../share}/data/symbols/java.se-A.sym.txt | 0 .../share}/data/symbols/java.se-B.sym.txt | 0 .../share}/data/symbols/java.se.ee-9.sym.txt | 0 .../share}/data/symbols/java.se.ee-A.sym.txt | 0 .../share}/data/symbols/java.se.ee-B.sym.txt | 0 .../data/symbols/java.security.jgss-7.sym.txt | 0 .../data/symbols/java.security.jgss-8.sym.txt | 0 .../data/symbols/java.security.jgss-9.sym.txt | 0 .../data/symbols/java.security.jgss-A.sym.txt | 0 .../data/symbols/java.security.jgss-B.sym.txt | 0 .../data/symbols/java.security.jgss-D.sym.txt | 0 .../data/symbols/java.security.jgss-G.sym.txt | 0 .../data/symbols/java.security.jgss-H.sym.txt | 0 .../data/symbols/java.security.jgss-I.sym.txt | 0 .../data/symbols/java.security.sasl-7.sym.txt | 0 .../data/symbols/java.security.sasl-8.sym.txt | 0 .../data/symbols/java.security.sasl-9.sym.txt | 0 .../data/symbols/java.security.sasl-A.sym.txt | 0 .../data/symbols/java.security.sasl-B.sym.txt | 0 .../data/symbols/java.security.sasl-G.sym.txt | 0 .../data/symbols/java.security.sasl-H.sym.txt | 0 .../data/symbols/java.security.sasl-I.sym.txt | 0 .../data/symbols/java.smartcardio-9.sym.txt | 0 .../data/symbols/java.smartcardio-A.sym.txt | 0 .../data/symbols/java.smartcardio-B.sym.txt | 0 .../data/symbols/java.smartcardio-G.sym.txt | 0 .../data/symbols/java.smartcardio-H.sym.txt | 0 .../data/symbols/java.smartcardio-I.sym.txt | 0 .../share}/data/symbols/java.sql-7.sym.txt | 0 .../share}/data/symbols/java.sql-8.sym.txt | 0 .../share}/data/symbols/java.sql-9.sym.txt | 0 .../share}/data/symbols/java.sql-A.sym.txt | 0 .../share}/data/symbols/java.sql-B.sym.txt | 0 .../share}/data/symbols/java.sql-G.sym.txt | 0 .../share}/data/symbols/java.sql-H.sym.txt | 0 .../share}/data/symbols/java.sql-I.sym.txt | 0 .../data/symbols/java.sql.rowset-7.sym.txt | 0 .../data/symbols/java.sql.rowset-8.sym.txt | 0 .../data/symbols/java.sql.rowset-9.sym.txt | 0 .../data/symbols/java.sql.rowset-A.sym.txt | 0 .../data/symbols/java.sql.rowset-B.sym.txt | 0 .../data/symbols/java.sql.rowset-G.sym.txt | 0 .../data/symbols/java.sql.rowset-H.sym.txt | 0 .../data/symbols/java.sql.rowset-I.sym.txt | 0 .../data/symbols/java.transaction-8.sym.txt | 0 .../data/symbols/java.transaction-9.sym.txt | 0 .../data/symbols/java.transaction-A.sym.txt | 0 .../data/symbols/java.transaction-B.sym.txt | 0 .../symbols/java.transaction.xa-B.sym.txt | 0 .../share}/data/symbols/java.xml-7.sym.txt | 0 .../share}/data/symbols/java.xml-8.sym.txt | 0 .../share}/data/symbols/java.xml-9.sym.txt | 0 .../share}/data/symbols/java.xml-A.sym.txt | 0 .../share}/data/symbols/java.xml-B.sym.txt | 0 .../share}/data/symbols/java.xml-C.sym.txt | 0 .../share}/data/symbols/java.xml-D.sym.txt | 0 .../share}/data/symbols/java.xml-E.sym.txt | 0 .../share}/data/symbols/java.xml-F.sym.txt | 0 .../share}/data/symbols/java.xml-G.sym.txt | 0 .../share}/data/symbols/java.xml-H.sym.txt | 0 .../share}/data/symbols/java.xml-I.sym.txt | 0 .../data/symbols/java.xml.bind-7.sym.txt | 0 .../data/symbols/java.xml.bind-8.sym.txt | 0 .../data/symbols/java.xml.bind-9.sym.txt | 0 .../data/symbols/java.xml.bind-A.sym.txt | 0 .../data/symbols/java.xml.bind-B.sym.txt | 0 .../data/symbols/java.xml.crypto-8.sym.txt | 0 .../data/symbols/java.xml.crypto-9.sym.txt | 0 .../data/symbols/java.xml.crypto-A.sym.txt | 0 .../data/symbols/java.xml.crypto-B.sym.txt | 0 .../data/symbols/java.xml.crypto-D.sym.txt | 0 .../data/symbols/java.xml.crypto-G.sym.txt | 0 .../data/symbols/java.xml.crypto-H.sym.txt | 0 .../data/symbols/java.xml.crypto-I.sym.txt | 0 .../share}/data/symbols/java.xml.ws-8.sym.txt | 0 .../share}/data/symbols/java.xml.ws-9.sym.txt | 0 .../share}/data/symbols/java.xml.ws-A.sym.txt | 0 .../share}/data/symbols/java.xml.ws-B.sym.txt | 0 .../symbols/java.xml.ws.annotation-7.sym.txt | 0 .../symbols/java.xml.ws.annotation-8.sym.txt | 0 .../symbols/java.xml.ws.annotation-9.sym.txt | 0 .../symbols/java.xml.ws.annotation-A.sym.txt | 0 .../symbols/java.xml.ws.annotation-B.sym.txt | 0 .../data/symbols/jdk.accessibility-9.sym.txt | 0 .../data/symbols/jdk.accessibility-A.sym.txt | 0 .../data/symbols/jdk.accessibility-B.sym.txt | 0 .../data/symbols/jdk.accessibility-G.sym.txt | 0 .../data/symbols/jdk.accessibility-H.sym.txt | 0 .../data/symbols/jdk.accessibility-I.sym.txt | 0 .../share}/data/symbols/jdk.attach-9.sym.txt | 0 .../share}/data/symbols/jdk.attach-A.sym.txt | 0 .../share}/data/symbols/jdk.attach-B.sym.txt | 0 .../share}/data/symbols/jdk.attach-G.sym.txt | 0 .../share}/data/symbols/jdk.attach-H.sym.txt | 0 .../share}/data/symbols/jdk.attach-I.sym.txt | 0 .../data/symbols/jdk.charsets-9.sym.txt | 0 .../data/symbols/jdk.charsets-A.sym.txt | 0 .../data/symbols/jdk.charsets-B.sym.txt | 0 .../data/symbols/jdk.compiler-9.sym.txt | 0 .../data/symbols/jdk.compiler-A.sym.txt | 0 .../data/symbols/jdk.compiler-B.sym.txt | 0 .../data/symbols/jdk.compiler-C.sym.txt | 0 .../data/symbols/jdk.compiler-D.sym.txt | 0 .../data/symbols/jdk.compiler-E.sym.txt | 0 .../data/symbols/jdk.compiler-F.sym.txt | 0 .../data/symbols/jdk.compiler-G.sym.txt | 0 .../data/symbols/jdk.compiler-H.sym.txt | 0 .../data/symbols/jdk.compiler-I.sym.txt | 0 .../symbols/jdk.crypto.cryptoki-9.sym.txt | 0 .../symbols/jdk.crypto.cryptoki-A.sym.txt | 0 .../symbols/jdk.crypto.cryptoki-B.sym.txt | 0 .../data/symbols/jdk.crypto.ec-9.sym.txt | 0 .../data/symbols/jdk.crypto.ec-A.sym.txt | 0 .../data/symbols/jdk.crypto.ec-B.sym.txt | 0 .../data/symbols/jdk.dynalink-9.sym.txt | 0 .../data/symbols/jdk.dynalink-A.sym.txt | 0 .../data/symbols/jdk.dynalink-B.sym.txt | 0 .../data/symbols/jdk.dynalink-G.sym.txt | 0 .../data/symbols/jdk.dynalink-H.sym.txt | 0 .../data/symbols/jdk.dynalink-I.sym.txt | 0 .../share}/data/symbols/jdk.editpad-9.sym.txt | 0 .../share}/data/symbols/jdk.editpad-A.sym.txt | 0 .../share}/data/symbols/jdk.editpad-B.sym.txt | 0 .../data/symbols/jdk.hotspot.agent-9.sym.txt | 0 .../data/symbols/jdk.hotspot.agent-A.sym.txt | 0 .../data/symbols/jdk.hotspot.agent-B.sym.txt | 0 .../data/symbols/jdk.httpserver-7.sym.txt | 0 .../data/symbols/jdk.httpserver-8.sym.txt | 0 .../data/symbols/jdk.httpserver-9.sym.txt | 0 .../data/symbols/jdk.httpserver-A.sym.txt | 0 .../data/symbols/jdk.httpserver-B.sym.txt | 0 .../data/symbols/jdk.httpserver-D.sym.txt | 0 .../data/symbols/jdk.httpserver-E.sym.txt | 0 .../data/symbols/jdk.httpserver-G.sym.txt | 0 .../data/symbols/jdk.httpserver-H.sym.txt | 0 .../data/symbols/jdk.httpserver-I.sym.txt | 0 .../symbols/jdk.incubator.foreign-E.sym.txt | 0 .../symbols/jdk.incubator.foreign-F.sym.txt | 0 .../symbols/jdk.incubator.foreign-G.sym.txt | 0 .../symbols/jdk.incubator.foreign-H.sym.txt | 0 .../symbols/jdk.incubator.foreign-I.sym.txt | 0 .../jdk.incubator.httpclient-9.sym.txt | 0 .../jdk.incubator.httpclient-A.sym.txt | 0 .../jdk.incubator.httpclient-B.sym.txt | 0 .../symbols/jdk.incubator.jpackage-E.sym.txt | 0 .../symbols/jdk.incubator.jpackage-G.sym.txt | 0 .../symbols/jdk.incubator.vector-G.sym.txt | 0 .../symbols/jdk.incubator.vector-H.sym.txt | 0 .../symbols/jdk.incubator.vector-I.sym.txt | 0 .../share}/data/symbols/jdk.jartool-9.sym.txt | 0 .../share}/data/symbols/jdk.jartool-A.sym.txt | 0 .../share}/data/symbols/jdk.jartool-B.sym.txt | 0 .../share}/data/symbols/jdk.jartool-D.sym.txt | 0 .../share}/data/symbols/jdk.jartool-F.sym.txt | 0 .../share}/data/symbols/jdk.jartool-G.sym.txt | 0 .../share}/data/symbols/jdk.jartool-H.sym.txt | 0 .../share}/data/symbols/jdk.jartool-I.sym.txt | 0 .../share}/data/symbols/jdk.javadoc-9.sym.txt | 0 .../share}/data/symbols/jdk.javadoc-A.sym.txt | 0 .../share}/data/symbols/jdk.javadoc-B.sym.txt | 0 .../share}/data/symbols/jdk.javadoc-D.sym.txt | 0 .../share}/data/symbols/jdk.javadoc-F.sym.txt | 0 .../share}/data/symbols/jdk.javadoc-G.sym.txt | 0 .../share}/data/symbols/jdk.javadoc-H.sym.txt | 0 .../share}/data/symbols/jdk.javadoc-I.sym.txt | 0 .../share}/data/symbols/jdk.jcmd-9.sym.txt | 0 .../share}/data/symbols/jdk.jcmd-A.sym.txt | 0 .../share}/data/symbols/jdk.jcmd-B.sym.txt | 0 .../data/symbols/jdk.jconsole-9.sym.txt | 0 .../data/symbols/jdk.jconsole-A.sym.txt | 0 .../data/symbols/jdk.jconsole-B.sym.txt | 0 .../data/symbols/jdk.jconsole-G.sym.txt | 0 .../data/symbols/jdk.jconsole-H.sym.txt | 0 .../data/symbols/jdk.jconsole-I.sym.txt | 0 .../share}/data/symbols/jdk.jdeps-9.sym.txt | 0 .../share}/data/symbols/jdk.jdeps-A.sym.txt | 0 .../share}/data/symbols/jdk.jdeps-B.sym.txt | 0 .../share}/data/symbols/jdk.jdi-9.sym.txt | 0 .../share}/data/symbols/jdk.jdi-A.sym.txt | 0 .../share}/data/symbols/jdk.jdi-B.sym.txt | 0 .../share}/data/symbols/jdk.jdi-F.sym.txt | 0 .../share}/data/symbols/jdk.jdi-G.sym.txt | 0 .../share}/data/symbols/jdk.jdi-H.sym.txt | 0 .../share}/data/symbols/jdk.jdi-I.sym.txt | 0 .../data/symbols/jdk.jdwp.agent-9.sym.txt | 0 .../data/symbols/jdk.jdwp.agent-A.sym.txt | 0 .../data/symbols/jdk.jdwp.agent-B.sym.txt | 0 .../share}/data/symbols/jdk.jfr-B.sym.txt | 0 .../share}/data/symbols/jdk.jfr-C.sym.txt | 0 .../share}/data/symbols/jdk.jfr-E.sym.txt | 0 .../share}/data/symbols/jdk.jfr-G.sym.txt | 0 .../share}/data/symbols/jdk.jfr-H.sym.txt | 0 .../share}/data/symbols/jdk.jlink-9.sym.txt | 0 .../share}/data/symbols/jdk.jlink-A.sym.txt | 0 .../share}/data/symbols/jdk.jlink-B.sym.txt | 0 .../share}/data/symbols/jdk.jlink-D.sym.txt | 0 .../share}/data/symbols/jdk.jlink-E.sym.txt | 0 .../share}/data/symbols/jdk.jlink-I.sym.txt | 0 .../data/symbols/jdk.jpackage-G.sym.txt | 0 .../share}/data/symbols/jdk.jshell-9.sym.txt | 0 .../share}/data/symbols/jdk.jshell-A.sym.txt | 0 .../share}/data/symbols/jdk.jshell-B.sym.txt | 0 .../share}/data/symbols/jdk.jshell-D.sym.txt | 0 .../share}/data/symbols/jdk.jshell-E.sym.txt | 0 .../share}/data/symbols/jdk.jshell-G.sym.txt | 0 .../share}/data/symbols/jdk.jshell-H.sym.txt | 0 .../share}/data/symbols/jdk.jshell-I.sym.txt | 0 .../data/symbols/jdk.jsobject-9.sym.txt | 0 .../data/symbols/jdk.jsobject-A.sym.txt | 0 .../data/symbols/jdk.jsobject-B.sym.txt | 0 .../data/symbols/jdk.jsobject-C.sym.txt | 0 .../data/symbols/jdk.jsobject-E.sym.txt | 0 .../data/symbols/jdk.jsobject-G.sym.txt | 0 .../data/symbols/jdk.jsobject-H.sym.txt | 0 .../data/symbols/jdk.jsobject-I.sym.txt | 0 .../share}/data/symbols/jdk.jstatd-9.sym.txt | 0 .../share}/data/symbols/jdk.jstatd-A.sym.txt | 0 .../share}/data/symbols/jdk.jstatd-B.sym.txt | 0 .../data/symbols/jdk.localedata-9.sym.txt | 0 .../data/symbols/jdk.localedata-A.sym.txt | 0 .../data/symbols/jdk.localedata-B.sym.txt | 0 .../data/symbols/jdk.management-7.sym.txt | 0 .../data/symbols/jdk.management-8.sym.txt | 0 .../data/symbols/jdk.management-9.sym.txt | 0 .../data/symbols/jdk.management-A.sym.txt | 0 .../data/symbols/jdk.management-B.sym.txt | 0 .../data/symbols/jdk.management-E.sym.txt | 0 .../data/symbols/jdk.management-G.sym.txt | 0 .../data/symbols/jdk.management-H.sym.txt | 0 .../data/symbols/jdk.management-I.sym.txt | 0 .../symbols/jdk.management.agent-9.sym.txt | 0 .../symbols/jdk.management.agent-A.sym.txt | 0 .../symbols/jdk.management.agent-B.sym.txt | 0 .../data/symbols/jdk.management.jfr-B.sym.txt | 0 .../data/symbols/jdk.management.jfr-G.sym.txt | 0 .../data/symbols/jdk.management.jfr-H.sym.txt | 0 .../data/symbols/jdk.management.jfr-I.sym.txt | 0 .../data/symbols/jdk.naming.dns-9.sym.txt | 0 .../data/symbols/jdk.naming.dns-A.sym.txt | 0 .../data/symbols/jdk.naming.dns-B.sym.txt | 0 .../data/symbols/jdk.naming.rmi-9.sym.txt | 0 .../data/symbols/jdk.naming.rmi-A.sym.txt | 0 .../data/symbols/jdk.naming.rmi-B.sym.txt | 0 .../share}/data/symbols/jdk.net-9.sym.txt | 0 .../share}/data/symbols/jdk.net-A.sym.txt | 0 .../share}/data/symbols/jdk.net-B.sym.txt | 0 .../share}/data/symbols/jdk.net-E.sym.txt | 0 .../share}/data/symbols/jdk.net-F.sym.txt | 0 .../share}/data/symbols/jdk.net-G.sym.txt | 0 .../share}/data/symbols/jdk.net-H.sym.txt | 0 .../share}/data/symbols/jdk.net-I.sym.txt | 0 .../data/symbols/jdk.nio.mapmode-F.sym.txt | 0 .../share}/data/symbols/jdk.pack-9.sym.txt | 0 .../share}/data/symbols/jdk.pack-A.sym.txt | 0 .../share}/data/symbols/jdk.pack-B.sym.txt | 0 .../share}/data/symbols/jdk.pack-E.sym.txt | 0 .../data/symbols/jdk.policytool-9.sym.txt | 0 .../data/symbols/jdk.policytool-A.sym.txt | 0 .../share}/data/symbols/jdk.rmic-9.sym.txt | 0 .../share}/data/symbols/jdk.rmic-A.sym.txt | 0 .../share}/data/symbols/jdk.rmic-B.sym.txt | 0 .../share}/data/symbols/jdk.rmic-F.sym.txt | 0 .../symbols/jdk.scripting.nashorn-7.sym.txt | 0 .../symbols/jdk.scripting.nashorn-8.sym.txt | 0 .../symbols/jdk.scripting.nashorn-9.sym.txt | 0 .../symbols/jdk.scripting.nashorn-A.sym.txt | 0 .../symbols/jdk.scripting.nashorn-B.sym.txt | 0 .../symbols/jdk.scripting.nashorn-F.sym.txt | 0 .../share}/data/symbols/jdk.sctp-7.sym.txt | 0 .../share}/data/symbols/jdk.sctp-8.sym.txt | 0 .../share}/data/symbols/jdk.sctp-9.sym.txt | 0 .../share}/data/symbols/jdk.sctp-A.sym.txt | 0 .../share}/data/symbols/jdk.sctp-B.sym.txt | 0 .../share}/data/symbols/jdk.sctp-G.sym.txt | 0 .../share}/data/symbols/jdk.sctp-H.sym.txt | 0 .../share}/data/symbols/jdk.sctp-I.sym.txt | 0 .../data/symbols/jdk.security.auth-7.sym.txt | 0 .../data/symbols/jdk.security.auth-8.sym.txt | 0 .../data/symbols/jdk.security.auth-9.sym.txt | 0 .../data/symbols/jdk.security.auth-A.sym.txt | 0 .../data/symbols/jdk.security.auth-B.sym.txt | 0 .../data/symbols/jdk.security.auth-G.sym.txt | 0 .../data/symbols/jdk.security.auth-H.sym.txt | 0 .../data/symbols/jdk.security.auth-I.sym.txt | 0 .../data/symbols/jdk.security.jgss-7.sym.txt | 0 .../data/symbols/jdk.security.jgss-8.sym.txt | 0 .../data/symbols/jdk.security.jgss-9.sym.txt | 0 .../data/symbols/jdk.security.jgss-A.sym.txt | 0 .../data/symbols/jdk.security.jgss-B.sym.txt | 0 .../data/symbols/jdk.security.jgss-G.sym.txt | 0 .../data/symbols/jdk.security.jgss-H.sym.txt | 0 .../data/symbols/jdk.security.jgss-I.sym.txt | 0 .../data/symbols/jdk.unsupported-9.sym.txt | 0 .../data/symbols/jdk.unsupported-A.sym.txt | 0 .../data/symbols/jdk.unsupported-B.sym.txt | 0 .../data/symbols/jdk.unsupported-C.sym.txt | 0 .../data/symbols/jdk.unsupported-F.sym.txt | 0 .../data/symbols/jdk.unsupported-G.sym.txt | 0 .../data/symbols/jdk.unsupported-H.sym.txt | 0 .../data/symbols/jdk.unsupported-I.sym.txt | 0 .../share}/data/symbols/jdk.xml.dom-9.sym.txt | 0 .../share}/data/symbols/jdk.xml.dom-A.sym.txt | 0 .../share}/data/symbols/jdk.xml.dom-B.sym.txt | 0 .../share}/data/symbols/jdk.xml.dom-G.sym.txt | 0 .../share}/data/symbols/jdk.xml.dom-H.sym.txt | 0 .../share}/data/symbols/jdk.xml.dom-I.sym.txt | 0 .../share}/data/symbols/jdk.zipfs-9.sym.txt | 0 .../share}/data/symbols/jdk.zipfs-A.sym.txt | 0 .../share}/data/symbols/jdk.zipfs-B.sym.txt | 0 .../jdk.compiler/share}/data/symbols/symbols | 0 test/jdk/java/security/misc/Versions.java | 4 +- test/jdk/java/util/Currency/CurrencyTest.java | 4 +- test/jdk/java/util/Locale/LSRDataTest.java | 10 ++--- .../lib/testlibrary/java/lang/UCDFiles.java | 9 ++-- test/jdk/sun/nio/cs/TestCharsetMapping.java | 4 +- test/jdk/sun/nio/cs/TestMS950.java | 2 +- .../sun/security/lib/CheckBlockedCerts.java | 4 +- .../sun/util/calendar/zi/TestZoneInfo310.java | 4 +- .../platform/CanHandleClassFilesTest.java | 2 +- .../tools/javac/sym/ElementStructureTest.java | 8 ++-- 619 files changed, 134 insertions(+), 126 deletions(-) rename {make/data/characterdata => src/java.base/share/classes/java/lang}/CharacterData00.java.template (100%) rename {make/data/characterdata => src/java.base/share/classes/java/lang}/CharacterData01.java.template (100%) rename {make/data/characterdata => src/java.base/share/classes/java/lang}/CharacterData02.java.template (100%) rename {make/data/characterdata => src/java.base/share/classes/java/lang}/CharacterData03.java.template (100%) rename {make/data/characterdata => src/java.base/share/classes/java/lang}/CharacterData0E.java.template (100%) rename {make/data/characterdata => src/java.base/share/classes/java/lang}/CharacterDataLatin1.java.template (100%) rename {make => src/java.base/share}/data/blockedcertsconverter/blocked.certs.pem (100%) rename {make => src/java.base/share}/data/cacerts/README (100%) rename {make => src/java.base/share}/data/cacerts/actalisauthenticationrootca (100%) rename {make => src/java.base/share}/data/cacerts/addtrustexternalca (100%) rename {make => src/java.base/share}/data/cacerts/addtrustqualifiedca (100%) rename {make => src/java.base/share}/data/cacerts/affirmtrustcommercialca (100%) rename {make => src/java.base/share}/data/cacerts/affirmtrustnetworkingca (100%) rename {make => src/java.base/share}/data/cacerts/affirmtrustpremiumca (100%) rename {make => src/java.base/share}/data/cacerts/affirmtrustpremiumeccca (100%) rename {make => src/java.base/share}/data/cacerts/amazonrootca1 (100%) rename {make => src/java.base/share}/data/cacerts/amazonrootca2 (100%) rename {make => src/java.base/share}/data/cacerts/amazonrootca3 (100%) rename {make => src/java.base/share}/data/cacerts/amazonrootca4 (100%) rename {make => src/java.base/share}/data/cacerts/baltimorecybertrustca (100%) rename {make => src/java.base/share}/data/cacerts/buypassclass2ca (100%) rename {make => src/java.base/share}/data/cacerts/buypassclass3ca (100%) rename {make => src/java.base/share}/data/cacerts/camerfirmachambersca (100%) rename {make => src/java.base/share}/data/cacerts/camerfirmachamberscommerceca (100%) rename {make => src/java.base/share}/data/cacerts/camerfirmachambersignca (100%) rename {make => src/java.base/share}/data/cacerts/certumca (100%) rename {make => src/java.base/share}/data/cacerts/certumtrustednetworkca (100%) rename {make => src/java.base/share}/data/cacerts/chunghwaepkirootca (100%) rename {make => src/java.base/share}/data/cacerts/comodoaaaca (100%) rename {make => src/java.base/share}/data/cacerts/comodoeccca (100%) rename {make => src/java.base/share}/data/cacerts/comodorsaca (100%) rename {make => src/java.base/share}/data/cacerts/digicertassuredidg2 (100%) rename {make => src/java.base/share}/data/cacerts/digicertassuredidg3 (100%) rename {make => src/java.base/share}/data/cacerts/digicertassuredidrootca (100%) rename {make => src/java.base/share}/data/cacerts/digicertglobalrootca (100%) rename {make => src/java.base/share}/data/cacerts/digicertglobalrootg2 (100%) rename {make => src/java.base/share}/data/cacerts/digicertglobalrootg3 (100%) rename {make => src/java.base/share}/data/cacerts/digicerthighassuranceevrootca (100%) rename {make => src/java.base/share}/data/cacerts/digicerttrustedrootg4 (100%) rename {make => src/java.base/share}/data/cacerts/dtrustclass3ca2 (100%) rename {make => src/java.base/share}/data/cacerts/dtrustclass3ca2ev (100%) rename {make => src/java.base/share}/data/cacerts/entrust2048ca (100%) rename {make => src/java.base/share}/data/cacerts/entrustevca (100%) rename {make => src/java.base/share}/data/cacerts/entrustrootcaec1 (100%) rename {make => src/java.base/share}/data/cacerts/entrustrootcag2 (100%) rename {make => src/java.base/share}/data/cacerts/entrustrootcag4 (100%) rename {make => src/java.base/share}/data/cacerts/geotrustglobalca (100%) rename {make => src/java.base/share}/data/cacerts/geotrustprimaryca (100%) rename {make => src/java.base/share}/data/cacerts/geotrustprimarycag2 (100%) rename {make => src/java.base/share}/data/cacerts/geotrustprimarycag3 (100%) rename {make => src/java.base/share}/data/cacerts/geotrustuniversalca (100%) rename {make => src/java.base/share}/data/cacerts/globalsignca (100%) rename {make => src/java.base/share}/data/cacerts/globalsigneccrootcar4 (100%) rename {make => src/java.base/share}/data/cacerts/globalsigneccrootcar5 (100%) rename {make => src/java.base/share}/data/cacerts/globalsignr3ca (100%) rename {make => src/java.base/share}/data/cacerts/globalsignrootcar6 (100%) rename {make => src/java.base/share}/data/cacerts/godaddyclass2ca (100%) rename {make => src/java.base/share}/data/cacerts/godaddyrootg2ca (100%) rename {make => src/java.base/share}/data/cacerts/haricaeccrootca2015 (100%) rename {make => src/java.base/share}/data/cacerts/haricarootca2015 (100%) rename {make => src/java.base/share}/data/cacerts/identrustcommercial (100%) rename {make => src/java.base/share}/data/cacerts/identrustpublicca (100%) rename {make => src/java.base/share}/data/cacerts/letsencryptisrgx1 (100%) rename {make => src/java.base/share}/data/cacerts/luxtrustglobalroot2ca (100%) rename {make => src/java.base/share}/data/cacerts/luxtrustglobalrootca (100%) rename {make => src/java.base/share}/data/cacerts/quovadisrootca (100%) rename {make => src/java.base/share}/data/cacerts/quovadisrootca1g3 (100%) rename {make => src/java.base/share}/data/cacerts/quovadisrootca2 (100%) rename {make => src/java.base/share}/data/cacerts/quovadisrootca2g3 (100%) rename {make => src/java.base/share}/data/cacerts/quovadisrootca3 (100%) rename {make => src/java.base/share}/data/cacerts/quovadisrootca3g3 (100%) rename {make => src/java.base/share}/data/cacerts/secomscrootca1 (100%) rename {make => src/java.base/share}/data/cacerts/secomscrootca2 (100%) rename {make => src/java.base/share}/data/cacerts/securetrustca (100%) rename {make => src/java.base/share}/data/cacerts/sslrooteccca (100%) rename {make => src/java.base/share}/data/cacerts/sslrootevrsaca (100%) rename {make => src/java.base/share}/data/cacerts/sslrootrsaca (100%) rename {make => src/java.base/share}/data/cacerts/starfieldclass2ca (100%) rename {make => src/java.base/share}/data/cacerts/starfieldrootg2ca (100%) rename {make => src/java.base/share}/data/cacerts/starfieldservicesrootg2ca (100%) rename {make => src/java.base/share}/data/cacerts/swisssigngoldg2ca (100%) rename {make => src/java.base/share}/data/cacerts/swisssignplatinumg2ca (100%) rename {make => src/java.base/share}/data/cacerts/swisssignsilverg2ca (100%) rename {make => src/java.base/share}/data/cacerts/teliasonerarootcav1 (100%) rename {make => src/java.base/share}/data/cacerts/thawteprimaryrootca (100%) rename {make => src/java.base/share}/data/cacerts/thawteprimaryrootcag2 (100%) rename {make => src/java.base/share}/data/cacerts/thawteprimaryrootcag3 (100%) rename {make => src/java.base/share}/data/cacerts/ttelesecglobalrootclass2ca (100%) rename {make => src/java.base/share}/data/cacerts/ttelesecglobalrootclass3ca (100%) rename {make => src/java.base/share}/data/cacerts/usertrusteccca (100%) rename {make => src/java.base/share}/data/cacerts/usertrustrsaca (100%) rename {make => src/java.base/share}/data/cacerts/utnuserfirstobjectca (100%) rename {make => src/java.base/share}/data/cacerts/verisignclass3g3ca (100%) rename {make => src/java.base/share}/data/cacerts/verisignclass3g4ca (100%) rename {make => src/java.base/share}/data/cacerts/verisignclass3g5ca (100%) rename {make => src/java.base/share}/data/cacerts/verisignuniversalrootca (100%) rename {make => src/java.base/share}/data/cacerts/xrampglobalca (100%) rename {make => src/java.base/share}/data/currency/CurrencyData.properties (100%) rename {make => src/java.base/share}/data/lsrdata/language-subtag-registry.txt (100%) rename {make => src/java.base/share}/data/publicsuffixlist/VERSION (100%) rename {make => src/java.base/share}/data/publicsuffixlist/public_suffix_list.dat (100%) rename {make => src/java.base/share}/data/tzdata/VERSION (100%) rename {make => src/java.base/share}/data/tzdata/africa (100%) rename {make => src/java.base/share}/data/tzdata/antarctica (100%) rename {make => src/java.base/share}/data/tzdata/asia (100%) rename {make => src/java.base/share}/data/tzdata/australasia (100%) rename {make => src/java.base/share}/data/tzdata/backward (100%) rename {make => src/java.base/share}/data/tzdata/etcetera (100%) rename {make => src/java.base/share}/data/tzdata/europe (100%) rename {make => src/java.base/share}/data/tzdata/factory (100%) rename {make => src/java.base/share}/data/tzdata/gmt (100%) rename {make => src/java.base/share}/data/tzdata/iso3166.tab (100%) rename {make => src/java.base/share}/data/tzdata/jdk11_backward (100%) rename {make => src/java.base/share}/data/tzdata/leapseconds (100%) rename {make => src/java.base/share}/data/tzdata/northamerica (100%) rename {make => src/java.base/share}/data/tzdata/solar87 (100%) rename {make => src/java.base/share}/data/tzdata/solar88 (100%) rename {make => src/java.base/share}/data/tzdata/solar89 (100%) rename {make => src/java.base/share}/data/tzdata/southamerica (100%) rename {make => src/java.base/share}/data/tzdata/zone.tab (100%) rename {make => src/java.base/share}/data/unicodedata/Blocks.txt (100%) rename {make => src/java.base/share}/data/unicodedata/DerivedCoreProperties.txt (100%) rename {make => src/java.base/share}/data/unicodedata/NormalizationTest.txt (100%) rename {make => src/java.base/share}/data/unicodedata/PropList.txt (100%) rename {make => src/java.base/share}/data/unicodedata/PropertyValueAliases.txt (100%) rename {make => src/java.base/share}/data/unicodedata/ReadMe.txt (100%) rename {make => src/java.base/share}/data/unicodedata/Scripts.txt (100%) rename {make => src/java.base/share}/data/unicodedata/SpecialCasing.txt (100%) rename {make => src/java.base/share}/data/unicodedata/UnicodeData.txt (100%) rename {make => src/java.base/share}/data/unicodedata/auxiliary/GraphemeBreakProperty.txt (100%) rename {make => src/java.base/share}/data/unicodedata/auxiliary/GraphemeBreakTest.txt (100%) rename {make => src/java.base/share}/data/unicodedata/emoji/emoji-data.txt (100%) rename make/data/fontconfig/aix.fontconfig.properties => src/java.desktop/aix/data/fontconfig/fontconfig.properties (100%) rename make/data/fontconfig/bsd.fontconfig.properties => src/java.desktop/bsd/data/fontconfig/fontconfig.properties (100%) rename make/data/fontconfig/macosx.fontconfig.properties => src/java.desktop/macosx/data/fontconfig/fontconfig.properties (100%) rename {make => src/java.desktop/macosx}/data/macosxicons/JavaApp.icns (100%) rename {make => src/java.desktop/share}/data/dtdbuilder/HTMLlat1.sgml (100%) rename {make => src/java.desktop/share}/data/dtdbuilder/HTMLspecial.sgml (100%) rename {make => src/java.desktop/share}/data/dtdbuilder/HTMLsymbol.sgml (100%) rename {make => src/java.desktop/share}/data/dtdbuilder/html32.dtd (100%) rename {make => src/java.desktop/share}/data/dtdbuilder/public.map (100%) rename {make => src/java.desktop/unix}/data/x11wrappergen/sizes-32.txt (100%) rename {make => src/java.desktop/unix}/data/x11wrappergen/sizes-64.txt (100%) rename {make => src/java.desktop/unix}/data/x11wrappergen/xlibtypes.txt (100%) rename make/data/fontconfig/windows.fontconfig.properties => src/java.desktop/windows/data/fontconfig/fontconfig.properties (100%) rename {make => src/java.se/share}/data/jdwp/jdwp.spec (100%) rename {make => src/jdk.compiler/share}/data/symbols/README (100%) rename {make => src/jdk.compiler/share}/data/symbols/include.list (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.activation-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.activation-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.activation-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.activation-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.base-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.compiler-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.corba-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.corba-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.corba-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.corba-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.datatransfer-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.datatransfer-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.datatransfer-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.datatransfer-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.datatransfer-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.datatransfer-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.datatransfer-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.datatransfer-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.desktop-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.instrument-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.instrument-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.instrument-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.instrument-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.instrument-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.instrument-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.instrument-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.logging-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.logging-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.logging-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.logging-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.logging-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.logging-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.logging-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.logging-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.management.rmi-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.naming-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.net.http-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.net.http-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.net.http-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.net.http-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.prefs-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.prefs-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.prefs-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.prefs-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.prefs-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.rmi-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.scripting-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.scripting-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.scripting-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.scripting-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.scripting-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.scripting-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.scripting-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.scripting-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.se-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.se-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.se-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.se.ee-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.se.ee-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.se.ee-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.jgss-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.sasl-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.sasl-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.sasl-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.sasl-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.sasl-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.sasl-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.sasl-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.security.sasl-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.smartcardio-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.smartcardio-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.smartcardio-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.smartcardio-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.smartcardio-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.smartcardio-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql.rowset-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql.rowset-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql.rowset-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql.rowset-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql.rowset-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql.rowset-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql.rowset-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.sql.rowset-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.transaction-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.transaction-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.transaction-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.transaction-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.transaction.xa-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.bind-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.bind-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.bind-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.bind-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.bind-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.crypto-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.crypto-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.crypto-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.crypto-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.crypto-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.crypto-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.crypto-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.crypto-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws.annotation-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws.annotation-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws.annotation-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws.annotation-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/java.xml.ws.annotation-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.accessibility-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.accessibility-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.accessibility-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.accessibility-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.accessibility-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.accessibility-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.attach-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.attach-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.attach-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.attach-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.attach-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.attach-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.charsets-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.charsets-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.charsets-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.compiler-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.crypto.cryptoki-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.crypto.cryptoki-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.crypto.cryptoki-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.crypto.ec-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.crypto.ec-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.crypto.ec-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.dynalink-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.dynalink-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.dynalink-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.dynalink-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.dynalink-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.dynalink-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.editpad-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.editpad-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.editpad-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.hotspot.agent-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.hotspot.agent-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.hotspot.agent-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.httpserver-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.foreign-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.foreign-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.foreign-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.foreign-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.foreign-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.httpclient-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.httpclient-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.httpclient-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.jpackage-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.jpackage-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.vector-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.vector-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.incubator.vector-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jartool-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jartool-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jartool-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jartool-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jartool-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jartool-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jartool-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jartool-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.javadoc-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.javadoc-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.javadoc-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.javadoc-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.javadoc-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.javadoc-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.javadoc-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.javadoc-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jcmd-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jcmd-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jcmd-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jconsole-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jconsole-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jconsole-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jconsole-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jconsole-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jconsole-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdeps-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdeps-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdeps-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdi-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdi-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdi-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdi-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdi-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdi-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdi-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdwp.agent-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdwp.agent-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jdwp.agent-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jfr-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jfr-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jfr-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jfr-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jfr-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jlink-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jlink-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jlink-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jlink-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jlink-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jlink-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jpackage-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jshell-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jshell-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jshell-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jshell-D.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jshell-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jshell-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jshell-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jshell-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jsobject-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jsobject-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jsobject-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jsobject-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jsobject-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jsobject-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jsobject-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jsobject-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jstatd-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jstatd-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.jstatd-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.localedata-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.localedata-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.localedata-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management.agent-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management.agent-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management.agent-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management.jfr-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management.jfr-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management.jfr-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.management.jfr-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.naming.dns-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.naming.dns-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.naming.dns-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.naming.rmi-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.naming.rmi-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.naming.rmi-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.net-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.net-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.net-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.net-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.net-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.net-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.net-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.net-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.nio.mapmode-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.pack-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.pack-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.pack-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.pack-E.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.policytool-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.policytool-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.rmic-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.rmic-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.rmic-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.rmic-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.scripting.nashorn-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.scripting.nashorn-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.scripting.nashorn-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.scripting.nashorn-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.scripting.nashorn-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.scripting.nashorn-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.sctp-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.sctp-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.sctp-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.sctp-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.sctp-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.sctp-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.sctp-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.sctp-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.auth-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.auth-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.auth-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.auth-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.auth-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.auth-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.auth-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.auth-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.jgss-7.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.jgss-8.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.jgss-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.jgss-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.jgss-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.jgss-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.jgss-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.security.jgss-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.unsupported-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.unsupported-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.unsupported-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.unsupported-C.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.unsupported-F.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.unsupported-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.unsupported-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.unsupported-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.xml.dom-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.xml.dom-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.xml.dom-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.xml.dom-G.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.xml.dom-H.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.xml.dom-I.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.zipfs-9.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.zipfs-A.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/jdk.zipfs-B.sym.txt (100%) rename {make => src/jdk.compiler/share}/data/symbols/symbols (100%) diff --git a/make/ModuleWrapper.gmk b/make/ModuleWrapper.gmk index e4a8db24aa3..d83af819a9b 100644 --- a/make/ModuleWrapper.gmk +++ b/make/ModuleWrapper.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2022, 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 @@ -35,6 +35,8 @@ default: all include $(SPEC) include MakeBase.gmk +MODULE_SRC := $(TOPDIR)/src/$(MODULE) + # All makefiles should add the targets to be built to this variable. TARGETS := diff --git a/make/ToolsJdk.gmk b/make/ToolsJdk.gmk index af9def3a415..9eef6969125 100644 --- a/make/ToolsJdk.gmk +++ b/make/ToolsJdk.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -53,7 +53,7 @@ TOOL_GENERATECHARACTER = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_cla TOOL_CHARACTERNAME = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \ build.tools.generatecharacter.CharacterName -TOOL_DTDBUILDER = $(JAVA_SMALL) -Ddtd_home=$(TOPDIR)/make/data/dtdbuilder \ +TOOL_DTDBUILDER = $(JAVA_SMALL) -Ddtd_home=$(TOPDIR)/src/java.desktop/share/data/dtdbuilder \ -Djava.awt.headless=true \ -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes build.tools.dtdbuilder.DTDBuilder diff --git a/make/UpdateX11Wrappers.gmk b/make/UpdateX11Wrappers.gmk index ad67966ec8a..3201b5f883f 100644 --- a/make/UpdateX11Wrappers.gmk +++ b/make/UpdateX11Wrappers.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2022, 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 @@ -50,7 +50,7 @@ endif X11WRAPPERS_OUTPUT := $(SUPPORT_OUTPUTDIR)/x11wrappers GENERATOR_SOURCE_FILE := $(X11WRAPPERS_OUTPUT)/src/data_generator.c -GENSRC_X11WRAPPERS_DATADIR := $(TOPDIR)/make/data/x11wrappergen +GENSRC_X11WRAPPERS_DATADIR := $(TOPDIR)/src/java.desktop/unix/data/x11wrappergen WRAPPER_OUTPUT_FILE := $(GENSRC_X11WRAPPERS_DATADIR)/sizes-$(BITS).txt BITS := $(OPENJDK_TARGET_CPU_BITS) diff --git a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java index ea700f0b660..41f600a817e 100644 --- a/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java +++ b/make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2022, 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 @@ -156,7 +156,7 @@ import java.util.Optional; * A tool for processing the .sym.txt files. * * To add historical data for JDK N, N >= 11, do the following: - * * cd /make/data/symbols + * * cd /src/jdk.compiler/share/data/symbols * * /bin/java --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \ * --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ * --add-exports jdk.compiler/com.sun.tools.javac.jvm=ALL-UNNAMED \ @@ -164,7 +164,7 @@ import java.util.Optional; * --add-modules jdk.jdeps \ * ../../../make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java \ * build-description-incremental symbols include.list - * * sanity-check the new and updates files in make/data/symbols and commit them + * * sanity-check the new and updates files in src/jdk.compiler/share/data/symbols and commit them * * The tools allows to: * * convert the .sym.txt into class/sig files for ct.sym @@ -212,7 +212,8 @@ import java.util.Optional; * To generate the .sym.txt files for OpenJDK 7 and 8: * /bin/java build.tools.symbolgenerator.Probe OpenJDK7.classes * /bin/java build.tools.symbolgenerator.Probe OpenJDK8.classes - * java build.tools.symbolgenerator.CreateSymbols build-description make/data/symbols $TOPDIR make/data/symbols/include.list + * java build.tools.symbolgenerator.CreateSymbols build-description src/jdk.compiler/share/data/symbols + * $TOPDIR src/jdk.compiler/share/data/symbols/include.list * 8 OpenJDK8.classes '' * 7 OpenJDK7.classes 8 * diff --git a/make/modules/java.base/Gendata.gmk b/make/modules/java.base/Gendata.gmk index 4b894eeae4a..9e5cfe2d0fc 100644 --- a/make/modules/java.base/Gendata.gmk +++ b/make/modules/java.base/Gendata.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -39,7 +39,7 @@ include gendata/GendataPublicSuffixList.gmk GENDATA_UNINAME := $(JDK_OUTPUTDIR)/modules/java.base/java/lang/uniName.dat -$(GENDATA_UNINAME): $(TOPDIR)/make/data/unicodedata/UnicodeData.txt $(BUILD_TOOLS_JDK) +$(GENDATA_UNINAME): $(MODULE_SRC)/share/data/unicodedata/UnicodeData.txt $(BUILD_TOOLS_JDK) $(call MakeDir, $(@D)) $(TOOL_CHARACTERNAME) $< $@ @@ -49,7 +49,7 @@ TARGETS += $(GENDATA_UNINAME) GENDATA_CURDATA := $(JDK_OUTPUTDIR)/modules/java.base/java/util/currency.data -$(GENDATA_CURDATA): $(TOPDIR)/make/data/currency/CurrencyData.properties $(BUILD_TOOLS_JDK) +$(GENDATA_CURDATA): $(MODULE_SRC)/share/data/currency/CurrencyData.properties $(BUILD_TOOLS_JDK) $(call MakeDir, $(@D)) $(RM) $@ $(TOOL_GENERATECURRENCYDATA) -o $@.tmp -i $< @@ -63,7 +63,7 @@ TARGETS += $(GENDATA_CURDATA) ifneq ($(CACERTS_SRC), ) GENDATA_CACERTS_SRC := $(CACERTS_SRC) else - GENDATA_CACERTS_SRC := $(TOPDIR)/make/data/cacerts/ + GENDATA_CACERTS_SRC := $(MODULE_SRC)/share/data/cacerts/ endif GENDATA_CACERTS := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/security/cacerts @@ -78,7 +78,7 @@ endif ################################################################################ -GENDATA_JAVA_SECURITY_SRC := $(TOPDIR)/src/java.base/share/conf/security/java.security +GENDATA_JAVA_SECURITY_SRC := $(MODULE_SRC)/share/conf/security/java.security GENDATA_JAVA_SECURITY := $(SUPPORT_OUTPUTDIR)/modules_conf/java.base/security/java.security ifeq ($(UNLIMITED_CRYPTO), true) diff --git a/make/modules/java.base/Gensrc.gmk b/make/modules/java.base/Gensrc.gmk index 9ea2d015d3b..9c9576bdd4a 100644 --- a/make/modules/java.base/Gensrc.gmk +++ b/make/modules/java.base/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -46,8 +46,8 @@ TARGETS += $(GENSRC_BASELOCALEDATA) CLDR_DATA_DIR := $(TOPDIR)/make/data/cldr/common GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base CLDR_GEN_DONE := $(GENSRC_DIR)/_cldr-gensrc.marker -TZ_DATA_DIR := $(TOPDIR)/make/data/tzdata -ZONENAME_TEMPLATE := $(TOPDIR)/src/java.base/share/classes/java/time/format/ZoneName.java.template +TZ_DATA_DIR := $(MODULE_SRC)/share/data/tzdata +ZONENAME_TEMPLATE := $(MODULE_SRC)/share/classes/java/time/format/ZoneName.java.template $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ $(wildcard $(CLDR_DATA_DIR)/main/en*.xml) \ @@ -74,12 +74,12 @@ TARGETS += $(CLDR_GEN_DONE) include GensrcProperties.gmk $(eval $(call SetupCompileProperties, LIST_RESOURCE_BUNDLE, \ - SRC_DIRS := $(TOPDIR)/src/java.base/share/classes/sun/launcher/resources, \ + SRC_DIRS := $(MODULE_SRC)/share/classes/sun/launcher/resources, \ CLASS := ListResourceBundle, \ )) $(eval $(call SetupCompileProperties, SUN_UTIL, \ - SRC_DIRS := $(TOPDIR)/src/java.base/share/classes/sun/util/resources, \ + SRC_DIRS := $(MODULE_SRC)/share/classes/sun/util/resources, \ CLASS := sun.util.resources.LocaleNamesBundle, \ )) @@ -98,7 +98,7 @@ TARGETS += $(COPY_ZH_HK) GENSRC_LSREQUIVMAPS := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/LocaleEquivalentMaps.java -$(GENSRC_LSREQUIVMAPS): $(TOPDIR)/make/data/lsrdata/language-subtag-registry.txt $(BUILD_TOOLS_JDK) +$(GENSRC_LSREQUIVMAPS): $(MODULE_SRC)/share/data/lsrdata/language-subtag-registry.txt $(BUILD_TOOLS_JDK) $(call MakeDir, $(@D)) $(TOOL_GENERATELSREQUIVMAPS) $< $@ $(COPYRIGHT_YEAR) diff --git a/make/modules/java.base/gendata/GendataBlockedCerts.gmk b/make/modules/java.base/gendata/GendataBlockedCerts.gmk index 65f75012a33..b6149b457cd 100644 --- a/make/modules/java.base/gendata/GendataBlockedCerts.gmk +++ b/make/modules/java.base/gendata/GendataBlockedCerts.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2022, 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 @@ # questions. # -GENDATA_BLOCKED_CERTS_SRC += $(TOPDIR)/make/data/blockedcertsconverter/blocked.certs.pem +GENDATA_BLOCKED_CERTS_SRC += $(MODULE_SRC)/share/data/blockedcertsconverter/blocked.certs.pem GENDATA_BLOCKED_CERTS := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/security/blocked.certs $(GENDATA_BLOCKED_CERTS): $(BUILD_TOOLS_JDK) $(GENDATA_BLOCKED_CERTS_SRC) diff --git a/make/modules/java.base/gendata/GendataBreakIterator.gmk b/make/modules/java.base/gendata/GendataBreakIterator.gmk index d314253b4fe..857ce2b7c34 100644 --- a/make/modules/java.base/gendata/GendataBreakIterator.gmk +++ b/make/modules/java.base/gendata/GendataBreakIterator.gmk @@ -1,5 +1,5 @@ -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -74,7 +74,7 @@ BREAK_ITERATOR_BOOTCLASSPATH := \ # Generate data resource files. # input -UNICODEDATA := $(TOPDIR)/make/data/unicodedata/UnicodeData.txt +UNICODEDATA := $(MODULE_SRC)/share/data/unicodedata/UnicodeData.txt # output BASE_DATA_PKG_DIR := $(JDK_OUTPUTDIR)/modules/java.base/sun/text/resources diff --git a/make/modules/java.base/gendata/GendataPublicSuffixList.gmk b/make/modules/java.base/gendata/GendataPublicSuffixList.gmk index 757098a619f..189fccf0c0d 100644 --- a/make/modules/java.base/gendata/GendataPublicSuffixList.gmk +++ b/make/modules/java.base/gendata/GendataPublicSuffixList.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2022, 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 @@ -25,7 +25,7 @@ include $(SPEC) -GENDATA_PUBLICSUFFIXLIST_SRC += $(TOPDIR)/make/data/publicsuffixlist/public_suffix_list.dat +GENDATA_PUBLICSUFFIXLIST_SRC += $(MODULE_SRC)/share/data/publicsuffixlist/public_suffix_list.dat GENDATA_PUBLICSUFFIXLIST := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE)/security/public_suffix_list.dat $(GENDATA_PUBLICSUFFIXLIST): $(GENDATA_PUBLICSUFFIXLIST_SRC) $(BUILD_TOOLS_JDK) diff --git a/make/modules/java.base/gendata/GendataTZDB.gmk b/make/modules/java.base/gendata/GendataTZDB.gmk index 1352178694f..593ed8a8f11 100644 --- a/make/modules/java.base/gendata/GendataTZDB.gmk +++ b/make/modules/java.base/gendata/GendataTZDB.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2022, 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 @@ -28,7 +28,7 @@ GENDATA_TZDB := # # Time zone data file creation # -TZDATA_DIR := $(TOPDIR)/make/data/tzdata +TZDATA_DIR := $(MODULE_SRC)/share/data/tzdata TZDATA_TZFILE := africa antarctica asia australasia europe northamerica southamerica backward etcetera gmt jdk11_backward TZDATA_TZFILES := $(addprefix $(TZDATA_DIR)/,$(TZDATA_TZFILE)) diff --git a/make/modules/java.base/gensrc/GensrcBuffer.gmk b/make/modules/java.base/gensrc/GensrcBuffer.gmk index 6ad432fb866..ce22230a8e1 100644 --- a/make/modules/java.base/gensrc/GensrcBuffer.gmk +++ b/make/modules/java.base/gensrc/GensrcBuffer.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -27,7 +27,7 @@ GENSRC_BUFFER := GENSRC_BUFFER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio -GENSRC_BUFFER_SRC := $(TOPDIR)/src/java.base/share/classes/java/nio +GENSRC_BUFFER_SRC := $(MODULE_SRC)/share/classes/java/nio ### diff --git a/make/modules/java.base/gensrc/GensrcCharacterData.gmk b/make/modules/java.base/gensrc/GensrcCharacterData.gmk index eb938016506..115a28309a2 100644 --- a/make/modules/java.base/gensrc/GensrcCharacterData.gmk +++ b/make/modules/java.base/gensrc/GensrcCharacterData.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -29,8 +29,8 @@ GENSRC_CHARACTERDATA := -CHARACTERDATA = $(TOPDIR)/make/data/characterdata -UNICODEDATA = $(TOPDIR)/make/data/unicodedata +CHARACTERDATA_TEMPLATES = $(MODULE_SRC)/share/classes/java/lang +UNICODEDATA = $(MODULE_SRC)/share/data/unicodedata ifneq ($(DEBUG_LEVEL), release) ifeq ($(ALLOW_ABSOLUTE_PATHS_IN_OUTPUT), true) @@ -40,11 +40,11 @@ endif define SetupCharacterData $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/$1.java: \ - $(CHARACTERDATA)/$1.java.template + $(CHARACTERDATA_TEMPLATES)/$1.java.template $$(call LogInfo, Generating $1.java) $$(call MakeDir, $$(@D)) $(TOOL_GENERATECHARACTER) $2 $(DEBUG_OPTION) \ - -template $(CHARACTERDATA)/$1.java.template \ + -template $(CHARACTERDATA_TEMPLATES)/$1.java.template \ -spec $(UNICODEDATA)/UnicodeData.txt \ -specialcasing $(UNICODEDATA)/SpecialCasing.txt \ -proplist $(UNICODEDATA)/PropList.txt \ diff --git a/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk b/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk index 79fa54b19cc..2940ba42319 100644 --- a/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk +++ b/make/modules/java.base/gensrc/GensrcCharsetCoder.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -27,7 +27,7 @@ GENSRC_CHARSETCODER := GENSRC_CHARSETCODER_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio/charset -GENSRC_CHARSETCODER_SRC := $(TOPDIR)/src/java.base/share/classes/java/nio +GENSRC_CHARSETCODER_SRC := $(MODULE_SRC)/share/classes/java/nio GENSRC_CHARSETCODER_TEMPLATE := $(GENSRC_CHARSETCODER_SRC)/charset/Charset-X-Coder.java.template diff --git a/make/modules/java.base/gensrc/GensrcEmojiData.gmk b/make/modules/java.base/gensrc/GensrcEmojiData.gmk index d92cb9354a3..1af03bcafe9 100644 --- a/make/modules/java.base/gensrc/GensrcEmojiData.gmk +++ b/make/modules/java.base/gensrc/GensrcEmojiData.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2019, 2022, 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 @@ -29,8 +29,8 @@ GENSRC_EMOJIDATA := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/util/regex/EmojiData.java -EMOJIDATATEMP = $(TOPDIR)/src/java.base/share/classes/java/util/regex/EmojiData.java.template -UNICODEDATA = $(TOPDIR)/make/data/unicodedata +EMOJIDATATEMP = $(MODULE_SRC)/share/classes/java/util/regex/EmojiData.java.template +UNICODEDATA = $(MODULE_SRC)/share/data/unicodedata $(GENSRC_EMOJIDATA): $(BUILD_TOOLS_JDK) $(EMOJIDATATEMP) $(UNICODEDATA)/emoji/emoji-data.txt $(call LogInfo, Generating $@) diff --git a/make/modules/java.base/gensrc/GensrcExceptions.gmk b/make/modules/java.base/gensrc/GensrcExceptions.gmk index 37fed896560..1c4974b4a28 100644 --- a/make/modules/java.base/gensrc/GensrcExceptions.gmk +++ b/make/modules/java.base/gensrc/GensrcExceptions.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -27,7 +27,7 @@ GENSRC_EXCEPTIONS := GENSRC_EXCEPTIONS_DST := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/nio -GENSRC_EXCEPTIONS_SRC := $(TOPDIR)/src/java.base/share/classes/java/nio +GENSRC_EXCEPTIONS_SRC := $(MODULE_SRC)/share/classes/java/nio GENSRC_EXCEPTIONS_CMD := $(TOPDIR)/make/scripts/genExceptions.sh GENSRC_EXCEPTIONS_SRC_DIRS := . charset channels diff --git a/make/modules/java.base/gensrc/GensrcLocaleData.gmk b/make/modules/java.base/gensrc/GensrcLocaleData.gmk index 1e28d91ab68..c04bab53175 100644 --- a/make/modules/java.base/gensrc/GensrcLocaleData.gmk +++ b/make/modules/java.base/gensrc/GensrcLocaleData.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -29,8 +29,8 @@ # First go look for all locale files LOCALE_FILES := $(call FindFiles, \ - $(TOPDIR)/src/$(MODULE)/share/classes/sun/text/resources \ - $(TOPDIR)/src/$(MODULE)/share/classes/sun/util/resources, \ + $(MODULE_SRC)/share/classes/sun/text/resources \ + $(MODULE_SRC)/share/classes/sun/util/resources, \ FormatData_*.java FormatData_*.properties \ CollationData_*.java CollationData_*.properties \ TimeZoneNames_*.java TimeZoneNames_*.properties \ diff --git a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk index b431acc14e1..54fea77571e 100644 --- a/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk +++ b/make/modules/java.base/gensrc/GensrcScopedMemoryAccess.gmk @@ -24,7 +24,7 @@ # SCOPED_MEMORY_ACCESS_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/jdk/internal/misc -SCOPED_MEMORY_ACCESS_SRC_DIR := $(TOPDIR)/src/java.base/share/classes/jdk/internal/misc +SCOPED_MEMORY_ACCESS_SRC_DIR := $(MODULE_SRC)/share/classes/jdk/internal/misc SCOPED_MEMORY_ACCESS_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess.java.template SCOPED_MEMORY_ACCESS_BIN_TEMPLATE := $(SCOPED_MEMORY_ACCESS_SRC_DIR)/X-ScopedMemoryAccess-bin.java.template SCOPED_MEMORY_ACCESS_DEST := $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)/ScopedMemoryAccess.java @@ -139,7 +139,7 @@ endef SCOPE_MEMORY_ACCESS_TYPES := Byte Short Char Int Long Float Double $(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ $(eval $(call GenerateScopedOp,BIN_$t,$t))) - + $(SCOPED_MEMORY_ACCESS_DEST): $(BUILD_TOOLS_JDK) $(SCOPED_MEMORY_ACCESS_TEMPLATE) $(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) $(call MakeDir, $(SCOPED_MEMORY_ACCESS_GENSRC_DIR)) $(CAT) $(SCOPED_MEMORY_ACCESS_TEMPLATE) > $(SCOPED_MEMORY_ACCESS_DEST) @@ -147,5 +147,5 @@ $(SCOPED_MEMORY_ACCESS_DEST): $(BUILD_TOOLS_JDK) $(SCOPED_MEMORY_ACCESS_TEMPLATE $(TOOL_SPP) -nel -K$(BIN_$t_type) -Dtype=$(BIN_$t_type) -DType=$(BIN_$t_Type) $(BIN_$t_ARGS) \ -i$(SCOPED_MEMORY_ACCESS_BIN_TEMPLATE) -o$(SCOPED_MEMORY_ACCESS_DEST) ;) $(PRINTF) "}\n" >> $(SCOPED_MEMORY_ACCESS_DEST) - + TARGETS += $(SCOPED_MEMORY_ACCESS_DEST) diff --git a/make/modules/java.base/gensrc/GensrcVarHandles.gmk b/make/modules/java.base/gensrc/GensrcVarHandles.gmk index 579488379c3..e1686834bf5 100644 --- a/make/modules/java.base/gensrc/GensrcVarHandles.gmk +++ b/make/modules/java.base/gensrc/GensrcVarHandles.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2022, 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 @@ -26,7 +26,7 @@ GENSRC_VARHANDLES := VARHANDLES_GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/java/lang/invoke -VARHANDLES_SRC_DIR := $(TOPDIR)/src/java.base/share/classes/java/lang/invoke +VARHANDLES_SRC_DIR := $(MODULE_SRC)/share/classes/java/lang/invoke ################################################################################ # Setup a rule for generating a VarHandle java class diff --git a/make/modules/java.desktop/gendata/GendataFontConfig.gmk b/make/modules/java.desktop/gendata/GendataFontConfig.gmk index 42e3f4b485f..92a64b986e1 100644 --- a/make/modules/java.desktop/gendata/GendataFontConfig.gmk +++ b/make/modules/java.desktop/gendata/GendataFontConfig.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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,30 +23,35 @@ # questions. # -GENDATA_FONT_CONFIG_DST := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE) +FONTCONFIG_DATA_DIR := $(MODULE_SRC)/$(OPENJDK_TARGET_OS)/data/fontconfig +FONTCONFIG_SRC_FILE := $(FONTCONFIG_DATA_DIR)/fontconfig.properties -GENDATA_FONT_CONFIG_DATA_DIR ?= $(TOPDIR)/make/data/fontconfig +FONTCONFIG_DEST_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE) +FONTCONFIG_OUT_FILE := $(FONTCONFIG_DEST_DIR)/fontconfig.properties.src +FONTCONFIG_OUT_BIN_FILE := $(FONTCONFIG_DEST_DIR)/fontconfig.bfc -GENDATA_FONT_CONFIG_SRC_FILES := \ - $(wildcard $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).*) +ifneq ($(findstring $(LOG_LEVEL), debug trace), ) + FONTCONFIG_VERBOSE_FLAG := -verbose +endif +# Not all OSes have a fontconfig file +ifneq ($(wildcard $(FONTCONFIG_SRC_FILE)), ) -$(GENDATA_FONT_CONFIG_DST)/%.src: \ - $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).% + # Copy properties file as-is + $(FONTCONFIG_OUT_FILE): $(FONTCONFIG_SRC_FILE) + $(call LogInfo, Copying fontconfig.properties) $(call install-file) -$(GENDATA_FONT_CONFIG_DST)/%.bfc: \ - $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).%.properties \ - $(BUILD_TOOLS_JDK) + TARGETS += $(FONTCONFIG_OUT_FILE) + + # Generate binary representation + $(FONTCONFIG_OUT_BIN_FILE): $(FONTCONFIG_SRC_FILE) $(BUILD_TOOLS_JDK) + $(call LogInfo, Compiling fontconfig.properties to binary) $(call MakeTargetDir) $(RM) $@ - $(TOOL_COMPILEFONTCONFIG) $< $@ + $(TOOL_COMPILEFONTCONFIG) $(FONTCONFIG_VERBOSE_FLAG) $< $@ $(CHMOD) 444 $@ + TARGETS += $(FONTCONFIG_OUT_BIN_FILE) -GENDATA_FONT_CONFIGS := $(patsubst $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).%, \ - $(GENDATA_FONT_CONFIG_DST)/%.src, $(GENDATA_FONT_CONFIG_SRC_FILES)) -GENDATA_BFONT_CONFIGS := $(patsubst $(GENDATA_FONT_CONFIG_DATA_DIR)/$(OPENJDK_TARGET_OS).%.properties, \ - $(GENDATA_FONT_CONFIG_DST)/%.bfc, $(GENDATA_FONT_CONFIG_SRC_FILES)) - -TARGETS := $(GENDATA_FONT_CONFIGS) $(GENDATA_BFONT_CONFIGS) +endif diff --git a/make/modules/java.desktop/gensrc/GensrcIcons.gmk b/make/modules/java.desktop/gensrc/GensrcIcons.gmk index e0a6c107ecc..28434d3f4c1 100644 --- a/make/modules/java.desktop/gensrc/GensrcIcons.gmk +++ b/make/modules/java.desktop/gensrc/GensrcIcons.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -29,7 +29,7 @@ GENSRC_AWT_ICONS_TMP := $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop GENSRC_AWT_ICONS_DST := $(GENSRC_AWT_ICONS_TMP)/sun/awt/ # Allow this to be overridden from a custom makefile -X11_ICONS_PATH_PREFIX ?= $(TOPDIR)/src/java.desktop/$(OPENJDK_TARGET_OS_TYPE) +X11_ICONS_PATH_PREFIX ?= $(MODULE_SRC)/$(OPENJDK_TARGET_OS_TYPE) GENSRC_AWT_ICONS_SRC += \ $(X11_ICONS_PATH_PREFIX)/classes/sun/awt/X11/java-icon16.png \ @@ -38,7 +38,7 @@ GENSRC_AWT_ICONS_SRC += \ $(X11_ICONS_PATH_PREFIX)/classes/sun/awt/X11/java-icon48.png -AWT_ICONPATH := $(TOPDIR)/src/java.desktop/share/classes/sun/awt/resources +AWT_ICONPATH := $(MODULE_SRC)/share/classes/sun/awt/resources GENSRC_AWT_ICONS_SRC += \ $(AWT_ICONPATH)/security-icon-bw16.png \ @@ -111,7 +111,7 @@ ifeq ($(call isTargetOs, macosx), true) GENSRC_OSX_ICONS_DST := $(SUPPORT_OUTPUTDIR)/headers/java.desktop GENSRC_OSX_ICONS := $(GENSRC_OSX_ICONS_DST)/AWTIconData.h - GENSRC_OSX_ICONS_SRC ?= $(TOPDIR)/make/data/macosxicons/JavaApp.icns + GENSRC_OSX_ICONS_SRC ?= $(MODULE_SRC)/macosx/data/macosxicons/JavaApp.icns $(GENSRC_OSX_ICONS): $(GENSRC_OSX_ICONS_SRC) $(BUILD_TOOLS_JDK) diff --git a/make/modules/java.desktop/gensrc/GensrcSwing.gmk b/make/modules/java.desktop/gensrc/GensrcSwing.gmk index cfb50831d1b..abd428f3641 100644 --- a/make/modules/java.desktop/gensrc/GensrcSwing.gmk +++ b/make/modules/java.desktop/gensrc/GensrcSwing.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -28,7 +28,7 @@ # NIMBUS_PACKAGE = javax.swing.plaf NIMBUS_GENSRC_DIR = $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/javax/swing/plaf/nimbus -NIMBUS_SKIN_FILE = $(TOPDIR)/src/java.desktop/share/classes/javax/swing/plaf/nimbus/skin.laf +NIMBUS_SKIN_FILE = $(MODULE_SRC)/share/classes/javax/swing/plaf/nimbus/skin.laf $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/_the.generated_nimbus: $(NIMBUS_SKIN_FILE) $(BUILD_TOOLS_JDK) $(call LogInfo, Generating Nimbus source files) diff --git a/make/modules/java.desktop/gensrc/GensrcX11Wrappers.gmk b/make/modules/java.desktop/gensrc/GensrcX11Wrappers.gmk index d46328f8607..25402ad035a 100644 --- a/make/modules/java.desktop/gensrc/GensrcX11Wrappers.gmk +++ b/make/modules/java.desktop/gensrc/GensrcX11Wrappers.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2022, 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 @@ -24,13 +24,13 @@ # # Generate java sources using the X11 offsets that are precalculated in files -# make/data/x11wrappergen/sizes-
    .txt. +# src/java.desktop/unix/data/x11wrappergen/sizes-
    .txt. # Put the generated Java classes used to interface X11 from awt here. GENSRC_X11WRAPPERS_OUTPUTDIR := $(SUPPORT_OUTPUTDIR)/gensrc/java.desktop/sun/awt/X11 # The pre-calculated offset file are stored here: -GENSRC_X11WRAPPERS_DATADIR := $(TOPDIR)/make/data/x11wrappergen +GENSRC_X11WRAPPERS_DATADIR := $(MODULE_SRC)/unix/data/x11wrappergen GENSRC_X11WRAPPERS_DATA := $(GENSRC_X11WRAPPERS_DATADIR)/sizes-$(OPENJDK_TARGET_CPU_BITS).txt # Run the tool on the offset files to generate several Java classes used in awt. diff --git a/make/modules/jdk.charsets/Gensrc.gmk b/make/modules/jdk.charsets/Gensrc.gmk index ca9c1940941..1fac37b2c4b 100644 --- a/make/modules/jdk.charsets/Gensrc.gmk +++ b/make/modules/jdk.charsets/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -38,8 +38,8 @@ CHARSET_TEMPLATES := \ $(CHARSET_DATA_DIR)/SingleByte-X.java.template \ $(CHARSET_DATA_DIR)/DoubleByte-X.java.template CHARSET_EXTENDED_JAVA_TEMPLATES := \ - $(TOPDIR)/src/jdk.charsets/share/classes/sun/nio/cs/ext/ExtendedCharsets.java.template -CHARSET_EXTENDED_JAVA_DIR := $(TOPDIR)/src/jdk.charsets/share/classes/sun/nio/cs/ext + $(MODULE_SRC)/share/classes/sun/nio/cs/ext/ExtendedCharsets.java.template +CHARSET_EXTENDED_JAVA_DIR := $(MODULE_SRC)/share/classes/sun/nio/cs/ext CHARSET_STANDARD_OS := stdcs-$(OPENJDK_TARGET_OS) $(CHARSET_DONE_CS)-extcs: $(CHARSET_DATA_DIR)/charsets \ diff --git a/make/modules/jdk.compiler/Gendata.gmk b/make/modules/jdk.compiler/Gendata.gmk index 85815e5524b..5471fa1127c 100644 --- a/make/modules/jdk.compiler/Gendata.gmk +++ b/make/modules/jdk.compiler/Gendata.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2022, 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 @@ -41,7 +41,7 @@ CT_MODULES := $(DOCS_MODULES) # Get the complete module source path: CT_MODULESOURCEPATH := $(call GetModuleSrcPath) -CT_DATA_DESCRIPTION += $(TOPDIR)/make/data/symbols/symbols +CT_DATA_DESCRIPTION += $(MODULE_SRC)/share/data/symbols/symbols COMPILECREATESYMBOLS_ADD_EXPORTS := \ --add-exports java.base/jdk.internal.javac=java.compiler.interim,jdk.compiler.interim \ @@ -65,7 +65,7 @@ $(eval $(call SetupJavaCompilation, COMPILE_CREATE_SYMBOLS, \ $(SUPPORT_OUTPUTDIR)/symbols/ct.sym: \ $(COMPILE_CREATE_SYMBOLS) \ - $(wildcard $(TOPDIR)/make/data/symbols/*) \ + $(wildcard $(MODULE_SRC)/share/data/symbols/*) \ $(MODULE_INFOS) $(RM) -r $(@D) $(MKDIR) -p $(@D) diff --git a/make/modules/jdk.javadoc/Gendata.gmk b/make/modules/jdk.javadoc/Gendata.gmk index 50ef87545a4..69c93c29468 100644 --- a/make/modules/jdk.javadoc/Gendata.gmk +++ b/make/modules/jdk.javadoc/Gendata.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2022, 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 @@ -39,7 +39,7 @@ JAVADOC_MODULES := $(DOCS_MODULES) # Get the complete module source path: JAVADOC_MODULESOURCEPATH := $(call GetModuleSrcPath) -CT_DATA_DESCRIPTION += $(TOPDIR)/make/data/symbols/symbols +CT_DATA_DESCRIPTION += $(TOPDIR)/src/jdk.compiler/share/data/symbols/symbols COMPILECREATESYMBOLS_ADD_EXPORTS := \ --add-exports java.base/jdk.internal=java.compiler.interim,jdk.compiler.interim \ @@ -68,7 +68,7 @@ ELEMENT_LISTS_DIR := $(JDK_JAVADOC_DIR)/$(ELEMENT_LISTS_PKG) $(JDK_JAVADOC_DIR)/_element_lists.marker: \ $(COMPILE_CREATE_SYMBOLS) \ - $(wildcard $(TOPDIR)/make/data/symbols/*) \ + $(wildcard $(TOPDIR)/src/jdk.compiler/share/data/symbols/*) \ $(MODULE_INFOS) $(call MakeTargetDir) $(call LogInfo, Creating javadoc element lists) diff --git a/make/modules/jdk.jdi/Gensrc.gmk b/make/modules/jdk.jdi/Gensrc.gmk index 5487e950921..7db06b5c958 100644 --- a/make/modules/jdk.jdi/Gensrc.gmk +++ b/make/modules/jdk.jdi/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -26,10 +26,11 @@ include GensrcCommonJdk.gmk ################################################################################ -# Translate the Java debugger wire protocol (jdwp.spec) file into a JDWP.java file -# and a JDWPCommands.h C-header file. +# Translate the Java debugger wire protocol (jdwp.spec) file into a front-end +# Java implementation (JDWP.java), a back-end C header file (JDWPCommands.h) and +# an HTML documentation file (jdwp-protocol.html). -JDWP_SPEC_FILE := $(TOPDIR)/make/data/jdwp/jdwp.spec +JDWP_SPEC_FILE := $(TOPDIR)/src/java.se/share/data/jdwp/jdwp.spec HEADER_FILE := $(SUPPORT_OUTPUTDIR)/headers/jdk.jdwp.agent/JDWPCommands.h JAVA_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/com/sun/tools/jdi/JDWP.java HTML_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/jdwp-protocol.html diff --git a/make/modules/jdk.localedata/Gensrc.gmk b/make/modules/jdk.localedata/Gensrc.gmk index 09f014e8607..233572c8a54 100644 --- a/make/modules/jdk.localedata/Gensrc.gmk +++ b/make/modules/jdk.localedata/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2022, 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 @@ -57,7 +57,7 @@ TARGETS += $(CLDR_GEN_DONE) include GensrcProperties.gmk $(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \ - SRC_DIRS := $(TOPDIR)/src/jdk.localedata/share/classes/sun/util/resources, \ + SRC_DIRS := $(MODULE_SRC)/share/classes/sun/util/resources, \ CLASS := sun.util.resources.LocaleNamesBundle, \ KEEP_ALL_TRANSLATIONS := true, \ )) diff --git a/make/scripts/generate-symbol-data.sh b/make/scripts/generate-symbol-data.sh index 56aa8016dd6..ee1d540715f 100644 --- a/make/scripts/generate-symbol-data.sh +++ b/make/scripts/generate-symbol-data.sh @@ -34,19 +34,19 @@ # - have a checkout the JDK to which the data should be added (or in which the data should be updated). # The checkout directory will be denoted as "${JDK_CHECKOUT}" in the further text. # The checkout must not have any local changes that could interfere with the new data. In particular, -# there must be absolutely no changed, new or removed files under the ${JDK_CHECKOUT}/make/data/symbols +# there must be absolutely no changed, new or removed files under the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols # directory. # - open a terminal program and run these commands: -# cd "${JDK_CHECKOUT}"/make/data/symbols +# cd "${JDK_CHECKOUT}"/src/jdk.compiler/share/data/symbols # bash ../../scripts/generate-symbol-data.sh "${JDK_N_INSTALL}" -# - this command will generate or update data for "--release N" into the ${JDK_CHECKOUT}/make/data/symbols +# - this command will generate or update data for "--release N" into the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols # directory, updating all registration necessary. If the goal was to update the data, and there are no -# new or changed files in the ${JDK_CHECKOUT}/make/data/symbols directory after running this script, +# new or changed files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory after running this script, # there were no relevant changes and no further action is necessary. Note that version for N > 9 are encoded # using capital letters, i.e. A represents version 10, B represents 11, and so on. The version numbers are in -# the names of the files in the ${JDK_CHECKOUT}/make/data/symbols directory, as well as in -# the ${JDK_CHECKOUT}/make/data/symbols/symbols file. -# - if there are any changed/new files in the ${JDK_CHECKOUT}/make/data/symbols directory after running this script, +# the names of the files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory, as well as in +# the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols/symbols file. +# - if there are any changed/new files in the ${JDK_CHECKOUT}/src/jdk.compiler/share/data/symbols directory after running this script, # then all the changes in this directory, including any new files, need to be sent for review and eventually pushed. # The commit message should specify which binary build was installed in the ${JDK_N_INSTALL} directory and also # include the SCM state that was used to build it, which can be found in ${JDK_N_INSTALL}/release, @@ -59,12 +59,12 @@ if [ "$1x" = "x" ] ; then fi; if [ ! -f symbols ] ; then - echo "Must run inside the make/data/symbols directory" >&2 + echo "Must run inside the src/jdk.compiler/share/data/symbols directory" >&2 exit 1 fi; if [ "`git status --porcelain=v1 .`x" != "x" ] ; then - echo "The make/data/symbols directory contains local changes!" >&2 + echo "The src/jdk.compiler/share/data/symbols directory contains local changes!" >&2 exit 1 fi; diff --git a/make/data/characterdata/CharacterData00.java.template b/src/java.base/share/classes/java/lang/CharacterData00.java.template similarity index 100% rename from make/data/characterdata/CharacterData00.java.template rename to src/java.base/share/classes/java/lang/CharacterData00.java.template diff --git a/make/data/characterdata/CharacterData01.java.template b/src/java.base/share/classes/java/lang/CharacterData01.java.template similarity index 100% rename from make/data/characterdata/CharacterData01.java.template rename to src/java.base/share/classes/java/lang/CharacterData01.java.template diff --git a/make/data/characterdata/CharacterData02.java.template b/src/java.base/share/classes/java/lang/CharacterData02.java.template similarity index 100% rename from make/data/characterdata/CharacterData02.java.template rename to src/java.base/share/classes/java/lang/CharacterData02.java.template diff --git a/make/data/characterdata/CharacterData03.java.template b/src/java.base/share/classes/java/lang/CharacterData03.java.template similarity index 100% rename from make/data/characterdata/CharacterData03.java.template rename to src/java.base/share/classes/java/lang/CharacterData03.java.template diff --git a/make/data/characterdata/CharacterData0E.java.template b/src/java.base/share/classes/java/lang/CharacterData0E.java.template similarity index 100% rename from make/data/characterdata/CharacterData0E.java.template rename to src/java.base/share/classes/java/lang/CharacterData0E.java.template diff --git a/make/data/characterdata/CharacterDataLatin1.java.template b/src/java.base/share/classes/java/lang/CharacterDataLatin1.java.template similarity index 100% rename from make/data/characterdata/CharacterDataLatin1.java.template rename to src/java.base/share/classes/java/lang/CharacterDataLatin1.java.template diff --git a/make/data/blockedcertsconverter/blocked.certs.pem b/src/java.base/share/data/blockedcertsconverter/blocked.certs.pem similarity index 100% rename from make/data/blockedcertsconverter/blocked.certs.pem rename to src/java.base/share/data/blockedcertsconverter/blocked.certs.pem diff --git a/make/data/cacerts/README b/src/java.base/share/data/cacerts/README similarity index 100% rename from make/data/cacerts/README rename to src/java.base/share/data/cacerts/README diff --git a/make/data/cacerts/actalisauthenticationrootca b/src/java.base/share/data/cacerts/actalisauthenticationrootca similarity index 100% rename from make/data/cacerts/actalisauthenticationrootca rename to src/java.base/share/data/cacerts/actalisauthenticationrootca diff --git a/make/data/cacerts/addtrustexternalca b/src/java.base/share/data/cacerts/addtrustexternalca similarity index 100% rename from make/data/cacerts/addtrustexternalca rename to src/java.base/share/data/cacerts/addtrustexternalca diff --git a/make/data/cacerts/addtrustqualifiedca b/src/java.base/share/data/cacerts/addtrustqualifiedca similarity index 100% rename from make/data/cacerts/addtrustqualifiedca rename to src/java.base/share/data/cacerts/addtrustqualifiedca diff --git a/make/data/cacerts/affirmtrustcommercialca b/src/java.base/share/data/cacerts/affirmtrustcommercialca similarity index 100% rename from make/data/cacerts/affirmtrustcommercialca rename to src/java.base/share/data/cacerts/affirmtrustcommercialca diff --git a/make/data/cacerts/affirmtrustnetworkingca b/src/java.base/share/data/cacerts/affirmtrustnetworkingca similarity index 100% rename from make/data/cacerts/affirmtrustnetworkingca rename to src/java.base/share/data/cacerts/affirmtrustnetworkingca diff --git a/make/data/cacerts/affirmtrustpremiumca b/src/java.base/share/data/cacerts/affirmtrustpremiumca similarity index 100% rename from make/data/cacerts/affirmtrustpremiumca rename to src/java.base/share/data/cacerts/affirmtrustpremiumca diff --git a/make/data/cacerts/affirmtrustpremiumeccca b/src/java.base/share/data/cacerts/affirmtrustpremiumeccca similarity index 100% rename from make/data/cacerts/affirmtrustpremiumeccca rename to src/java.base/share/data/cacerts/affirmtrustpremiumeccca diff --git a/make/data/cacerts/amazonrootca1 b/src/java.base/share/data/cacerts/amazonrootca1 similarity index 100% rename from make/data/cacerts/amazonrootca1 rename to src/java.base/share/data/cacerts/amazonrootca1 diff --git a/make/data/cacerts/amazonrootca2 b/src/java.base/share/data/cacerts/amazonrootca2 similarity index 100% rename from make/data/cacerts/amazonrootca2 rename to src/java.base/share/data/cacerts/amazonrootca2 diff --git a/make/data/cacerts/amazonrootca3 b/src/java.base/share/data/cacerts/amazonrootca3 similarity index 100% rename from make/data/cacerts/amazonrootca3 rename to src/java.base/share/data/cacerts/amazonrootca3 diff --git a/make/data/cacerts/amazonrootca4 b/src/java.base/share/data/cacerts/amazonrootca4 similarity index 100% rename from make/data/cacerts/amazonrootca4 rename to src/java.base/share/data/cacerts/amazonrootca4 diff --git a/make/data/cacerts/baltimorecybertrustca b/src/java.base/share/data/cacerts/baltimorecybertrustca similarity index 100% rename from make/data/cacerts/baltimorecybertrustca rename to src/java.base/share/data/cacerts/baltimorecybertrustca diff --git a/make/data/cacerts/buypassclass2ca b/src/java.base/share/data/cacerts/buypassclass2ca similarity index 100% rename from make/data/cacerts/buypassclass2ca rename to src/java.base/share/data/cacerts/buypassclass2ca diff --git a/make/data/cacerts/buypassclass3ca b/src/java.base/share/data/cacerts/buypassclass3ca similarity index 100% rename from make/data/cacerts/buypassclass3ca rename to src/java.base/share/data/cacerts/buypassclass3ca diff --git a/make/data/cacerts/camerfirmachambersca b/src/java.base/share/data/cacerts/camerfirmachambersca similarity index 100% rename from make/data/cacerts/camerfirmachambersca rename to src/java.base/share/data/cacerts/camerfirmachambersca diff --git a/make/data/cacerts/camerfirmachamberscommerceca b/src/java.base/share/data/cacerts/camerfirmachamberscommerceca similarity index 100% rename from make/data/cacerts/camerfirmachamberscommerceca rename to src/java.base/share/data/cacerts/camerfirmachamberscommerceca diff --git a/make/data/cacerts/camerfirmachambersignca b/src/java.base/share/data/cacerts/camerfirmachambersignca similarity index 100% rename from make/data/cacerts/camerfirmachambersignca rename to src/java.base/share/data/cacerts/camerfirmachambersignca diff --git a/make/data/cacerts/certumca b/src/java.base/share/data/cacerts/certumca similarity index 100% rename from make/data/cacerts/certumca rename to src/java.base/share/data/cacerts/certumca diff --git a/make/data/cacerts/certumtrustednetworkca b/src/java.base/share/data/cacerts/certumtrustednetworkca similarity index 100% rename from make/data/cacerts/certumtrustednetworkca rename to src/java.base/share/data/cacerts/certumtrustednetworkca diff --git a/make/data/cacerts/chunghwaepkirootca b/src/java.base/share/data/cacerts/chunghwaepkirootca similarity index 100% rename from make/data/cacerts/chunghwaepkirootca rename to src/java.base/share/data/cacerts/chunghwaepkirootca diff --git a/make/data/cacerts/comodoaaaca b/src/java.base/share/data/cacerts/comodoaaaca similarity index 100% rename from make/data/cacerts/comodoaaaca rename to src/java.base/share/data/cacerts/comodoaaaca diff --git a/make/data/cacerts/comodoeccca b/src/java.base/share/data/cacerts/comodoeccca similarity index 100% rename from make/data/cacerts/comodoeccca rename to src/java.base/share/data/cacerts/comodoeccca diff --git a/make/data/cacerts/comodorsaca b/src/java.base/share/data/cacerts/comodorsaca similarity index 100% rename from make/data/cacerts/comodorsaca rename to src/java.base/share/data/cacerts/comodorsaca diff --git a/make/data/cacerts/digicertassuredidg2 b/src/java.base/share/data/cacerts/digicertassuredidg2 similarity index 100% rename from make/data/cacerts/digicertassuredidg2 rename to src/java.base/share/data/cacerts/digicertassuredidg2 diff --git a/make/data/cacerts/digicertassuredidg3 b/src/java.base/share/data/cacerts/digicertassuredidg3 similarity index 100% rename from make/data/cacerts/digicertassuredidg3 rename to src/java.base/share/data/cacerts/digicertassuredidg3 diff --git a/make/data/cacerts/digicertassuredidrootca b/src/java.base/share/data/cacerts/digicertassuredidrootca similarity index 100% rename from make/data/cacerts/digicertassuredidrootca rename to src/java.base/share/data/cacerts/digicertassuredidrootca diff --git a/make/data/cacerts/digicertglobalrootca b/src/java.base/share/data/cacerts/digicertglobalrootca similarity index 100% rename from make/data/cacerts/digicertglobalrootca rename to src/java.base/share/data/cacerts/digicertglobalrootca diff --git a/make/data/cacerts/digicertglobalrootg2 b/src/java.base/share/data/cacerts/digicertglobalrootg2 similarity index 100% rename from make/data/cacerts/digicertglobalrootg2 rename to src/java.base/share/data/cacerts/digicertglobalrootg2 diff --git a/make/data/cacerts/digicertglobalrootg3 b/src/java.base/share/data/cacerts/digicertglobalrootg3 similarity index 100% rename from make/data/cacerts/digicertglobalrootg3 rename to src/java.base/share/data/cacerts/digicertglobalrootg3 diff --git a/make/data/cacerts/digicerthighassuranceevrootca b/src/java.base/share/data/cacerts/digicerthighassuranceevrootca similarity index 100% rename from make/data/cacerts/digicerthighassuranceevrootca rename to src/java.base/share/data/cacerts/digicerthighassuranceevrootca diff --git a/make/data/cacerts/digicerttrustedrootg4 b/src/java.base/share/data/cacerts/digicerttrustedrootg4 similarity index 100% rename from make/data/cacerts/digicerttrustedrootg4 rename to src/java.base/share/data/cacerts/digicerttrustedrootg4 diff --git a/make/data/cacerts/dtrustclass3ca2 b/src/java.base/share/data/cacerts/dtrustclass3ca2 similarity index 100% rename from make/data/cacerts/dtrustclass3ca2 rename to src/java.base/share/data/cacerts/dtrustclass3ca2 diff --git a/make/data/cacerts/dtrustclass3ca2ev b/src/java.base/share/data/cacerts/dtrustclass3ca2ev similarity index 100% rename from make/data/cacerts/dtrustclass3ca2ev rename to src/java.base/share/data/cacerts/dtrustclass3ca2ev diff --git a/make/data/cacerts/entrust2048ca b/src/java.base/share/data/cacerts/entrust2048ca similarity index 100% rename from make/data/cacerts/entrust2048ca rename to src/java.base/share/data/cacerts/entrust2048ca diff --git a/make/data/cacerts/entrustevca b/src/java.base/share/data/cacerts/entrustevca similarity index 100% rename from make/data/cacerts/entrustevca rename to src/java.base/share/data/cacerts/entrustevca diff --git a/make/data/cacerts/entrustrootcaec1 b/src/java.base/share/data/cacerts/entrustrootcaec1 similarity index 100% rename from make/data/cacerts/entrustrootcaec1 rename to src/java.base/share/data/cacerts/entrustrootcaec1 diff --git a/make/data/cacerts/entrustrootcag2 b/src/java.base/share/data/cacerts/entrustrootcag2 similarity index 100% rename from make/data/cacerts/entrustrootcag2 rename to src/java.base/share/data/cacerts/entrustrootcag2 diff --git a/make/data/cacerts/entrustrootcag4 b/src/java.base/share/data/cacerts/entrustrootcag4 similarity index 100% rename from make/data/cacerts/entrustrootcag4 rename to src/java.base/share/data/cacerts/entrustrootcag4 diff --git a/make/data/cacerts/geotrustglobalca b/src/java.base/share/data/cacerts/geotrustglobalca similarity index 100% rename from make/data/cacerts/geotrustglobalca rename to src/java.base/share/data/cacerts/geotrustglobalca diff --git a/make/data/cacerts/geotrustprimaryca b/src/java.base/share/data/cacerts/geotrustprimaryca similarity index 100% rename from make/data/cacerts/geotrustprimaryca rename to src/java.base/share/data/cacerts/geotrustprimaryca diff --git a/make/data/cacerts/geotrustprimarycag2 b/src/java.base/share/data/cacerts/geotrustprimarycag2 similarity index 100% rename from make/data/cacerts/geotrustprimarycag2 rename to src/java.base/share/data/cacerts/geotrustprimarycag2 diff --git a/make/data/cacerts/geotrustprimarycag3 b/src/java.base/share/data/cacerts/geotrustprimarycag3 similarity index 100% rename from make/data/cacerts/geotrustprimarycag3 rename to src/java.base/share/data/cacerts/geotrustprimarycag3 diff --git a/make/data/cacerts/geotrustuniversalca b/src/java.base/share/data/cacerts/geotrustuniversalca similarity index 100% rename from make/data/cacerts/geotrustuniversalca rename to src/java.base/share/data/cacerts/geotrustuniversalca diff --git a/make/data/cacerts/globalsignca b/src/java.base/share/data/cacerts/globalsignca similarity index 100% rename from make/data/cacerts/globalsignca rename to src/java.base/share/data/cacerts/globalsignca diff --git a/make/data/cacerts/globalsigneccrootcar4 b/src/java.base/share/data/cacerts/globalsigneccrootcar4 similarity index 100% rename from make/data/cacerts/globalsigneccrootcar4 rename to src/java.base/share/data/cacerts/globalsigneccrootcar4 diff --git a/make/data/cacerts/globalsigneccrootcar5 b/src/java.base/share/data/cacerts/globalsigneccrootcar5 similarity index 100% rename from make/data/cacerts/globalsigneccrootcar5 rename to src/java.base/share/data/cacerts/globalsigneccrootcar5 diff --git a/make/data/cacerts/globalsignr3ca b/src/java.base/share/data/cacerts/globalsignr3ca similarity index 100% rename from make/data/cacerts/globalsignr3ca rename to src/java.base/share/data/cacerts/globalsignr3ca diff --git a/make/data/cacerts/globalsignrootcar6 b/src/java.base/share/data/cacerts/globalsignrootcar6 similarity index 100% rename from make/data/cacerts/globalsignrootcar6 rename to src/java.base/share/data/cacerts/globalsignrootcar6 diff --git a/make/data/cacerts/godaddyclass2ca b/src/java.base/share/data/cacerts/godaddyclass2ca similarity index 100% rename from make/data/cacerts/godaddyclass2ca rename to src/java.base/share/data/cacerts/godaddyclass2ca diff --git a/make/data/cacerts/godaddyrootg2ca b/src/java.base/share/data/cacerts/godaddyrootg2ca similarity index 100% rename from make/data/cacerts/godaddyrootg2ca rename to src/java.base/share/data/cacerts/godaddyrootg2ca diff --git a/make/data/cacerts/haricaeccrootca2015 b/src/java.base/share/data/cacerts/haricaeccrootca2015 similarity index 100% rename from make/data/cacerts/haricaeccrootca2015 rename to src/java.base/share/data/cacerts/haricaeccrootca2015 diff --git a/make/data/cacerts/haricarootca2015 b/src/java.base/share/data/cacerts/haricarootca2015 similarity index 100% rename from make/data/cacerts/haricarootca2015 rename to src/java.base/share/data/cacerts/haricarootca2015 diff --git a/make/data/cacerts/identrustcommercial b/src/java.base/share/data/cacerts/identrustcommercial similarity index 100% rename from make/data/cacerts/identrustcommercial rename to src/java.base/share/data/cacerts/identrustcommercial diff --git a/make/data/cacerts/identrustpublicca b/src/java.base/share/data/cacerts/identrustpublicca similarity index 100% rename from make/data/cacerts/identrustpublicca rename to src/java.base/share/data/cacerts/identrustpublicca diff --git a/make/data/cacerts/letsencryptisrgx1 b/src/java.base/share/data/cacerts/letsencryptisrgx1 similarity index 100% rename from make/data/cacerts/letsencryptisrgx1 rename to src/java.base/share/data/cacerts/letsencryptisrgx1 diff --git a/make/data/cacerts/luxtrustglobalroot2ca b/src/java.base/share/data/cacerts/luxtrustglobalroot2ca similarity index 100% rename from make/data/cacerts/luxtrustglobalroot2ca rename to src/java.base/share/data/cacerts/luxtrustglobalroot2ca diff --git a/make/data/cacerts/luxtrustglobalrootca b/src/java.base/share/data/cacerts/luxtrustglobalrootca similarity index 100% rename from make/data/cacerts/luxtrustglobalrootca rename to src/java.base/share/data/cacerts/luxtrustglobalrootca diff --git a/make/data/cacerts/quovadisrootca b/src/java.base/share/data/cacerts/quovadisrootca similarity index 100% rename from make/data/cacerts/quovadisrootca rename to src/java.base/share/data/cacerts/quovadisrootca diff --git a/make/data/cacerts/quovadisrootca1g3 b/src/java.base/share/data/cacerts/quovadisrootca1g3 similarity index 100% rename from make/data/cacerts/quovadisrootca1g3 rename to src/java.base/share/data/cacerts/quovadisrootca1g3 diff --git a/make/data/cacerts/quovadisrootca2 b/src/java.base/share/data/cacerts/quovadisrootca2 similarity index 100% rename from make/data/cacerts/quovadisrootca2 rename to src/java.base/share/data/cacerts/quovadisrootca2 diff --git a/make/data/cacerts/quovadisrootca2g3 b/src/java.base/share/data/cacerts/quovadisrootca2g3 similarity index 100% rename from make/data/cacerts/quovadisrootca2g3 rename to src/java.base/share/data/cacerts/quovadisrootca2g3 diff --git a/make/data/cacerts/quovadisrootca3 b/src/java.base/share/data/cacerts/quovadisrootca3 similarity index 100% rename from make/data/cacerts/quovadisrootca3 rename to src/java.base/share/data/cacerts/quovadisrootca3 diff --git a/make/data/cacerts/quovadisrootca3g3 b/src/java.base/share/data/cacerts/quovadisrootca3g3 similarity index 100% rename from make/data/cacerts/quovadisrootca3g3 rename to src/java.base/share/data/cacerts/quovadisrootca3g3 diff --git a/make/data/cacerts/secomscrootca1 b/src/java.base/share/data/cacerts/secomscrootca1 similarity index 100% rename from make/data/cacerts/secomscrootca1 rename to src/java.base/share/data/cacerts/secomscrootca1 diff --git a/make/data/cacerts/secomscrootca2 b/src/java.base/share/data/cacerts/secomscrootca2 similarity index 100% rename from make/data/cacerts/secomscrootca2 rename to src/java.base/share/data/cacerts/secomscrootca2 diff --git a/make/data/cacerts/securetrustca b/src/java.base/share/data/cacerts/securetrustca similarity index 100% rename from make/data/cacerts/securetrustca rename to src/java.base/share/data/cacerts/securetrustca diff --git a/make/data/cacerts/sslrooteccca b/src/java.base/share/data/cacerts/sslrooteccca similarity index 100% rename from make/data/cacerts/sslrooteccca rename to src/java.base/share/data/cacerts/sslrooteccca diff --git a/make/data/cacerts/sslrootevrsaca b/src/java.base/share/data/cacerts/sslrootevrsaca similarity index 100% rename from make/data/cacerts/sslrootevrsaca rename to src/java.base/share/data/cacerts/sslrootevrsaca diff --git a/make/data/cacerts/sslrootrsaca b/src/java.base/share/data/cacerts/sslrootrsaca similarity index 100% rename from make/data/cacerts/sslrootrsaca rename to src/java.base/share/data/cacerts/sslrootrsaca diff --git a/make/data/cacerts/starfieldclass2ca b/src/java.base/share/data/cacerts/starfieldclass2ca similarity index 100% rename from make/data/cacerts/starfieldclass2ca rename to src/java.base/share/data/cacerts/starfieldclass2ca diff --git a/make/data/cacerts/starfieldrootg2ca b/src/java.base/share/data/cacerts/starfieldrootg2ca similarity index 100% rename from make/data/cacerts/starfieldrootg2ca rename to src/java.base/share/data/cacerts/starfieldrootg2ca diff --git a/make/data/cacerts/starfieldservicesrootg2ca b/src/java.base/share/data/cacerts/starfieldservicesrootg2ca similarity index 100% rename from make/data/cacerts/starfieldservicesrootg2ca rename to src/java.base/share/data/cacerts/starfieldservicesrootg2ca diff --git a/make/data/cacerts/swisssigngoldg2ca b/src/java.base/share/data/cacerts/swisssigngoldg2ca similarity index 100% rename from make/data/cacerts/swisssigngoldg2ca rename to src/java.base/share/data/cacerts/swisssigngoldg2ca diff --git a/make/data/cacerts/swisssignplatinumg2ca b/src/java.base/share/data/cacerts/swisssignplatinumg2ca similarity index 100% rename from make/data/cacerts/swisssignplatinumg2ca rename to src/java.base/share/data/cacerts/swisssignplatinumg2ca diff --git a/make/data/cacerts/swisssignsilverg2ca b/src/java.base/share/data/cacerts/swisssignsilverg2ca similarity index 100% rename from make/data/cacerts/swisssignsilverg2ca rename to src/java.base/share/data/cacerts/swisssignsilverg2ca diff --git a/make/data/cacerts/teliasonerarootcav1 b/src/java.base/share/data/cacerts/teliasonerarootcav1 similarity index 100% rename from make/data/cacerts/teliasonerarootcav1 rename to src/java.base/share/data/cacerts/teliasonerarootcav1 diff --git a/make/data/cacerts/thawteprimaryrootca b/src/java.base/share/data/cacerts/thawteprimaryrootca similarity index 100% rename from make/data/cacerts/thawteprimaryrootca rename to src/java.base/share/data/cacerts/thawteprimaryrootca diff --git a/make/data/cacerts/thawteprimaryrootcag2 b/src/java.base/share/data/cacerts/thawteprimaryrootcag2 similarity index 100% rename from make/data/cacerts/thawteprimaryrootcag2 rename to src/java.base/share/data/cacerts/thawteprimaryrootcag2 diff --git a/make/data/cacerts/thawteprimaryrootcag3 b/src/java.base/share/data/cacerts/thawteprimaryrootcag3 similarity index 100% rename from make/data/cacerts/thawteprimaryrootcag3 rename to src/java.base/share/data/cacerts/thawteprimaryrootcag3 diff --git a/make/data/cacerts/ttelesecglobalrootclass2ca b/src/java.base/share/data/cacerts/ttelesecglobalrootclass2ca similarity index 100% rename from make/data/cacerts/ttelesecglobalrootclass2ca rename to src/java.base/share/data/cacerts/ttelesecglobalrootclass2ca diff --git a/make/data/cacerts/ttelesecglobalrootclass3ca b/src/java.base/share/data/cacerts/ttelesecglobalrootclass3ca similarity index 100% rename from make/data/cacerts/ttelesecglobalrootclass3ca rename to src/java.base/share/data/cacerts/ttelesecglobalrootclass3ca diff --git a/make/data/cacerts/usertrusteccca b/src/java.base/share/data/cacerts/usertrusteccca similarity index 100% rename from make/data/cacerts/usertrusteccca rename to src/java.base/share/data/cacerts/usertrusteccca diff --git a/make/data/cacerts/usertrustrsaca b/src/java.base/share/data/cacerts/usertrustrsaca similarity index 100% rename from make/data/cacerts/usertrustrsaca rename to src/java.base/share/data/cacerts/usertrustrsaca diff --git a/make/data/cacerts/utnuserfirstobjectca b/src/java.base/share/data/cacerts/utnuserfirstobjectca similarity index 100% rename from make/data/cacerts/utnuserfirstobjectca rename to src/java.base/share/data/cacerts/utnuserfirstobjectca diff --git a/make/data/cacerts/verisignclass3g3ca b/src/java.base/share/data/cacerts/verisignclass3g3ca similarity index 100% rename from make/data/cacerts/verisignclass3g3ca rename to src/java.base/share/data/cacerts/verisignclass3g3ca diff --git a/make/data/cacerts/verisignclass3g4ca b/src/java.base/share/data/cacerts/verisignclass3g4ca similarity index 100% rename from make/data/cacerts/verisignclass3g4ca rename to src/java.base/share/data/cacerts/verisignclass3g4ca diff --git a/make/data/cacerts/verisignclass3g5ca b/src/java.base/share/data/cacerts/verisignclass3g5ca similarity index 100% rename from make/data/cacerts/verisignclass3g5ca rename to src/java.base/share/data/cacerts/verisignclass3g5ca diff --git a/make/data/cacerts/verisignuniversalrootca b/src/java.base/share/data/cacerts/verisignuniversalrootca similarity index 100% rename from make/data/cacerts/verisignuniversalrootca rename to src/java.base/share/data/cacerts/verisignuniversalrootca diff --git a/make/data/cacerts/xrampglobalca b/src/java.base/share/data/cacerts/xrampglobalca similarity index 100% rename from make/data/cacerts/xrampglobalca rename to src/java.base/share/data/cacerts/xrampglobalca diff --git a/make/data/currency/CurrencyData.properties b/src/java.base/share/data/currency/CurrencyData.properties similarity index 100% rename from make/data/currency/CurrencyData.properties rename to src/java.base/share/data/currency/CurrencyData.properties diff --git a/make/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt similarity index 100% rename from make/data/lsrdata/language-subtag-registry.txt rename to src/java.base/share/data/lsrdata/language-subtag-registry.txt diff --git a/make/data/publicsuffixlist/VERSION b/src/java.base/share/data/publicsuffixlist/VERSION similarity index 100% rename from make/data/publicsuffixlist/VERSION rename to src/java.base/share/data/publicsuffixlist/VERSION diff --git a/make/data/publicsuffixlist/public_suffix_list.dat b/src/java.base/share/data/publicsuffixlist/public_suffix_list.dat similarity index 100% rename from make/data/publicsuffixlist/public_suffix_list.dat rename to src/java.base/share/data/publicsuffixlist/public_suffix_list.dat diff --git a/make/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION similarity index 100% rename from make/data/tzdata/VERSION rename to src/java.base/share/data/tzdata/VERSION diff --git a/make/data/tzdata/africa b/src/java.base/share/data/tzdata/africa similarity index 100% rename from make/data/tzdata/africa rename to src/java.base/share/data/tzdata/africa diff --git a/make/data/tzdata/antarctica b/src/java.base/share/data/tzdata/antarctica similarity index 100% rename from make/data/tzdata/antarctica rename to src/java.base/share/data/tzdata/antarctica diff --git a/make/data/tzdata/asia b/src/java.base/share/data/tzdata/asia similarity index 100% rename from make/data/tzdata/asia rename to src/java.base/share/data/tzdata/asia diff --git a/make/data/tzdata/australasia b/src/java.base/share/data/tzdata/australasia similarity index 100% rename from make/data/tzdata/australasia rename to src/java.base/share/data/tzdata/australasia diff --git a/make/data/tzdata/backward b/src/java.base/share/data/tzdata/backward similarity index 100% rename from make/data/tzdata/backward rename to src/java.base/share/data/tzdata/backward diff --git a/make/data/tzdata/etcetera b/src/java.base/share/data/tzdata/etcetera similarity index 100% rename from make/data/tzdata/etcetera rename to src/java.base/share/data/tzdata/etcetera diff --git a/make/data/tzdata/europe b/src/java.base/share/data/tzdata/europe similarity index 100% rename from make/data/tzdata/europe rename to src/java.base/share/data/tzdata/europe diff --git a/make/data/tzdata/factory b/src/java.base/share/data/tzdata/factory similarity index 100% rename from make/data/tzdata/factory rename to src/java.base/share/data/tzdata/factory diff --git a/make/data/tzdata/gmt b/src/java.base/share/data/tzdata/gmt similarity index 100% rename from make/data/tzdata/gmt rename to src/java.base/share/data/tzdata/gmt diff --git a/make/data/tzdata/iso3166.tab b/src/java.base/share/data/tzdata/iso3166.tab similarity index 100% rename from make/data/tzdata/iso3166.tab rename to src/java.base/share/data/tzdata/iso3166.tab diff --git a/make/data/tzdata/jdk11_backward b/src/java.base/share/data/tzdata/jdk11_backward similarity index 100% rename from make/data/tzdata/jdk11_backward rename to src/java.base/share/data/tzdata/jdk11_backward diff --git a/make/data/tzdata/leapseconds b/src/java.base/share/data/tzdata/leapseconds similarity index 100% rename from make/data/tzdata/leapseconds rename to src/java.base/share/data/tzdata/leapseconds diff --git a/make/data/tzdata/northamerica b/src/java.base/share/data/tzdata/northamerica similarity index 100% rename from make/data/tzdata/northamerica rename to src/java.base/share/data/tzdata/northamerica diff --git a/make/data/tzdata/solar87 b/src/java.base/share/data/tzdata/solar87 similarity index 100% rename from make/data/tzdata/solar87 rename to src/java.base/share/data/tzdata/solar87 diff --git a/make/data/tzdata/solar88 b/src/java.base/share/data/tzdata/solar88 similarity index 100% rename from make/data/tzdata/solar88 rename to src/java.base/share/data/tzdata/solar88 diff --git a/make/data/tzdata/solar89 b/src/java.base/share/data/tzdata/solar89 similarity index 100% rename from make/data/tzdata/solar89 rename to src/java.base/share/data/tzdata/solar89 diff --git a/make/data/tzdata/southamerica b/src/java.base/share/data/tzdata/southamerica similarity index 100% rename from make/data/tzdata/southamerica rename to src/java.base/share/data/tzdata/southamerica diff --git a/make/data/tzdata/zone.tab b/src/java.base/share/data/tzdata/zone.tab similarity index 100% rename from make/data/tzdata/zone.tab rename to src/java.base/share/data/tzdata/zone.tab diff --git a/make/data/unicodedata/Blocks.txt b/src/java.base/share/data/unicodedata/Blocks.txt similarity index 100% rename from make/data/unicodedata/Blocks.txt rename to src/java.base/share/data/unicodedata/Blocks.txt diff --git a/make/data/unicodedata/DerivedCoreProperties.txt b/src/java.base/share/data/unicodedata/DerivedCoreProperties.txt similarity index 100% rename from make/data/unicodedata/DerivedCoreProperties.txt rename to src/java.base/share/data/unicodedata/DerivedCoreProperties.txt diff --git a/make/data/unicodedata/NormalizationTest.txt b/src/java.base/share/data/unicodedata/NormalizationTest.txt similarity index 100% rename from make/data/unicodedata/NormalizationTest.txt rename to src/java.base/share/data/unicodedata/NormalizationTest.txt diff --git a/make/data/unicodedata/PropList.txt b/src/java.base/share/data/unicodedata/PropList.txt similarity index 100% rename from make/data/unicodedata/PropList.txt rename to src/java.base/share/data/unicodedata/PropList.txt diff --git a/make/data/unicodedata/PropertyValueAliases.txt b/src/java.base/share/data/unicodedata/PropertyValueAliases.txt similarity index 100% rename from make/data/unicodedata/PropertyValueAliases.txt rename to src/java.base/share/data/unicodedata/PropertyValueAliases.txt diff --git a/make/data/unicodedata/ReadMe.txt b/src/java.base/share/data/unicodedata/ReadMe.txt similarity index 100% rename from make/data/unicodedata/ReadMe.txt rename to src/java.base/share/data/unicodedata/ReadMe.txt diff --git a/make/data/unicodedata/Scripts.txt b/src/java.base/share/data/unicodedata/Scripts.txt similarity index 100% rename from make/data/unicodedata/Scripts.txt rename to src/java.base/share/data/unicodedata/Scripts.txt diff --git a/make/data/unicodedata/SpecialCasing.txt b/src/java.base/share/data/unicodedata/SpecialCasing.txt similarity index 100% rename from make/data/unicodedata/SpecialCasing.txt rename to src/java.base/share/data/unicodedata/SpecialCasing.txt diff --git a/make/data/unicodedata/UnicodeData.txt b/src/java.base/share/data/unicodedata/UnicodeData.txt similarity index 100% rename from make/data/unicodedata/UnicodeData.txt rename to src/java.base/share/data/unicodedata/UnicodeData.txt diff --git a/make/data/unicodedata/auxiliary/GraphemeBreakProperty.txt b/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakProperty.txt similarity index 100% rename from make/data/unicodedata/auxiliary/GraphemeBreakProperty.txt rename to src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakProperty.txt diff --git a/make/data/unicodedata/auxiliary/GraphemeBreakTest.txt b/src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakTest.txt similarity index 100% rename from make/data/unicodedata/auxiliary/GraphemeBreakTest.txt rename to src/java.base/share/data/unicodedata/auxiliary/GraphemeBreakTest.txt diff --git a/make/data/unicodedata/emoji/emoji-data.txt b/src/java.base/share/data/unicodedata/emoji/emoji-data.txt similarity index 100% rename from make/data/unicodedata/emoji/emoji-data.txt rename to src/java.base/share/data/unicodedata/emoji/emoji-data.txt diff --git a/make/data/fontconfig/aix.fontconfig.properties b/src/java.desktop/aix/data/fontconfig/fontconfig.properties similarity index 100% rename from make/data/fontconfig/aix.fontconfig.properties rename to src/java.desktop/aix/data/fontconfig/fontconfig.properties diff --git a/make/data/fontconfig/bsd.fontconfig.properties b/src/java.desktop/bsd/data/fontconfig/fontconfig.properties similarity index 100% rename from make/data/fontconfig/bsd.fontconfig.properties rename to src/java.desktop/bsd/data/fontconfig/fontconfig.properties diff --git a/make/data/fontconfig/macosx.fontconfig.properties b/src/java.desktop/macosx/data/fontconfig/fontconfig.properties similarity index 100% rename from make/data/fontconfig/macosx.fontconfig.properties rename to src/java.desktop/macosx/data/fontconfig/fontconfig.properties diff --git a/make/data/macosxicons/JavaApp.icns b/src/java.desktop/macosx/data/macosxicons/JavaApp.icns similarity index 100% rename from make/data/macosxicons/JavaApp.icns rename to src/java.desktop/macosx/data/macosxicons/JavaApp.icns diff --git a/make/data/dtdbuilder/HTMLlat1.sgml b/src/java.desktop/share/data/dtdbuilder/HTMLlat1.sgml similarity index 100% rename from make/data/dtdbuilder/HTMLlat1.sgml rename to src/java.desktop/share/data/dtdbuilder/HTMLlat1.sgml diff --git a/make/data/dtdbuilder/HTMLspecial.sgml b/src/java.desktop/share/data/dtdbuilder/HTMLspecial.sgml similarity index 100% rename from make/data/dtdbuilder/HTMLspecial.sgml rename to src/java.desktop/share/data/dtdbuilder/HTMLspecial.sgml diff --git a/make/data/dtdbuilder/HTMLsymbol.sgml b/src/java.desktop/share/data/dtdbuilder/HTMLsymbol.sgml similarity index 100% rename from make/data/dtdbuilder/HTMLsymbol.sgml rename to src/java.desktop/share/data/dtdbuilder/HTMLsymbol.sgml diff --git a/make/data/dtdbuilder/html32.dtd b/src/java.desktop/share/data/dtdbuilder/html32.dtd similarity index 100% rename from make/data/dtdbuilder/html32.dtd rename to src/java.desktop/share/data/dtdbuilder/html32.dtd diff --git a/make/data/dtdbuilder/public.map b/src/java.desktop/share/data/dtdbuilder/public.map similarity index 100% rename from make/data/dtdbuilder/public.map rename to src/java.desktop/share/data/dtdbuilder/public.map diff --git a/make/data/x11wrappergen/sizes-32.txt b/src/java.desktop/unix/data/x11wrappergen/sizes-32.txt similarity index 100% rename from make/data/x11wrappergen/sizes-32.txt rename to src/java.desktop/unix/data/x11wrappergen/sizes-32.txt diff --git a/make/data/x11wrappergen/sizes-64.txt b/src/java.desktop/unix/data/x11wrappergen/sizes-64.txt similarity index 100% rename from make/data/x11wrappergen/sizes-64.txt rename to src/java.desktop/unix/data/x11wrappergen/sizes-64.txt diff --git a/make/data/x11wrappergen/xlibtypes.txt b/src/java.desktop/unix/data/x11wrappergen/xlibtypes.txt similarity index 100% rename from make/data/x11wrappergen/xlibtypes.txt rename to src/java.desktop/unix/data/x11wrappergen/xlibtypes.txt diff --git a/make/data/fontconfig/windows.fontconfig.properties b/src/java.desktop/windows/data/fontconfig/fontconfig.properties similarity index 100% rename from make/data/fontconfig/windows.fontconfig.properties rename to src/java.desktop/windows/data/fontconfig/fontconfig.properties diff --git a/make/data/jdwp/jdwp.spec b/src/java.se/share/data/jdwp/jdwp.spec similarity index 100% rename from make/data/jdwp/jdwp.spec rename to src/java.se/share/data/jdwp/jdwp.spec diff --git a/make/data/symbols/README b/src/jdk.compiler/share/data/symbols/README similarity index 100% rename from make/data/symbols/README rename to src/jdk.compiler/share/data/symbols/README diff --git a/make/data/symbols/include.list b/src/jdk.compiler/share/data/symbols/include.list similarity index 100% rename from make/data/symbols/include.list rename to src/jdk.compiler/share/data/symbols/include.list diff --git a/make/data/symbols/java.activation-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.activation-8.sym.txt similarity index 100% rename from make/data/symbols/java.activation-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.activation-8.sym.txt diff --git a/make/data/symbols/java.activation-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.activation-9.sym.txt similarity index 100% rename from make/data/symbols/java.activation-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.activation-9.sym.txt diff --git a/make/data/symbols/java.activation-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.activation-A.sym.txt similarity index 100% rename from make/data/symbols/java.activation-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.activation-A.sym.txt diff --git a/make/data/symbols/java.activation-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.activation-B.sym.txt similarity index 100% rename from make/data/symbols/java.activation-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.activation-B.sym.txt diff --git a/make/data/symbols/java.base-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-7.sym.txt similarity index 100% rename from make/data/symbols/java.base-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-7.sym.txt diff --git a/make/data/symbols/java.base-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-8.sym.txt similarity index 100% rename from make/data/symbols/java.base-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-8.sym.txt diff --git a/make/data/symbols/java.base-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-9.sym.txt similarity index 100% rename from make/data/symbols/java.base-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-9.sym.txt diff --git a/make/data/symbols/java.base-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-A.sym.txt similarity index 100% rename from make/data/symbols/java.base-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-A.sym.txt diff --git a/make/data/symbols/java.base-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-B.sym.txt similarity index 100% rename from make/data/symbols/java.base-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-B.sym.txt diff --git a/make/data/symbols/java.base-C.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-C.sym.txt similarity index 100% rename from make/data/symbols/java.base-C.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-C.sym.txt diff --git a/make/data/symbols/java.base-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-D.sym.txt similarity index 100% rename from make/data/symbols/java.base-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-D.sym.txt diff --git a/make/data/symbols/java.base-E.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-E.sym.txt similarity index 100% rename from make/data/symbols/java.base-E.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-E.sym.txt diff --git a/make/data/symbols/java.base-F.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-F.sym.txt similarity index 100% rename from make/data/symbols/java.base-F.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-F.sym.txt diff --git a/make/data/symbols/java.base-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-G.sym.txt similarity index 100% rename from make/data/symbols/java.base-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-G.sym.txt diff --git a/make/data/symbols/java.base-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-H.sym.txt similarity index 100% rename from make/data/symbols/java.base-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-H.sym.txt diff --git a/make/data/symbols/java.base-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-I.sym.txt similarity index 100% rename from make/data/symbols/java.base-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.base-I.sym.txt diff --git a/make/data/symbols/java.compiler-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-7.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-7.sym.txt diff --git a/make/data/symbols/java.compiler-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-8.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-8.sym.txt diff --git a/make/data/symbols/java.compiler-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-9.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-9.sym.txt diff --git a/make/data/symbols/java.compiler-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-A.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-A.sym.txt diff --git a/make/data/symbols/java.compiler-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-B.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-B.sym.txt diff --git a/make/data/symbols/java.compiler-C.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-C.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-C.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-C.sym.txt diff --git a/make/data/symbols/java.compiler-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-D.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-D.sym.txt diff --git a/make/data/symbols/java.compiler-E.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-E.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-E.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-E.sym.txt diff --git a/make/data/symbols/java.compiler-F.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-F.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-F.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-F.sym.txt diff --git a/make/data/symbols/java.compiler-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-G.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-G.sym.txt diff --git a/make/data/symbols/java.compiler-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-H.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-H.sym.txt diff --git a/make/data/symbols/java.compiler-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.compiler-I.sym.txt similarity index 100% rename from make/data/symbols/java.compiler-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.compiler-I.sym.txt diff --git a/make/data/symbols/java.corba-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.corba-8.sym.txt similarity index 100% rename from make/data/symbols/java.corba-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.corba-8.sym.txt diff --git a/make/data/symbols/java.corba-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.corba-9.sym.txt similarity index 100% rename from make/data/symbols/java.corba-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.corba-9.sym.txt diff --git a/make/data/symbols/java.corba-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.corba-A.sym.txt similarity index 100% rename from make/data/symbols/java.corba-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.corba-A.sym.txt diff --git a/make/data/symbols/java.corba-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.corba-B.sym.txt similarity index 100% rename from make/data/symbols/java.corba-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.corba-B.sym.txt diff --git a/make/data/symbols/java.datatransfer-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.datatransfer-7.sym.txt similarity index 100% rename from make/data/symbols/java.datatransfer-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.datatransfer-7.sym.txt diff --git a/make/data/symbols/java.datatransfer-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.datatransfer-8.sym.txt similarity index 100% rename from make/data/symbols/java.datatransfer-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.datatransfer-8.sym.txt diff --git a/make/data/symbols/java.datatransfer-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.datatransfer-9.sym.txt similarity index 100% rename from make/data/symbols/java.datatransfer-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.datatransfer-9.sym.txt diff --git a/make/data/symbols/java.datatransfer-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.datatransfer-A.sym.txt similarity index 100% rename from make/data/symbols/java.datatransfer-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.datatransfer-A.sym.txt diff --git a/make/data/symbols/java.datatransfer-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.datatransfer-B.sym.txt similarity index 100% rename from make/data/symbols/java.datatransfer-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.datatransfer-B.sym.txt diff --git a/make/data/symbols/java.datatransfer-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.datatransfer-G.sym.txt similarity index 100% rename from make/data/symbols/java.datatransfer-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.datatransfer-G.sym.txt diff --git a/make/data/symbols/java.datatransfer-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.datatransfer-H.sym.txt similarity index 100% rename from make/data/symbols/java.datatransfer-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.datatransfer-H.sym.txt diff --git a/make/data/symbols/java.datatransfer-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.datatransfer-I.sym.txt similarity index 100% rename from make/data/symbols/java.datatransfer-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.datatransfer-I.sym.txt diff --git a/make/data/symbols/java.desktop-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-7.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-7.sym.txt diff --git a/make/data/symbols/java.desktop-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-8.sym.txt diff --git a/make/data/symbols/java.desktop-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-9.sym.txt diff --git a/make/data/symbols/java.desktop-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-A.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-A.sym.txt diff --git a/make/data/symbols/java.desktop-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-B.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-B.sym.txt diff --git a/make/data/symbols/java.desktop-C.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-C.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-C.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-C.sym.txt diff --git a/make/data/symbols/java.desktop-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-D.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-D.sym.txt diff --git a/make/data/symbols/java.desktop-E.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-E.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-E.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-E.sym.txt diff --git a/make/data/symbols/java.desktop-F.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-F.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-F.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-F.sym.txt diff --git a/make/data/symbols/java.desktop-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-G.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-G.sym.txt diff --git a/make/data/symbols/java.desktop-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-H.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-H.sym.txt diff --git a/make/data/symbols/java.desktop-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.desktop-I.sym.txt similarity index 100% rename from make/data/symbols/java.desktop-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.desktop-I.sym.txt diff --git a/make/data/symbols/java.instrument-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.instrument-8.sym.txt similarity index 100% rename from make/data/symbols/java.instrument-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.instrument-8.sym.txt diff --git a/make/data/symbols/java.instrument-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.instrument-9.sym.txt similarity index 100% rename from make/data/symbols/java.instrument-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.instrument-9.sym.txt diff --git a/make/data/symbols/java.instrument-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.instrument-A.sym.txt similarity index 100% rename from make/data/symbols/java.instrument-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.instrument-A.sym.txt diff --git a/make/data/symbols/java.instrument-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.instrument-B.sym.txt similarity index 100% rename from make/data/symbols/java.instrument-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.instrument-B.sym.txt diff --git a/make/data/symbols/java.instrument-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.instrument-G.sym.txt similarity index 100% rename from make/data/symbols/java.instrument-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.instrument-G.sym.txt diff --git a/make/data/symbols/java.instrument-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.instrument-H.sym.txt similarity index 100% rename from make/data/symbols/java.instrument-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.instrument-H.sym.txt diff --git a/make/data/symbols/java.instrument-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.instrument-I.sym.txt similarity index 100% rename from make/data/symbols/java.instrument-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.instrument-I.sym.txt diff --git a/make/data/symbols/java.logging-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.logging-7.sym.txt similarity index 100% rename from make/data/symbols/java.logging-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.logging-7.sym.txt diff --git a/make/data/symbols/java.logging-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.logging-8.sym.txt similarity index 100% rename from make/data/symbols/java.logging-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.logging-8.sym.txt diff --git a/make/data/symbols/java.logging-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.logging-9.sym.txt similarity index 100% rename from make/data/symbols/java.logging-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.logging-9.sym.txt diff --git a/make/data/symbols/java.logging-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.logging-A.sym.txt similarity index 100% rename from make/data/symbols/java.logging-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.logging-A.sym.txt diff --git a/make/data/symbols/java.logging-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.logging-B.sym.txt similarity index 100% rename from make/data/symbols/java.logging-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.logging-B.sym.txt diff --git a/make/data/symbols/java.logging-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.logging-G.sym.txt similarity index 100% rename from make/data/symbols/java.logging-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.logging-G.sym.txt diff --git a/make/data/symbols/java.logging-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.logging-H.sym.txt similarity index 100% rename from make/data/symbols/java.logging-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.logging-H.sym.txt diff --git a/make/data/symbols/java.logging-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.logging-I.sym.txt similarity index 100% rename from make/data/symbols/java.logging-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.logging-I.sym.txt diff --git a/make/data/symbols/java.management-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-7.sym.txt similarity index 100% rename from make/data/symbols/java.management-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-7.sym.txt diff --git a/make/data/symbols/java.management-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-8.sym.txt similarity index 100% rename from make/data/symbols/java.management-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-8.sym.txt diff --git a/make/data/symbols/java.management-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-9.sym.txt similarity index 100% rename from make/data/symbols/java.management-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-9.sym.txt diff --git a/make/data/symbols/java.management-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-A.sym.txt similarity index 100% rename from make/data/symbols/java.management-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-A.sym.txt diff --git a/make/data/symbols/java.management-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-B.sym.txt similarity index 100% rename from make/data/symbols/java.management-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-B.sym.txt diff --git a/make/data/symbols/java.management-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-D.sym.txt similarity index 100% rename from make/data/symbols/java.management-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-D.sym.txt diff --git a/make/data/symbols/java.management-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-G.sym.txt similarity index 100% rename from make/data/symbols/java.management-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-G.sym.txt diff --git a/make/data/symbols/java.management-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-H.sym.txt similarity index 100% rename from make/data/symbols/java.management-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-H.sym.txt diff --git a/make/data/symbols/java.management-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.management-I.sym.txt similarity index 100% rename from make/data/symbols/java.management-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management-I.sym.txt diff --git a/make/data/symbols/java.management.rmi-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-8.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-8.sym.txt diff --git a/make/data/symbols/java.management.rmi-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-9.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-9.sym.txt diff --git a/make/data/symbols/java.management.rmi-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-A.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-A.sym.txt diff --git a/make/data/symbols/java.management.rmi-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-B.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-B.sym.txt diff --git a/make/data/symbols/java.management.rmi-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-D.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-D.sym.txt diff --git a/make/data/symbols/java.management.rmi-F.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-F.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-F.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-F.sym.txt diff --git a/make/data/symbols/java.management.rmi-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-G.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-G.sym.txt diff --git a/make/data/symbols/java.management.rmi-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-H.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-H.sym.txt diff --git a/make/data/symbols/java.management.rmi-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.management.rmi-I.sym.txt similarity index 100% rename from make/data/symbols/java.management.rmi-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.management.rmi-I.sym.txt diff --git a/make/data/symbols/java.naming-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-7.sym.txt similarity index 100% rename from make/data/symbols/java.naming-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-7.sym.txt diff --git a/make/data/symbols/java.naming-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-8.sym.txt similarity index 100% rename from make/data/symbols/java.naming-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-8.sym.txt diff --git a/make/data/symbols/java.naming-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-9.sym.txt similarity index 100% rename from make/data/symbols/java.naming-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-9.sym.txt diff --git a/make/data/symbols/java.naming-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-A.sym.txt similarity index 100% rename from make/data/symbols/java.naming-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-A.sym.txt diff --git a/make/data/symbols/java.naming-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-B.sym.txt similarity index 100% rename from make/data/symbols/java.naming-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-B.sym.txt diff --git a/make/data/symbols/java.naming-C.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-C.sym.txt similarity index 100% rename from make/data/symbols/java.naming-C.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-C.sym.txt diff --git a/make/data/symbols/java.naming-F.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-F.sym.txt similarity index 100% rename from make/data/symbols/java.naming-F.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-F.sym.txt diff --git a/make/data/symbols/java.naming-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-G.sym.txt similarity index 100% rename from make/data/symbols/java.naming-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-G.sym.txt diff --git a/make/data/symbols/java.naming-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-H.sym.txt similarity index 100% rename from make/data/symbols/java.naming-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-H.sym.txt diff --git a/make/data/symbols/java.naming-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.naming-I.sym.txt similarity index 100% rename from make/data/symbols/java.naming-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.naming-I.sym.txt diff --git a/make/data/symbols/java.net.http-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.net.http-B.sym.txt similarity index 100% rename from make/data/symbols/java.net.http-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.net.http-B.sym.txt diff --git a/make/data/symbols/java.net.http-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.net.http-D.sym.txt similarity index 100% rename from make/data/symbols/java.net.http-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.net.http-D.sym.txt diff --git a/make/data/symbols/java.net.http-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.net.http-G.sym.txt similarity index 100% rename from make/data/symbols/java.net.http-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.net.http-G.sym.txt diff --git a/make/data/symbols/java.net.http-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.net.http-I.sym.txt similarity index 100% rename from make/data/symbols/java.net.http-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.net.http-I.sym.txt diff --git a/make/data/symbols/java.prefs-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.prefs-7.sym.txt similarity index 100% rename from make/data/symbols/java.prefs-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.prefs-7.sym.txt diff --git a/make/data/symbols/java.prefs-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.prefs-8.sym.txt similarity index 100% rename from make/data/symbols/java.prefs-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.prefs-8.sym.txt diff --git a/make/data/symbols/java.prefs-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.prefs-9.sym.txt similarity index 100% rename from make/data/symbols/java.prefs-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.prefs-9.sym.txt diff --git a/make/data/symbols/java.prefs-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.prefs-A.sym.txt similarity index 100% rename from make/data/symbols/java.prefs-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.prefs-A.sym.txt diff --git a/make/data/symbols/java.prefs-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.prefs-B.sym.txt similarity index 100% rename from make/data/symbols/java.prefs-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.prefs-B.sym.txt diff --git a/make/data/symbols/java.rmi-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-7.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-7.sym.txt diff --git a/make/data/symbols/java.rmi-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-8.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-8.sym.txt diff --git a/make/data/symbols/java.rmi-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-9.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-9.sym.txt diff --git a/make/data/symbols/java.rmi-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-A.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-A.sym.txt diff --git a/make/data/symbols/java.rmi-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-B.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-B.sym.txt diff --git a/make/data/symbols/java.rmi-C.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-C.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-C.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-C.sym.txt diff --git a/make/data/symbols/java.rmi-F.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-F.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-F.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-F.sym.txt diff --git a/make/data/symbols/java.rmi-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-G.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-G.sym.txt diff --git a/make/data/symbols/java.rmi-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-H.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-H.sym.txt diff --git a/make/data/symbols/java.rmi-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.rmi-I.sym.txt similarity index 100% rename from make/data/symbols/java.rmi-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.rmi-I.sym.txt diff --git a/make/data/symbols/java.scripting-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.scripting-7.sym.txt similarity index 100% rename from make/data/symbols/java.scripting-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.scripting-7.sym.txt diff --git a/make/data/symbols/java.scripting-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.scripting-8.sym.txt similarity index 100% rename from make/data/symbols/java.scripting-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.scripting-8.sym.txt diff --git a/make/data/symbols/java.scripting-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.scripting-9.sym.txt similarity index 100% rename from make/data/symbols/java.scripting-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.scripting-9.sym.txt diff --git a/make/data/symbols/java.scripting-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.scripting-A.sym.txt similarity index 100% rename from make/data/symbols/java.scripting-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.scripting-A.sym.txt diff --git a/make/data/symbols/java.scripting-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.scripting-B.sym.txt similarity index 100% rename from make/data/symbols/java.scripting-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.scripting-B.sym.txt diff --git a/make/data/symbols/java.scripting-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.scripting-G.sym.txt similarity index 100% rename from make/data/symbols/java.scripting-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.scripting-G.sym.txt diff --git a/make/data/symbols/java.scripting-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.scripting-H.sym.txt similarity index 100% rename from make/data/symbols/java.scripting-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.scripting-H.sym.txt diff --git a/make/data/symbols/java.scripting-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.scripting-I.sym.txt similarity index 100% rename from make/data/symbols/java.scripting-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.scripting-I.sym.txt diff --git a/make/data/symbols/java.se-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.se-9.sym.txt similarity index 100% rename from make/data/symbols/java.se-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.se-9.sym.txt diff --git a/make/data/symbols/java.se-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.se-A.sym.txt similarity index 100% rename from make/data/symbols/java.se-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.se-A.sym.txt diff --git a/make/data/symbols/java.se-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.se-B.sym.txt similarity index 100% rename from make/data/symbols/java.se-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.se-B.sym.txt diff --git a/make/data/symbols/java.se.ee-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.se.ee-9.sym.txt similarity index 100% rename from make/data/symbols/java.se.ee-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.se.ee-9.sym.txt diff --git a/make/data/symbols/java.se.ee-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.se.ee-A.sym.txt similarity index 100% rename from make/data/symbols/java.se.ee-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.se.ee-A.sym.txt diff --git a/make/data/symbols/java.se.ee-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.se.ee-B.sym.txt similarity index 100% rename from make/data/symbols/java.se.ee-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.se.ee-B.sym.txt diff --git a/make/data/symbols/java.security.jgss-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-7.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-7.sym.txt diff --git a/make/data/symbols/java.security.jgss-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-8.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-8.sym.txt diff --git a/make/data/symbols/java.security.jgss-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-9.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-9.sym.txt diff --git a/make/data/symbols/java.security.jgss-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-A.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-A.sym.txt diff --git a/make/data/symbols/java.security.jgss-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-B.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-B.sym.txt diff --git a/make/data/symbols/java.security.jgss-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-D.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-D.sym.txt diff --git a/make/data/symbols/java.security.jgss-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-G.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-G.sym.txt diff --git a/make/data/symbols/java.security.jgss-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-H.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-H.sym.txt diff --git a/make/data/symbols/java.security.jgss-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.jgss-I.sym.txt similarity index 100% rename from make/data/symbols/java.security.jgss-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.jgss-I.sym.txt diff --git a/make/data/symbols/java.security.sasl-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.sasl-7.sym.txt similarity index 100% rename from make/data/symbols/java.security.sasl-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.sasl-7.sym.txt diff --git a/make/data/symbols/java.security.sasl-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.sasl-8.sym.txt similarity index 100% rename from make/data/symbols/java.security.sasl-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.sasl-8.sym.txt diff --git a/make/data/symbols/java.security.sasl-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.sasl-9.sym.txt similarity index 100% rename from make/data/symbols/java.security.sasl-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.sasl-9.sym.txt diff --git a/make/data/symbols/java.security.sasl-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.sasl-A.sym.txt similarity index 100% rename from make/data/symbols/java.security.sasl-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.sasl-A.sym.txt diff --git a/make/data/symbols/java.security.sasl-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.sasl-B.sym.txt similarity index 100% rename from make/data/symbols/java.security.sasl-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.sasl-B.sym.txt diff --git a/make/data/symbols/java.security.sasl-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.sasl-G.sym.txt similarity index 100% rename from make/data/symbols/java.security.sasl-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.sasl-G.sym.txt diff --git a/make/data/symbols/java.security.sasl-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.sasl-H.sym.txt similarity index 100% rename from make/data/symbols/java.security.sasl-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.sasl-H.sym.txt diff --git a/make/data/symbols/java.security.sasl-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.security.sasl-I.sym.txt similarity index 100% rename from make/data/symbols/java.security.sasl-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.security.sasl-I.sym.txt diff --git a/make/data/symbols/java.smartcardio-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.smartcardio-9.sym.txt similarity index 100% rename from make/data/symbols/java.smartcardio-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.smartcardio-9.sym.txt diff --git a/make/data/symbols/java.smartcardio-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.smartcardio-A.sym.txt similarity index 100% rename from make/data/symbols/java.smartcardio-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.smartcardio-A.sym.txt diff --git a/make/data/symbols/java.smartcardio-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.smartcardio-B.sym.txt similarity index 100% rename from make/data/symbols/java.smartcardio-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.smartcardio-B.sym.txt diff --git a/make/data/symbols/java.smartcardio-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.smartcardio-G.sym.txt similarity index 100% rename from make/data/symbols/java.smartcardio-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.smartcardio-G.sym.txt diff --git a/make/data/symbols/java.smartcardio-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.smartcardio-H.sym.txt similarity index 100% rename from make/data/symbols/java.smartcardio-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.smartcardio-H.sym.txt diff --git a/make/data/symbols/java.smartcardio-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.smartcardio-I.sym.txt similarity index 100% rename from make/data/symbols/java.smartcardio-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.smartcardio-I.sym.txt diff --git a/make/data/symbols/java.sql-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-7.sym.txt similarity index 100% rename from make/data/symbols/java.sql-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql-7.sym.txt diff --git a/make/data/symbols/java.sql-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-8.sym.txt similarity index 100% rename from make/data/symbols/java.sql-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql-8.sym.txt diff --git a/make/data/symbols/java.sql-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-9.sym.txt similarity index 100% rename from make/data/symbols/java.sql-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql-9.sym.txt diff --git a/make/data/symbols/java.sql-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-A.sym.txt similarity index 100% rename from make/data/symbols/java.sql-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql-A.sym.txt diff --git a/make/data/symbols/java.sql-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-B.sym.txt similarity index 100% rename from make/data/symbols/java.sql-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql-B.sym.txt diff --git a/make/data/symbols/java.sql-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-G.sym.txt similarity index 100% rename from make/data/symbols/java.sql-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql-G.sym.txt diff --git a/make/data/symbols/java.sql-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-H.sym.txt similarity index 100% rename from make/data/symbols/java.sql-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql-H.sym.txt diff --git a/make/data/symbols/java.sql-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql-I.sym.txt similarity index 100% rename from make/data/symbols/java.sql-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql-I.sym.txt diff --git a/make/data/symbols/java.sql.rowset-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql.rowset-7.sym.txt similarity index 100% rename from make/data/symbols/java.sql.rowset-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql.rowset-7.sym.txt diff --git a/make/data/symbols/java.sql.rowset-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql.rowset-8.sym.txt similarity index 100% rename from make/data/symbols/java.sql.rowset-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql.rowset-8.sym.txt diff --git a/make/data/symbols/java.sql.rowset-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql.rowset-9.sym.txt similarity index 100% rename from make/data/symbols/java.sql.rowset-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql.rowset-9.sym.txt diff --git a/make/data/symbols/java.sql.rowset-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql.rowset-A.sym.txt similarity index 100% rename from make/data/symbols/java.sql.rowset-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql.rowset-A.sym.txt diff --git a/make/data/symbols/java.sql.rowset-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql.rowset-B.sym.txt similarity index 100% rename from make/data/symbols/java.sql.rowset-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql.rowset-B.sym.txt diff --git a/make/data/symbols/java.sql.rowset-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql.rowset-G.sym.txt similarity index 100% rename from make/data/symbols/java.sql.rowset-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql.rowset-G.sym.txt diff --git a/make/data/symbols/java.sql.rowset-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql.rowset-H.sym.txt similarity index 100% rename from make/data/symbols/java.sql.rowset-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql.rowset-H.sym.txt diff --git a/make/data/symbols/java.sql.rowset-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.sql.rowset-I.sym.txt similarity index 100% rename from make/data/symbols/java.sql.rowset-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.sql.rowset-I.sym.txt diff --git a/make/data/symbols/java.transaction-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.transaction-8.sym.txt similarity index 100% rename from make/data/symbols/java.transaction-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.transaction-8.sym.txt diff --git a/make/data/symbols/java.transaction-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.transaction-9.sym.txt similarity index 100% rename from make/data/symbols/java.transaction-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.transaction-9.sym.txt diff --git a/make/data/symbols/java.transaction-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.transaction-A.sym.txt similarity index 100% rename from make/data/symbols/java.transaction-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.transaction-A.sym.txt diff --git a/make/data/symbols/java.transaction-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.transaction-B.sym.txt similarity index 100% rename from make/data/symbols/java.transaction-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.transaction-B.sym.txt diff --git a/make/data/symbols/java.transaction.xa-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.transaction.xa-B.sym.txt similarity index 100% rename from make/data/symbols/java.transaction.xa-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.transaction.xa-B.sym.txt diff --git a/make/data/symbols/java.xml-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-7.sym.txt similarity index 100% rename from make/data/symbols/java.xml-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-7.sym.txt diff --git a/make/data/symbols/java.xml-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-8.sym.txt similarity index 100% rename from make/data/symbols/java.xml-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-8.sym.txt diff --git a/make/data/symbols/java.xml-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-9.sym.txt similarity index 100% rename from make/data/symbols/java.xml-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-9.sym.txt diff --git a/make/data/symbols/java.xml-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-A.sym.txt similarity index 100% rename from make/data/symbols/java.xml-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-A.sym.txt diff --git a/make/data/symbols/java.xml-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-B.sym.txt similarity index 100% rename from make/data/symbols/java.xml-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-B.sym.txt diff --git a/make/data/symbols/java.xml-C.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-C.sym.txt similarity index 100% rename from make/data/symbols/java.xml-C.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-C.sym.txt diff --git a/make/data/symbols/java.xml-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-D.sym.txt similarity index 100% rename from make/data/symbols/java.xml-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-D.sym.txt diff --git a/make/data/symbols/java.xml-E.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-E.sym.txt similarity index 100% rename from make/data/symbols/java.xml-E.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-E.sym.txt diff --git a/make/data/symbols/java.xml-F.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-F.sym.txt similarity index 100% rename from make/data/symbols/java.xml-F.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-F.sym.txt diff --git a/make/data/symbols/java.xml-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-G.sym.txt similarity index 100% rename from make/data/symbols/java.xml-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-G.sym.txt diff --git a/make/data/symbols/java.xml-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-H.sym.txt similarity index 100% rename from make/data/symbols/java.xml-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-H.sym.txt diff --git a/make/data/symbols/java.xml-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml-I.sym.txt similarity index 100% rename from make/data/symbols/java.xml-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml-I.sym.txt diff --git a/make/data/symbols/java.xml.bind-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.bind-7.sym.txt similarity index 100% rename from make/data/symbols/java.xml.bind-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.bind-7.sym.txt diff --git a/make/data/symbols/java.xml.bind-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.bind-8.sym.txt similarity index 100% rename from make/data/symbols/java.xml.bind-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.bind-8.sym.txt diff --git a/make/data/symbols/java.xml.bind-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt similarity index 100% rename from make/data/symbols/java.xml.bind-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.bind-9.sym.txt diff --git a/make/data/symbols/java.xml.bind-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.bind-A.sym.txt similarity index 100% rename from make/data/symbols/java.xml.bind-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.bind-A.sym.txt diff --git a/make/data/symbols/java.xml.bind-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.bind-B.sym.txt similarity index 100% rename from make/data/symbols/java.xml.bind-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.bind-B.sym.txt diff --git a/make/data/symbols/java.xml.crypto-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.crypto-8.sym.txt similarity index 100% rename from make/data/symbols/java.xml.crypto-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.crypto-8.sym.txt diff --git a/make/data/symbols/java.xml.crypto-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.crypto-9.sym.txt similarity index 100% rename from make/data/symbols/java.xml.crypto-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.crypto-9.sym.txt diff --git a/make/data/symbols/java.xml.crypto-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.crypto-A.sym.txt similarity index 100% rename from make/data/symbols/java.xml.crypto-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.crypto-A.sym.txt diff --git a/make/data/symbols/java.xml.crypto-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.crypto-B.sym.txt similarity index 100% rename from make/data/symbols/java.xml.crypto-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.crypto-B.sym.txt diff --git a/make/data/symbols/java.xml.crypto-D.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.crypto-D.sym.txt similarity index 100% rename from make/data/symbols/java.xml.crypto-D.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.crypto-D.sym.txt diff --git a/make/data/symbols/java.xml.crypto-G.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.crypto-G.sym.txt similarity index 100% rename from make/data/symbols/java.xml.crypto-G.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.crypto-G.sym.txt diff --git a/make/data/symbols/java.xml.crypto-H.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.crypto-H.sym.txt similarity index 100% rename from make/data/symbols/java.xml.crypto-H.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.crypto-H.sym.txt diff --git a/make/data/symbols/java.xml.crypto-I.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.crypto-I.sym.txt similarity index 100% rename from make/data/symbols/java.xml.crypto-I.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.crypto-I.sym.txt diff --git a/make/data/symbols/java.xml.ws-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws-8.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws-8.sym.txt diff --git a/make/data/symbols/java.xml.ws-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws-9.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws-9.sym.txt diff --git a/make/data/symbols/java.xml.ws-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws-A.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws-A.sym.txt diff --git a/make/data/symbols/java.xml.ws-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws-B.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws-B.sym.txt diff --git a/make/data/symbols/java.xml.ws.annotation-7.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-7.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws.annotation-7.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-7.sym.txt diff --git a/make/data/symbols/java.xml.ws.annotation-8.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-8.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws.annotation-8.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-8.sym.txt diff --git a/make/data/symbols/java.xml.ws.annotation-9.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-9.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws.annotation-9.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-9.sym.txt diff --git a/make/data/symbols/java.xml.ws.annotation-A.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-A.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws.annotation-A.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-A.sym.txt diff --git a/make/data/symbols/java.xml.ws.annotation-B.sym.txt b/src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-B.sym.txt similarity index 100% rename from make/data/symbols/java.xml.ws.annotation-B.sym.txt rename to src/jdk.compiler/share/data/symbols/java.xml.ws.annotation-B.sym.txt diff --git a/make/data/symbols/jdk.accessibility-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.accessibility-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.accessibility-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.accessibility-9.sym.txt diff --git a/make/data/symbols/jdk.accessibility-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.accessibility-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.accessibility-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.accessibility-A.sym.txt diff --git a/make/data/symbols/jdk.accessibility-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.accessibility-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.accessibility-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.accessibility-B.sym.txt diff --git a/make/data/symbols/jdk.accessibility-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.accessibility-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.accessibility-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.accessibility-G.sym.txt diff --git a/make/data/symbols/jdk.accessibility-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.accessibility-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.accessibility-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.accessibility-H.sym.txt diff --git a/make/data/symbols/jdk.accessibility-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.accessibility-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.accessibility-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.accessibility-I.sym.txt diff --git a/make/data/symbols/jdk.attach-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.attach-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.attach-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.attach-9.sym.txt diff --git a/make/data/symbols/jdk.attach-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.attach-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.attach-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.attach-A.sym.txt diff --git a/make/data/symbols/jdk.attach-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.attach-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.attach-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.attach-B.sym.txt diff --git a/make/data/symbols/jdk.attach-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.attach-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.attach-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.attach-G.sym.txt diff --git a/make/data/symbols/jdk.attach-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.attach-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.attach-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.attach-H.sym.txt diff --git a/make/data/symbols/jdk.attach-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.attach-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.attach-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.attach-I.sym.txt diff --git a/make/data/symbols/jdk.charsets-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.charsets-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.charsets-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.charsets-9.sym.txt diff --git a/make/data/symbols/jdk.charsets-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.charsets-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.charsets-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.charsets-A.sym.txt diff --git a/make/data/symbols/jdk.charsets-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.charsets-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.charsets-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.charsets-B.sym.txt diff --git a/make/data/symbols/jdk.compiler-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-9.sym.txt diff --git a/make/data/symbols/jdk.compiler-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-A.sym.txt diff --git a/make/data/symbols/jdk.compiler-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-B.sym.txt diff --git a/make/data/symbols/jdk.compiler-C.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-C.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-C.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-C.sym.txt diff --git a/make/data/symbols/jdk.compiler-D.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-D.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-D.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-D.sym.txt diff --git a/make/data/symbols/jdk.compiler-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-E.sym.txt diff --git a/make/data/symbols/jdk.compiler-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-F.sym.txt diff --git a/make/data/symbols/jdk.compiler-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-G.sym.txt diff --git a/make/data/symbols/jdk.compiler-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-H.sym.txt diff --git a/make/data/symbols/jdk.compiler-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.compiler-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.compiler-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.compiler-I.sym.txt diff --git a/make/data/symbols/jdk.crypto.cryptoki-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.crypto.cryptoki-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.crypto.cryptoki-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.crypto.cryptoki-9.sym.txt diff --git a/make/data/symbols/jdk.crypto.cryptoki-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.crypto.cryptoki-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.crypto.cryptoki-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.crypto.cryptoki-A.sym.txt diff --git a/make/data/symbols/jdk.crypto.cryptoki-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.crypto.cryptoki-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.crypto.cryptoki-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.crypto.cryptoki-B.sym.txt diff --git a/make/data/symbols/jdk.crypto.ec-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.crypto.ec-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.crypto.ec-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.crypto.ec-9.sym.txt diff --git a/make/data/symbols/jdk.crypto.ec-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.crypto.ec-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.crypto.ec-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.crypto.ec-A.sym.txt diff --git a/make/data/symbols/jdk.crypto.ec-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.crypto.ec-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.crypto.ec-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.crypto.ec-B.sym.txt diff --git a/make/data/symbols/jdk.dynalink-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.dynalink-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.dynalink-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.dynalink-9.sym.txt diff --git a/make/data/symbols/jdk.dynalink-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.dynalink-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.dynalink-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.dynalink-A.sym.txt diff --git a/make/data/symbols/jdk.dynalink-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.dynalink-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.dynalink-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.dynalink-B.sym.txt diff --git a/make/data/symbols/jdk.dynalink-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.dynalink-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.dynalink-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.dynalink-G.sym.txt diff --git a/make/data/symbols/jdk.dynalink-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.dynalink-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.dynalink-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.dynalink-H.sym.txt diff --git a/make/data/symbols/jdk.dynalink-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.dynalink-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.dynalink-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.dynalink-I.sym.txt diff --git a/make/data/symbols/jdk.editpad-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.editpad-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.editpad-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.editpad-9.sym.txt diff --git a/make/data/symbols/jdk.editpad-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.editpad-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.editpad-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.editpad-A.sym.txt diff --git a/make/data/symbols/jdk.editpad-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.editpad-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.editpad-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.editpad-B.sym.txt diff --git a/make/data/symbols/jdk.hotspot.agent-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.hotspot.agent-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.hotspot.agent-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.hotspot.agent-9.sym.txt diff --git a/make/data/symbols/jdk.hotspot.agent-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.hotspot.agent-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.hotspot.agent-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.hotspot.agent-A.sym.txt diff --git a/make/data/symbols/jdk.hotspot.agent-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.hotspot.agent-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.hotspot.agent-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.hotspot.agent-B.sym.txt diff --git a/make/data/symbols/jdk.httpserver-7.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-7.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-7.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-7.sym.txt diff --git a/make/data/symbols/jdk.httpserver-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-8.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-8.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-8.sym.txt diff --git a/make/data/symbols/jdk.httpserver-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-9.sym.txt diff --git a/make/data/symbols/jdk.httpserver-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-A.sym.txt diff --git a/make/data/symbols/jdk.httpserver-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-B.sym.txt diff --git a/make/data/symbols/jdk.httpserver-D.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-D.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-D.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-D.sym.txt diff --git a/make/data/symbols/jdk.httpserver-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-E.sym.txt diff --git a/make/data/symbols/jdk.httpserver-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-G.sym.txt diff --git a/make/data/symbols/jdk.httpserver-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-H.sym.txt diff --git a/make/data/symbols/jdk.httpserver-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.httpserver-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.httpserver-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.httpserver-I.sym.txt diff --git a/make/data/symbols/jdk.incubator.foreign-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.foreign-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-E.sym.txt diff --git a/make/data/symbols/jdk.incubator.foreign-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.foreign-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-F.sym.txt diff --git a/make/data/symbols/jdk.incubator.foreign-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.foreign-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-G.sym.txt diff --git a/make/data/symbols/jdk.incubator.foreign-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.foreign-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-H.sym.txt diff --git a/make/data/symbols/jdk.incubator.foreign-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.foreign-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.foreign-I.sym.txt diff --git a/make/data/symbols/jdk.incubator.httpclient-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.httpclient-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.httpclient-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.httpclient-9.sym.txt diff --git a/make/data/symbols/jdk.incubator.httpclient-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.httpclient-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.httpclient-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.httpclient-A.sym.txt diff --git a/make/data/symbols/jdk.incubator.httpclient-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.httpclient-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.httpclient-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.httpclient-B.sym.txt diff --git a/make/data/symbols/jdk.incubator.jpackage-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.jpackage-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.jpackage-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.jpackage-E.sym.txt diff --git a/make/data/symbols/jdk.incubator.jpackage-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.jpackage-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.jpackage-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.jpackage-G.sym.txt diff --git a/make/data/symbols/jdk.incubator.vector-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.vector-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.vector-G.sym.txt diff --git a/make/data/symbols/jdk.incubator.vector-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.vector-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.vector-H.sym.txt diff --git a/make/data/symbols/jdk.incubator.vector-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.incubator.vector-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.incubator.vector-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.incubator.vector-I.sym.txt diff --git a/make/data/symbols/jdk.jartool-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jartool-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jartool-9.sym.txt diff --git a/make/data/symbols/jdk.jartool-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jartool-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jartool-A.sym.txt diff --git a/make/data/symbols/jdk.jartool-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jartool-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jartool-B.sym.txt diff --git a/make/data/symbols/jdk.jartool-D.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-D.sym.txt similarity index 100% rename from make/data/symbols/jdk.jartool-D.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jartool-D.sym.txt diff --git a/make/data/symbols/jdk.jartool-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.jartool-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jartool-F.sym.txt diff --git a/make/data/symbols/jdk.jartool-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.jartool-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jartool-G.sym.txt diff --git a/make/data/symbols/jdk.jartool-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.jartool-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jartool-H.sym.txt diff --git a/make/data/symbols/jdk.jartool-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jartool-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.jartool-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jartool-I.sym.txt diff --git a/make/data/symbols/jdk.javadoc-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.javadoc-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.javadoc-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.javadoc-9.sym.txt diff --git a/make/data/symbols/jdk.javadoc-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.javadoc-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.javadoc-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.javadoc-A.sym.txt diff --git a/make/data/symbols/jdk.javadoc-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.javadoc-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.javadoc-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.javadoc-B.sym.txt diff --git a/make/data/symbols/jdk.javadoc-D.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.javadoc-D.sym.txt similarity index 100% rename from make/data/symbols/jdk.javadoc-D.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.javadoc-D.sym.txt diff --git a/make/data/symbols/jdk.javadoc-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.javadoc-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.javadoc-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.javadoc-F.sym.txt diff --git a/make/data/symbols/jdk.javadoc-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.javadoc-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.javadoc-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.javadoc-G.sym.txt diff --git a/make/data/symbols/jdk.javadoc-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.javadoc-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.javadoc-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.javadoc-H.sym.txt diff --git a/make/data/symbols/jdk.javadoc-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.javadoc-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.javadoc-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.javadoc-I.sym.txt diff --git a/make/data/symbols/jdk.jcmd-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jcmd-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jcmd-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jcmd-9.sym.txt diff --git a/make/data/symbols/jdk.jcmd-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jcmd-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jcmd-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jcmd-A.sym.txt diff --git a/make/data/symbols/jdk.jcmd-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jcmd-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jcmd-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jcmd-B.sym.txt diff --git a/make/data/symbols/jdk.jconsole-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jconsole-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jconsole-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jconsole-9.sym.txt diff --git a/make/data/symbols/jdk.jconsole-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jconsole-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jconsole-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jconsole-A.sym.txt diff --git a/make/data/symbols/jdk.jconsole-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jconsole-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jconsole-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jconsole-B.sym.txt diff --git a/make/data/symbols/jdk.jconsole-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jconsole-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.jconsole-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jconsole-G.sym.txt diff --git a/make/data/symbols/jdk.jconsole-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jconsole-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.jconsole-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jconsole-H.sym.txt diff --git a/make/data/symbols/jdk.jconsole-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jconsole-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.jconsole-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jconsole-I.sym.txt diff --git a/make/data/symbols/jdk.jdeps-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdeps-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdeps-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdeps-9.sym.txt diff --git a/make/data/symbols/jdk.jdeps-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdeps-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdeps-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdeps-A.sym.txt diff --git a/make/data/symbols/jdk.jdeps-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdeps-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdeps-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdeps-B.sym.txt diff --git a/make/data/symbols/jdk.jdi-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdi-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdi-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdi-9.sym.txt diff --git a/make/data/symbols/jdk.jdi-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdi-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdi-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdi-A.sym.txt diff --git a/make/data/symbols/jdk.jdi-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdi-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdi-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdi-B.sym.txt diff --git a/make/data/symbols/jdk.jdi-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdi-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdi-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdi-F.sym.txt diff --git a/make/data/symbols/jdk.jdi-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdi-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdi-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdi-G.sym.txt diff --git a/make/data/symbols/jdk.jdi-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdi-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdi-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdi-H.sym.txt diff --git a/make/data/symbols/jdk.jdi-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdi-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdi-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdi-I.sym.txt diff --git a/make/data/symbols/jdk.jdwp.agent-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdwp.agent-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdwp.agent-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdwp.agent-9.sym.txt diff --git a/make/data/symbols/jdk.jdwp.agent-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdwp.agent-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdwp.agent-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdwp.agent-A.sym.txt diff --git a/make/data/symbols/jdk.jdwp.agent-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jdwp.agent-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jdwp.agent-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jdwp.agent-B.sym.txt diff --git a/make/data/symbols/jdk.jfr-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jfr-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jfr-B.sym.txt diff --git a/make/data/symbols/jdk.jfr-C.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-C.sym.txt similarity index 100% rename from make/data/symbols/jdk.jfr-C.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jfr-C.sym.txt diff --git a/make/data/symbols/jdk.jfr-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.jfr-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jfr-E.sym.txt diff --git a/make/data/symbols/jdk.jfr-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.jfr-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jfr-G.sym.txt diff --git a/make/data/symbols/jdk.jfr-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jfr-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.jfr-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jfr-H.sym.txt diff --git a/make/data/symbols/jdk.jlink-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jlink-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jlink-9.sym.txt diff --git a/make/data/symbols/jdk.jlink-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jlink-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jlink-A.sym.txt diff --git a/make/data/symbols/jdk.jlink-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jlink-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jlink-B.sym.txt diff --git a/make/data/symbols/jdk.jlink-D.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-D.sym.txt similarity index 100% rename from make/data/symbols/jdk.jlink-D.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jlink-D.sym.txt diff --git a/make/data/symbols/jdk.jlink-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.jlink-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jlink-E.sym.txt diff --git a/make/data/symbols/jdk.jlink-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jlink-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.jlink-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jlink-I.sym.txt diff --git a/make/data/symbols/jdk.jpackage-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jpackage-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.jpackage-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jpackage-G.sym.txt diff --git a/make/data/symbols/jdk.jshell-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jshell-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jshell-9.sym.txt diff --git a/make/data/symbols/jdk.jshell-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jshell-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jshell-A.sym.txt diff --git a/make/data/symbols/jdk.jshell-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jshell-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jshell-B.sym.txt diff --git a/make/data/symbols/jdk.jshell-D.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-D.sym.txt similarity index 100% rename from make/data/symbols/jdk.jshell-D.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jshell-D.sym.txt diff --git a/make/data/symbols/jdk.jshell-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.jshell-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jshell-E.sym.txt diff --git a/make/data/symbols/jdk.jshell-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.jshell-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jshell-G.sym.txt diff --git a/make/data/symbols/jdk.jshell-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.jshell-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jshell-H.sym.txt diff --git a/make/data/symbols/jdk.jshell-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jshell-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.jshell-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jshell-I.sym.txt diff --git a/make/data/symbols/jdk.jsobject-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jsobject-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jsobject-9.sym.txt diff --git a/make/data/symbols/jdk.jsobject-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jsobject-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jsobject-A.sym.txt diff --git a/make/data/symbols/jdk.jsobject-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jsobject-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jsobject-B.sym.txt diff --git a/make/data/symbols/jdk.jsobject-C.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-C.sym.txt similarity index 100% rename from make/data/symbols/jdk.jsobject-C.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jsobject-C.sym.txt diff --git a/make/data/symbols/jdk.jsobject-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.jsobject-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jsobject-E.sym.txt diff --git a/make/data/symbols/jdk.jsobject-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.jsobject-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jsobject-G.sym.txt diff --git a/make/data/symbols/jdk.jsobject-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.jsobject-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jsobject-H.sym.txt diff --git a/make/data/symbols/jdk.jsobject-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jsobject-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.jsobject-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jsobject-I.sym.txt diff --git a/make/data/symbols/jdk.jstatd-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jstatd-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.jstatd-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jstatd-9.sym.txt diff --git a/make/data/symbols/jdk.jstatd-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jstatd-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.jstatd-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jstatd-A.sym.txt diff --git a/make/data/symbols/jdk.jstatd-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.jstatd-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.jstatd-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.jstatd-B.sym.txt diff --git a/make/data/symbols/jdk.localedata-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.localedata-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.localedata-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.localedata-9.sym.txt diff --git a/make/data/symbols/jdk.localedata-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.localedata-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.localedata-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.localedata-A.sym.txt diff --git a/make/data/symbols/jdk.localedata-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.localedata-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.localedata-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.localedata-B.sym.txt diff --git a/make/data/symbols/jdk.management-7.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-7.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-7.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-7.sym.txt diff --git a/make/data/symbols/jdk.management-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-8.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-8.sym.txt diff --git a/make/data/symbols/jdk.management-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-9.sym.txt diff --git a/make/data/symbols/jdk.management-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-A.sym.txt diff --git a/make/data/symbols/jdk.management-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-B.sym.txt diff --git a/make/data/symbols/jdk.management-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-E.sym.txt diff --git a/make/data/symbols/jdk.management-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-G.sym.txt diff --git a/make/data/symbols/jdk.management-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-H.sym.txt diff --git a/make/data/symbols/jdk.management-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.management-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management-I.sym.txt diff --git a/make/data/symbols/jdk.management.agent-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management.agent-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.management.agent-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management.agent-9.sym.txt diff --git a/make/data/symbols/jdk.management.agent-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management.agent-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.management.agent-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management.agent-A.sym.txt diff --git a/make/data/symbols/jdk.management.agent-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management.agent-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.management.agent-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management.agent-B.sym.txt diff --git a/make/data/symbols/jdk.management.jfr-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management.jfr-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.management.jfr-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management.jfr-B.sym.txt diff --git a/make/data/symbols/jdk.management.jfr-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management.jfr-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.management.jfr-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management.jfr-G.sym.txt diff --git a/make/data/symbols/jdk.management.jfr-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management.jfr-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.management.jfr-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management.jfr-H.sym.txt diff --git a/make/data/symbols/jdk.management.jfr-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.management.jfr-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.management.jfr-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.management.jfr-I.sym.txt diff --git a/make/data/symbols/jdk.naming.dns-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.naming.dns-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.naming.dns-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.naming.dns-9.sym.txt diff --git a/make/data/symbols/jdk.naming.dns-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.naming.dns-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.naming.dns-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.naming.dns-A.sym.txt diff --git a/make/data/symbols/jdk.naming.dns-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.naming.dns-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.naming.dns-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.naming.dns-B.sym.txt diff --git a/make/data/symbols/jdk.naming.rmi-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.naming.rmi-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.naming.rmi-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.naming.rmi-9.sym.txt diff --git a/make/data/symbols/jdk.naming.rmi-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.naming.rmi-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.naming.rmi-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.naming.rmi-A.sym.txt diff --git a/make/data/symbols/jdk.naming.rmi-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.naming.rmi-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.naming.rmi-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.naming.rmi-B.sym.txt diff --git a/make/data/symbols/jdk.net-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.net-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.net-9.sym.txt diff --git a/make/data/symbols/jdk.net-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.net-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.net-A.sym.txt diff --git a/make/data/symbols/jdk.net-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.net-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.net-B.sym.txt diff --git a/make/data/symbols/jdk.net-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.net-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.net-E.sym.txt diff --git a/make/data/symbols/jdk.net-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.net-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.net-F.sym.txt diff --git a/make/data/symbols/jdk.net-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.net-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.net-G.sym.txt diff --git a/make/data/symbols/jdk.net-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.net-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.net-H.sym.txt diff --git a/make/data/symbols/jdk.net-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.net-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.net-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.net-I.sym.txt diff --git a/make/data/symbols/jdk.nio.mapmode-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.nio.mapmode-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.nio.mapmode-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.nio.mapmode-F.sym.txt diff --git a/make/data/symbols/jdk.pack-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.pack-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.pack-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.pack-9.sym.txt diff --git a/make/data/symbols/jdk.pack-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.pack-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.pack-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.pack-A.sym.txt diff --git a/make/data/symbols/jdk.pack-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.pack-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.pack-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.pack-B.sym.txt diff --git a/make/data/symbols/jdk.pack-E.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.pack-E.sym.txt similarity index 100% rename from make/data/symbols/jdk.pack-E.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.pack-E.sym.txt diff --git a/make/data/symbols/jdk.policytool-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.policytool-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.policytool-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.policytool-9.sym.txt diff --git a/make/data/symbols/jdk.policytool-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.policytool-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.policytool-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.policytool-A.sym.txt diff --git a/make/data/symbols/jdk.rmic-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.rmic-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.rmic-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.rmic-9.sym.txt diff --git a/make/data/symbols/jdk.rmic-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.rmic-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.rmic-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.rmic-A.sym.txt diff --git a/make/data/symbols/jdk.rmic-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.rmic-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.rmic-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.rmic-B.sym.txt diff --git a/make/data/symbols/jdk.rmic-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.rmic-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.rmic-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.rmic-F.sym.txt diff --git a/make/data/symbols/jdk.scripting.nashorn-7.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-7.sym.txt similarity index 100% rename from make/data/symbols/jdk.scripting.nashorn-7.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-7.sym.txt diff --git a/make/data/symbols/jdk.scripting.nashorn-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-8.sym.txt similarity index 100% rename from make/data/symbols/jdk.scripting.nashorn-8.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-8.sym.txt diff --git a/make/data/symbols/jdk.scripting.nashorn-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.scripting.nashorn-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-9.sym.txt diff --git a/make/data/symbols/jdk.scripting.nashorn-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.scripting.nashorn-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-A.sym.txt diff --git a/make/data/symbols/jdk.scripting.nashorn-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.scripting.nashorn-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-B.sym.txt diff --git a/make/data/symbols/jdk.scripting.nashorn-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.scripting.nashorn-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.scripting.nashorn-F.sym.txt diff --git a/make/data/symbols/jdk.sctp-7.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.sctp-7.sym.txt similarity index 100% rename from make/data/symbols/jdk.sctp-7.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.sctp-7.sym.txt diff --git a/make/data/symbols/jdk.sctp-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.sctp-8.sym.txt similarity index 100% rename from make/data/symbols/jdk.sctp-8.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.sctp-8.sym.txt diff --git a/make/data/symbols/jdk.sctp-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.sctp-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.sctp-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.sctp-9.sym.txt diff --git a/make/data/symbols/jdk.sctp-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.sctp-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.sctp-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.sctp-A.sym.txt diff --git a/make/data/symbols/jdk.sctp-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.sctp-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.sctp-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.sctp-B.sym.txt diff --git a/make/data/symbols/jdk.sctp-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.sctp-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.sctp-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.sctp-G.sym.txt diff --git a/make/data/symbols/jdk.sctp-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.sctp-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.sctp-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.sctp-H.sym.txt diff --git a/make/data/symbols/jdk.sctp-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.sctp-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.sctp-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.sctp-I.sym.txt diff --git a/make/data/symbols/jdk.security.auth-7.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.auth-7.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.auth-7.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.auth-7.sym.txt diff --git a/make/data/symbols/jdk.security.auth-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.auth-8.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.auth-8.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.auth-8.sym.txt diff --git a/make/data/symbols/jdk.security.auth-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.auth-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.auth-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.auth-9.sym.txt diff --git a/make/data/symbols/jdk.security.auth-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.auth-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.auth-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.auth-A.sym.txt diff --git a/make/data/symbols/jdk.security.auth-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.auth-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.auth-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.auth-B.sym.txt diff --git a/make/data/symbols/jdk.security.auth-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.auth-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.auth-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.auth-G.sym.txt diff --git a/make/data/symbols/jdk.security.auth-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.auth-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.auth-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.auth-H.sym.txt diff --git a/make/data/symbols/jdk.security.auth-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.auth-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.auth-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.auth-I.sym.txt diff --git a/make/data/symbols/jdk.security.jgss-7.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.jgss-7.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.jgss-7.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.jgss-7.sym.txt diff --git a/make/data/symbols/jdk.security.jgss-8.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.jgss-8.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.jgss-8.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.jgss-8.sym.txt diff --git a/make/data/symbols/jdk.security.jgss-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.jgss-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.jgss-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.jgss-9.sym.txt diff --git a/make/data/symbols/jdk.security.jgss-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.jgss-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.jgss-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.jgss-A.sym.txt diff --git a/make/data/symbols/jdk.security.jgss-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.jgss-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.jgss-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.jgss-B.sym.txt diff --git a/make/data/symbols/jdk.security.jgss-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.jgss-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.jgss-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.jgss-G.sym.txt diff --git a/make/data/symbols/jdk.security.jgss-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.jgss-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.jgss-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.jgss-H.sym.txt diff --git a/make/data/symbols/jdk.security.jgss-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.security.jgss-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.security.jgss-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.security.jgss-I.sym.txt diff --git a/make/data/symbols/jdk.unsupported-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.unsupported-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.unsupported-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.unsupported-9.sym.txt diff --git a/make/data/symbols/jdk.unsupported-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.unsupported-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.unsupported-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.unsupported-A.sym.txt diff --git a/make/data/symbols/jdk.unsupported-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.unsupported-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.unsupported-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.unsupported-B.sym.txt diff --git a/make/data/symbols/jdk.unsupported-C.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.unsupported-C.sym.txt similarity index 100% rename from make/data/symbols/jdk.unsupported-C.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.unsupported-C.sym.txt diff --git a/make/data/symbols/jdk.unsupported-F.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.unsupported-F.sym.txt similarity index 100% rename from make/data/symbols/jdk.unsupported-F.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.unsupported-F.sym.txt diff --git a/make/data/symbols/jdk.unsupported-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.unsupported-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.unsupported-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.unsupported-G.sym.txt diff --git a/make/data/symbols/jdk.unsupported-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.unsupported-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.unsupported-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.unsupported-H.sym.txt diff --git a/make/data/symbols/jdk.unsupported-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.unsupported-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.unsupported-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.unsupported-I.sym.txt diff --git a/make/data/symbols/jdk.xml.dom-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.xml.dom-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.xml.dom-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.xml.dom-9.sym.txt diff --git a/make/data/symbols/jdk.xml.dom-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.xml.dom-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.xml.dom-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.xml.dom-A.sym.txt diff --git a/make/data/symbols/jdk.xml.dom-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.xml.dom-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.xml.dom-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.xml.dom-B.sym.txt diff --git a/make/data/symbols/jdk.xml.dom-G.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.xml.dom-G.sym.txt similarity index 100% rename from make/data/symbols/jdk.xml.dom-G.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.xml.dom-G.sym.txt diff --git a/make/data/symbols/jdk.xml.dom-H.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.xml.dom-H.sym.txt similarity index 100% rename from make/data/symbols/jdk.xml.dom-H.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.xml.dom-H.sym.txt diff --git a/make/data/symbols/jdk.xml.dom-I.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.xml.dom-I.sym.txt similarity index 100% rename from make/data/symbols/jdk.xml.dom-I.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.xml.dom-I.sym.txt diff --git a/make/data/symbols/jdk.zipfs-9.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.zipfs-9.sym.txt similarity index 100% rename from make/data/symbols/jdk.zipfs-9.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.zipfs-9.sym.txt diff --git a/make/data/symbols/jdk.zipfs-A.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.zipfs-A.sym.txt similarity index 100% rename from make/data/symbols/jdk.zipfs-A.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.zipfs-A.sym.txt diff --git a/make/data/symbols/jdk.zipfs-B.sym.txt b/src/jdk.compiler/share/data/symbols/jdk.zipfs-B.sym.txt similarity index 100% rename from make/data/symbols/jdk.zipfs-B.sym.txt rename to src/jdk.compiler/share/data/symbols/jdk.zipfs-B.sym.txt diff --git a/make/data/symbols/symbols b/src/jdk.compiler/share/data/symbols/symbols similarity index 100% rename from make/data/symbols/symbols rename to src/jdk.compiler/share/data/symbols/symbols diff --git a/test/jdk/java/security/misc/Versions.java b/test/jdk/java/security/misc/Versions.java index 6c14b2bc212..ebfe9a13a88 100644 --- a/test/jdk/java/security/misc/Versions.java +++ b/test/jdk/java/security/misc/Versions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -51,7 +51,7 @@ public class Versions { "src/java.xml.crypto/share/legal/santuario.md", Pattern.compile("## Apache Santuario v(?\\S+)"), "java.xml.crypto/santuario.md"}, - {"make/data/publicsuffixlist/VERSION", + {"src/java.base/share/data/publicsuffixlist/VERSION", Pattern.compile("list/(?[0-9a-f]+)/public_suffix_list.dat"), "src/java.base/share/legal/public_suffix.md", Pattern.compile("list/(?[0-9a-f]+)/public_suffix_list.dat"), diff --git a/test/jdk/java/util/Currency/CurrencyTest.java b/test/jdk/java/util/Currency/CurrencyTest.java index ad7c596485b..f82b032e2f8 100644 --- a/test/jdk/java/util/Currency/CurrencyTest.java +++ b/test/jdk/java/util/Currency/CurrencyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, 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 @@ -139,7 +139,7 @@ public class CurrencyTest { /* * check currency changes - * In current implementation, there is no data of old currency and transition date at jdk/make/data/currency/CurrencyData.properties. + * In current implementation, there is no data of old currency and transition date at jdk/src/java.base/share/data/currency/CurrencyData.properties. * So, all the switch data arrays are empty. In the future, if data of old currency and transition date are necessary for any country, the * arrays here can be updated so that the program can check the currency switch. */ diff --git a/test/jdk/java/util/Locale/LSRDataTest.java b/test/jdk/java/util/Locale/LSRDataTest.java index 81edf48b9b0..f32642981b5 100644 --- a/test/jdk/java/util/Locale/LSRDataTest.java +++ b/test/jdk/java/util/Locale/LSRDataTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -52,11 +52,11 @@ public class LSRDataTest { private static final Map> multiLangEquivsMap = new HashMap<>(); private static final Map regionVariantEquivMap = new HashMap<>(); - // path to the lsr file from the make folder, this test relies on the - // relative path to the file in the make folder, considering - // test and make will always exist in the same jdk layout + // path to the lsr file from the data folder, this test relies on the + // relative path to the file in the data folder, considering + // test and src/.../data will always exist in the same jdk layout private static final String LSR_FILE_PATH = System.getProperty("test.src", ".") - + "/../../../../../make/data/lsrdata/language-subtag-registry.txt"; + + "/../../../../../src/java.base/share/data/lsrdata/language-subtag-registry.txt"; public static void main(String[] args) throws IOException { diff --git a/test/jdk/lib/testlibrary/java/lang/UCDFiles.java b/test/jdk/lib/testlibrary/java/lang/UCDFiles.java index 10c6243f615..83054c5c0fb 100644 --- a/test/jdk/lib/testlibrary/java/lang/UCDFiles.java +++ b/test/jdk/lib/testlibrary/java/lang/UCDFiles.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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,16 +23,15 @@ /** * Holds the file paths to the Unicode Character Database source files. - * Paths to the source files in the "make" directory are relative, and - * subject to change due to future repository structure re-org. + * Paths to the source files in the "data" directory are relative. */ import java.nio.file.Path; import java.nio.file.Paths; public class UCDFiles { - public static Path UCD_DIR = Paths.get( - System.getProperty("test.root"), "..", "..", "make", "data", "unicodedata"); + public static Path UCD_DIR = Paths.get(System.getProperty("test.root"), + "../../src/java.base/share/data/unicodedata"); public static Path BLOCKS = UCD_DIR.resolve("Blocks.txt"); diff --git a/test/jdk/sun/nio/cs/TestCharsetMapping.java b/test/jdk/sun/nio/cs/TestCharsetMapping.java index 63eeba1774e..c7bd101aa42 100644 --- a/test/jdk/sun/nio/cs/TestCharsetMapping.java +++ b/test/jdk/sun/nio/cs/TestCharsetMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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 @@ -569,7 +569,7 @@ public class TestCharsetMapping { public static void main(String args[]) throws Exception { Path dir = Paths.get(System.getProperty("test.src", ".") + - "/../../../../make/data/charsetmapping"); + "/../../../../src/java.base/share/data/charsetmapping"); if (!Files.exists(dir)) { // not inside jdk repo, no mappings, exit silently log.println("Nothing done, not in a jdk repo: "); diff --git a/test/jdk/sun/nio/cs/TestMS950.java b/test/jdk/sun/nio/cs/TestMS950.java index 6d567e07751..36820f381a0 100644 --- a/test/jdk/sun/nio/cs/TestMS950.java +++ b/test/jdk/sun/nio/cs/TestMS950.java @@ -33,7 +33,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; public class TestMS950 { - // Data is listed from make/data/charsetmapping/MS950.map + // Data is listed from src/java.base/share/data/charsetmapping/MS950.map private final static String[] MS950B2C = new String[] { "0xF9FA 0x256D", "0xF9FB 0x256E", diff --git a/test/jdk/sun/security/lib/CheckBlockedCerts.java b/test/jdk/sun/security/lib/CheckBlockedCerts.java index e5561bf15b8..5afbf4b610b 100644 --- a/test/jdk/sun/security/lib/CheckBlockedCerts.java +++ b/test/jdk/sun/security/lib/CheckBlockedCerts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, 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 @@ -61,7 +61,7 @@ public class CheckBlockedCerts { // Assumes the full src is available File blockedCertsFile = new File(System.getProperty("test.src"), - "../../../../../make/data/blockedcertsconverter/blocked.certs.pem"); + "../../../../../src/java.base/share/data/blockedcertsconverter/blocked.certs.pem"); CertificateFactory cf = CertificateFactory.getInstance("X.509"); try (FileInputStream fis = new FileInputStream(blockedCertsFile)) { diff --git a/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java b/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java index 7b50c342a0d..ef6405860f5 100644 --- a/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java +++ b/test/jdk/sun/util/calendar/zi/TestZoneInfo310.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -47,7 +47,7 @@ public class TestZoneInfo310 { String TESTDIR = System.getProperty("test.dir", "."); Path tzdir = Paths.get(System.getProperty("test.root"), - "..", "..", "make", "data", "tzdata"); + "../../src/java.base/share/data/tzdata"); String tzfiles = "africa antarctica asia australasia europe northamerica southamerica backward etcetera gmt"; Path jdk_tzdir = Paths.get(System.getProperty("test.src"), "tzdata_jdk"); String jdk_tzfiles = "jdk11_backward"; diff --git a/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java b/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java index 8afdf54f40d..ae4f525e4ee 100644 --- a/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java +++ b/test/langtools/tools/javac/platform/CanHandleClassFilesTest.java @@ -64,7 +64,7 @@ public class CanHandleClassFilesTest { Path test = d.resolve("make/langtools/src/classes/build/tools/symbolgenerator/CreateSymbols.java"); if (Files.exists(test)) { createSymbols = test; - includeList = d.resolve("make/data/symbols/include.list"); + includeList = d.resolve("src/jdk.compiler/share/data/symbols/include.list"); break; } } diff --git a/test/langtools/tools/javac/sym/ElementStructureTest.java b/test/langtools/tools/javac/sym/ElementStructureTest.java index db5ae5f4582..791785b2452 100644 --- a/test/langtools/tools/javac/sym/ElementStructureTest.java +++ b/test/langtools/tools/javac/sym/ElementStructureTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -104,7 +104,7 @@ import toolbox.ToolBox; /**To generate the hash values for version N, invoke this class like: * - * java ElementStructureTest generate-hashes $LANGTOOLS_DIR/make/data/symbols/include.list ( N)+ + * java ElementStructureTest generate-hashes $LANGTOOLS_DIR/src/jdk.compiler/share/data/symbols/include.list ( N)+ * * Where is the file produced by make/src/classes/build/tools/symbolgenerator/Probe.java. * So, to produce hashes for 6, 7 and 8, this command can be used: @@ -113,11 +113,11 @@ import toolbox.ToolBox; * * To inspect differences between the actual and expected output for version N, invoke this class like: * - * java ElementStructureTest generate-output $LANGTOOLS_DIR/make/data/symbols/include.list ( N )+ + * java ElementStructureTest generate-output $LANGTOOLS_DIR/src/jdk.compiler/share/data/symbols/include.list ( N )+ * * For example, to get the actual and expected output for 6 in /tmp/actual and /tmp/expected, respectively: * - * java ElementStructureTest generate-output $LANGTOOLS_DIR/make/data/symbols/include.list classes-6 6 /tmp/actual /tmp/expected + * java ElementStructureTest generate-output $LANGTOOLS_DIR/src/jdk.compiler/share/data/symbols/include.list classes-6 6 /tmp/actual /tmp/expected */ public class ElementStructureTest { -- GitLab From f3dc0c88ea00a3745f5f105404e0788a0f616407 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 22 Mar 2022 01:12:29 +0000 Subject: [PATCH 107/237] 8282721: HotSpot Style Guide should allow considered use of C++ thread_local Reviewed-by: kbarrett, jrose, dcubed, stuefe, mdoerr, kvn --- doc/hotspot-style.html | 6 +++--- doc/hotspot-style.md | 34 +++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 453b9fbc14b..c93b941c988 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -210,7 +210,7 @@ while ( test_foo(args...) ) { // No, excess spaces around controlRationale: Other than to implement exceptions (which HotSpot doesn't use), most potential uses of RTTI are better done via virtual functions. Some of the remainder can be replaced by bespoke mechanisms. The cost of the additional runtime data structures needed to support RTTI are deemed not worthwhile, given the alternatives.

    Memory Allocation

    Do not use the standard global allocation and deallocation functions (operator new and related functions). Use of these functions by HotSpot code is disabled for some platforms.

    -

    Rationale: HotSpot often uses "resource" or "arena" allocation. Even where heap allocation is used, the standard global functions are avoided in favor of wrappers around malloc and free that support the VM's Native Memory Tracking (NMT) feature.

    +

    Rationale: HotSpot often uses "resource" or "arena" allocation. Even where heap allocation is used, the standard global functions are avoided in favor of wrappers around malloc and free that support the VM's Native Memory Tracking (NMT) feature. Typically, uses of the global operator new are inadvertent and therefore often associated with memory leaks.

    Native memory allocation failures are often treated as non-recoverable. The place where "out of memory" is (first) detected may be an innocent bystander, unrelated to the actual culprit.

    Class Inheritance

    Use public single inheritance.

    @@ -270,8 +270,8 @@ while ( test_foo(args...) ) { // No, excess spaces around controlThe underlying type of a scoped-enum should also be specified explicitly if conversions may be applied to values of that type.

    Due to bugs in certain (very old) compilers, there is widespread use of enums and avoidance of in-class initialization of static integral constant members. Compilers having such bugs are no longer supported. Except where an enum is semantically appropriate, new code should use integral constants.

    thread_local

    -

    Do not use thread_local (n2659); instead, use the HotSpot macro THREAD_LOCAL. The initializer must be a constant expression.

    -

    As was discussed in the review for JDK-8230877, thread_local allows dynamic initialization and destruction semantics. However, that support requires a run-time penalty for references to non-function-local thread_local variables defined in a different translation unit, even if they don't need dynamic initialization. Dynamic initialization and destruction of namespace-scoped thread local variables also has the same ordering problems as for ordinary namespace-scoped variables.

    +

    Avoid use of thread_local (n2659); and instead, use the HotSpot macro THREAD_LOCAL, for which the initializer must be a constant expression. When thread_local must be used, use the Hotspot macro APPROVED_CPP_THREAD_LOCAL to indicate that the use has been given appropriate consideration.

    +

    As was discussed in the review for JDK-8230877, thread_local allows dynamic initialization and destruction semantics. However, that support requires a run-time penalty for references to non-function-local thread_local variables defined in a different translation unit, even if they don't need dynamic initialization. Dynamic initialization and destruction of non-local thread_local variables also has the same ordering problems as for ordinary non-local variables. So we avoid use of thread_local in general, limiting its use to only those cases where dynamic initialization or destruction are essential. See JDK-8282469 for further discussion.

    nullptr

    Prefer nullptr (n2431) to NULL. Don't use (constexpr or literal) 0 for pointers.

    For historical reasons there are widespread uses of both NULL and of integer 0 as a pointer value.

    diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 84cb22a1bda..89d9684672d 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -471,7 +471,9 @@ code is disabled for some platforms. Rationale: HotSpot often uses "resource" or "arena" allocation. Even where heap allocation is used, the standard global functions are avoided in favor of wrappers around malloc and free that support the -VM's Native Memory Tracking (NMT) feature. +VM's Native Memory Tracking (NMT) feature. Typically, uses of the global +operator new are inadvertent and therefore often associated with memory +leaks. Native memory allocation failures are often treated as non-recoverable. The place where "out of memory" is (first) detected may be an innocent @@ -631,7 +633,7 @@ Here are a few closely related example bugs:
    ### enum Where appropriate, _scoped-enums_ should be used. -([n2347](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf)) +([n2347](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf)) Use of _unscoped-enums_ is permitted, though ordinary constants may be preferable when the automatic initializer feature isn't used. @@ -651,10 +653,12 @@ integral constants. ### thread_local -Do not use `thread_local` +Avoid use of `thread_local` ([n2659](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm)); -instead, use the HotSpot macro `THREAD_LOCAL`. The initializer must -be a constant expression. +and instead, use the HotSpot macro `THREAD_LOCAL`, for which the initializer must +be a constant expression. When `thread_local` must be used, use the Hotspot macro +`APPROVED_CPP_THREAD_LOCAL` to indicate that the use has been given appropriate +consideration. As was discussed in the review for [JDK-8230877](https://mail.openjdk.java.net/pipermail/hotspot-dev/2019-September/039487.html), @@ -663,14 +667,18 @@ semantics. However, that support requires a run-time penalty for references to non-function-local `thread_local` variables defined in a different translation unit, even if they don't need dynamic initialization. Dynamic initialization and destruction of -namespace-scoped thread local variables also has the same ordering -problems as for ordinary namespace-scoped variables. +non-local `thread_local` variables also has the same ordering +problems as for ordinary non-local variables. So we avoid use of +`thread_local` in general, limiting its use to only those cases where dynamic +initialization or destruction are essential. See +[JDK-8282469](https://bugs.openjdk.java.net/browse/JDK-8282469) +for further discussion. ### nullptr Prefer `nullptr` ([n2431](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf)) -to `NULL`. Don't use (constexpr or literal) 0 for pointers. +to `NULL`. Don't use (constexpr or literal) 0 for pointers. For historical reasons there are widespread uses of both `NULL` and of integer 0 as a pointer value. @@ -939,7 +947,7 @@ References: * Generalized lambda capture (init-capture) ([N3648]) * Generic (polymorphic) lambda expressions ([N3649]) -[n2657]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm +[n2657]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm [n2927]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2927.pdf [N3648]: https://isocpp.org/files/papers/N3648.html [N3649]: https://isocpp.org/files/papers/N3649.html @@ -980,7 +988,7 @@ References from C++23 ### Additional Permitted Features * `constexpr` -([n2235](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf)) +([n2235](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf)) ([n3652](https://isocpp.org/files/papers/N3652.html)) * Sized deallocation @@ -1087,14 +1095,14 @@ in HotSpot code because of the "no implicit boolean" guideline.) * Avoid covariant return types. -* Avoid `goto` statements. +* Avoid `goto` statements. ### Undecided Features This list is incomplete; it serves to explicitly call out some features that have not yet been discussed. -* Trailing return type syntax for functions +* Trailing return type syntax for functions ([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm)) * Variable templates @@ -1108,7 +1116,7 @@ features that have not yet been discussed. * Rvalue references and move semantics -[ADL]: https://en.cppreference.com/w/cpp/language/adl +[ADL]: https://en.cppreference.com/w/cpp/language/adl "Argument Dependent Lookup" [ODR]: https://en.cppreference.com/w/cpp/language/definition -- GitLab From 81d63734bc2e2a18063cb6afbc53f8813a0ba880 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Tue, 22 Mar 2022 01:20:31 +0000 Subject: [PATCH 108/237] 8282469: Allow considered use of C++ thread_local in Hotspot Reviewed-by: kbarrett, dcubed --- src/hotspot/share/memory/operator_new.cpp | 100 ------------------ .../share/utilities/globalDefinitions.hpp | 4 + 2 files changed, 4 insertions(+), 100 deletions(-) delete mode 100644 src/hotspot/share/memory/operator_new.cpp diff --git a/src/hotspot/share/memory/operator_new.cpp b/src/hotspot/share/memory/operator_new.cpp deleted file mode 100644 index 357e26f9c88..00000000000 --- a/src/hotspot/share/memory/operator_new.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 1997, 2021, 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. - * - */ - -#include "precompiled.hpp" -#include "utilities/debug.hpp" - -#include - -//-------------------------------------------------------------------------------------- -// Non-product code - -#ifndef PRODUCT -// The global operator new should never be called since it will usually indicate -// a memory leak. Use CHeapObj as the base class of such objects to make it explicit -// that they're allocated on the C heap. -// Commented out in product version to avoid conflicts with third-party C++ native code. -// -// In C++98/03 the throwing new operators are defined with the following signature: -// -// void* operator new(std::size_tsize) throw(std::bad_alloc); -// void* operator new[](std::size_tsize) throw(std::bad_alloc); -// -// while all the other (non-throwing) new and delete operators are defined with an empty -// throw clause (i.e. "operator delete(void* p) throw()") which means that they do not -// throw any exceptions (see section 18.4 of the C++ standard). -// -// In the new C++11/14 standard, the signature of the throwing new operators was changed -// by completely omitting the throw clause (which effectively means they could throw any -// exception) while all the other new/delete operators where changed to have a 'nothrow' -// clause instead of an empty throw clause. -// -// Unfortunately, the support for exception specifications among C++ compilers is still -// very fragile. While some more strict compilers like AIX xlC or HP aCC reject to -// override the default throwing new operator with a user operator with an empty throw() -// clause, the MS Visual C++ compiler warns for every non-empty throw clause like -// throw(std::bad_alloc) that it will ignore the exception specification. The following -// operator definitions have been checked to correctly work with all currently supported -// compilers and they should be upwards compatible with C++11/14. Therefore -// PLEASE BE CAREFUL if you change the signature of the following operators! - -static void * zero = (void *) 0; - -void* operator new(size_t size) /* throw(std::bad_alloc) */ { - fatal("Should not call global operator new"); - return zero; -} - -void* operator new [](size_t size) /* throw(std::bad_alloc) */ { - fatal("Should not call global operator new[]"); - return zero; -} - -void* operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() { - fatal("Should not call global operator new"); - return 0; -} - -void* operator new [](size_t size, std::nothrow_t& nothrow_constant) throw() { - fatal("Should not call global operator new[]"); - return 0; -} - -void operator delete(void* p) throw() { - fatal("Should not call global delete"); -} - -void operator delete [](void* p) throw() { - fatal("Should not call global delete []"); -} - -void operator delete(void* p, size_t size) throw() { - fatal("Should not call global sized delete"); -} - -void operator delete [](void* p, size_t size) throw() { - fatal("Should not call global sized delete []"); -} - -#endif // Non-product diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 1b0b90e70fc..fdd3db8875a 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -1219,5 +1219,9 @@ template bool primitive_equals(const K& k0, const K& k1) { return k0 == k1; } +//---------------------------------------------------------------------------------------------------- + +// Allow use of C++ thread_local when approved - see JDK-8282469. +#define APPROVED_CPP_THREAD_LOCAL thread_local #endif // SHARE_UTILITIES_GLOBALDEFINITIONS_HPP -- GitLab From 849b19523a666bd2ec110876bfd5679b20be77f4 Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Tue, 22 Mar 2022 01:28:06 +0000 Subject: [PATCH 109/237] 8282937: Write a regression test for JDK-4820080 Reviewed-by: serb --- .../4820080/JSplitPaneDragColorTest.java | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 test/jdk/javax/swing/JSplitPane/4820080/JSplitPaneDragColorTest.java diff --git a/test/jdk/javax/swing/JSplitPane/4820080/JSplitPaneDragColorTest.java b/test/jdk/javax/swing/JSplitPane/4820080/JSplitPaneDragColorTest.java new file mode 100644 index 00000000000..7e107f1265c --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/4820080/JSplitPaneDragColorTest.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2003, 2022, 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. + */ + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.InputEvent; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.imageio.ImageIO; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4820080 + * @summary This test confirms that the Drag color of JSplitPane divider should + * be the user specified one(Red here). + * @run main JSplitPaneDragColorTest + */ +public class JSplitPaneDragColorTest { + + // Tolerance is set inorder to negate small differences in pixel color values, + // especially in Mac machines. + private final static int COLOR_TOLERANCE = 9; + private static final Color EXPECTED_DRAG_COLOR = Color.RED; + private static JFrame frame; + private static JSplitPane pane; + private static Robot robot; + + public static void main(String[] args) throws Exception { + + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + // Skipping NimbusLookAndFeel & GTKLookAndFeel, + // as both are not supported for this feature - JDK-8075914, JDK-8075608 + List lafs = Arrays.stream(getInstalledLookAndFeels()) + .filter(laf -> !(laf.getName().contains("GTK") + || laf.getName().contains("Nimbus"))) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + Rectangle dividerRect = getDividerRect(); + + // Mouse click and right drag split pane divider + robot.mouseMove(dividerRect.x + 5, dividerRect.y + 36); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseMove(dividerRect.x + 15, dividerRect.y + 36); + robot.mouseMove(dividerRect.x + 5, dividerRect.y + 36); + + // Get the color of one of the pixels of the splitpane divider + // after the drag has started. Ideally it should be the + // SplitPaneDivider.draggingColor set by user, otherwise the test fails + final Color actualDragColor = robot.getPixelColor(dividerRect.x + 2, + dividerRect.y + 2); + if (checkDragColor(actualDragColor)) { + System.out.println("Test passed in " + laf); + } else { + System.out.print("Expected pixel color = "); + System.out.printf("%X", EXPECTED_DRAG_COLOR.getRGB()); + System.out.print(", but actual color = "); + System.out.printf("%X", actualDragColor.getRGB()); + System.out.println(); + captureScreen(); + throw new RuntimeException("Test failed, drag color is wrong in " + + laf); + } + } finally { + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + SwingUtilities.invokeAndWait(JSplitPaneDragColorTest::disposeFrame); + } + } + } + + private static boolean checkDragColor(Color actualDragColor) { + int actualRed = actualDragColor.getRed(); + int actualGreen = actualDragColor.getGreen(); + int actualBlue = actualDragColor.getBlue(); + int expectedRed = EXPECTED_DRAG_COLOR.getRed(); + int expectedGreen = EXPECTED_DRAG_COLOR.getGreen(); + int expectedBlue = EXPECTED_DRAG_COLOR.getBlue(); + + final double tolerance = Math.sqrt( + (actualRed - expectedRed) * (actualRed - expectedRed) + + (actualGreen - expectedGreen) * (actualGreen - expectedGreen) + + (actualBlue - expectedBlue) * (actualBlue - expectedBlue)); + return (tolerance <= COLOR_TOLERANCE); + } + + private static Rectangle getDividerRect() { + final AtomicReference rect = new AtomicReference<>(); + SwingUtilities.invokeLater(() -> { + javax.swing.plaf.basic.BasicSplitPaneUI ui = + (javax.swing.plaf.basic.BasicSplitPaneUI) pane.getUI(); + + javax.swing.plaf.basic.BasicSplitPaneDivider divider = ui.getDivider(); + Point dividerLoc = divider.getLocationOnScreen(); + rect.set(new Rectangle(dividerLoc.x, dividerLoc.y, divider.getWidth(), + divider.getHeight())); + }); + robot.waitForIdle(); + return rect.get(); + } + + private static void captureScreen() { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + try { + ImageIO.write( + robot.createScreenCapture(new Rectangle(0, 0, + screenSize.width, + screenSize.height)), + "png", + new File("screen1.png") + ); + } catch (IOException ignore) { + } + } + + private static void createUI() { + frame = new JFrame(); + UIManager.put("SplitPaneDivider.draggingColor", EXPECTED_DRAG_COLOR); + JLabel l1 = new JLabel("LEFT LABEL", JLabel.CENTER); + JLabel l2 = new JLabel("RIGHT LABEL", JLabel.CENTER); + pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, l1, l2); + frame.setSize(400, 400); + pane.setDividerSize(15); + pane.setDividerLocation(frame.getSize().width / 2); + frame.getContentPane().add(pane, BorderLayout.CENTER); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} -- GitLab From 37fc77ef60dd97c4acc468ecfeb6753132974720 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Tue, 22 Mar 2022 07:54:41 +0000 Subject: [PATCH 110/237] 8283092: JMX subclass permission check redundant with strong encapsulation Reviewed-by: dfuchs, mchung --- .../lang/management/ManagementFactory.java | 3 +- .../management/spi/PlatformMBeanProvider.java | 18 +-- .../jdk/internal/agent/spi/AgentProvider.java | 19 +--- ...PlatformMBeanProviderConstructorCheck.java | 103 ++++++++++-------- 4 files changed, 63 insertions(+), 80 deletions(-) diff --git a/src/java.management/share/classes/java/lang/management/ManagementFactory.java b/src/java.management/share/classes/java/lang/management/ManagementFactory.java index 13db85d0f09..375f0ebb719 100644 --- a/src/java.management/share/classes/java/lang/management/ManagementFactory.java +++ b/src/java.management/share/classes/java/lang/management/ManagementFactory.java @@ -936,8 +936,7 @@ public class ManagementFactory { all.add(new DefaultPlatformMBeanProvider()); return all; } - }, null, new FilePermission("<>", "read"), - new RuntimePermission("sun.management.spi.PlatformMBeanProvider.subclass")); + }, null, new FilePermission("<>", "read")); // load all platform components into a map var map = new HashMap>(); diff --git a/src/java.management/share/classes/sun/management/spi/PlatformMBeanProvider.java b/src/java.management/share/classes/sun/management/spi/PlatformMBeanProvider.java index 93779f0a811..12472cabfcc 100644 --- a/src/java.management/share/classes/sun/management/spi/PlatformMBeanProvider.java +++ b/src/java.management/share/classes/sun/management/spi/PlatformMBeanProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -203,15 +203,8 @@ public abstract class PlatformMBeanProvider { /** * Instantiates a new PlatformMBeanProvider. - * - * @throws SecurityException if the subclass (and calling code) does not - * have {@code RuntimePermission("sun.management.spi.PlatformMBeanProvider.subclass")} */ protected PlatformMBeanProvider () { - this(checkSubclassPermission()); - } - - private PlatformMBeanProvider(Void unused) { } /** @@ -222,13 +215,4 @@ public abstract class PlatformMBeanProvider { * MBeans provided by this provider. */ public abstract List> getPlatformComponentList(); - - private static Void checkSubclassPermission() { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission(PlatformMBeanProvider.class.getName()+".subclass")); - } - return null; - } } diff --git a/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java b/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java index ea42d597486..395961cad96 100644 --- a/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java +++ b/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, 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 @@ -33,25 +33,8 @@ public abstract class AgentProvider { /** * Instantiates a new AgentProvider. - * - * @throws SecurityException if the subclass (and calling code) does not - * have - * {@code RuntimePermission("sun.management.spi.AgentProvider.subclass")} */ protected AgentProvider() { - this(checkSubclassPermission()); - } - - private AgentProvider(Void unused) { - } - - private static Void checkSubclassPermission() { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new RuntimePermission(AgentProvider.class.getName() + ".subclass")); - } - return null; } /** diff --git a/test/jdk/sun/management/PlatformMBeanProviderConstructorCheck.java b/test/jdk/sun/management/PlatformMBeanProviderConstructorCheck.java index b7b4edc8c98..16fee912a7c 100644 --- a/test/jdk/sun/management/PlatformMBeanProviderConstructorCheck.java +++ b/test/jdk/sun/management/PlatformMBeanProviderConstructorCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -21,63 +21,79 @@ * questions. */ -import java.security.AccessControlException; -import java.security.Permission; -import java.security.Policy; -import java.security.ProtectionDomain; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; import java.util.List; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import static jdk.test.lib.Asserts.*; + /* * @test - * @bug 8042901 - * @summary Check permission for PlatformMBeanProvider Constructor + * @library /test/lib + * @build jdk.test.lib.Asserts + * @bug 8042901 8283092 + * @summary Check encapsulation of PlatformMBeanProvider Constructor * @modules java.management/sun.management.spi - * @author Shanliang Jiang - * @run main/othervm -Djava.security.manager=allow PlatformMBeanProviderConstructorCheck + * @run main PlatformMBeanProviderConstructorCheck */ public class PlatformMBeanProviderConstructorCheck { - public static void main(String[] args) throws Exception { - Policy origPolicy = Policy.getPolicy(); - SecurityManager origSM = System.getSecurityManager(); - try { - System.out.println("---PlatformMBeanProviderConstructorCheck starting..."); - Policy.setPolicy(new MyPolicy()); - System.setSecurityManager(new SecurityManager()); + /** + * jtreg invokes this test with module arguments that permit compilation + * of the MyProvider class, which extends PlatformMBeanProvider. + * First check we can invoke that class, then re-invoke ourself without + * those module arguments, and expect a failure calling MyProvider. + */ + public static void main(String[] args) throws Exception { + System.out.println("---PlatformMBeanProviderConstructorCheck:"); + boolean expectedFail = false; - System.out.println("---PlatformMBeanProviderConstructorCheck Testing without permission..."); - try { - new MyProvider(); - throw new RuntimeException("Does not get expected AccessControlException!"); - } catch (AccessControlException ace) { - System.out.println("---PlatformMBeanProviderConstructorCheck got the expected exception: " - + ace); + // Recognise argument to signify we were re-invoked, and MyProvider should fail: + if (args.length == 1) { + if (args[0].equals("--nomoduleargs")) { + expectedFail = true; + verifyNoModuleArguments(); + } else { + throw new RuntimeException("unknown argument: '" + args[0] + "'"); } - - System.out.println("---PlatformMBeanProviderConstructorCheck Testing with permission..."); - MyPolicy.allowed = true; + } + System.out.println("---PlatformMBeanProviderConstructorCheck: invoke MyProvider with expectedFail = " + expectedFail); + Throwable e = null; + try { new MyProvider(); - - System.out.println("---PlatformMBeanProviderConstructorCheck PASSED!"); - } finally { - System.setSecurityManager(origSM); - Policy.setPolicy(origPolicy); + } catch (IllegalAccessError iae) { + System.out.println("---PlatformMBeanProviderConstructorCheck got exception: " + iae); + e = iae; } - } - private static class MyPolicy extends Policy { - private static String permName = "sun.management.spi.PlatformMBeanProvider.subclass"; - private static boolean allowed = false; + if (!expectedFail) { + // This was the first invocation, should have worked OK: + assertNull(e); + System.out.println("---PlatformMBeanProviderConstructorCheck PASSED (1) (expectedFail = " + expectedFail + ")"); - @Override - public boolean implies(ProtectionDomain domain, Permission permission) { - if (permName.equals(permission.getName())) { - System.out.println("---MyPolicy-implies checks permission for " - +permName+" and returns "+allowed); + // Re-invoke this test to check failure: + System.out.println("---PlatformMBeanProviderConstructorCheck: re-invoke without --add-modules or --add-exports"); + OutputAnalyzer output = ProcessTools.executeTestJava("PlatformMBeanProviderConstructorCheck", "--nomoduleargs"); + output.reportDiagnosticSummary(); + output.shouldContain("java.lang.IllegalAccessError: superclass access check failed:"); + output.shouldContain(" module java.management does not export sun.management.spi to "); + output.shouldNotContain("MyProvider constructor."); + } else { + // This was the re-invocation without module access, should fail: + assertNotNull(e); + System.out.println("---PlatformMBeanProviderConstructorCheck PASSED (2) (expectedFail = " + expectedFail + ")"); + } + } - return allowed; - } else { - return true; + private static void verifyNoModuleArguments() { + RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean(); + for (String s : mxbean.getInputArguments()) { + if (s.startsWith("--add-modules") || s.startsWith("--add-exports")) { + System.out.println("arg: " + s); + throw new RuntimeException("argument list contains: " + s); } } } @@ -85,6 +101,7 @@ public class PlatformMBeanProviderConstructorCheck { private static class MyProvider extends sun.management.spi.PlatformMBeanProvider { @Override public List> getPlatformComponentList() { + System.out.println("MyProvider constructor."); return null; } } -- GitLab From a6fd0b21ddc1575366eed8d47191f6b14b2d7cb6 Mon Sep 17 00:00:00 2001 From: Srinivas Mandalika Date: Tue, 22 Mar 2022 09:20:12 +0000 Subject: [PATCH 111/237] 8283087: Create a test or JDK-4715503 Reviewed-by: serb --- ...ssibleJTableCellBoundingRectangleTest.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 test/jdk/javax/accessibility/4715503/AccessibleJTableCellBoundingRectangleTest.java diff --git a/test/jdk/javax/accessibility/4715503/AccessibleJTableCellBoundingRectangleTest.java b/test/jdk/javax/accessibility/4715503/AccessibleJTableCellBoundingRectangleTest.java new file mode 100644 index 00000000000..716925a51e6 --- /dev/null +++ b/test/jdk/javax/accessibility/4715503/AccessibleJTableCellBoundingRectangleTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022, 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 + * @key headful + * @bug 4715503 + * @summary AccessibleTable cannot get the Bounding Rectangle of Table Header Cells. + * @run main AccessibleJTableCellBoundingRectangleTest + */ + +import java.awt.Rectangle; +import java.awt.Robot; + +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.SwingUtilities; + +public class AccessibleJTableCellBoundingRectangleTest { + private static JTable jTable; + private static JFrame jFrame; + + private static Object[][] rowData = { { "01", "02", "03", "04", "05" }, + { "11", "12", "13", "14", "15" }, { "21", "22", "23", "24", "25" }, + { "31", "32", "33", "34", "35" }, { "41", "42", "43", "44", "45" } }; + + private static Object[] colNames = { "1", "2", "3", "4", "5" }; + + private static void doTest() throws Exception { + try { + SwingUtilities.invokeAndWait(() -> createGUI()); + Robot robot = new Robot(); + robot.setAutoDelay(500); + robot.waitForIdle(); + + for (int i = 0; i <= colNames.length - 1; i++) { + try { + Rectangle bounds = + jTable.getTableHeader().getAccessibleContext().getAccessibleChild(i) + .getAccessibleContext().getAccessibleComponent().getBounds(); + + if (bounds != null) { + System.out.println("Column " + i + " Bounds: " + bounds); + } else { + throw new RuntimeException( + "Bounding Rectangles getting bounding rectangle for table header cells is null"); + } + } catch (Exception e) { + throw new RuntimeException("Bounding Rectangles getting bounding rectangle for " + + "table header cells threw an exception:\n" + e); + } + } + } finally { + SwingUtilities.invokeAndWait(() -> jFrame.dispose()); + } + } + + private static void createGUI() { + jTable = new JTable(rowData, colNames); + jFrame = new JFrame(); + jFrame.setBounds(100, 100, 300, 300); + jFrame.getContentPane().add(jTable); + jFrame.setVisible(true); + } + + public static void main(String args[]) throws Exception { + doTest(); + System.out.println("Test Passed"); + } +} + -- GitLab From 85628a871df3fdeec1b422d1c01c222abe45d0a8 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 22 Mar 2022 10:34:33 +0000 Subject: [PATCH 112/237] 8282592: C2: assert(false) failed: graph should be schedulable Reviewed-by: chagedorn, thartmann --- src/hotspot/share/opto/loopTransform.cpp | 6 ++ src/hotspot/share/opto/loopopts.cpp | 2 + .../c2/irTests/TestSkeletonPredicates.java | 78 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 4257b0fd6e5..dc9c2064ed9 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1954,6 +1954,12 @@ bool IdealLoopTree::is_invariant(Node* n) const { } void PhaseIdealLoop::update_main_loop_skeleton_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, int stride_con) { + if (init->Opcode() == Op_CastII) { + // skip over the cast added by PhaseIdealLoop::cast_incr_before_loop() when pre/post/main loops are created because + // it can get in the way of type propagation + assert(((CastIINode*)init)->carry_dependency() && loop_head->skip_predicates() == init->in(0), "casted iv phi from pre loop expected"); + init = init->in(1); + } // Search for skeleton predicates and update them according to the new stride Node* entry = ctrl; Node* prev_proj = ctrl; diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index a7c82ad2ee1..dc9cddfdabf 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -3828,6 +3828,8 @@ void PhaseIdealLoop::reorg_offsets(IdealLoopTree *loop) { set_ctrl(neg_stride, C->root()); Node *post = new AddINode(opaq, neg_stride); register_new_node(post, c); + post = new CastIINode(post, phi->bottom_type()); // preserve the iv phi's type + register_new_node(post, c); _igvn.rehash_node_delayed(use); for (uint j = 1; j < use->req(); j++) { if (use->in(j) == phi) diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java b/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java new file mode 100644 index 00000000000..79bcd16cfb2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestSkeletonPredicates.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Utils; +import java.util.Random; + +/* + * @test + * @bug 8278228 + * @summary C2: Improve identical back-to-back if elimination + * @library /test/lib / + * @run driver compiler.c2.irTests.TestSkeletonPredicates + */ + +public class TestSkeletonPredicates { + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:-UseLoopPredicate", "-XX:LoopUnrollLimit=240", "-XX:+StressIGVN", "-XX:StressSeed=255527877"); + TestFramework.runWithFlags("-XX:-UseLoopPredicate", "-XX:LoopUnrollLimit=240", "-XX:+StressIGVN"); + } + + static volatile int barrier; + + @ForceInline + static boolean test1_helper(int start, int stop, double[] array1, double[] array2) { + for (int i = start; i < stop; i++) { + if ((i % 2) == 0) { + array1[i] = 42.42; + } else { + barrier = 0x42; + } + } + return false; + } + + @Test + @IR(counts = { IRNode.COUNTEDLOOP, "3" }) + static double[] test1(int stop, double[] array2) { + double[] array1 = null; + array1 = new double[10]; + for (int j = 0; j < stop; j++) { + if (test1_helper(8, j, array1, array2)) { + return null; + } + } + return array1; + } + + @Run(test = "test1") + void test1_runner() { + double[] array2 = new double[10]; + double[] array3 = new double[1000]; + test1_helper(1, 1000, array3, array3); + test1(11, array3); + } +} -- GitLab From c0f984e5fbba7b44fa7b0a4309896ef9ccb4e666 Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Tue, 22 Mar 2022 13:30:26 +0000 Subject: [PATCH 113/237] 8283456: Make CompiledICHolder::live_count/live_not_claimed_count debug only Reviewed-by: dholmes --- src/hotspot/share/oops/compiledICHolder.cpp | 5 +++-- src/hotspot/share/oops/compiledICHolder.hpp | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/oops/compiledICHolder.cpp b/src/hotspot/share/oops/compiledICHolder.cpp index a285998a236..c6ca6be2030 100644 --- a/src/hotspot/share/oops/compiledICHolder.cpp +++ b/src/hotspot/share/oops/compiledICHolder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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 @@ -26,9 +26,10 @@ #include "oops/compiledICHolder.hpp" #include "runtime/atomic.hpp" +#ifdef ASSERT volatile int CompiledICHolder::_live_count; volatile int CompiledICHolder::_live_not_claimed_count; - +#endif CompiledICHolder::CompiledICHolder(Metadata* metadata, Klass* klass, bool is_method) : _holder_metadata(metadata), _holder_klass(klass), _is_metadata_method(is_method) { diff --git a/src/hotspot/share/oops/compiledICHolder.hpp b/src/hotspot/share/oops/compiledICHolder.hpp index b3d0c8715bf..5ddcf07d9ce 100644 --- a/src/hotspot/share/oops/compiledICHolder.hpp +++ b/src/hotspot/share/oops/compiledICHolder.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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 @@ -44,9 +44,11 @@ class CompiledICHolder : public CHeapObj { friend class VMStructs; private: +#ifdef ASSERT static volatile int _live_count; // allocated static volatile int _live_not_claimed_count; // allocated but not yet in use so not // reachable by iterating over nmethods +#endif Metadata* _holder_metadata; Klass* _holder_klass; // to avoid name conflict with oopDesc::_klass @@ -58,8 +60,10 @@ class CompiledICHolder : public CHeapObj { CompiledICHolder(Metadata* metadata, Klass* klass, bool is_method = true); ~CompiledICHolder() NOT_DEBUG_RETURN; +#ifdef ASSERT static int live_count() { return _live_count; } static int live_not_claimed_count() { return _live_not_claimed_count; } +#endif // accessors Klass* holder_klass() const { return _holder_klass; } -- GitLab From fabde3b7b8ed5e576febe8138c14696ccdf636d5 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Tue, 22 Mar 2022 14:06:49 +0000 Subject: [PATCH 114/237] 8283451: C2: assert(_base == Long) failed: Not a Long Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/phaseX.cpp | 4 +- .../jtreg/compiler/c2/TestModDivTopInput.java | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 0589d1eab0c..9df9a18dbf7 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1691,7 +1691,7 @@ bool PhaseIterGVN::no_dependent_zero_check(Node* n) const { case Op_DivI: case Op_ModI: { // Type of divisor includes 0? - if (n->in(2)->is_top()) { + if (type(n->in(2)) == Type::TOP) { // 'n' is dead. Treat as if zero check is still there to avoid any further optimizations. return false; } @@ -1701,7 +1701,7 @@ bool PhaseIterGVN::no_dependent_zero_check(Node* n) const { case Op_DivL: case Op_ModL: { // Type of divisor includes 0? - if (n->in(2)->is_top()) { + if (type(n->in(2)) == Type::TOP) { // 'n' is dead. Treat as if zero check is still there to avoid any further optimizations. return false; } diff --git a/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java b/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java new file mode 100644 index 00000000000..9e4ba1dd6f0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestModDivTopInput.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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 8283451 + * @summary C2: assert(_base == Long) failed: Not a Long + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM -XX:+StressGCM -XX:+StressCCP -XX:+StressIGVN + * -Xcomp -XX:CompileOnly=TestModDivTopInput -XX:-TieredCompilation -XX:StressSeed=87628618 TestModDivTopInput + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM -XX:+StressGCM -XX:+StressCCP -XX:+StressIGVN + * -Xcomp -XX:CompileOnly=TestModDivTopInput -XX:-TieredCompilation TestModDivTopInput + */ + +public class TestModDivTopInput { + + public static final int N = 400; + + public static float fFld=-2.447F; + public long lFld=-189L; + + public void mainTest(String[] strArr1) { + + int i18, i20=-14, i21, iArr2[]=new int[N]; + boolean b2=true; + double d2; + long l; + + init(iArr2, -13265); + + for (i18 = 13; i18 < 315; ++i18) { + if (b2) continue; + for (d2 = 5; d2 < 83; d2++) { + } + for (i21 = 4; i21 < 83; i21++) { + for (l = 1; 2 > l; l++) { + } + b2 = b2; + lFld %= (i20 | 1); + i20 = (int)fFld; + i20 += (int)d2; + } + } + } + + public static void main(String[] strArr) { + TestModDivTopInput _instance = new TestModDivTopInput(); + for (int i = 0; i < 10; i++ ) { + _instance.mainTest(strArr); + } + } + + static void init(int[] arr, int v) { + for (int i = 0; i < arr.length; i++) { + arr[i] = v; + } + } + +} -- GitLab From 557ff4b3558f95723ebaff680b8524b0cb979559 Mon Sep 17 00:00:00 2001 From: Jim Laskey Date: Tue, 22 Mar 2022 15:32:46 +0000 Subject: [PATCH 115/237] 8282625: Formatter caches Locale/DecimalFormatSymbols poorly Reviewed-by: naoto, rriggs, jpai --- .../java/text/DecimalFormatSymbols.java | 11 ++- .../share/classes/java/util/Formatter.java | 78 +++++++++---------- .../IntlTestDecimalFormatSymbols.java | 11 ++- 3 files changed, 58 insertions(+), 42 deletions(-) diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index 11fd24573ef..795e087a351 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -188,6 +188,15 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { return dfsyms; } + /** + * {@return locale used to create this instance} + * + * @since 19 + */ + public Locale getLocale() { + return locale; + } + /** * Gets the character used for zero. Different for Arabic, etc. * diff --git a/src/java.base/share/classes/java/util/Formatter.java b/src/java.base/share/classes/java/util/Formatter.java index 65f67656087..5c5859c767d 100644 --- a/src/java.base/share/classes/java/util/Formatter.java +++ b/src/java.base/share/classes/java/util/Formatter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -2008,15 +2008,41 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter; * @since 1.5 */ public final class Formatter implements Closeable, Flushable { + // Caching DecimalFormatSymbols. Non-volatile to avoid thread slamming. + private static DecimalFormatSymbols DFS = null; + private static DecimalFormatSymbols getDecimalFormatSymbols(Locale locale) { + // Capture local copy to avoid thread race. + DecimalFormatSymbols dfs = DFS; + if (dfs != null && dfs.getLocale().equals(locale)) { + return dfs; + } + // Fetch a new local instance of DecimalFormatSymbols. Note that DFS are mutable + // and this instance is reserved for Formatter. + dfs = DecimalFormatSymbols.getInstance(locale); + // Non-volatile here is acceptable heuristic. + DFS = dfs; + return dfs; + } + + // Use zero from cached DecimalFormatSymbols. + private static char getZero(Locale locale) { + return locale == null ? '0' : getDecimalFormatSymbols(locale).getZeroDigit(); + } + + // Use decimal separator from cached DecimalFormatSymbols. + private static char getDecimalSeparator(Locale locale) { + return locale == null ? '.' : getDecimalFormatSymbols(locale).getDecimalSeparator(); + } + + // Use grouping separator from cached DecimalFormatSymbols. + private static char getGroupingSeparator(Locale locale) { + return locale == null ? ',' : getDecimalFormatSymbols(locale).getGroupingSeparator(); + } + private Appendable a; private final Locale l; - private IOException lastException; - // Non-character value used to mark zero as uninitialized - private static final char ZERO_SENTINEL = '\uFFFE'; - private char zero = ZERO_SENTINEL; - /** * Returns a charset object for the given charset name. * @throws NullPointerException is csn is null @@ -2523,20 +2549,6 @@ public final class Formatter implements Closeable, Flushable { this(l, new BufferedWriter(new OutputStreamWriter(os, charset))); } - private char zero() { - char zero = this.zero; - if (zero == ZERO_SENTINEL) { - if ((l != null) && !l.equals(Locale.US)) { - DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - zero = dfs.getZeroDigit(); - } else { - zero = '0'; - } - this.zero = zero; - } - return zero; - } - /** * Returns the locale set by the construction of this formatter. * @@ -4498,14 +4510,6 @@ public final class Formatter implements Closeable, Flushable { throw new IllegalFormatConversionException(c, arg.getClass()); } - private char getZero(Formatter fmt, Locale l) { - if ((l != null) && !l.equals(fmt.locale())) { - DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - return dfs.getZeroDigit(); - } - return fmt.zero(); - } - private StringBuilder localizedMagnitude(Formatter fmt, StringBuilder sb, long value, int flags, int width, Locale l) { return localizedMagnitude(fmt, sb, Long.toString(value, 10), 0, flags, width, l); @@ -4519,7 +4523,7 @@ public final class Formatter implements Closeable, Flushable { } int begin = sb.length(); - char zero = getZero(fmt, l); + char zero = getZero(l); // determine localized grouping separator and size char grpSep = '\0'; @@ -4536,21 +4540,15 @@ public final class Formatter implements Closeable, Flushable { } if (dot < len) { - if (l == null || l.equals(Locale.US)) { - decSep = '.'; - } else { - DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - decSep = dfs.getDecimalSeparator(); - } + decSep = getDecimalSeparator(l); } if (Flags.contains(f, Flags.GROUP)) { + grpSep = getGroupingSeparator(l); + if (l == null || l.equals(Locale.US)) { - grpSep = ','; grpSize = 3; } else { - DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l); - grpSep = dfs.getGroupingSeparator(); DecimalFormat df = null; NumberFormat nf = NumberFormat.getNumberInstance(l); if (nf instanceof DecimalFormat) { @@ -4567,7 +4565,7 @@ public final class Formatter implements Closeable, Flushable { } String[] all = adapter.getLocaleResources(l) .getNumberPatterns(); - df = new DecimalFormat(all[0], dfs); + df = new DecimalFormat(all[0], getDecimalFormatSymbols(l)); } grpSize = df.getGroupingSize(); // Some locales do not use grouping (the number @@ -4612,7 +4610,7 @@ public final class Formatter implements Closeable, Flushable { // group separators is added for any locale. private void localizedMagnitudeExp(Formatter fmt, StringBuilder sb, char[] value, final int offset, Locale l) { - char zero = getZero(fmt, l); + char zero = getZero(l); int len = value.length; for (int j = offset; j < len; j++) { diff --git a/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java b/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java index cd19fee1e35..30905ee46f1 100644 --- a/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java +++ b/test/jdk/java/text/Format/NumberFormat/IntlTestDecimalFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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,6 +23,7 @@ /* * @test + * @bug 8282625 * @library /java/text/testlib * @summary test International Decimal Format Symbols */ @@ -60,6 +61,14 @@ public class IntlTestDecimalFormatSymbols extends IntlTest // just do some VERY basic tests to make sure that get/set work + if (!fr.getLocale().equals(Locale.FRENCH)) { + errln("ERROR: French DecimalFormatSymbols not Locale.FRENCH"); + } + + if (!en.getLocale().equals(Locale.ENGLISH)) { + errln("ERROR: English DecimalFormatSymbols not Locale.ENGLISH"); + } + char zero = en.getZeroDigit(); fr.setZeroDigit(zero); if(fr.getZeroDigit() != en.getZeroDigit()) { -- GitLab From d29c7e740d51cb50a1aa0a941a5b460782f8da68 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Tue, 22 Mar 2022 16:23:23 +0000 Subject: [PATCH 116/237] 8282590: C2: assert(addp->is_AddP() && addp->outcnt() > 0) failed: Don't process dead nodes Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/arraycopynode.cpp | 27 ++++++++++++++----- src/hotspot/share/opto/subtypenode.cpp | 4 +-- .../arraycopy/TestArrayCopyAsLoadsStores.java | 13 +++++++++ 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp index 11560f6419b..b0f30703f91 100644 --- a/src/hotspot/share/opto/arraycopynode.cpp +++ b/src/hotspot/share/opto/arraycopynode.cpp @@ -189,9 +189,8 @@ Node* ArrayCopyNode::try_clone_instance(PhaseGVN *phase, bool can_reshape, int c } MergeMemNode* mem = phase->transform(MergeMemNode::make(in_mem))->as_MergeMem(); - PhaseIterGVN* igvn = phase->is_IterGVN(); - if (igvn != NULL) { - igvn->_worklist.push(mem); + if (can_reshape) { + phase->is_IterGVN()->_worklist.push(mem); } if (!inst_src->klass_is_exact()) { @@ -294,9 +293,17 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, uint header = arrayOopDesc::base_offset_in_bytes(dest_elem); src_offset = Compile::conv_I2X_index(phase, src_offset, ary_src->size()); + if (src_offset->is_top()) { + // Offset is out of bounds (the ArrayCopyNode will be removed) + return false; + } dest_offset = Compile::conv_I2X_index(phase, dest_offset, ary_dest->size()); - if (src_offset->is_top() || dest_offset->is_top()) { + if (dest_offset->is_top()) { // Offset is out of bounds (the ArrayCopyNode will be removed) + if (can_reshape) { + // record src_offset, so it can be deleted later (if it is dead) + phase->is_IterGVN()->_worklist.push(src_offset); + } return false; } @@ -316,9 +323,6 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, disjoint_bases = true; - adr_src = phase->transform(new AddPNode(base_src, base_src, src_offset)); - adr_dest = phase->transform(new AddPNode(base_dest, base_dest, dest_offset)); - BasicType elem = ary_src->klass()->as_array_klass()->element_type()->basic_type(); if (is_reference_type(elem)) { elem = T_OBJECT; @@ -329,6 +333,9 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape, return false; } + adr_src = phase->transform(new AddPNode(base_src, base_src, src_offset)); + adr_dest = phase->transform(new AddPNode(base_dest, base_dest, dest_offset)); + // The address is offseted to an aligned address where a raw copy would start. // If the clone copy is decomposed into load-stores - the address is adjusted to // point at where the array starts. @@ -566,6 +573,8 @@ Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (!prepare_array_copy(phase, can_reshape, adr_src, base_src, adr_dest, base_dest, copy_type, value_type, disjoint_bases)) { + assert(adr_src == NULL, "no node can be left behind"); + assert(adr_dest == NULL, "no node can be left behind"); return NULL; } @@ -629,6 +638,10 @@ Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) { } if (!finish_transform(phase, can_reshape, ctl, mem)) { + if (can_reshape) { + // put in worklist, so that if it happens to be dead it is removed + phase->is_IterGVN()->_worklist.push(mem); + } return NULL; } diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp index 10604cfebcc..c90b74b7d22 100644 --- a/src/hotspot/share/opto/subtypenode.cpp +++ b/src/hotspot/share/opto/subtypenode.cpp @@ -135,7 +135,7 @@ Node *SubTypeCheckNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* obj = AddPNode::Ideal_base_and_offset(addr, phase, con); if (con == oopDesc::klass_offset_in_bytes() && obj != NULL) { assert(is_oop(phase, obj), "only for oop input"); - set_req(ObjOrSubKlass, obj); + set_req_X(ObjOrSubKlass, obj, phase); return this; } } @@ -144,7 +144,7 @@ Node *SubTypeCheckNode::Ideal(PhaseGVN* phase, bool can_reshape) { Node* allocated_klass = AllocateNode::Ideal_klass(obj_or_subklass, phase); if (allocated_klass != NULL) { assert(is_oop(phase, obj_or_subklass), "only for oop input"); - set_req(ObjOrSubKlass, allocated_klass); + set_req_X(ObjOrSubKlass, allocated_klass, phase); return this; } diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java index 4c4c38848d8..103e99fefef 100644 --- a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyAsLoadsStores.java @@ -38,6 +38,19 @@ * compiler.arraycopy.TestArrayCopyAsLoadsStores */ +/* + * @test + * @bug 8282590 + * @library / + * + * @run main/othervm -ea -XX:-BackgroundCompilation -XX:-UseOnStackReplacement + * -XX:CompileCommand=dontinline,compiler.arraycopy.TestArrayCopyAsLoadsStores::m* + * -XX:TypeProfileLevel=200 + * -XX:+IgnoreUnrecognizedVMOptions -XX:+StressArrayCopyMacroNode + * -XX:-TieredCompilation -XX:+StressReflectiveCode -XX:-ReduceInitialCardMarks + * compiler.arraycopy.TestArrayCopyAsLoadsStores + */ + package compiler.arraycopy; import java.util.Arrays; -- GitLab From f7d21c3523d87584b62a1143bfe52d067cf77519 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Tue, 22 Mar 2022 16:26:23 +0000 Subject: [PATCH 117/237] 8283480: Make AbstractStringBuilder sealed Reviewed-by: jjg, rriggs, jlaskey, dfuchs --- .../share/classes/java/lang/AbstractStringBuilder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index cf83c825d38..fed3a6f9178 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -56,7 +56,8 @@ import static java.lang.String.checkOffset; * @author Ulf Zibis * @since 1.5 */ -abstract class AbstractStringBuilder implements Appendable, CharSequence { +abstract sealed class AbstractStringBuilder implements Appendable, CharSequence + permits StringBuilder, StringBuffer { /** * The value is used for character storage. */ -- GitLab From 33eb89dfeb4a43e1ad2c3dd657ec3b6ee7abbb3a Mon Sep 17 00:00:00 2001 From: Phil Race Date: Tue, 22 Mar 2022 21:48:42 +0000 Subject: [PATCH 118/237] 8283457: [macos] libpng build failures with Xcode13.3 Reviewed-by: erikj --- make/modules/java.desktop/lib/Awt2dLibraries.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index a0c40825546..3cf8ca8a820 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -742,7 +742,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) maybe-uninitialized shift-negative-value implicit-fallthrough \ unused-function, \ DISABLED_WARNINGS_clang := incompatible-pointer-types sign-compare \ - deprecated-declarations, \ + deprecated-declarations null-pointer-subtraction, \ DISABLED_WARNINGS_microsoft := 4018 4244 4267, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ -- GitLab From 8cc12350294c202ae4050471587b95135a9f6ac6 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 23 Mar 2022 00:06:53 +0000 Subject: [PATCH 119/237] 8282952: Thread::exit should be immune to Thread.stop Reviewed-by: dcubed, pchilanomate, alanb --- src/hotspot/share/runtime/thread.cpp | 36 ++++++++++++--------- src/hotspot/share/runtime/thread.hpp | 17 +++++++--- src/hotspot/share/runtime/thread.inline.hpp | 13 +++++++- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index eb6bce1fdbb..c1e327d40a5 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -1373,23 +1373,24 @@ void JavaThread::exit(bool destroy_vm, ExitType exit_type) { } } - // Call Thread.exit(). We try 3 times in case we got another Thread.stop during - // the execution of the method. If that is not enough, then we don't really care. Thread.stop - // is deprecated anyhow. if (!is_Compiler_thread()) { - int count = 3; - while (java_lang_Thread::threadGroup(threadObj()) != NULL && (count-- > 0)) { - EXCEPTION_MARK; - JavaValue result(T_VOID); - Klass* thread_klass = vmClasses::Thread_klass(); - JavaCalls::call_virtual(&result, - threadObj, thread_klass, - vmSymbols::exit_method_name(), - vmSymbols::void_method_signature(), - THREAD); - CLEAR_PENDING_EXCEPTION; - } + // We have finished executing user-defined Java code and now have to do the + // implementation specific clean-up by calling Thread.exit(). We prevent any + // asynchronous exceptions from being delivered while in Thread.exit() + // to ensure the clean-up is not corrupted. + NoAsyncExceptionDeliveryMark _no_async(this); + + EXCEPTION_MARK; + JavaValue result(T_VOID); + Klass* thread_klass = vmClasses::Thread_klass(); + JavaCalls::call_virtual(&result, + threadObj, thread_klass, + vmSymbols::exit_method_name(), + vmSymbols::void_method_signature(), + THREAD); + CLEAR_PENDING_EXCEPTION; } + // notify JVMTI if (JvmtiExport::should_post_thread_life()) { JvmtiExport::post_thread_end(this); @@ -1592,7 +1593,7 @@ void JavaThread::check_and_handle_async_exceptions() { // If we are at a polling page safepoint (not a poll return) // then we must defer async exception because live registers // will be clobbered by the exception path. Poll return is - // ok because the call we a returning from already collides + // ok because the call we are returning from already collides // with exception handling registers and so there is no issue. // (The exception handling path kills call result registers but // this is ok since the exception kills the result anyway). @@ -1613,6 +1614,9 @@ void JavaThread::check_and_handle_async_exceptions() { } if (!clear_async_exception_condition()) { + if ((_suspend_flags & _async_delivery_disabled) != 0) { + log_info(exceptions)("Async exception delivery is disabled"); + } return; } diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 0d56f3dc682..4256a44c39c 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -785,9 +785,10 @@ class JavaThread: public Thread { enum SuspendFlags { // NOTE: avoid using the sign-bit as cc generates different test code // when the sign-bit is used, and sometimes incorrectly - see CR 6398077 - _has_async_exception = 0x00000001U, // there is a pending async exception - _trace_flag = 0x00000004U, // call tracing backend - _obj_deopt = 0x00000008U // suspend for object reallocation and relocking for JVMTI agent + _has_async_exception = 0x00000001U, // there is a pending async exception + _async_delivery_disabled = 0x00000002U, // async exception delivery is disabled + _trace_flag = 0x00000004U, // call tracing backend + _obj_deopt = 0x00000008U // suspend for object reallocation and relocking for JVMTI agent }; // various suspension related flags - atomically updated @@ -815,7 +816,8 @@ class JavaThread: public Thread { inline bool clear_async_exception_condition(); public: bool has_async_exception_condition() { - return (_suspend_flags & _has_async_exception) != 0; + return (_suspend_flags & _has_async_exception) != 0 && + (_suspend_flags & _async_delivery_disabled) == 0; } inline void set_pending_async_exception(oop e); inline void set_pending_unsafe_access_error(); @@ -823,6 +825,13 @@ class JavaThread: public Thread { void send_thread_stop(oop throwable); void check_and_handle_async_exceptions(); + class NoAsyncExceptionDeliveryMark : public StackObj { + friend JavaThread; + JavaThread *_target; + inline NoAsyncExceptionDeliveryMark(JavaThread *t); + inline ~NoAsyncExceptionDeliveryMark(); + }; + // Safepoint support public: // Expose _thread_state for SafeFetchInt() volatile JavaThreadState _thread_state; diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp index 7d27a3bf257..cdb8d9abb23 100644 --- a/src/hotspot/share/runtime/thread.inline.hpp +++ b/src/hotspot/share/runtime/thread.inline.hpp @@ -124,7 +124,9 @@ inline void JavaThread::clear_obj_deopt_flag() { inline bool JavaThread::clear_async_exception_condition() { bool ret = has_async_exception_condition(); - clear_suspend_flag(_has_async_exception); + if (ret) { + clear_suspend_flag(_has_async_exception); + } return ret; } @@ -138,6 +140,15 @@ inline void JavaThread::set_pending_unsafe_access_error() { DEBUG_ONLY(_is_unsafe_access_error = true); } + +inline JavaThread::NoAsyncExceptionDeliveryMark::NoAsyncExceptionDeliveryMark(JavaThread *t) : _target(t) { + assert((_target->_suspend_flags & _async_delivery_disabled) == 0, "Nesting is not supported"); + _target->set_suspend_flag(_async_delivery_disabled); +} +inline JavaThread::NoAsyncExceptionDeliveryMark::~NoAsyncExceptionDeliveryMark() { + _target->clear_suspend_flag(_async_delivery_disabled); +} + inline JavaThreadState JavaThread::thread_state() const { #if defined(PPC64) || defined (AARCH64) // Use membars when accessing volatile _thread_state. See -- GitLab From 6ea996c20591cafa9673d9c697437ce2c48e4616 Mon Sep 17 00:00:00 2001 From: Ichiroh Takiguchi Date: Wed, 23 Mar 2022 01:39:20 +0000 Subject: [PATCH 120/237] 8282422: JTable.print() failed with UnsupportedCharsetException on AIX ko_KR locale Reviewed-by: prr, serb --- .../share/classes/sun/awt/FontConfiguration.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/java.desktop/share/classes/sun/awt/FontConfiguration.java b/src/java.desktop/share/classes/sun/awt/FontConfiguration.java index e2e7ab3e5ae..45035042992 100644 --- a/src/java.desktop/share/classes/sun/awt/FontConfiguration.java +++ b/src/java.desktop/share/classes/sun/awt/FontConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -960,7 +960,9 @@ public abstract class FontConfiguration { return fc.newEncoder(); } - if (!charsetName.startsWith("sun.awt.") && !charsetName.equals("default")) { + if (!charsetName.startsWith("sun.awt.") && + !charsetName.equals("default") && + !charsetName.startsWith("sun.font.")) { fc = Charset.forName(charsetName); } else { @SuppressWarnings("removal") -- GitLab From b035fda459284fa130bf936743a8579a6888160b Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 23 Mar 2022 06:06:51 +0000 Subject: [PATCH 121/237] 8283497: [windows] print TMP and TEMP in hs_err and VM.info Reviewed-by: ysuenaga, dholmes --- src/hotspot/share/utilities/vmError.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 89b4645fa45..984c57a13ec 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -115,7 +115,7 @@ static const char* env_list[] = { "DYLD_INSERT_LIBRARIES", // defined on Windows - "OS", "PROCESSOR_IDENTIFIER", "_ALT_JAVA_HOME_DIR", + "OS", "PROCESSOR_IDENTIFIER", "_ALT_JAVA_HOME_DIR", "TMP", "TEMP", (const char *)0 }; -- GitLab From 82e1a1cf8bafddfa2ecf11c2ce88ed4eaa091757 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 23 Mar 2022 06:30:19 +0000 Subject: [PATCH 122/237] 8283257: x86: Clean up invocation/branch counter updates code Reviewed-by: redestad, kvn --- src/hotspot/cpu/x86/interp_masm_x86.cpp | 19 +++++++++---------- src/hotspot/cpu/x86/interp_masm_x86.hpp | 6 ++---- .../x86/templateInterpreterGenerator_x86.cpp | 6 ++---- src/hotspot/cpu/x86/templateTable_x86.cpp | 7 +++---- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index bf8b94a6319..34d4178b8da 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -1972,19 +1972,18 @@ void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { #endif } -// Jump if ((*counter_addr += increment) & mask) satisfies the condition. -void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, - int increment, Address mask, - Register scratch, bool preloaded, - Condition cond, Label* where) { - if (!preloaded) { - movl(scratch, counter_addr); - } - incrementl(scratch, increment); +// Jump if ((*counter_addr += increment) & mask) == 0 +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, Address mask, + Register scratch, Label* where) { + // This update is actually not atomic and can lose a number of updates + // under heavy contention, but the alternative of using the (contended) + // atomic update here penalizes profiling paths too much. + movl(scratch, counter_addr); + incrementl(scratch, InvocationCounter::count_increment); movl(counter_addr, scratch); andl(scratch, mask); if (where != NULL) { - jcc(cond, *where); + jcc(Assembler::zero, *where); } } diff --git a/src/hotspot/cpu/x86/interp_masm_x86.hpp b/src/hotspot/cpu/x86/interp_masm_x86.hpp index 0aecb6b4a25..a94f35426b8 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.hpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp @@ -248,10 +248,8 @@ class InterpreterMacroAssembler: public MacroAssembler { bool decrement = false); void increment_mdp_data_at(Register mdp_in, Register reg, int constant, bool decrement = false); - void increment_mask_and_jump(Address counter_addr, - int increment, Address mask, - Register scratch, bool preloaded, - Condition cond, Label* where); + void increment_mask_and_jump(Address counter_addr, Address mask, + Register scratch, Label* where); void set_mdp_flag_at(Register mdp_in, int flag_constant); void test_mdp_data_at(Register mdp_in, int offset, Register value, Register test_value_out, diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index 7177d7ca34c..7b14aff6f1f 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -388,7 +388,6 @@ address TemplateInterpreterGenerator::generate_safept_entry_for( void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow) { Label done; // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. - int increment = InvocationCounter::count_increment; Label no_mdo; if (ProfileInterpreter) { // Are we profiling? @@ -399,7 +398,7 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow) { const Address mdo_invocation_counter(rax, in_bytes(MethodData::invocation_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); const Address mask(rax, in_bytes(MethodData::invoke_mask_offset())); - __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, rcx, false, Assembler::zero, overflow); + __ increment_mask_and_jump(mdo_invocation_counter, mask, rcx, overflow); __ jmp(done); } __ bind(no_mdo); @@ -409,8 +408,7 @@ void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow) { InvocationCounter::counter_offset()); __ get_method_counters(rbx, rax, done); const Address mask(rax, in_bytes(MethodCounters::invoke_mask_offset())); - __ increment_mask_and_jump(invocation_counter, increment, mask, rcx, - false, Assembler::zero, overflow); + __ increment_mask_and_jump(invocation_counter, mask, rcx, overflow); __ bind(done); } diff --git a/src/hotspot/cpu/x86/templateTable_x86.cpp b/src/hotspot/cpu/x86/templateTable_x86.cpp index cadc71916db..531ff7956b4 100644 --- a/src/hotspot/cpu/x86/templateTable_x86.cpp +++ b/src/hotspot/cpu/x86/templateTable_x86.cpp @@ -2197,7 +2197,6 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { __ bind(has_counters); Label no_mdo; - int increment = InvocationCounter::count_increment; if (ProfileInterpreter) { // Are we profiling? __ movptr(rbx, Address(rcx, in_bytes(Method::method_data_offset()))); @@ -2207,7 +2206,7 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { const Address mdo_backedge_counter(rbx, in_bytes(MethodData::backedge_counter_offset()) + in_bytes(InvocationCounter::counter_offset())); const Address mask(rbx, in_bytes(MethodData::backedge_mask_offset())); - __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, rax, false, Assembler::zero, + __ increment_mask_and_jump(mdo_backedge_counter, mask, rax, UseOnStackReplacement ? &backedge_counter_overflow : NULL); __ jmp(dispatch); } @@ -2215,8 +2214,8 @@ void TemplateTable::branch(bool is_jsr, bool is_wide) { // Increment backedge counter in MethodCounters* __ movptr(rcx, Address(rcx, Method::method_counters_offset())); const Address mask(rcx, in_bytes(MethodCounters::backedge_mask_offset())); - __ increment_mask_and_jump(Address(rcx, be_offset), increment, mask, - rax, false, Assembler::zero, UseOnStackReplacement ? &backedge_counter_overflow : NULL); + __ increment_mask_and_jump(Address(rcx, be_offset), mask, rax, + UseOnStackReplacement ? &backedge_counter_overflow : NULL); __ bind(dispatch); } -- GitLab From 1443f6b9191c127abdae38cadb1a44af3c652f1d Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 23 Mar 2022 06:31:36 +0000 Subject: [PATCH 123/237] 8283199: Linux os::cpu_microcode_revision() stalls cold startup Reviewed-by: dholmes, redestad, stuefe --- src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index 5e346efee54..c6b945fdd79 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -459,11 +459,26 @@ bool os::supports_sse() { } juint os::cpu_microcode_revision() { + // Note: this code runs on startup, and therefore should not be slow, + // see JDK-8283200. + juint result = 0; - char data[2048] = {0}; // lines should fit in 2K buf - size_t len = sizeof(data); - FILE *fp = os::fopen("/proc/cpuinfo", "r"); + + // Attempt 1 (faster): Read the microcode version off the sysfs. + FILE *fp = os::fopen("/sys/devices/system/cpu/cpu0/microcode/version", "r"); + if (fp) { + int read = fscanf(fp, "%x", &result); + fclose(fp); + if (read > 0) { + return result; + } + } + + // Attempt 2 (slower): Read the microcode version off the procfs. + fp = os::fopen("/proc/cpuinfo", "r"); if (fp) { + char data[2048] = {0}; // lines should fit in 2K buf + size_t len = sizeof(data); while (!feof(fp)) { if (fgets(data, len, fp)) { if (strstr(data, "microcode") != NULL) { @@ -475,6 +490,7 @@ juint os::cpu_microcode_revision() { } fclose(fp); } + return result; } -- GitLab From 86015e15a5105a779ee065cca64479c8d4fbc074 Mon Sep 17 00:00:00 2001 From: Sibabrata Sahoo Date: Wed, 23 Mar 2022 06:45:37 +0000 Subject: [PATCH 124/237] 8282293: Domain value for system property jdk.https.negotiate.cbt should be case-insensitive Reviewed-by: weijun, rhalade --- .../https/AbstractDelegateHttpsURLConnection.java | 5 +++-- test/jdk/sun/security/krb5/auto/HttpsCB.java | 9 ++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java index 7ed4381dda6..ff54e474b8e 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java @@ -332,10 +332,11 @@ public abstract class AbstractDelegateHttpsURLConnection extends if (prop.startsWith("domain:")) { String[] domains = prop.substring(7).split(","); for (String domain : domains) { - if (target.equals(domain)) { + if (target.equalsIgnoreCase(domain)) { return true; } - if (domain.startsWith("*.") && target.endsWith(domain.substring(1))) { + if (domain.startsWith("*.") && target.regionMatches( + true, target.length() - domain.length() + 1, domain, 1, domain.length() - 1)) { return true; } } diff --git a/test/jdk/sun/security/krb5/auto/HttpsCB.java b/test/jdk/sun/security/krb5/auto/HttpsCB.java index a65aa5d0241..1f9f0de33ac 100644 --- a/test/jdk/sun/security/krb5/auto/HttpsCB.java +++ b/test/jdk/sun/security/krb5/auto/HttpsCB.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8279842 + * @bug 8279842 8282293 * @modules java.base/sun.security.util * java.security.jgss/sun.security.jgss * java.security.jgss/sun.security.jgss.krb5 @@ -52,7 +52,13 @@ * @run main/othervm -Djdk.net.hosts.file=TestHosts * -Djdk.https.negotiate.cbt=domain:host.web.domain HttpsCB true true * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:HOST.WEB.DOMAIN HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts * -Djdk.https.negotiate.cbt=domain:*.web.domain HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:*.WEB.Domain HttpsCB true true + * @run main/othervm -Djdk.net.hosts.file=TestHosts + * -Djdk.https.negotiate.cbt=domain:*.Invalid,*.WEB.Domain HttpsCB true true */ import com.sun.net.httpserver.Headers; @@ -198,6 +204,7 @@ public class HttpsCB { conn.getInputStream())); return reader.readLine().equals(CONTENT); } catch (IOException e) { + e.printStackTrace(System.out); return false; } } -- GitLab From 58487ddc170f73123668f29c99097b16ba84aa9b Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 23 Mar 2022 06:46:55 +0000 Subject: [PATCH 125/237] 8283249: CompressedClassPointers.java fails on ppc with 'Narrow klass shift: 0' missing Reviewed-by: iklam --- .../runtime/CompressedOops/CompressedClassPointers.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java index c46b32b220d..8e2033e7329 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointers.java @@ -224,8 +224,8 @@ public class CompressedClassPointers { "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000"); - if (!Platform.isAArch64()) { - // Currently relax this test for Aarch64. + if (!Platform.isAArch64() && !Platform.isPPC()) { + // Currently relax this test for Aarch64 and ppc. output.shouldContain("Narrow klass shift: 0"); } output.shouldHaveExitValue(0); @@ -244,8 +244,8 @@ public class CompressedClassPointers { "-XX:+VerifyBeforeGC", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("Narrow klass base: 0x0000000000000000"); - if (!Platform.isAArch64()) { - // Currently relax this test for Aarch64. + if (!Platform.isAArch64() && !Platform.isPPC()) { + // Currently relax this test for Aarch64 and ppc. output.shouldContain("Narrow klass shift: 0"); } output.shouldHaveExitValue(0); -- GitLab From 026b85303c01326bc49a1105a89853d7641fcd50 Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Wed, 23 Mar 2022 08:48:17 +0000 Subject: [PATCH 126/237] 8283298: Make CodeCacheSegmentSize a product flag Reviewed-by: dlong, kvn --- src/hotspot/share/interpreter/templateInterpreter.cpp | 8 ++++++-- src/hotspot/share/prims/methodHandles.cpp | 8 ++++++-- src/hotspot/share/runtime/globals.hpp | 2 +- .../jtreg/compiler/arguments/TestCodeEntryAlignment.java | 1 - 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/interpreter/templateInterpreter.cpp b/src/hotspot/share/interpreter/templateInterpreter.cpp index 732c12532f7..322a21b6aa7 100644 --- a/src/hotspot/share/interpreter/templateInterpreter.cpp +++ b/src/hotspot/share/interpreter/templateInterpreter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -47,7 +47,11 @@ void TemplateInterpreter::initialize_stub() { // allocate interpreter int code_size = InterpreterCodeSize; NOT_PRODUCT(code_size *= 4;) // debug uses extra interpreter code space - _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL, + // 270+ interpreter codelets are generated and each of them is required to be aligned to + // CodeEntryAlignment twice. So we need additional size due to alignment. + int max_aligned_codelets = 280; + int max_aligned_bytes = max_aligned_codelets * CodeEntryAlignment * 2; + _code = new StubQueue(new InterpreterCodeletInterface, code_size + max_aligned_bytes, NULL, "Interpreter"); } diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 5ae35e34a8c..cb66076eeca 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -89,7 +89,11 @@ void MethodHandles::generate_adapters() { ResourceMark rm; TraceTime timer("MethodHandles adapters generation", TRACETIME_LOG(Info, startuptime)); - _adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size); + // The adapter entry is required to be aligned to CodeEntryAlignment. + // So we need additional bytes due to alignment. + int adapter_num = (int)Interpreter::method_handle_invoke_LAST - (int)Interpreter::method_handle_invoke_FIRST + 1; + int max_aligned_bytes = adapter_num * CodeEntryAlignment; + _adapter_code = MethodHandlesAdapterBlob::create(adapter_code_size + max_aligned_bytes); CodeBuffer code(_adapter_code); MethodHandlesAdapterGenerator g(&code); g.generate(); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 7dd589b58c5..0ab10a117f1 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1522,7 +1522,7 @@ const intx ObjectAlignmentInBytes = 8; "Stack space (bytes) required for JVM_InvokeMethod to complete") \ \ /* code cache parameters */ \ - develop_pd(uintx, CodeCacheSegmentSize, \ + product_pd(uintx, CodeCacheSegmentSize, EXPERIMENTAL, \ "Code cache segment size (in bytes) - smallest unit of " \ "allocation") \ range(1, 1024) \ diff --git a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java index 0ea1aee6bd6..15a60382245 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java +++ b/test/hotspot/jtreg/compiler/arguments/TestCodeEntryAlignment.java @@ -27,7 +27,6 @@ * @library /test/lib / * @bug 8281467 * @requires vm.flagless - * @requires vm.debug * @requires os.arch=="amd64" | os.arch=="x86_64" * * @summary Test large CodeEntryAlignments are accepted -- GitLab From d8c55725e0f85e21c16bb81e3f1a9bcfacc59f87 Mon Sep 17 00:00:00 2001 From: Quan Anh Mai Date: Wed, 23 Mar 2022 09:45:23 +0000 Subject: [PATCH 127/237] 8282204: Use lea instructions for arithmetic operations on x86_64 Reviewed-by: jiefu, sviswanathan, thartmann --- src/hotspot/cpu/x86/assembler_x86.cpp | 3 - src/hotspot/cpu/x86/vm_version_x86.hpp | 19 ++ src/hotspot/cpu/x86/x86_64.ad | 164 +++++++++++++++--- .../bench/vm/compiler/LeaInstruction.java | 122 +++++++++++++ 4 files changed, 282 insertions(+), 26 deletions(-) create mode 100644 test/micro/org/openjdk/bench/vm/compiler/LeaInstruction.java diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index e287512b93c..3505e081d38 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -2410,10 +2410,7 @@ void Assembler::ldmxcsr( Address src) { void Assembler::leal(Register dst, Address src) { InstructionMark im(this); -#ifdef _LP64 - emit_int8(0x67); // addr32 prefix(src, dst); -#endif // LP64 emit_int8((unsigned char)0x8D); emit_operand(dst, src); } diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index 2fd1bbc9617..2f4e31b4708 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -1044,6 +1044,25 @@ public: static bool supports_clflushopt() { return ((_features & CPU_FLUSHOPT) != 0); } static bool supports_clwb() { return ((_features & CPU_CLWB) != 0); } + // Old CPUs perform lea on AGU which causes additional latency transfering the + // value from/to ALU for other operations + static bool supports_fast_2op_lea() { + return (is_intel() && supports_avx()) || // Sandy Bridge and above + (is_amd() && supports_avx()); // Jaguar and Bulldozer and above + } + + // Pre Icelake Intels suffer inefficiency regarding 3-operand lea, which contains + // all of base register, index register and displacement immediate, with 3 latency. + // Note that when the address contains no displacement but the base register is + // rbp or r13, the machine code must contain a zero displacement immediate, + // effectively transform a 2-operand lea into a 3-operand lea. This can be + // replaced by add-add or lea-add + static bool supports_fast_3op_lea() { + return supports_fast_2op_lea() && + ((is_intel() && supports_clwb() && !is_intel_skylake()) || // Icelake and above + is_amd()); + } + #ifdef __APPLE__ // Is the CPU running emulated (for example macOS Rosetta running x86_64 code on M1 ARM (aarch64) static bool is_cpu_emulated(); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 3eed117ece8..09ff7075994 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2003, 2022, 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 @@ -241,6 +241,11 @@ reg_class long_no_rcx_reg %{ return _LONG_NO_RCX_REG_mask; %} +// Class for all long registers (excluding RBP and R13) +reg_class long_no_rbp_r13_reg %{ + return _LONG_NO_RBP_R13_REG_mask; +%} + // Class for all int registers (excluding RSP) reg_class int_reg %{ return _INT_REG_mask; @@ -256,6 +261,11 @@ reg_class int_no_rcx_reg %{ return _INT_NO_RCX_REG_mask; %} +// Class for all int registers (excluding RBP and R13) +reg_class int_no_rbp_r13_reg %{ + return _INT_NO_RBP_R13_REG_mask; +%} + // Singleton class for RAX pointer register reg_class ptr_rax_reg(RAX, RAX_H); @@ -319,9 +329,11 @@ extern RegMask _PTR_NO_RAX_RBX_REG_mask; extern RegMask _LONG_REG_mask; extern RegMask _LONG_NO_RAX_RDX_REG_mask; extern RegMask _LONG_NO_RCX_REG_mask; +extern RegMask _LONG_NO_RBP_R13_REG_mask; extern RegMask _INT_REG_mask; extern RegMask _INT_NO_RAX_RDX_REG_mask; extern RegMask _INT_NO_RCX_REG_mask; +extern RegMask _INT_NO_RBP_R13_REG_mask; extern RegMask _FLOAT_REG_mask; extern RegMask _STACK_OR_PTR_REG_mask; @@ -348,9 +360,11 @@ RegMask _PTR_NO_RAX_RBX_REG_mask; RegMask _LONG_REG_mask; RegMask _LONG_NO_RAX_RDX_REG_mask; RegMask _LONG_NO_RCX_REG_mask; +RegMask _LONG_NO_RBP_R13_REG_mask; RegMask _INT_REG_mask; RegMask _INT_NO_RAX_RDX_REG_mask; RegMask _INT_NO_RCX_REG_mask; +RegMask _INT_NO_RBP_R13_REG_mask; RegMask _FLOAT_REG_mask; RegMask _STACK_OR_PTR_REG_mask; RegMask _STACK_OR_LONG_REG_mask; @@ -409,6 +423,12 @@ void reg_mask_init() { _LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg())); _LONG_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg()->next())); + _LONG_NO_RBP_R13_REG_mask = _LONG_REG_mask; + _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg()->next())); + _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg())); + _LONG_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg()->next())); + _INT_REG_mask = _ALL_INT_REG_mask; if (PreserveFramePointer) { _INT_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg())); @@ -427,6 +447,10 @@ void reg_mask_init() { _INT_NO_RCX_REG_mask = _INT_REG_mask; _INT_NO_RCX_REG_mask.Remove(OptoReg::as_OptoReg(rcx->as_VMReg())); + _INT_NO_RBP_R13_REG_mask = _INT_REG_mask; + _INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(rbp->as_VMReg())); + _INT_NO_RBP_R13_REG_mask.Remove(OptoReg::as_OptoReg(r13->as_VMReg())); + // _FLOAT_REG_LEGACY_mask/_FLOAT_REG_EVEX_mask is generated by adlc // from the float_reg_legacy/float_reg_evex register class. _FLOAT_REG_mask = VM_Version::supports_evex() ? _FLOAT_REG_EVEX_mask : _FLOAT_REG_LEGACY_mask; @@ -3491,6 +3515,21 @@ operand no_rax_rdx_RegI() interface(REG_INTER); %} +operand no_rbp_r13_RegI() +%{ + constraint(ALLOC_IN_RC(int_no_rbp_r13_reg)); + match(RegI); + match(rRegI); + match(rax_RegI); + match(rbx_RegI); + match(rcx_RegI); + match(rdx_RegI); + match(rdi_RegI); + + format %{ %} + interface(REG_INTER); +%} + // Pointer Register operand any_RegP() %{ @@ -3718,6 +3757,19 @@ operand rdx_RegL() interface(REG_INTER); %} +operand no_rbp_r13_RegL() +%{ + constraint(ALLOC_IN_RC(long_no_rbp_r13_reg)); + match(RegL); + match(rRegL); + match(rax_RegL); + match(rcx_RegL); + match(rdx_RegL); + + format %{ %} + interface(REG_INTER); +%} + // Flags register, used as output of compare instructions operand rFlagsReg() %{ @@ -7443,14 +7495,53 @@ instruct decI_mem(memory dst, immI_M1 src, rFlagsReg cr) ins_pipe(ialu_mem_imm); %} -instruct leaI_rReg_immI(rRegI dst, rRegI src0, immI src1) +instruct leaI_rReg_immI2_immI(rRegI dst, rRegI index, immI2 scale, immI disp) %{ - match(Set dst (AddI src0 src1)); + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddI (LShiftI index scale) disp)); - ins_cost(110); - format %{ "addr32 leal $dst, [$src0 + $src1]\t# int" %} + format %{ "leal $dst, [$index << $scale + $disp]\t# int" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address(noreg, $index$$Register, scale, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI(rRegI dst, rRegI base, rRegI index, immI disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddI (AddI base index) disp)); + + format %{ "leal $dst, [$base + $index + $disp]\t# int" %} ins_encode %{ - __ leal($dst$$Register, Address($src0$$Register, $src1$$constant)); + __ leal($dst$$Register, Address($base$$Register, $index$$Register, Address::times_1, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI2(rRegI dst, no_rbp_r13_RegI base, rRegI index, immI2 scale) +%{ + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddI base (LShiftI index scale))); + + format %{ "leal $dst, [$base + $index << $scale]\t# int" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address($base$$Register, $index$$Register, scale)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaI_rReg_rReg_immI2_immI(rRegI dst, rRegI base, rRegI index, immI2 scale, immI disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddI (AddI base (LShiftI index scale)) disp)); + + format %{ "leal $dst, [$base + $index << $scale + $disp]\t# int" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leal($dst$$Register, Address($base$$Register, $index$$Register, scale, $disp$$constant)); %} ins_pipe(ialu_reg_reg); %} @@ -7574,14 +7665,53 @@ instruct decL_mem(memory dst, immL_M1 src, rFlagsReg cr) ins_pipe(ialu_mem_imm); %} -instruct leaL_rReg_immL(rRegL dst, rRegL src0, immL32 src1) +instruct leaL_rReg_immI2_immL32(rRegL dst, rRegL index, immI2 scale, immL32 disp) %{ - match(Set dst (AddL src0 src1)); + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddL (LShiftL index scale) disp)); - ins_cost(110); - format %{ "leaq $dst, [$src0 + $src1]\t# long" %} + format %{ "leaq $dst, [$index << $scale + $disp]\t# long" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address(noreg, $index$$Register, scale, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immL32(rRegL dst, rRegL base, rRegL index, immL32 disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddL (AddL base index) disp)); + + format %{ "leaq $dst, [$base + $index + $disp]\t# long" %} + ins_encode %{ + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, Address::times_1, $disp$$constant)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immI2(rRegL dst, no_rbp_r13_RegL base, rRegL index, immI2 scale) +%{ + predicate(VM_Version::supports_fast_2op_lea()); + match(Set dst (AddL base (LShiftL index scale))); + + format %{ "leaq $dst, [$base + $index << $scale]\t# long" %} + ins_encode %{ + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, scale)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct leaL_rReg_rReg_immI2_immL32(rRegL dst, rRegL base, rRegL index, immI2 scale, immL32 disp) +%{ + predicate(VM_Version::supports_fast_3op_lea()); + match(Set dst (AddL (AddL base (LShiftL index scale)) disp)); + + format %{ "leaq $dst, [$base + $index << $scale + $disp]\t# long" %} ins_encode %{ - __ leaq($dst$$Register, Address($src0$$Register, $src1$$constant)); + Address::ScaleFactor scale = static_cast($scale$$constant); + __ leaq($dst$$Register, Address($base$$Register, $index$$Register, scale, $disp$$constant)); %} ins_pipe(ialu_reg_reg); %} @@ -7612,18 +7742,6 @@ instruct addP_rReg_imm(rRegP dst, immL32 src, rFlagsReg cr) // XXX addP mem ops ???? -instruct leaP_rReg_imm(rRegP dst, rRegP src0, immL32 src1) -%{ - match(Set dst (AddP src0 src1)); - - ins_cost(110); - format %{ "leaq $dst, [$src0 + $src1]\t# ptr" %} - ins_encode %{ - __ leaq($dst$$Register, Address($src0$$Register, $src1$$constant)); - %} - ins_pipe(ialu_reg_reg); -%} - instruct checkCastPP(rRegP dst) %{ match(Set dst (CheckCastPP dst)); diff --git a/test/micro/org/openjdk/bench/vm/compiler/LeaInstruction.java b/test/micro/org/openjdk/bench/vm/compiler/LeaInstruction.java new file mode 100644 index 00000000000..02b10d7ddf7 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/LeaInstruction.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2022, 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. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 1, jvmArgsAppend = {"-XX:LoopUnrollLimit=1"}) +@State(Scope.Thread) +public class LeaInstruction { + static final int ITERATION = 1000; + + int x, y; + + @Benchmark + public void IS_D_int(Blackhole bh) { + int x = this.x; + for (int i = 0; i < ITERATION; i++) { + x = x * 4 + 10; + } + bh.consume(x); + } + + @Benchmark + public void B_I_D_int(Blackhole bh) { + int x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y + 10; + y = x + y + 20; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void B_IS_int(Blackhole bh) { + int x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y * 4; + y = x + y * 8; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void B_IS_D_int(Blackhole bh) { + int x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y * 4 + 10; + y = x + y * 8 + 20; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void IS_D_long(Blackhole bh) { + long x = this.x; + for (int i = 0; i < ITERATION; i++) { + x = x * 4 + 10; + } + bh.consume(x); + } + + @Benchmark + public void B_I_D_long(Blackhole bh) { + long x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y + 10; + y = x + y + 20; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void B_IS_long(Blackhole bh) { + long x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y * 4; + y = x + y * 8; + } + bh.consume(x); + bh.consume(y); + } + + @Benchmark + public void B_IS_D_long(Blackhole bh) { + long x = this.x, y = this.y; + for (int i = 0; i < ITERATION; i++) { + x = x + y * 4 + 10; + y = x + y * 8 + 20; + } + bh.consume(x); + bh.consume(y); + } +} -- GitLab From 91fab6ad59d2a4baf58802fc6e6039af3dd8d578 Mon Sep 17 00:00:00 2001 From: Jaikiran Pai Date: Wed, 23 Mar 2022 09:47:44 +0000 Subject: [PATCH 128/237] 8283411: InflaterInputStream holds on to a temporary byte array of 512 bytes Reviewed-by: lancea, vtewari, alanb --- .../share/classes/java/util/zip/InflaterInputStream.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/util/zip/InflaterInputStream.java b/src/java.base/share/classes/java/util/zip/InflaterInputStream.java index e17f561224f..a87f78b3838 100644 --- a/src/java.base/share/classes/java/util/zip/InflaterInputStream.java +++ b/src/java.base/share/classes/java/util/zip/InflaterInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -189,8 +189,6 @@ public class InflaterInputStream extends FilterInputStream { } } - private byte[] b = new byte[512]; - /** * Skips specified number of bytes of uncompressed data. * @param n the number of bytes to skip @@ -205,6 +203,7 @@ public class InflaterInputStream extends FilterInputStream { ensureOpen(); int max = (int)Math.min(n, Integer.MAX_VALUE); int total = 0; + byte[] b = new byte[Math.min(max, 512)]; while (total < max) { int len = max - total; if (len > b.length) { -- GitLab From 6ed0ba2f8a2af58c45a6b7be684ef30d15af6ead Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Wed, 23 Mar 2022 10:34:09 +0000 Subject: [PATCH 129/237] 8283543: indentation error at com.sun.tools.javac.comp.Enter::visitTopLevel Reviewed-by: darcy, iris --- .../share/classes/com/sun/tools/javac/comp/Enter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java index 5cf8c5d5387..dbb4f1a46a4 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Enter.java @@ -377,7 +377,7 @@ public class Enter extends JCTree.Visitor { ClassSymbol c = syms.enterClass(tree.modle, name, tree.packge); c.flatname = names.fromString(tree.packge + "." + name); c.classfile = c.sourcefile = tree.sourcefile; - c.completer = Completer.NULL_COMPLETER; + c.completer = Completer.NULL_COMPLETER; c.members_field = WriteableScope.create(c); tree.packge.package_info = c; tree.packge.sourcefile = tree.sourcefile; -- GitLab From 61d7d868db030d878f4a1c4467075e8d4e116a6e Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Wed, 23 Mar 2022 11:03:25 +0000 Subject: [PATCH 130/237] 8283254: Remove redundant class jdk/internal/agent/spi/AgentProvider Reviewed-by: mchung, redestad, dfuchs --- .../classes/jdk/internal/agent/Agent.java | 1 - .../jdk/internal/agent/spi/AgentProvider.java | 76 ------------------- .../share/classes/module-info.java | 4 +- 3 files changed, 1 insertion(+), 80 deletions(-) delete mode 100644 src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java diff --git a/src/jdk.management.agent/share/classes/jdk/internal/agent/Agent.java b/src/jdk.management.agent/share/classes/jdk/internal/agent/Agent.java index 2d261bfb3a7..175c736e420 100644 --- a/src/jdk.management.agent/share/classes/jdk/internal/agent/Agent.java +++ b/src/jdk.management.agent/share/classes/jdk/internal/agent/Agent.java @@ -51,7 +51,6 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXServiceURL; import static jdk.internal.agent.AgentConfigurationError.*; -import jdk.internal.agent.spi.AgentProvider; import jdk.internal.vm.VMSupport; import sun.management.jdp.JdpController; import sun.management.jdp.JdpException; diff --git a/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java b/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java deleted file mode 100644 index 395961cad96..00000000000 --- a/src/jdk.management.agent/share/classes/jdk/internal/agent/spi/AgentProvider.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2016, 2022, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -package jdk.internal.agent.spi; - -import java.util.Properties; - -/** - * Service interface for management agent - */ -public abstract class AgentProvider { - - /** - * Instantiates a new AgentProvider. - */ - protected AgentProvider() { - } - - /** - * Gets the name of the agent provider. - * - * @return name of agent provider - */ - public abstract String getName(); - - /** - * Initializes and starts the agent. - * - * @throws IllegalStateException if this agent has already been started. - */ - public abstract void startAgent(); - - /** - * Initializes and starts the agent at given port and with given properties - * - * @param props environment variables for agent - * - * @throws IllegalStateException if this agent has already been started. - */ - public abstract void startAgent(Properties props); - - /** - * Checks if agent is started and not terminated. - * - * @return true if agent is running, false otherwise. - */ - public abstract boolean isActive(); - - /** - * Stops this agent. - * - * @throws IllegalStateException if this agent is not started. - */ - public abstract void stopAgent(); -} diff --git a/src/jdk.management.agent/share/classes/module-info.java b/src/jdk.management.agent/share/classes/module-info.java index 921744822b6..9688e22b9f9 100644 --- a/src/jdk.management.agent/share/classes/module-info.java +++ b/src/jdk.management.agent/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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 @@ -39,6 +39,4 @@ module jdk.management.agent { requires java.management.rmi; exports jdk.internal.agent to jdk.jconsole; - - uses jdk.internal.agent.spi.AgentProvider; } -- GitLab From 78ef2fdef68c5161c8875296e9479026ac89743a Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Wed, 23 Mar 2022 12:55:28 +0000 Subject: [PATCH 131/237] 8283562: JDK-8282306 breaks gtests on zero Reviewed-by: shade --- test/hotspot/gtest/runtime/test_os.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 0f78630d460..270710e94c0 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -868,7 +868,7 @@ TEST_VM(os, iso8601_time) { } TEST_VM(os, is_first_C_frame) { -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(ZERO) frame invalid_frame; EXPECT_TRUE(os::is_first_C_frame(&invalid_frame)); // the frame has zeroes for all values -- GitLab From dc45b0ac58f46e2e46b3302a7e1d81888726f6f4 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 23 Mar 2022 14:09:01 +0000 Subject: [PATCH 132/237] 8283513: Parallel: Skip the card marking in PSRootsClosure Reviewed-by: tschatzl, iwalulya --- src/hotspot/share/gc/parallel/psClosure.inline.hpp | 9 ++++++--- .../gc/parallel/psPromotionManager.inline.hpp | 14 ++++---------- src/hotspot/share/gc/parallel/psScavenge.hpp | 4 ++++ 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psClosure.inline.hpp b/src/hotspot/share/gc/parallel/psClosure.inline.hpp index cd78583bb80..3499b179f46 100644 --- a/src/hotspot/share/gc/parallel/psClosure.inline.hpp +++ b/src/hotspot/share/gc/parallel/psClosure.inline.hpp @@ -60,9 +60,12 @@ private: PSPromotionManager* _promotion_manager; template void do_oop_work(T *p) { - if (PSScavenge::should_scavenge(p)) { - // We never card mark roots, maybe call a func without test? - _promotion_manager->copy_and_push_safe_barrier(p); + assert(!ParallelScavengeHeap::heap()->is_in_reserved(p), "roots should be outside of heap"); + oop o = RawAccess<>::oop_load(p); + if (PSScavenge::is_obj_in_young(o)) { + assert(!PSScavenge::is_obj_in_to_space(o), "Revisiting roots?"); + oop new_obj = _promotion_manager->copy_to_survivor_space(o); + RawAccess::oop_store(p, new_obj); } } public: diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 1b7b00d9fba..64ee5f286b5 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -300,24 +300,18 @@ inline oop PSPromotionManager::copy_unmarked_to_survivor_space(oop o, } // Attempt to "claim" oop at p via CAS, push the new obj if successful -// This version tests the oop* to make sure it is within the heap before -// attempting marking. template inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) { + assert(ParallelScavengeHeap::heap()->is_in_reserved(p), "precondition"); assert(should_scavenge(p, true), "revisiting object?"); oop o = RawAccess::oop_load(p); oop new_obj = copy_to_survivor_space(o); RawAccess::oop_store(p, new_obj); - // We cannot mark without test, as some code passes us pointers - // that are outside the heap. These pointers are either from roots - // or from metadata. - if ((!PSScavenge::is_obj_in_young((HeapWord*)p)) && - ParallelScavengeHeap::heap()->is_in_reserved(p)) { - if (PSScavenge::is_obj_in_young(new_obj)) { - PSScavenge::card_table()->inline_write_ref_field_gc(p, new_obj); - } + if (!PSScavenge::is_obj_in_young((HeapWord*)p) && + PSScavenge::is_obj_in_young(new_obj)) { + PSScavenge::card_table()->inline_write_ref_field_gc(p, new_obj); } } diff --git a/src/hotspot/share/gc/parallel/psScavenge.hpp b/src/hotspot/share/gc/parallel/psScavenge.hpp index c575e8a3f2c..01bc154e552 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.hpp +++ b/src/hotspot/share/gc/parallel/psScavenge.hpp @@ -135,6 +135,10 @@ class PSScavenge: AllStatic { inline static bool is_obj_in_young(HeapWord* o) { return o >= _young_generation_boundary; } + + static bool is_obj_in_to_space(oop o) { + return ParallelScavengeHeap::young_gen()->to_space()->contains(o); + } }; #endif // SHARE_GC_PARALLEL_PSSCAVENGE_HPP -- GitLab From 2b291d837ebfd9d0a61f26541107c6a5f1d43773 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Wed, 23 Mar 2022 14:57:36 +0000 Subject: [PATCH 133/237] 8282536: java.net.InetAddress should be a sealed class Reviewed-by: dfuchs, jpai, rriggs, michaelm --- .../share/classes/java/net/Inet6Address.java | 6 +---- .../share/classes/java/net/InetAddress.java | 24 ++++--------------- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/src/java.base/share/classes/java/net/Inet6Address.java b/src/java.base/share/classes/java/net/Inet6Address.java index 751623536e7..325765ff3b6 100644 --- a/src/java.base/share/classes/java/net/Inet6Address.java +++ b/src/java.base/share/classes/java/net/Inet6Address.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -593,10 +593,6 @@ class Inet6Address extends InetAddress { throws IOException, ClassNotFoundException { NetworkInterface scope_ifname = null; - if (getClass().getClassLoader() != null) { - throw new SecurityException ("invalid address type"); - } - ObjectInputStream.GetField gf = s.readFields(); byte[] ipaddress = (byte[])gf.get("ipaddress", new byte[0]); int scope_id = gf.get("scope_id", -1); diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index 3875216768b..3bad2755978 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2022, 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 @@ -44,6 +44,7 @@ import java.io.ObjectInputStream; import java.io.ObjectInputStream.GetField; import java.io.ObjectOutputStream; import java.io.ObjectOutputStream.PutField; +import java.io.Serializable; import java.lang.annotation.Native; import java.util.ServiceLoader; import java.util.concurrent.ConcurrentHashMap; @@ -223,7 +224,7 @@ import static java.net.spi.InetAddressResolver.LookupPolicy.IPV6_FIRST; * @see java.net.InetAddress#getLocalHost() * @since 1.0 */ -public class InetAddress implements java.io.Serializable { +public sealed class InetAddress implements Serializable permits Inet4Address, Inet6Address { /** * Specify the address family: Internet Protocol, Version 4 @@ -1769,16 +1770,6 @@ public class InetAddress implements java.io.Serializable { return impl.anyLocalAddress(); } - /** - * Initializes an empty InetAddress. - */ - @java.io.Serial - private void readObjectNoData () { - if (getClass().getClassLoader() != null) { - throw new SecurityException ("invalid address type"); - } - } - private static final jdk.internal.misc.Unsafe UNSAFE = jdk.internal.misc.Unsafe.getUnsafe(); private static final long FIELDS_OFFSET @@ -1794,9 +1785,6 @@ public class InetAddress implements java.io.Serializable { @java.io.Serial private void readObject (ObjectInputStream s) throws IOException, ClassNotFoundException { - if (getClass().getClassLoader() != null) { - throw new SecurityException ("invalid address type"); - } GetField gf = s.readFields(); String host = (String)gf.get("hostName", null); int address = gf.get("address", 0); @@ -1830,11 +1818,7 @@ public class InetAddress implements java.io.Serializable { * @throws IOException if an I/O error occurs */ @java.io.Serial - private void writeObject (ObjectOutputStream s) throws - IOException { - if (getClass().getClassLoader() != null) { - throw new SecurityException ("invalid address type"); - } + private void writeObject (ObjectOutputStream s) throws IOException { PutField pf = s.putFields(); pf.put("hostName", holder().getHostName()); pf.put("address", holder().getAddress()); -- GitLab From a77160065bb6f62314711514f7694fe50f0dc35b Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Wed, 23 Mar 2022 15:00:05 +0000 Subject: [PATCH 134/237] 8283279: [Testbug] Improve TestGetSwapSpaceSize Reviewed-by: jiefu --- .../platform/docker/GetFreeSwapSpaceSize.java | 28 ++++++++++++++++--- .../docker/TestGetFreeSwapSpaceSize.java | 11 ++++---- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java index efb6a39e479..92b8cf282b7 100644 --- a/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/GetFreeSwapSpaceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. 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 @@ -24,16 +24,36 @@ import com.sun.management.OperatingSystemMXBean; import java.lang.management.ManagementFactory; +// Usage: +// GetFreeSwapSpaceSize public class GetFreeSwapSpaceSize { public static void main(String[] args) { - System.out.println("TestGetFreeSwapSpaceSize"); + if (args.length != 4) { + throw new RuntimeException("Unexpected arguments. Expected 4, got " + args.length); + } + String memoryAlloc = args[0]; + long expectedMemory = Long.parseLong(args[1]); + String memorySwapAlloc = args[2]; + long expectedSwap = Long.parseLong(args[3]); + System.out.println("TestGetFreeSwapSpaceSize (memory=" + memoryAlloc + ", memorySwap=" + memorySwapAlloc + ")"); + if (expectedSwap != 0) { + throw new RuntimeException("Precondition of test not met: Expected swap size of 0, got: " + expectedSwap); + } OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean(); + long osBeanTotalSwap = osBean.getTotalSwapSpaceSize(); + // Premise of this test is to test on a system where --memory and --memory-swap are set to + // the same amount via the container engine (i.e. no swap). In that case the OSBean must + // not report negative values for free swap space. Assert this precondition. + if (osBeanTotalSwap != expectedSwap) { + throw new RuntimeException("OperatingSystemMXBean.getTotalSwapSpaceSize() reported " + osBeanTotalSwap + " expected " + expectedSwap); + } + System.out.println("TestGetFreeSwapSpaceSize precondition met, osBeanTotalSwap = " + expectedSwap + ". Running test... "); for (int i = 0; i < 100; i++) { long size = osBean.getFreeSwapSpaceSize(); if (size < 0) { - System.out.println("Error: getFreeSwapSpaceSize returns " + size); - System.exit(-1); + throw new RuntimeException("Test failed! getFreeSwapSpaceSize returns " + size); } } + System.out.println("TestGetFreeSwapSpaceSize PASSED." ); } } diff --git a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java index 319c55ab518..92f3364da10 100644 --- a/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java +++ b/test/jdk/jdk/internal/platform/docker/TestGetFreeSwapSpaceSize.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (C) 2020, 2022 THL A29 Limited, a Tencent company. 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 @@ -36,7 +36,7 @@ import jdk.test.lib.containers.docker.DockerTestUtils; import jdk.test.lib.process.OutputAnalyzer; public class TestGetFreeSwapSpaceSize { - private static final String imageName = Common.imageName("memory"); + private static final String imageName = Common.imageName("osbeanSwapSpace"); public static void main(String[] args) throws Exception { if (!DockerTestUtils.canTestDocker()) { @@ -58,17 +58,18 @@ public class TestGetFreeSwapSpaceSize { } private static void testGetFreeSwapSpaceSize(String memoryAllocation, String expectedMemory, - String swapAllocation, String expectedSwap) throws Exception { + String memorySwapAllocation, String expectedSwap) throws Exception { Common.logNewTestCase("TestGetFreeSwapSpaceSize"); DockerRunOptions opts = Common.newOpts(imageName, "GetFreeSwapSpaceSize") + .addClassOptions(memoryAllocation, expectedMemory, memorySwapAllocation, expectedSwap) .addDockerOpts( "--memory", memoryAllocation, - "--memory-swap", swapAllocation + "--memory-swap", memorySwapAllocation ); OutputAnalyzer out = DockerTestUtils.dockerRunJava(opts); out.shouldHaveExitValue(0) - .shouldContain("TestGetFreeSwapSpaceSize"); + .shouldContain("TestGetFreeSwapSpaceSize PASSED."); } } -- GitLab From 3e73a0b726a97df0a4e92f9cf917429346090f45 Mon Sep 17 00:00:00 2001 From: liach Date: Wed, 23 Mar 2022 16:43:06 +0000 Subject: [PATCH 135/237] 8283237: CallSite should be a sealed class Reviewed-by: jkuhn, mchung --- .../share/classes/java/lang/invoke/CallSite.java | 8 ++++---- .../share/classes/java/lang/invoke/ConstantCallSite.java | 4 ++-- .../share/classes/java/lang/invoke/MutableCallSite.java | 4 ++-- .../share/classes/java/lang/invoke/VolatileCallSite.java | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/CallSite.java b/src/java.base/share/classes/java/lang/invoke/CallSite.java index e159e235f30..ec002e1fc46 100644 --- a/src/java.base/share/classes/java/lang/invoke/CallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/CallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -40,9 +40,9 @@ import jdk.internal.vm.annotation.Stable; * In any case, it may be invoked through an associated method handle * called its {@linkplain #dynamicInvoker dynamic invoker}. *

    - * {@code CallSite} is an abstract class which does not allow + * {@code CallSite} is an abstract sealed class which does not allow * direct subclassing by users. It has three immediate, - * concrete subclasses that may be either instantiated or subclassed. + * concrete non-sealed subclasses that may be either instantiated or subclassed. *

      *
    • If a mutable target is not required, an {@code invokedynamic} instruction * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}. @@ -85,7 +85,7 @@ private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String nam * @since 1.7 */ public -abstract class CallSite { +abstract sealed class CallSite permits ConstantCallSite, MutableCallSite, VolatileCallSite { // The actual payload of this call site. // Can be modified using {@link MethodHandleNatives#setCallSiteTargetNormal} or {@link MethodHandleNatives#setCallSiteTargetVolatile}. diff --git a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java index e2e3f478a3c..29e557ad141 100644 --- a/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/ConstantCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, 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 @@ -35,7 +35,7 @@ import jdk.internal.vm.annotation.Stable; * @author John Rose, JSR 292 EG * @since 1.7 */ -public class ConstantCallSite extends CallSite { +public non-sealed class ConstantCallSite extends CallSite { private static final Unsafe UNSAFE = Unsafe.getUnsafe(); @Stable // should NOT be constant folded during instance initialization (isFrozen == false) diff --git a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java index c16483d02ae..50ba77d8f96 100644 --- a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -83,7 +83,7 @@ assertEquals("Wilma, dear?", (String) worker2.invokeExact()); * @author John Rose, JSR 292 EG * @since 1.7 */ -public class MutableCallSite extends CallSite { +public non-sealed class MutableCallSite extends CallSite { /** * Creates a blank call site object with the given method type. * The initial target is set to a method handle of the given type diff --git a/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java b/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java index 742fa23737d..faf10fd79f4 100644 --- a/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/VolatileCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, 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 @@ -42,7 +42,7 @@ package java.lang.invoke; * @author John Rose, JSR 292 EG * @since 1.7 */ -public class VolatileCallSite extends CallSite { +public non-sealed class VolatileCallSite extends CallSite { /** * Creates a call site with a volatile binding to its target. * The initial target is set to a method handle -- GitLab From f01773956fbc092b00c18392735a020ca05257ed Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Wed, 23 Mar 2022 18:31:34 +0000 Subject: [PATCH 136/237] 8282241: Invalid generic signature for redefined classes Reviewed-by: coleenp, sspitsyn --- .../share/prims/jvmtiRedefineClasses.cpp | 19 +- .../RedefineGenericSignatureTest.java | 196 ++++++++++++++++++ 2 files changed, 205 insertions(+), 10 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineGenericSignatureTest.java diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 586c0679177..e8ba72cbc0e 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1856,14 +1856,15 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite( if (old_cp->has_dynamic_constant()) { scratch_cp->set_has_dynamic_constant(); } - // Copy attributes from scratch_cp to merge_cp - merge_cp->copy_fields(scratch_cp()); log_info(redefine, class, constantpool)("merge_cp_len=%d, index_map_len=%d", merge_cp_length, _index_map_count); if (_index_map_count == 0) { // there is nothing to map between the new and merged constant pools + // Copy attributes from scratch_cp to merge_cp + merge_cp->copy_fields(scratch_cp()); + if (old_cp->length() == scratch_cp->length()) { // The old and new constant pools are the same length and the // index map is empty. This means that the three constant pools @@ -1917,6 +1918,9 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite( return JVMTI_ERROR_INTERNAL; } + // Copy attributes from scratch_cp to merge_cp (should be done after rewrite_cp_refs()) + merge_cp->copy_fields(scratch_cp()); + // Replace the new constant pool with a shrunken copy of the // merged constant pool so now the rewritten bytecodes have // valid references; the previous new constant pool will get @@ -3492,10 +3496,9 @@ void VM_RedefineClasses::rewrite_cp_refs_in_verification_type_info( } // end rewrite_cp_refs_in_verification_type_info() -// Change the constant pool associated with klass scratch_class to -// scratch_cp. If shrink is true, then scratch_cp_length elements -// are copied from scratch_cp to a smaller constant pool and the -// smaller constant pool is associated with scratch_class. +// Change the constant pool associated with klass scratch_class to scratch_cp. +// scratch_cp_length elements are copied from scratch_cp to a smaller constant pool +// and the smaller constant pool is associated with scratch_class. void VM_RedefineClasses::set_new_constant_pool( ClassLoaderData* loader_data, InstanceKlass* scratch_class, constantPoolHandle scratch_cp, @@ -4357,10 +4360,6 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas // Leave arrays of jmethodIDs and itable index cache unchanged - // Copy the "source file name" attribute from new class version - the_class->set_source_file_name_index( - scratch_class->source_file_name_index()); - // Copy the "source debug extension" attribute from new class version the_class->set_source_debug_extension( scratch_class->source_debug_extension(), diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineGenericSignatureTest.java b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineGenericSignatureTest.java new file mode 100644 index 00000000000..b16120037e2 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineGenericSignatureTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2022, 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 8282241 + * @summary Verifies class redefinition correctly updates generic_signature and source_file_name attributes + * @requires vm.jvmti + * @modules java.base/jdk.internal.org.objectweb.asm + * java.instrument + * @library /test/lib + * @run compile -g RedefineGenericSignatureTest.java + * @run main RedefineClassHelper + * @run main/othervm -javaagent:redefineagent.jar --add-opens=java.base/java.lang=ALL-UNNAMED RedefineGenericSignatureTest + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.util.List; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.ClassWriter; +import jdk.internal.org.objectweb.asm.Opcodes; +import jdk.test.lib.Asserts; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.compiler.InMemoryJavaCompiler; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +class GenericSignatureTester { + public GenericSignatureTarget> method1() { + return null; + } +} + +class GenericSignatureTarget> { + public GenericSignatureTarget foo() { return null; } + public static void throwException() { throw new RuntimeException(); } +} + +public class RedefineGenericSignatureTest { + private static final String newTargetClassSource = + "class GenericSignatureTarget {\n" + + " public GenericSignatureTarget foo() { return null; }\n" + + " public static void throwException() { throw new RuntimeException(); }\n" + + "}\n"; + + public static void main (String[] args) throws Throwable { + RedefineGenericSignatureTest test = new RedefineGenericSignatureTest(); + test.runTest(); + } + + private final static String sourceFileName = "RedefineGenericSignatureTest.java"; + private final static String sourceFileNameNew = "RedefineGenericSignatureTestNew.java"; + // expected signature of GenericSignatureTester.method1 return type + private final static String expectedRetType = "GenericSignatureTarget>"; + // expected generic signature of the original GenericSignatureTarget + private final static String expectedSigOld = ";>Ljava/lang/Object;"; + // expected generic signature of the redefined GenericSignatureTarget + private final static String expectedSigNew = "Ljava/lang/Object;"; + + private static void log(Object o) { + System.out.println(o); + } + + private String getTargetGenSig() throws Throwable { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + MethodHandles.Lookup classLookup = MethodHandles.privateLookupIn(Class.class, lookup); + MethodHandle getGenericSignature0 = classLookup.findVirtual( + Class.class, "getGenericSignature0", MethodType.methodType(String.class)); + Object genericSignature = getGenericSignature0.invoke(GenericSignatureTarget.class); + return String.valueOf(genericSignature); + } + + private String getTesterRetType() throws Throwable { + Type type = GenericSignatureTester.class.getDeclaredMethod("method1").getGenericReturnType(); + return String.valueOf(type); + } + + private String getTargetSourceFilename() { + try { + GenericSignatureTarget.throwException(); + } catch (RuntimeException ex) { + return ex.getStackTrace()[0].getFileName(); + } + return "Cannot get source file name"; + } + + // Prints dissassembled class bytes. + private void printDisassembled(String description, Class cls, byte[] bytes) throws Exception { + log(description + " -------------------"); + + File f = new File(cls.getSimpleName()+".class"); + try (FileOutputStream fos = new FileOutputStream(f)) { + fos.write(bytes); + } + JDKToolLauncher javap = JDKToolLauncher.create("javap") + .addToolArg("-verbose") + .addToolArg("-p") // Shows all classes and members. + //.addToolArg("-c") // Prints out disassembled code + .addToolArg("-s") // Prints internal type signatures. + .addToolArg(f.toString()); + ProcessBuilder pb = new ProcessBuilder(javap.getCommand()); + OutputAnalyzer out = ProcessTools.executeProcess(pb); + out.shouldHaveExitValue(0); + try { + Files.delete(f.toPath()); + } catch (Exception ex) { + // ignore + } + out.asLines().forEach(s -> log(s)); + log("=========================================="); + Files.deleteIfExists(f.toPath()); + } + + private byte[] getNewClassBytes() { + byte[] bytecode = InMemoryJavaCompiler.compile(GenericSignatureTarget.class.getName(), newTargetClassSource, "-g"); + + ClassWriter cw = new ClassWriter(0); + ClassReader cr = new ClassReader(bytecode); + cr.accept(new ClassVisitor(Opcodes.ASM7, cw) { + private boolean sourceSet = false; + @Override + public void visitSource(String source, String debug) { + sourceSet = true; + log("Changing source: \"" + source + "\" -> \"" + sourceFileNameNew + "\""); + super.visitSource(sourceFileNameNew, debug); + } + + @Override + public void visitEnd() { + if (!sourceSet) { + log("Set source: \"" + sourceFileNameNew + "\""); + super.visitSource(sourceFileNameNew, null); + } + super.visitEnd(); + } + }, 0); + return cw.toByteArray(); + } + + private void runTest() throws Throwable { + Class targetClass = GenericSignatureTarget.class; + + String oldSig = getTargetGenSig(); + log("old target class sig: \"" + oldSig + "\""); + + byte[] oldClassBytes = targetClass.getResourceAsStream(targetClass.getName() + ".class").readAllBytes(); + printDisassembled("Old " + targetClass.getName(), targetClass, oldClassBytes); + + log("Redefining " + targetClass.getName() + " class"); + byte[] newClassBytes = getNewClassBytes(); + printDisassembled("New " + targetClass.getName(), targetClass, newClassBytes); + RedefineClassHelper.redefineClass(targetClass, newClassBytes); + + String newSig = getTargetGenSig(); + log("new target class sig: \"" + newSig + "\""); + + String newRetType = getTesterRetType(); + log("new tester ret type: \"" + newRetType + "\""); + + String newSrcFileName = getTargetSourceFilename(); + log("new source file name: \"" + newSrcFileName + "\""); + + Asserts.assertStringsEqual(expectedSigOld, oldSig, "wrong old generic signature"); + Asserts.assertStringsEqual(expectedSigNew, newSig, "wrong new generic signature"); + Asserts.assertStringsEqual(expectedRetType, newRetType, "wrong ret type"); + Asserts.assertStringsEqual(sourceFileNameNew, newSrcFileName, "wrong new source file name"); + } +} -- GitLab From 138460c004a9a21a84f892896cf2f172fab2ac99 Mon Sep 17 00:00:00 2001 From: Sean Mullan Date: Wed, 23 Mar 2022 18:32:55 +0000 Subject: [PATCH 137/237] 8163327: Remove 3DES from the default enabled cipher suites list Reviewed-by: xuelei --- .../classes/sun/security/ssl/CipherSuite.java | 76 +++++++++---------- test/jdk/javax/net/ssl/DTLS/CipherSuite.java | 12 ++- .../ssl/ciphersuites/DisabledAlgorithms.java | 43 ++++++++--- ...uite.java => NoDesRC4DesEdeCiphSuite.java} | 27 +++++-- 4 files changed, 103 insertions(+), 55 deletions(-) rename test/jdk/sun/security/ssl/CipherSuite/{NoDesRC4CiphSuite.java => NoDesRC4DesEdeCiphSuite.java} (92%) diff --git a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java index 8500ae7e188..d957d7b20bd 100644 --- a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java +++ b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2022, 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 @@ -54,9 +54,9 @@ enum CipherSuite { // changed later, see below). // 2. Prefer forward secrecy cipher suites. // 3. Prefer the stronger bulk cipher, in the order of AES_256(GCM), - // AES_128(GCM), AES_256, AES_128, 3DES-EDE. + // AES_128(GCM), AES_256, AES_128. // 4. Prefer the stronger MAC algorithm, in the order of SHA384, - // SHA256, SHA, MD5. + // SHA256, SHA. // 5. Prefer the better performance of key exchange and digital // signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, // DHE-RSA, DHE-DSS, ECDH-ECDSA, ECDH-RSA, RSA. @@ -327,41 +327,6 @@ enum CipherSuite { ProtocolVersion.PROTOCOLS_TO_12, K_RSA, B_AES_128, M_SHA, H_SHA256), - // 3DES_EDE, forward secrecy. - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA( - 0xC008, true, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDHE_ECDSA, B_3DES, M_SHA, H_SHA256), - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA( - 0xC012, true, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDHE_RSA, B_3DES, M_SHA, H_SHA256), - SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA( - 0x0016, true, "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_RSA, B_3DES, M_SHA, H_SHA256), - SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA( - 0x0013, true, "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_DSS, B_3DES, M_SHA, H_SHA256), - - // 3DES_EDE, not forward secrecy. - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA( - 0xC003, true, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_ECDSA, B_3DES, M_SHA, H_SHA256), - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA( - 0xC00D, true, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_RSA, B_3DES, M_SHA, H_SHA256), - SSL_RSA_WITH_3DES_EDE_CBC_SHA( - 0x000A, true, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_RSA_WITH_3DES_EDE_CBC_SHA", - ProtocolVersion.PROTOCOLS_TO_12, - K_RSA, B_3DES, M_SHA, H_SHA256), - // Renegotiation protection request Signalling Cipher Suite Value (SCSV). TLS_EMPTY_RENEGOTIATION_INFO_SCSV( // RFC 5746, TLS 1.2 and prior 0x00FF, true, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", "", @@ -413,6 +378,41 @@ enum CipherSuite { 0x0034, false, "TLS_DH_anon_WITH_AES_128_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_DH_ANON, B_AES_128, M_SHA, H_SHA256), + + // 3DES_EDE, forward secrecy. + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA( + 0xC008, false, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDHE_ECDSA, B_3DES, M_SHA, H_SHA256), + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA( + 0xC012, false, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDHE_RSA, B_3DES, M_SHA, H_SHA256), + SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA( + 0x0016, false, "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + ProtocolVersion.PROTOCOLS_TO_12, + K_DHE_RSA, B_3DES, M_SHA, H_SHA256), + SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA( + 0x0013, false, "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + ProtocolVersion.PROTOCOLS_TO_12, + K_DHE_DSS, B_3DES, M_SHA, H_SHA256), + + // 3DES_EDE, not forward secrecy. + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA( + 0xC003, false, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_ECDSA, B_3DES, M_SHA, H_SHA256), + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA( + 0xC00D, false, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_RSA, B_3DES, M_SHA, H_SHA256), + SSL_RSA_WITH_3DES_EDE_CBC_SHA( + 0x000A, false, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + ProtocolVersion.PROTOCOLS_TO_12, + K_RSA, B_3DES, M_SHA, H_SHA256), TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA( 0xC017, false, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, diff --git a/test/jdk/javax/net/ssl/DTLS/CipherSuite.java b/test/jdk/javax/net/ssl/DTLS/CipherSuite.java index 773fb08d317..1c4b1c6d84f 100644 --- a/test/jdk/javax/net/ssl/DTLS/CipherSuite.java +++ b/test/jdk/javax/net/ssl/DTLS/CipherSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -51,6 +51,9 @@ import javax.net.ssl.SSLEngine; import java.security.Security; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * Test common DTLS cipher suites. @@ -59,10 +62,12 @@ public class CipherSuite extends DTLSOverDatagram { // use the specific cipher suite volatile static String cipherSuite; + private static boolean reenable; public static void main(String[] args) throws Exception { if (args.length > 1 && "re-enable".equals(args[1])) { Security.setProperty("jdk.tls.disabledAlgorithms", ""); + reenable = true; } cipherSuite = args[0]; @@ -77,6 +82,11 @@ public class CipherSuite extends DTLSOverDatagram { if (isClient) { engine.setEnabledCipherSuites(new String[]{cipherSuite}); + } else if (reenable) { + List cipherSuites = + new ArrayList(Arrays.asList(engine.getEnabledCipherSuites())); + cipherSuites.add(cipherSuite); + engine.setEnabledCipherSuites(cipherSuites.toArray(new String[0])); } return engine; diff --git a/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java b/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java index 7bb3e2c8d2b..441f6bdff48 100644 --- a/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java +++ b/test/jdk/javax/net/ssl/ciphersuites/DisabledAlgorithms.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 8076221 8211883 + * @bug 8076221 8211883 8163327 * @summary Check if weak cipher suites are disabled * @modules jdk.crypto.ec * @run main/othervm DisabledAlgorithms default @@ -60,9 +60,10 @@ public class DisabledAlgorithms { System.getProperty("test.src", "./") + "/" + pathToStores + "/" + trustStoreFile; - // supported RC4, NULL, and anon cipher suites + // supported 3DES, DES, RC4, NULL, and anon cipher suites // it does not contain KRB5 cipher suites because they need a KDC - private static final String[] rc4_null_anon_ciphersuites = new String[] { + private static final String[] desede_des_rc4_null_anon_ciphersuites + = new String[] { "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "TLS_ECDHE_RSA_WITH_RC4_128_SHA", "SSL_RSA_WITH_RC4_128_SHA", @@ -90,11 +91,25 @@ public class DisabledAlgorithms { "TLS_DH_anon_WITH_AES_256_CBC_SHA", "TLS_DH_anon_WITH_AES_256_CBC_SHA256", "TLS_DH_anon_WITH_AES_256_GCM_SHA384", + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "TLS_ECDH_anon_WITH_NULL_SHA", - "TLS_ECDH_anon_WITH_RC4_128_SHA" + "TLS_ECDH_anon_WITH_RC4_128_SHA", + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA" }; public static void main(String[] args) throws Exception { @@ -113,19 +128,25 @@ public class DisabledAlgorithms { System.out.println("jdk.tls.disabledAlgorithms = " + Security.getProperty("jdk.tls.disabledAlgorithms")); - // check if RC4, NULL, and anon cipher suites + // check if 3DES, DES, RC4, NULL, and anon cipher suites // can't be used by default - checkFailure(rc4_null_anon_ciphersuites); + checkFailure(desede_des_rc4_null_anon_ciphersuites); break; case "empty": // reset jdk.tls.disabledAlgorithms Security.setProperty("jdk.tls.disabledAlgorithms", ""); System.out.println("jdk.tls.disabledAlgorithms = " + Security.getProperty("jdk.tls.disabledAlgorithms")); - - // check if RC4, NULL, and anon cipher suites can be used - // if jdk.tls.disabledAlgorithms is empty - checkSuccess(rc4_null_anon_ciphersuites); + // reset jdk.certpath.disabledAlgorithms. This is necessary + // to allow the RSA_EXPORT suites to pass which use an RSA 512 + // bit key which violates the default certpath constraints. + Security.setProperty("jdk.certpath.disabledAlgorithms", ""); + System.out.println("jdk.certpath.disabledAlgorithms = " + + Security.getProperty("jdk.certpath.disabledAlgorithms")); + + // check if 3DES, DES, RC4, NULL, and anon cipher suites + // can be used if jdk.{tls,certpath}.disabledAlgorithms is empty + checkSuccess(desede_des_rc4_null_anon_ciphersuites); break; default: throw new RuntimeException("Wrong parameter: " + args[0]); diff --git a/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java b/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4DesEdeCiphSuite.java similarity index 92% rename from test/jdk/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java rename to test/jdk/sun/security/ssl/CipherSuite/NoDesRC4DesEdeCiphSuite.java index 22238d38e1d..c9861324237 100644 --- a/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4CiphSuite.java +++ b/test/jdk/sun/security/ssl/CipherSuite/NoDesRC4DesEdeCiphSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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,9 +23,9 @@ /* * @test - * @bug 8208350 - * @summary Disable all DES cipher suites - * @run main/othervm NoDesRC4CiphSuite + * @bug 8208350 8163327 + * @summary Disable all DES, RC4, and 3DES/DesEde cipher suites + * @run main/othervm NoDesRC4DesEdeCiphSuite */ /* @@ -43,7 +43,7 @@ import java.util.List; import java.util.ArrayList; import java.util.Arrays; -public class NoDesRC4CiphSuite { +public class NoDesRC4DesEdeCiphSuite { private static final boolean DEBUG = false; @@ -80,6 +80,18 @@ public class NoDesRC4CiphSuite { "SSL_RSA_EXPORT_WITH_RC4_40_MD5", "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5" }; + private static final List DESEDE_CS_LIST = Arrays.asList( + 0xC008, 0xC012, 0x0016, 0x0013, 0xC003, 0xC00D, 0x000A + ); + private static final String[] DESEDE_CS_LIST_NAMES = new String[] { + "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", + "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA" + }; private static final ByteBuffer CLIOUTBUF = ByteBuffer.wrap("Client Side".getBytes()); @@ -99,6 +111,11 @@ public class NoDesRC4CiphSuite { allGood &= testEngAddDisabled(RC4_CS_LIST_NAMES, RC4_CS_LIST); allGood &= testEngOnlyDisabled(RC4_CS_LIST_NAMES); + // Disabled 3DES tests + allGood &= testDefaultCase(DESEDE_CS_LIST); + allGood &= testEngAddDisabled(DESEDE_CS_LIST_NAMES, DESEDE_CS_LIST); + allGood &= testEngOnlyDisabled(DESEDE_CS_LIST_NAMES); + if (allGood) { System.err.println("All tests passed"); } else { -- GitLab From 0b11b576a2a53446444a6d4899faa0be9e7bb18a Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 23 Mar 2022 19:18:57 +0000 Subject: [PATCH 138/237] 8283222: improve diagnosability of runtime/8176717/TestInheritFD.java timeouts Reviewed-by: dholmes, hseigel --- .../jtreg/runtime/8176717/TestInheritFD.java | 208 +++++++++++++++--- 1 file changed, 177 insertions(+), 31 deletions(-) diff --git a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java index 37c5280d236..c84bc7e0159 100644 --- a/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java +++ b/test/hotspot/jtreg/runtime/8176717/TestInheritFD.java @@ -21,6 +21,7 @@ * questions. */ +import static java.lang.Character.isDigit; import static java.lang.Long.parseLong; import static java.lang.System.getProperty; import static java.nio.file.Files.readAllBytes; @@ -40,6 +41,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.Collection; +import java.util.concurrent.TimeUnit; import java.util.Optional; import java.util.stream.Stream; @@ -60,17 +62,18 @@ import java.util.stream.Stream; * * This test is performed in three steps. The first VM starts a second VM with * gc logging enabled. The second VM starts a third VM and redirects the third - * VMs output to the first VM, it then exits and hopefully closes its log file. + * VMs output to the first VM. The second VM then exits and hopefully closes + * its log file. * - * The third VM waits for the second to exit and close its log file. After that, - * the third VM tries to rename the log file of the second VM. If it succeeds in - * doing so it means that the third VM did not inherit the open log file - * (windows can not rename opened files easily) + * The third VM waits for the second to exit and close its log file. + * On Windows, the third VM tries to rename the log file of the second VM. + * If it succeeds in doing so it means that the third VM did not inherit + * the open log file (windows cannot rename opened files easily). + * On unix like systems, the third VM uses "lsof" for verification. * - * The third VM communicates the success to rename the file by printing "CLOSED - * FD". The first VM checks that the string was printed by the third VM. - * - * On unix like systems "lsof" is used. + * The third VM communicates success by printing "RETAINS FD". The first VM + * waits for the third VM to exit and checks that the string was printed by + * the third VM. */ public class TestInheritFD { @@ -80,9 +83,145 @@ public class TestInheritFD { public static final String EXIT = "VM RESULT => VM EXIT"; public static final String LOG_SUFFIX = ".strangelogsuffixthatcanbecheckedfor"; public static final String USER_DIR = System.getProperty("user.dir"); + public static final String LSOF_PID_PREFIX = " VM lsof pid="; + public static final String SECOND_VM_PID_PREFIX = "Second VM pid="; + public static final String THIRD_VM_PID_PREFIX = "Third VM pid="; + public static final String THIRD_VM_WAITING_PREFIX = "Third VM waiting for second VM pid="; + + public static float timeoutFactor = Float.parseFloat(System.getProperty("test.timeout.factor", "1.0")); + public static long subProcessTimeout = (long)(15L * timeoutFactor); + + // Extract a pid from the specified String at the specified start offset. + private static long extractPidFromStringOffset(String str, int start) { + int end; + for (end = start; end < str.length(); end++) { + if (!isDigit(str.charAt(end))) { + break; + } + } + if (start == end) { // no digits at all + return -1; + } + return parseLong(str.substring(start, end)); + } + + // Wait for the sub-process pids identified in commFile to finish executing. + // Returns true if RETAINS_FD was found in the commFile and false otherwise. + private static boolean waitForSubPids(File commFile) throws Exception { + String out = ""; + int sleepCnt = 0; + long secondVMPID = -1; + long secondVMlsofPID = -1; + long thirdVMPID = -1; + long thirdVMlsofPID = -1; + // Only have to gather info until the doneWithPattern shows up in the output: + String doneWithPattern; + if (isWindows()) { + doneWithPattern = THIRD_VM_PID_PREFIX; + } else { + doneWithPattern = "Third" + LSOF_PID_PREFIX; + } + do { + out = new String(readAllBytes(commFile.toPath())); + if (secondVMPID == -1) { + int ind = out.indexOf(SECOND_VM_PID_PREFIX); + if (ind != -1) { + int startPid = ind + SECOND_VM_PID_PREFIX.length(); + secondVMPID = extractPidFromStringOffset(out, startPid); + System.out.println("secondVMPID=" + secondVMPID); + } + } + if (!isWindows() && secondVMlsofPID == -1) { + String prefix = "Second" + LSOF_PID_PREFIX; + int ind = out.indexOf(prefix); + if (ind != -1) { + int startPid = ind + prefix.length(); + secondVMlsofPID = extractPidFromStringOffset(out, startPid); + System.out.println("secondVMlsofPID=" + secondVMlsofPID); + } + } + if (thirdVMPID == -1) { + int ind = out.indexOf(THIRD_VM_PID_PREFIX); + if (ind != -1) { + int startPid = ind + THIRD_VM_PID_PREFIX.length(); + thirdVMPID = extractPidFromStringOffset(out, startPid); + System.out.println("thirdVMPID=" + thirdVMPID); + } + } + if (!isWindows() && thirdVMlsofPID == -1) { + String prefix = "Third" + LSOF_PID_PREFIX; + int ind = out.indexOf(prefix); + if (ind != -1) { + int startPid = ind + prefix.length(); + thirdVMlsofPID = extractPidFromStringOffset(out, startPid); + System.out.println("thirdVMlsofPID=" + thirdVMlsofPID); + } + } + Thread.sleep(100); + sleepCnt++; + } while (!out.contains(doneWithPattern) && !out.contains(EXIT)); + + System.out.println("Called Thread.sleep(100) " + sleepCnt + " times."); + + long subPids[] = new long[4]; // At most 4 pids to check. + String subNames[] = new String[4]; // At most 4 names for those pids. + int ind = 0; + if (!isWindows() && secondVMlsofPID != -1) { + // The second VM's lsof cmd should be the first non-windows sub-process to finish: + subPids[ind] = secondVMlsofPID; + subNames[ind] = "second VM lsof"; + ind++; + } + // The second VM should the second non-windows or first windows sub-process to finish: + subPids[ind] = secondVMPID; + subNames[ind] = "second VM"; + ind++; + if (!isWindows() && thirdVMlsofPID != -1) { + // The third VM's lsof cmd should be the third non-windows sub-process to finish: + subPids[ind] = thirdVMlsofPID; + subNames[ind] = "third VM lsof"; + ind++; + } + // The third VM should the last sub-process to finish: + subPids[ind] = thirdVMPID; + subNames[ind] = "third VM"; + ind++; + if (isWindows()) { + // No lsof pids on windows so we use fewer array slots. + // Make sure they are marked as not used. + for (; ind < subPids.length; ind++) { + subPids[ind] = -1; + } + } + + try { + for (ind = 0; ind < subPids.length; ind++) { + if (subPids[ind] == -1) { + continue; + } + System.out.print("subs[" + ind + "]={pid=" + subPids[ind] + ", name=" + subNames[ind] + "}"); + ProcessHandle.of(subPids[ind]).ifPresent(handle -> handle.onExit().orTimeout(subProcessTimeout, TimeUnit.SECONDS).join()); + System.out.println(" finished."); + } + } catch (Exception e) { + // Terminate the "subs" line from above: + System.out.println(" Exception was thrown while trying to join() subPids: " + e.toString()); + throw e; + } finally { + // Reread to get everything in the commFile: + out = new String(readAllBytes(commFile.toPath())); + System.out.println(""); + System.out.println(out); + System.out.println(""); + } + + return out.contains(RETAINS_FD); + } // first VM public static void main(String[] args) throws Exception { + System.out.println("subProcessTimeout=" + subProcessTimeout + " seconds."); + System.out.println("First VM starts."); String logPath = Utils.createTempFile("logging", LOG_SUFFIX).toFile().getName(); File commFile = Utils.createTempFile("communication", ".txt").toFile(); @@ -99,24 +238,18 @@ public class TestInheritFD { pb.redirectOutput(commFile); // use temp file to communicate between processes pb.start(); - String out = ""; - do { - out = new String(readAllBytes(commFile.toPath())); - Thread.sleep(100); - System.out.println("SLEEP 100 millis"); - } while (!out.contains(EXIT)); - - System.out.println(out); - if (out.contains(RETAINS_FD)) { - System.out.println("Log file was not inherited by third VM"); + if (waitForSubPids(commFile)) { + System.out.println("Log file was not inherited by third VM."); } else { - throw new RuntimeException("could not match: " + RETAINS_FD); + throw new RuntimeException("Log file was leaked to the third VM."); } + System.out.println("First VM ends."); } static class VMStartedWithLogging { // second VM public static void main(String[] args) throws IOException, InterruptedException { + System.out.println(SECOND_VM_PID_PREFIX + ProcessHandle.current().pid()); ProcessBuilder pb = createJavaProcessBuilder( "-Dtest.jdk=" + getProperty("test.jdk"), VMShouldNotInheritFileDescriptors.class.getName(), @@ -126,30 +259,43 @@ public class TestInheritFD { pb.start(); if (!isWindows()) { - System.out.println("(Second VM) Open file descriptors:\n" + outputContainingFilenames().stream().collect(joining("\n"))); + System.out.println("(Second VM) Open file descriptors:\n" + outputContainingFilenames("Second").stream().collect(joining("\n"))); + } + if (false) { // Enable to simulate a timeout in the second VM. + Thread.sleep(300 * 1000); } + System.out.println("Second VM ends."); } } static class VMShouldNotInheritFileDescriptors { // third VM public static void main(String[] args) throws InterruptedException { + System.out.println(THIRD_VM_PID_PREFIX + ProcessHandle.current().pid()); try { File logFile = new File(args[0]); long parentPid = parseLong(args[1]); fakeLeakyJVM(false); // for debugging of test case + System.out.println(THIRD_VM_WAITING_PREFIX + parentPid); + ProcessHandle.of(parentPid).ifPresent(handle -> handle.onExit().orTimeout(subProcessTimeout, TimeUnit.SECONDS).join()); + if (isWindows()) { - windows(logFile, parentPid); + windows(logFile); } else { - Collection output = outputContainingFilenames(); + Collection output = outputContainingFilenames("Third"); System.out.println("(Third VM) Open file descriptors:\n" + output.stream().collect(joining("\n"))); System.out.println(findOpenLogFile(output) ? LEAKS_FD : RETAINS_FD); } + if (false) { // Enable to simulate a timeout in the third VM. + Thread.sleep(300 * 1000); + } } catch (Exception e) { - System.out.println(e.toString()); + System.out.println("Exception was thrown: " + e.toString()); + throw e; } finally { System.out.println(EXIT); + System.out.println("Third VM ends."); } } } @@ -165,9 +311,11 @@ public class TestInheritFD { } } - static Stream run(String... args){ + static Stream runLsof(String whichVM, String... args){ try { - return new BufferedReader(new InputStreamReader(new ProcessBuilder(args).start().getInputStream())).lines(); + Process lsof = new ProcessBuilder(args).start(); + System.out.println(whichVM + LSOF_PID_PREFIX + lsof.pid()); + return new BufferedReader(new InputStreamReader(lsof.getInputStream())).lines(); } catch (IOException e) { throw new RuntimeException(e); } @@ -186,12 +334,12 @@ public class TestInheritFD { return lsofCommandCache; } - static Collection outputContainingFilenames() { + static Collection outputContainingFilenames(String whichVM) { long pid = ProcessHandle.current().pid(); String[] command = lsofCommand().orElseThrow(() -> new RuntimeException("lsof like command not found")); // Only search the directory in which the VM is running (user.dir property). System.out.println("using command: " + command[0] + " -a +d " + USER_DIR + " " + command[1] + " " + pid); - return run(command[0], "-a", "+d", USER_DIR, command[1], "" + pid).collect(toList()); + return runLsof(whichVM, command[0], "-a", "+d", USER_DIR, command[1], "" + pid).collect(toList()); } static boolean findOpenLogFile(Collection fileNames) { @@ -208,9 +356,7 @@ public class TestInheritFD { .isPresent(); } - static void windows(File f, long parentPid) throws InterruptedException { - System.out.println("waiting for pid: " + parentPid); - ProcessHandle.of(parentPid).ifPresent(handle -> handle.onExit().join()); + static void windows(File f) throws InterruptedException { System.out.println("trying to rename file to the same name: " + f); System.out.println(f.renameTo(f) ? RETAINS_FD : LEAKS_FD); // this parts communicates a closed file descriptor by printing "VM RESULT => RETAINS FD" } -- GitLab From f9137cb7b79f86e96247e7b4bc4abb03857afe75 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Wed, 23 Mar 2022 19:27:56 +0000 Subject: [PATCH 139/237] 8280896: java/nio/file/Files/probeContentType/Basic.java fails on Windows 11 Reviewed-by: jpai, bpb --- test/jdk/java/nio/file/Files/probeContentType/Basic.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/jdk/java/nio/file/Files/probeContentType/Basic.java b/test/jdk/java/nio/file/Files/probeContentType/Basic.java index b404673b2f4..74e4cd5ab39 100644 --- a/test/jdk/java/nio/file/Files/probeContentType/Basic.java +++ b/test/jdk/java/nio/file/Files/probeContentType/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -161,7 +161,7 @@ public class Basic { new ExType("doc", List.of("application/msword")), new ExType("docx", List.of("application/vnd.openxmlformats-officedocument.wordprocessingml.document")), new ExType("gz", List.of("application/gzip", "application/x-gzip")), - new ExType("jar", List.of("application/java-archive", "application/x-java-archive")), + new ExType("jar", List.of("application/java-archive", "application/x-java-archive", "application/jar")), new ExType("jpg", List.of("image/jpeg")), new ExType("js", List.of("text/javascript", "application/javascript")), new ExType("json", List.of("application/json")), -- GitLab From 0ee65e1ff3eaed4a8a2542562f0ba2a61d0f5894 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 23 Mar 2022 19:44:04 +0000 Subject: [PATCH 140/237] 8283465: Character.UnicodeBlock.NUM_ENTITIES is out of date Reviewed-by: bpb, iris, smarks --- .../share/classes/java/lang/Character.java | 7 +- .../UnicodeBlock/NumberEntities.java | 50 +++++++++++++ .../UnicodeBlock/OptimalMapSize.java | 73 ------------------- 3 files changed, 55 insertions(+), 75 deletions(-) create mode 100644 test/jdk/java/lang/Character/UnicodeBlock/NumberEntities.java delete mode 100644 test/jdk/java/lang/Character/UnicodeBlock/OptimalMapSize.java diff --git a/src/java.base/share/classes/java/lang/Character.java b/src/java.base/share/classes/java/lang/Character.java index 92e9b5b43f5..d30743b143c 100644 --- a/src/java.base/share/classes/java/lang/Character.java +++ b/src/java.base/share/classes/java/lang/Character.java @@ -737,10 +737,13 @@ class Character implements java.io.Serializable, Comparable, Constabl */ public static final class UnicodeBlock extends Subset { /** - * 696 - the expected number of entities + * NUM_ENTITIES should match the total number of UnicodeBlocks + * to calculate the initial capacity of the map. It should be + * adjusted whenever the Unicode Character Database is upgraded. + * * 0.75 - the default load factor of HashMap */ - private static final int NUM_ENTITIES = 696; + private static final int NUM_ENTITIES = 737; private static Map map = new HashMap<>((int)(NUM_ENTITIES / 0.75f + 1.0f)); diff --git a/test/jdk/java/lang/Character/UnicodeBlock/NumberEntities.java b/test/jdk/java/lang/Character/UnicodeBlock/NumberEntities.java new file mode 100644 index 00000000000..a2a2312d6e3 --- /dev/null +++ b/test/jdk/java/lang/Character/UnicodeBlock/NumberEntities.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 2022, 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 8080535 8191410 8215194 8221431 8239383 8268081 8283465 + * @summary Check if the NUM_ENTITIES field reflects the correct number + * of Character.UnicodeBlock constants. + * @modules java.base/java.lang:open + * @run testng NumberEntities + */ + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.Test; + +import java.lang.reflect.Field; +import java.util.Map; + +@Test +public class NumberEntities { + public void test_NumberEntities() throws Throwable { + // The number of entries in Character.UnicodeBlock.map. + // See src/java.base/share/classes/java/lang/Character.java + Field n = Character.UnicodeBlock.class.getDeclaredField("NUM_ENTITIES"); + Field m = Character.UnicodeBlock.class.getDeclaredField("map"); + n.setAccessible(true); + m.setAccessible(true); + assertEquals(((Map)m.get(null)).size(), n.getInt(null)); + } +} diff --git a/test/jdk/java/lang/Character/UnicodeBlock/OptimalMapSize.java b/test/jdk/java/lang/Character/UnicodeBlock/OptimalMapSize.java deleted file mode 100644 index abe63eb0b7c..00000000000 --- a/test/jdk/java/lang/Character/UnicodeBlock/OptimalMapSize.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015, 2022, 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 8080535 8191410 8215194 8221431 8239383 8268081 - * @summary Expected size of Character.UnicodeBlock.map is not optimal - * @library /test/lib - * @modules java.base/java.lang:open - * java.base/java.util:open - * @build jdk.test.lib.util.OptimalCapacity - * @run main OptimalMapSize - */ - -import java.lang.reflect.Field; -import jdk.test.lib.util.OptimalCapacity; - -// What will be the number of the Unicode blocks in the future. -// -// According to http://www.unicode.org/versions/Unicode7.0.0/ , -// in Unicode 7 there will be added 32 new blocks (96 with aliases). -// According to http://www.unicode.org/versions/beta-8.0.0.html , -// in Unicode 8 there will be added 10 more blocks (30 with aliases). -// -// After implementing support of Unicode 9 and 10 in Java, there will -// be 638 entries in Character.UnicodeBlock.map. -// -// As of Unicode 11, 667 entries are expected. -// As of Unicode 12.1, 676 entries are expected. -// As of Unicode 13.0, 684 entries are expected. -// As of Unicode 14.0, 696 entries are expected. -// -// Initialization of the map and this test will have to be adjusted -// accordingly then. -// -// Note that HashMap's implementation aligns the initial capacity to -// a power of two size, so it will end up 1024 (and thus succeed) in -// cases, such as 638, 667, 676, 684, and 696. - -public class OptimalMapSize { - public static void main(String[] args) throws Throwable { - // The initial size of Character.UnicodeBlock.map. - // See src/java.base/share/classes/java/lang/Character.java - Field f = Character.UnicodeBlock.class.getDeclaredField("NUM_ENTITIES"); - f.setAccessible(true); - int num_entities = f.getInt(null); - assert num_entities == 696; - int initialCapacity = (int)(num_entities / 0.75f + 1.0f); - - OptimalCapacity.ofHashMap(Character.UnicodeBlock.class, - "map", initialCapacity); - } -} -- GitLab From 6917c39e450e0564b8db7c96be132881a6b0a112 Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Wed, 23 Mar 2022 23:42:39 +0000 Subject: [PATCH 141/237] 8283493: Create an automated regression test for RFE 4231298 Reviewed-by: serb --- .../JComboBoxPrototypeDisplayValueTest.java | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 test/jdk/javax/swing/JComboBox/4231298/JComboBoxPrototypeDisplayValueTest.java diff --git a/test/jdk/javax/swing/JComboBox/4231298/JComboBoxPrototypeDisplayValueTest.java b/test/jdk/javax/swing/JComboBox/4231298/JComboBoxPrototypeDisplayValueTest.java new file mode 100644 index 00000000000..bd71c4fabac --- /dev/null +++ b/test/jdk/javax/swing/JComboBox/4231298/JComboBoxPrototypeDisplayValueTest.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2003, 2022, 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. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Robot; +import java.util.Arrays; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListCellRenderer; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4231298 + * @summary This testcase tests the RFE 4231298 request, JComboBox Custom + * Renderer should not be called for non displaying elements if + * setPrototypeDisplayValue() has been invoked. + * @run main JComboBoxPrototypeDisplayValueTest + */ +public class JComboBoxPrototypeDisplayValueTest { + + private static Robot robot; + private static JFrame frame; + private static JComboBox buttonComboBox; + private static volatile int count; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + List lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + count = 0; + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + SwingUtilities + .invokeAndWait(() -> buttonComboBox.getPreferredSize()); + + robot.waitForIdle(); + if (count > 6) { + System.out.println("Test Failed"); + throw new RuntimeException( + "Custom Renderer got called " + count + " times, " + + "even after calling setPrototypeDisplayValue(), " + + "but the expected maximum is 6 times for " + laf); + } else { + System.out.println("Test Passed for " + laf); + } + } finally { + SwingUtilities.invokeAndWait( + JComboBoxPrototypeDisplayValueTest::disposeFrame); + } + } + } + + public static void createUI() { + Vector data = new Vector(IntStream.rangeClosed(1, 100).boxed() + .map(i -> new JButton("" + i)) + .collect(Collectors.toList())); + buttonComboBox = new JComboBox(data); + ButtonRenderer renderer = new ButtonRenderer(); + buttonComboBox.setRenderer(renderer); + buttonComboBox.setMaximumRowCount(25); + + // New method introduced in Java 1.4 + buttonComboBox.setPrototypeDisplayValue(new JButton("111111111")); + + frame = new JFrame(); + JPanel panel = new JPanel(); + panel.add(buttonComboBox); + frame.getContentPane().add(panel); + frame.setSize(200, 100); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.setVisible(true); + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + /** + * Custom ListCellRenderer used for the drop down portion and the text + * portion of the ComboBox. + */ + private static class ButtonRenderer implements ListCellRenderer { + private final Color selectedBackground; + private final Color selectedForeground; + private final Color background; + private final Color foreground; + + public ButtonRenderer() { + selectedBackground = Color.BLUE; + selectedForeground = Color.YELLOW; + background = Color.GRAY; + foreground = Color.RED; + } + + public Component getListCellRendererComponent(JList list, Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + JButton button = (JButton) value; + System.out.println( + "getListCellRendererComponent index = " + index + ", " + + "isSelected = " + isSelected + ", cellHasFocus = " + + cellHasFocus); + + button.setBackground(isSelected ? selectedBackground : background); + button.setForeground(isSelected ? selectedForeground : foreground); + + count++; + System.out.println("Value of the Counter is " + count); + + return button; + } + + } + +} -- GitLab From 8a044649bd722da54999f55ff2cf907682fdc180 Mon Sep 17 00:00:00 2001 From: Manukumar V S Date: Wed, 23 Mar 2022 23:46:58 +0000 Subject: [PATCH 142/237] 8282860: Write a regression test for JDK-4164779 Reviewed-by: serb --- .../JSplitPaneKeyboardNavigationTest.java | 220 ++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 test/jdk/javax/swing/JSplitPane/4164779/JSplitPaneKeyboardNavigationTest.java diff --git a/test/jdk/javax/swing/JSplitPane/4164779/JSplitPaneKeyboardNavigationTest.java b/test/jdk/javax/swing/JSplitPane/4164779/JSplitPaneKeyboardNavigationTest.java new file mode 100644 index 00000000000..ced7410bf06 --- /dev/null +++ b/test/jdk/javax/swing/JSplitPane/4164779/JSplitPaneKeyboardNavigationTest.java @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2002, 2022, 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. + */ + +import java.awt.BorderLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSplitPane; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/* + * @test + * @key headful + * @bug 4164779 + * @summary This test confirms that JSplitPane keyboard navigation supports F6 and Ctrl+Tab. + * @run main JSplitPaneKeyboardNavigationTest + */ +public class JSplitPaneKeyboardNavigationTest { + + private static final StringBuffer failedVerifiers = new StringBuffer(); + private static JPanel panel; + private static JButton leftButton; + private static JButton rightButton1; + private static JButton rightButton2; + private static JButton topButton; + private static JButton bottomButton; + private static Robot robot; + private static JFrame frame; + + public static void main(String[] s) throws Exception { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + List lafs = Arrays.stream(getInstalledLookAndFeels()) + .map(LookAndFeelInfo::getClassName) + .collect(Collectors.toList()); + for (final String laf : lafs) { + try { + AtomicBoolean lafSetSuccess = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + lafSetSuccess.set(setLookAndFeel(laf)); + if (lafSetSuccess.get()) { + createUI(); + } + }); + if (!lafSetSuccess.get()) { + continue; + } + robot.waitForIdle(); + + // Press Right button 1 and move focus to it. + pressButton(rightButton1); + hitKeys(KeyEvent.VK_F6); + + // Verifier1 - Verifies that, F6 transfers focus to the right/bottom side of the splitpane + if (isFocusOwner(rightButton2)) { + System.out.println("Verifier 1 passed"); + } else { + failedVerifiers.append("1,"); + System.out.println("Verifier 1 failed, rightButton2 is not focus owner," + + "F6 doesn't transfer focus to the right/bottom side of the splitpane"); + } + + // Press Right button 2 and move focus to it. + pressButton(rightButton2); + hitKeys(KeyEvent.VK_F6); + + // Verifier2 - Verifies that, F6 transfers focus to the left side of the parent splitpane, + // if the right/bottom side of splitpane already has focus, and it is contained within another splitpane + if (isFocusOwner(leftButton)) { + System.out.println("Verifier 2 passed"); + } else { + failedVerifiers.append("2,"); + System.out.println("Verifier 2 failed, leftButton is not focus owner, " + + "F6 doesn't transfer focus to the left side of the splitpane"); + } + + // Press Left button and move focus to it. + pressButton(leftButton); + hitKeys(KeyEvent.VK_CONTROL, KeyEvent.VK_TAB); + // Verifier3 - Verifies that, CTRL-TAB navigates forward outside the JSplitPane + if (isFocusOwner(bottomButton)) { + System.out.println("Verifier 3 passed"); + } else { + failedVerifiers.append("3,"); + System.out.println("Verifier 3 failed, bottomButton is not focus owner, " + + "CTRL-TAB doesn't navigate forward outside the JSplitPane"); + } + + // Press Left button and move focus to it. + pressButton(leftButton); + hitKeys(KeyEvent.VK_CONTROL, KeyEvent.VK_SHIFT, KeyEvent.VK_TAB); + + // Verifier4 - Verifies that, CTRL-SHIFT-TAB navigates backward outside the JSplitPane + if (isFocusOwner(topButton)) { + System.out.println("Verifier 4 passed"); + } else { + failedVerifiers.append("4"); + System.out.println("Verifier 4 failed, topButton is not focus owner, " + + "CTRL-SHIFT-TAB doesn't navigate backward outside the JSplitPane"); + } + + if (failedVerifiers.toString().isEmpty()) { + System.out.println("Test passed, All verifiers succeeded for " + laf); + } else { + throw new RuntimeException("Test failed, verifiers " + failedVerifiers.toString() + " failed for " + laf); + } + } finally { + SwingUtilities.invokeAndWait(JSplitPaneKeyboardNavigationTest::disposeFrame); + } + } + } + + private static boolean isFocusOwner(JButton button) throws Exception { + final AtomicBoolean isFocusOwner = new AtomicBoolean(false); + SwingUtilities.invokeAndWait(() -> { + isFocusOwner.set(button.isFocusOwner()); + }); + return isFocusOwner.get(); + } + + private static void pressButton(JButton button) throws Exception { + final AtomicReference loc = new AtomicReference<>(); + SwingUtilities.invokeAndWait(() -> { + loc.set(button.getLocationOnScreen()); + }); + final Point buttonLoc = loc.get(); + robot.mouseMove(buttonLoc.x + 8, buttonLoc.y + 8); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + } + + public static void createUI() { + frame = new JFrame(); + panel = new JPanel(); + panel.setLayout(new BorderLayout()); + leftButton = new JButton("Left Button"); + rightButton1 = new JButton("Right Button 1"); + rightButton2 = new JButton("Right Button 2"); + topButton = new JButton("Top Button"); + bottomButton = new JButton("Bottom Button"); + panel.add(topButton, BorderLayout.NORTH); + panel.add(bottomButton, BorderLayout.SOUTH); + final JSplitPane splitPane2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, rightButton1, rightButton2); + final JSplitPane splitPane1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, leftButton, splitPane2); + panel.add(splitPane1, BorderLayout.CENTER); + frame.setContentPane(panel); + frame.setSize(200, 200); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setAlwaysOnTop(true); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void hitKeys(int... keys) { + for (int key : keys) { + robot.keyPress(key); + } + + for (int i = keys.length - 1; i >= 0; i--) { + robot.keyRelease(keys[i]); + } + } + + private static boolean setLookAndFeel(String lafName) { + try { + UIManager.setLookAndFeel(lafName); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Ignoring Unsupported L&F: " + lafName); + return false; + } catch (ClassNotFoundException | InstantiationException + | IllegalAccessException e) { + throw new RuntimeException(e); + } + return true; + } + + private static void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + +} -- GitLab From 1a84d7590ae8d120c86d72e5b15ec89754f39ba0 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 24 Mar 2022 00:57:54 +0000 Subject: [PATCH 143/237] 8283594: Improve docs of ElementScanner classes Reviewed-by: jjg --- .../lang/model/util/ElementScanner14.java | 21 ++++++++++--------- .../lang/model/util/ElementScanner6.java | 18 +++++++++------- .../lang/model/util/ElementScanner7.java | 20 ++++++++++-------- .../lang/model/util/ElementScanner8.java | 20 ++++++++++-------- .../lang/model/util/ElementScanner9.java | 21 ++++++++++--------- 5 files changed, 54 insertions(+), 46 deletions(-) diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index ac1bc4976ca..4365c6df53c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -37,15 +37,16 @@ import static javax.lang.model.SourceVersion.*; * appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14} * source version. * - * The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * The visitXyz methods in this class scan their + * component elements by calling {@link ElementScanner6#scan(Element, + * Object) scan} on their {@linkplain Element#getEnclosedElements + * enclosed elements}, {@linkplain ExecutableElement#getParameters + * parameters}, etc., as indicated in the individual method + * specifications. A subclass can control the order elements are + * visited by overriding the visitXyz methods. + * Note that clients of a scanner may get the desired behavior by + * invoking {@code v.scan(e, p)} rather than {@code v.visit(e, p)} on + * the root objects of interest. * *

      When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java index b13bd3cd0cc..c2b628b033c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java @@ -35,14 +35,16 @@ import static javax.lang.model.SourceVersion.*; * A scanning visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_6 RELEASE_6} * source version. The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * class scan their component elements by calling {@link + * #scan(Element, P) scan} on their {@linkplain + * Element#getEnclosedElements enclosed elements}, {@linkplain + * ExecutableElement#getParameters parameters}, etc., as indicated in + * the individual method specifications. A subclass can control the + * order elements are visited by overriding the + * visitXyz methods. Note that clients of a + * scanner may get the desired behavior by invoking {@code v.scan(e, + * p)} rather than {@code v.visit(e, p)} on the root objects of + * interest. * *

      When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java index e79af27dacf..73e286cea55 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, 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 @@ -35,14 +35,16 @@ import static javax.lang.model.SourceVersion.*; * A scanning visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_7 RELEASE_7} * source version. The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * class scan their component elements by calling {@link + * ElementScanner6#scan(Element, Object) scan} on their {@linkplain + * Element#getEnclosedElements enclosed elements}, {@linkplain + * ExecutableElement#getParameters parameters}, etc., as indicated in + * the individual method specifications. A subclass can control the + * order elements are visited by overriding the + * visitXyz methods. Note that clients of a + * scanner may get the desired behavior by invoking {@code v.scan(e, + * p)} rather than {@code v.visit(e, p)} on the root objects of + * interest. * *

      When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java index 229ab1a512c..db3ee069d4b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner8.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, 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 @@ -35,14 +35,16 @@ import static javax.lang.model.SourceVersion.*; * A scanning visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_8 RELEASE_8} * source version. The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * class scan their component elements by calling {@link + * ElementScanner6#scan(Element, Object) scan} on their {@linkplain + * Element#getEnclosedElements enclosed elements}, {@linkplain + * ExecutableElement#getParameters parameters}, etc., as indicated in + * the individual method specifications. A subclass can control the + * order elements are visited by overriding the + * visitXyz methods. Note that clients of a + * scanner may get the desired behavior by invoking {@code v.scan(e, + * p)} rather than {@code v.visit(e, p)} on the root objects of + * interest. * *

      When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java index b36235afd2a..3ee290d70cf 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, 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 @@ -36,15 +36,16 @@ import static javax.lang.model.SourceVersion.*; * appropriate for source versions {@link SourceVersion#RELEASE_9 * RELEASE_9} through {@link SourceVersion#RELEASE_14 RELEASE_14}. * - * The visitXyz methods in this - * class scan their component elements by calling {@code scan} on - * their {@linkplain Element#getEnclosedElements enclosed elements}, - * {@linkplain ExecutableElement#getParameters parameters}, etc., as - * indicated in the individual method specifications. A subclass can - * control the order elements are visited by overriding the - * visitXyz methods. Note that clients of a scanner - * may get the desired behavior be invoking {@code v.scan(e, p)} rather - * than {@code v.visit(e, p)} on the root objects of interest. + * The visitXyz methods in this class scan their + * component elements by calling {@link ElementScanner6#scan(Element, + * Object) scan} on their {@linkplain Element#getEnclosedElements + * enclosed elements}, {@linkplain ExecutableElement#getParameters + * parameters}, etc., as indicated in the individual method + * specifications. A subclass can control the order elements are + * visited by overriding the visitXyz methods. + * Note that clients of a scanner may get the desired behavior by + * invoking {@code v.scan(e, p)} rather than {@code v.visit(e, p)} on + * the root objects of interest. * *

      When a subclass overrides a visitXyz method, the * new method can cause the enclosed elements to be scanned in the -- GitLab From a6740c010b7d37f991c8547be6ea72b198e9094f Mon Sep 17 00:00:00 2001 From: Pengfei Li Date: Thu, 24 Mar 2022 01:50:04 +0000 Subject: [PATCH 144/237] 8283408: Fix a C2 crash when filling arrays with unsafe Reviewed-by: roland, thartmann --- src/hotspot/share/opto/loopTransform.cpp | 13 +++- .../loopopts/FillArrayWithUnsafe.java | 63 +++++++++++++++++++ 2 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index dc9c2064ed9..253340a6be5 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -4047,10 +4047,17 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { index = new LShiftXNode(index, shift->in(2)); _igvn.register_new_node_with_optimizer(index); } - index = new AddPNode(base, base, index); - _igvn.register_new_node_with_optimizer(index); - Node* from = new AddPNode(base, index, offset); + Node* from = new AddPNode(base, base, index); _igvn.register_new_node_with_optimizer(from); + // For normal array fills, C2 uses two AddP nodes for array element + // addressing. But for array fills with Unsafe call, there's only one + // AddP node adding an absolute offset, so we do a NULL check here. + assert(offset != NULL || C->has_unsafe_access(), + "Only array fills with unsafe have no extra offset"); + if (offset != NULL) { + from = new AddPNode(base, from, offset); + _igvn.register_new_node_with_optimizer(from); + } // Compute the number of elements to copy Node* len = new SubINode(head->limit(), head->init_trip()); _igvn.register_new_node_with_optimizer(len); diff --git a/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java b/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java new file mode 100644 index 00000000000..6e3b840987a --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/FillArrayWithUnsafe.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022, Arm Limited. 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 8283408 + * @summary Fill a byte array with Java Unsafe API + * @run main/othervm -XX:+OptimizeFill compiler.loopopts.FillArrayWithUnsafe + */ + +package compiler.loopopts; + +import java.lang.reflect.Field; + +import sun.misc.Unsafe; + +public class FillArrayWithUnsafe { + + private static Unsafe unsafe; + + public static void main(String[] args) throws Exception { + Class klass = Unsafe.class; + Field field = klass.getDeclaredField("theUnsafe"); + field.setAccessible(true); + unsafe = (Unsafe) field.get(null); + + byte[] buffer; + // Make sure method newByteArray is compiled by C2 + for (int i = 0; i < 50000; i++) { + buffer = newByteArray(100, (byte) 0x80); + } + } + + public static byte[] newByteArray(int size, byte val) { + byte[] arr = new byte[size]; + int offset = unsafe.arrayBaseOffset(byte[].class); + for (int i = offset; i < offset + size; i++) { + unsafe.putByte(arr, i, val); + } + return arr; + } +} + -- GitLab From 2ef9767aae8e1798661fea615b096833bdb9d985 Mon Sep 17 00:00:00 2001 From: "lawrence.andrews" Date: Thu, 24 Mar 2022 02:55:21 +0000 Subject: [PATCH 145/237] 8270331: [TESTBUG] Error: Not a test or directory containing tests: java/awt/print/PrinterJob/InitToBlack.java Reviewed-by: prr --- .../awt/print/PrinterJob/InitToBlack.java | 146 ++++++++++++++++-- 1 file changed, 131 insertions(+), 15 deletions(-) diff --git a/test/jdk/java/awt/print/PrinterJob/InitToBlack.java b/test/jdk/java/awt/print/PrinterJob/InitToBlack.java index 783320829b6..a4d7dd0a958 100644 --- a/test/jdk/java/awt/print/PrinterJob/InitToBlack.java +++ b/test/jdk/java/awt/print/PrinterJob/InitToBlack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2022, 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 @@ -22,21 +22,57 @@ */ /** + * @test * @bug 4184565 * @summary Confirm that the default foreground color on a printer * graphics object is black so that rendering will appear * without having to execute setColor first. - * @run applet/manual=yesno InitToBlack.html + * @run main/manual InitToBlack */ -import java.awt.*; -import java.awt.print.*; -import java.applet.Applet; +import java.awt.BorderLayout; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.print.Book; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; -public class InitToBlack extends Applet implements Printable { +public class InitToBlack implements Printable { - public void init() { + private static volatile JFrame frame; + private static volatile boolean testResult = false; + private static volatile CountDownLatch printButtonCountDownLatch = + new CountDownLatch(1); + private static volatile CountDownLatch CountDownLatch = + new CountDownLatch(1); + private static volatile String failureReason; + + @Override + public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { + Graphics2D g2d = (Graphics2D) graphics; + g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); + graphics.drawString("Test Passes", 200, 200); + return PAGE_EXISTS; + } + + private void test() { PrinterJob pjob = PrinterJob.getPrinterJob(); + if (pjob.getPrintService() == null) { + System.out.println("There is no printer configured on this system"); + return; + } Book book = new Book(); book.append(this, pjob.defaultPage()); @@ -49,17 +85,97 @@ public class InitToBlack extends Applet implements Printable { } } - public int print(Graphics g, PageFormat pf, int pageIndex) { - Graphics2D g2d = (Graphics2D) g; - g2d.translate(pf.getImageableX(), pf.getImageableY()); + private static void createTestUI() { + frame = new JFrame("Test InitToBlack"); + String INSTRUCTION = """ + Aim: This test checks whether the default foreground color on a printer + graphics object is black so that rendering will appear without having + to execute setColor. + Step: + 1) Click on the "Print" button. Check whether page is printed on the printer. + 2) Check whether "Test Passes" is printed on the page and it should be in + black color. If yes then press "Pass" button else press "Fail" button. + """; + JTextArea instructionTextArea = new JTextArea(INSTRUCTION, 4, 40); + instructionTextArea.setEditable(false); - g.drawString("Test Passes", 200, 200); + JPanel buttonPanel = new JPanel(); + JButton printButton = new JButton("Print"); + printButton.addActionListener((ae) -> { + InitToBlack initToBlack = new InitToBlack(); + initToBlack.test(); + printButtonCountDownLatch.countDown(); + }); - return PAGE_EXISTS; + JButton passButton = new JButton("Pass"); + passButton.addActionListener((ae) -> { + testResult = true; + CountDownLatch.countDown(); + frame.dispose(); + }); + JButton failButton = new JButton("Fail"); + failButton.addActionListener((ae) -> { + getFailureReason(); + frame.dispose(); + }); + buttonPanel.add(printButton); + buttonPanel.add(passButton); + buttonPanel.add(failButton); + + JPanel panel = new JPanel(new BorderLayout()); + panel.add(instructionTextArea, BorderLayout.CENTER); + panel.add(buttonPanel, BorderLayout.SOUTH); + + frame.add(panel); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.pack(); + frame.setVisible(true); + } + + public static void getFailureReason() { + final JDialog dialog = new JDialog(); + dialog.setTitle("Read testcase failure reason"); + JPanel jPanel = new JPanel(new BorderLayout()); + JTextArea jTextArea = new JTextArea(5, 20); + + JButton okButton = new JButton("Ok"); + okButton.addActionListener((ae) -> { + failureReason = jTextArea.getText(); + testResult = false; + CountDownLatch.countDown(); + dialog.dispose(); + }); + + jPanel.add(new JLabel("Enter the testcase failed reason below and " + + "click OK button", JLabel.CENTER), BorderLayout.NORTH); + jPanel.add(jTextArea, BorderLayout.CENTER); + + JPanel okayBtnPanel = new JPanel(); + okayBtnPanel.add(okButton); + + jPanel.add(okayBtnPanel, BorderLayout.SOUTH); + dialog.add(jPanel); + dialog.setLocationRelativeTo(null); + dialog.pack(); + dialog.setVisible(true); } - public static void main(String[] args) { - new InitToBlack().init(); - System.exit(0); + public static void main(String[] args) throws InterruptedException, InvocationTargetException { + SwingUtilities.invokeAndWait(InitToBlack::createTestUI); + if (!printButtonCountDownLatch.await(2, TimeUnit.MINUTES)) { + throw new RuntimeException("Timeout: User did not perform action " + + "on Print button."); + } + if (!CountDownLatch.await(2, TimeUnit.MINUTES)) { + throw new RuntimeException("Timeout : User did not decide " + + "whether test passed or failed"); + } + + if (!testResult) { + throw new RuntimeException("Test failed : " + failureReason); + } else { + System.out.println("Test Passed"); + } } } -- GitLab From 5cf580e0fb57245c43c9c719b9b03baa323f2245 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Thu, 24 Mar 2022 04:41:38 +0000 Subject: [PATCH 146/237] 8283587: [BACKOUT] Invalid generic signature for redefined classes Reviewed-by: lmesnik, dcubed, sspitsyn --- .../share/prims/jvmtiRedefineClasses.cpp | 19 +- .../RedefineGenericSignatureTest.java | 196 ------------------ 2 files changed, 10 insertions(+), 205 deletions(-) delete mode 100644 test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineGenericSignatureTest.java diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index e8ba72cbc0e..586c0679177 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1856,15 +1856,14 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite( if (old_cp->has_dynamic_constant()) { scratch_cp->set_has_dynamic_constant(); } + // Copy attributes from scratch_cp to merge_cp + merge_cp->copy_fields(scratch_cp()); log_info(redefine, class, constantpool)("merge_cp_len=%d, index_map_len=%d", merge_cp_length, _index_map_count); if (_index_map_count == 0) { // there is nothing to map between the new and merged constant pools - // Copy attributes from scratch_cp to merge_cp - merge_cp->copy_fields(scratch_cp()); - if (old_cp->length() == scratch_cp->length()) { // The old and new constant pools are the same length and the // index map is empty. This means that the three constant pools @@ -1918,9 +1917,6 @@ jvmtiError VM_RedefineClasses::merge_cp_and_rewrite( return JVMTI_ERROR_INTERNAL; } - // Copy attributes from scratch_cp to merge_cp (should be done after rewrite_cp_refs()) - merge_cp->copy_fields(scratch_cp()); - // Replace the new constant pool with a shrunken copy of the // merged constant pool so now the rewritten bytecodes have // valid references; the previous new constant pool will get @@ -3496,9 +3492,10 @@ void VM_RedefineClasses::rewrite_cp_refs_in_verification_type_info( } // end rewrite_cp_refs_in_verification_type_info() -// Change the constant pool associated with klass scratch_class to scratch_cp. -// scratch_cp_length elements are copied from scratch_cp to a smaller constant pool -// and the smaller constant pool is associated with scratch_class. +// Change the constant pool associated with klass scratch_class to +// scratch_cp. If shrink is true, then scratch_cp_length elements +// are copied from scratch_cp to a smaller constant pool and the +// smaller constant pool is associated with scratch_class. void VM_RedefineClasses::set_new_constant_pool( ClassLoaderData* loader_data, InstanceKlass* scratch_class, constantPoolHandle scratch_cp, @@ -4360,6 +4357,10 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas // Leave arrays of jmethodIDs and itable index cache unchanged + // Copy the "source file name" attribute from new class version + the_class->set_source_file_name_index( + scratch_class->source_file_name_index()); + // Copy the "source debug extension" attribute from new class version the_class->set_source_debug_extension( scratch_class->source_debug_extension(), diff --git a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineGenericSignatureTest.java b/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineGenericSignatureTest.java deleted file mode 100644 index b16120037e2..00000000000 --- a/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineGenericSignatureTest.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2022, 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 8282241 - * @summary Verifies class redefinition correctly updates generic_signature and source_file_name attributes - * @requires vm.jvmti - * @modules java.base/jdk.internal.org.objectweb.asm - * java.instrument - * @library /test/lib - * @run compile -g RedefineGenericSignatureTest.java - * @run main RedefineClassHelper - * @run main/othervm -javaagent:redefineagent.jar --add-opens=java.base/java.lang=ALL-UNNAMED RedefineGenericSignatureTest - */ - -import java.io.File; -import java.io.FileOutputStream; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Type; -import java.nio.file.Files; -import java.util.List; - -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.test.lib.Asserts; -import jdk.test.lib.JDKToolLauncher; -import jdk.test.lib.compiler.InMemoryJavaCompiler; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; - -class GenericSignatureTester { - public GenericSignatureTarget> method1() { - return null; - } -} - -class GenericSignatureTarget> { - public GenericSignatureTarget foo() { return null; } - public static void throwException() { throw new RuntimeException(); } -} - -public class RedefineGenericSignatureTest { - private static final String newTargetClassSource = - "class GenericSignatureTarget {\n" + - " public GenericSignatureTarget foo() { return null; }\n" + - " public static void throwException() { throw new RuntimeException(); }\n" + - "}\n"; - - public static void main (String[] args) throws Throwable { - RedefineGenericSignatureTest test = new RedefineGenericSignatureTest(); - test.runTest(); - } - - private final static String sourceFileName = "RedefineGenericSignatureTest.java"; - private final static String sourceFileNameNew = "RedefineGenericSignatureTestNew.java"; - // expected signature of GenericSignatureTester.method1 return type - private final static String expectedRetType = "GenericSignatureTarget>"; - // expected generic signature of the original GenericSignatureTarget - private final static String expectedSigOld = ";>Ljava/lang/Object;"; - // expected generic signature of the redefined GenericSignatureTarget - private final static String expectedSigNew = "Ljava/lang/Object;"; - - private static void log(Object o) { - System.out.println(o); - } - - private String getTargetGenSig() throws Throwable { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - MethodHandles.Lookup classLookup = MethodHandles.privateLookupIn(Class.class, lookup); - MethodHandle getGenericSignature0 = classLookup.findVirtual( - Class.class, "getGenericSignature0", MethodType.methodType(String.class)); - Object genericSignature = getGenericSignature0.invoke(GenericSignatureTarget.class); - return String.valueOf(genericSignature); - } - - private String getTesterRetType() throws Throwable { - Type type = GenericSignatureTester.class.getDeclaredMethod("method1").getGenericReturnType(); - return String.valueOf(type); - } - - private String getTargetSourceFilename() { - try { - GenericSignatureTarget.throwException(); - } catch (RuntimeException ex) { - return ex.getStackTrace()[0].getFileName(); - } - return "Cannot get source file name"; - } - - // Prints dissassembled class bytes. - private void printDisassembled(String description, Class cls, byte[] bytes) throws Exception { - log(description + " -------------------"); - - File f = new File(cls.getSimpleName()+".class"); - try (FileOutputStream fos = new FileOutputStream(f)) { - fos.write(bytes); - } - JDKToolLauncher javap = JDKToolLauncher.create("javap") - .addToolArg("-verbose") - .addToolArg("-p") // Shows all classes and members. - //.addToolArg("-c") // Prints out disassembled code - .addToolArg("-s") // Prints internal type signatures. - .addToolArg(f.toString()); - ProcessBuilder pb = new ProcessBuilder(javap.getCommand()); - OutputAnalyzer out = ProcessTools.executeProcess(pb); - out.shouldHaveExitValue(0); - try { - Files.delete(f.toPath()); - } catch (Exception ex) { - // ignore - } - out.asLines().forEach(s -> log(s)); - log("=========================================="); - Files.deleteIfExists(f.toPath()); - } - - private byte[] getNewClassBytes() { - byte[] bytecode = InMemoryJavaCompiler.compile(GenericSignatureTarget.class.getName(), newTargetClassSource, "-g"); - - ClassWriter cw = new ClassWriter(0); - ClassReader cr = new ClassReader(bytecode); - cr.accept(new ClassVisitor(Opcodes.ASM7, cw) { - private boolean sourceSet = false; - @Override - public void visitSource(String source, String debug) { - sourceSet = true; - log("Changing source: \"" + source + "\" -> \"" + sourceFileNameNew + "\""); - super.visitSource(sourceFileNameNew, debug); - } - - @Override - public void visitEnd() { - if (!sourceSet) { - log("Set source: \"" + sourceFileNameNew + "\""); - super.visitSource(sourceFileNameNew, null); - } - super.visitEnd(); - } - }, 0); - return cw.toByteArray(); - } - - private void runTest() throws Throwable { - Class targetClass = GenericSignatureTarget.class; - - String oldSig = getTargetGenSig(); - log("old target class sig: \"" + oldSig + "\""); - - byte[] oldClassBytes = targetClass.getResourceAsStream(targetClass.getName() + ".class").readAllBytes(); - printDisassembled("Old " + targetClass.getName(), targetClass, oldClassBytes); - - log("Redefining " + targetClass.getName() + " class"); - byte[] newClassBytes = getNewClassBytes(); - printDisassembled("New " + targetClass.getName(), targetClass, newClassBytes); - RedefineClassHelper.redefineClass(targetClass, newClassBytes); - - String newSig = getTargetGenSig(); - log("new target class sig: \"" + newSig + "\""); - - String newRetType = getTesterRetType(); - log("new tester ret type: \"" + newRetType + "\""); - - String newSrcFileName = getTargetSourceFilename(); - log("new source file name: \"" + newSrcFileName + "\""); - - Asserts.assertStringsEqual(expectedSigOld, oldSig, "wrong old generic signature"); - Asserts.assertStringsEqual(expectedSigNew, newSig, "wrong new generic signature"); - Asserts.assertStringsEqual(expectedRetType, newRetType, "wrong ret type"); - Asserts.assertStringsEqual(sourceFileNameNew, newSrcFileName, "wrong new source file name"); - } -} -- GitLab From af18b1111a7382a366d26ea1646282bdfb4ac495 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Thu, 24 Mar 2022 06:02:09 +0000 Subject: [PATCH 147/237] 8283574: Use Klass::_id for type checks in the C++ code Reviewed-by: tschatzl, kbarrett --- .../share/gc/g1/g1FullGCMarker.inline.hpp | 2 +- .../share/oops/instanceClassLoaderKlass.hpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 8 +++--- src/hotspot/share/oops/instanceKlass.hpp | 26 +------------------ .../share/oops/instanceMirrorKlass.hpp | 4 +-- src/hotspot/share/oops/instanceRefKlass.cpp | 3 +-- src/hotspot/share/oops/instanceRefKlass.hpp | 2 +- src/hotspot/share/oops/klass.hpp | 22 +++++++--------- src/hotspot/share/oops/oop.cpp | 9 ++++--- src/hotspot/share/oops/oop.hpp | 18 +++++++------ src/hotspot/share/oops/oop.inline.hpp | 9 ++++--- 11 files changed, 40 insertions(+), 65 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp index 256fd766f82..ce3013138ce 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp @@ -138,7 +138,7 @@ inline void G1FullGCMarker::follow_object(oop obj) { } else { obj->oop_iterate(mark_closure()); if (VerifyDuringGC) { - if (obj->is_instance() && InstanceKlass::cast(obj->klass())->is_reference_instance_klass()) { + if (obj->is_instanceRef()) { return; } _verify_closure.set_containing_obj(obj); diff --git a/src/hotspot/share/oops/instanceClassLoaderKlass.hpp b/src/hotspot/share/oops/instanceClassLoaderKlass.hpp index b0261854626..e1a42ae3181 100644 --- a/src/hotspot/share/oops/instanceClassLoaderKlass.hpp +++ b/src/hotspot/share/oops/instanceClassLoaderKlass.hpp @@ -43,7 +43,7 @@ public: static const KlassID ID = InstanceClassLoaderKlassID; private: - InstanceClassLoaderKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_kind_class_loader, ID) {} + InstanceClassLoaderKlass(const ClassFileParser& parser) : InstanceKlass(parser, ID) {} public: InstanceClassLoaderKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index e5dbd1f293e..f5dcaebd96a 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -442,13 +442,12 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& par if (class_name == vmSymbols::java_lang_Class()) { // mirror ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser); - } - else if (is_class_loader(class_name, parser)) { + } else if (is_class_loader(class_name, parser)) { // class loader ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser); } else { // normal - ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_kind_other); + ik = new (loader_data, size, THREAD) InstanceKlass(parser); } } else { // reference @@ -486,7 +485,7 @@ Array* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) { return vtable_indices; } -InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, KlassID id) : +InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassID id) : Klass(id), _nest_members(NULL), _nest_host(NULL), @@ -501,7 +500,6 @@ InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind, Klass _init_thread(NULL) { set_vtable_length(parser.vtable_size()); - set_kind(kind); set_access_flags(parser.access_flags()); if (parser.is_hidden()) set_is_hidden(); set_layout_helper(Klass::instance_layout_helper(parser.layout_size(), diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 9ec3535e0dc..623c3e24a95 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -136,7 +136,7 @@ class InstanceKlass: public Klass { static const KlassID ID = InstanceKlassID; protected: - InstanceKlass(const ClassFileParser& parser, unsigned kind, KlassID id = ID); + InstanceKlass(const ClassFileParser& parser, KlassID id = ID); public: InstanceKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } @@ -229,15 +229,7 @@ class InstanceKlass: public Klass { // _idnum_allocated_count. u1 _init_state; // state of class - // This can be used to quickly discriminate among the four kinds of - // InstanceKlass. This should be an enum (?) - static const unsigned _kind_other = 0; // concrete InstanceKlass - static const unsigned _kind_reference = 1; // InstanceRefKlass - static const unsigned _kind_class_loader = 2; // InstanceClassLoaderKlass - static const unsigned _kind_mirror = 3; // InstanceMirrorKlass - u1 _reference_type; // reference type - u1 _kind; // kind of InstanceKlass enum { _misc_rewritten = 1 << 0, // methods rewritten. @@ -787,24 +779,8 @@ public: void set_has_resolved_methods() { _access_flags.set_has_resolved_methods(); } -private: - - void set_kind(unsigned kind) { - _kind = (u1)kind; - } - - bool is_kind(unsigned desired) const { - return _kind == (u1)desired; - } public: - - // Other is anything that is not one of the more specialized kinds of InstanceKlass. - bool is_other_instance_klass() const { return is_kind(_kind_other); } - bool is_reference_instance_klass() const { return is_kind(_kind_reference); } - bool is_mirror_instance_klass() const { return is_kind(_kind_mirror); } - bool is_class_loader_instance_klass() const { return is_kind(_kind_class_loader); } - #if INCLUDE_JVMTI void init_previous_versions() { diff --git a/src/hotspot/share/oops/instanceMirrorKlass.hpp b/src/hotspot/share/oops/instanceMirrorKlass.hpp index 154151932f7..00258e13bc3 100644 --- a/src/hotspot/share/oops/instanceMirrorKlass.hpp +++ b/src/hotspot/share/oops/instanceMirrorKlass.hpp @@ -50,7 +50,7 @@ class InstanceMirrorKlass: public InstanceKlass { private: static int _offset_of_static_fields; - InstanceMirrorKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_kind_mirror, ID) {} + InstanceMirrorKlass(const ClassFileParser& parser) : InstanceKlass(parser, ID) {} public: InstanceMirrorKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } @@ -60,7 +60,7 @@ class InstanceMirrorKlass: public InstanceKlass { } static const InstanceMirrorKlass* cast(const Klass* k) { - assert(InstanceKlass::cast(k)->is_mirror_instance_klass(), "cast to InstanceMirrorKlass"); + assert(k->is_mirror_instance_klass(), "cast to InstanceMirrorKlass"); return static_cast(k); } diff --git a/src/hotspot/share/oops/instanceRefKlass.cpp b/src/hotspot/share/oops/instanceRefKlass.cpp index aab23761e27..0b3e5e4e0ec 100644 --- a/src/hotspot/share/oops/instanceRefKlass.cpp +++ b/src/hotspot/share/oops/instanceRefKlass.cpp @@ -87,7 +87,6 @@ void InstanceRefKlass::oop_verify_on(oop obj, outputStream* st) { oop next = java_lang_ref_Reference::next(obj); if (next != NULL) { guarantee(oopDesc::is_oop(next), "next field should be an oop"); - guarantee(next->is_instance(), "next field should be an instance"); - guarantee(InstanceKlass::cast(next->klass())->is_reference_instance_klass(), "next field verify failed"); + guarantee(next->is_instanceRef(), "next field verify failed"); } } diff --git a/src/hotspot/share/oops/instanceRefKlass.hpp b/src/hotspot/share/oops/instanceRefKlass.hpp index 16a9bb53c3a..5e271ebb762 100644 --- a/src/hotspot/share/oops/instanceRefKlass.hpp +++ b/src/hotspot/share/oops/instanceRefKlass.hpp @@ -53,7 +53,7 @@ class InstanceRefKlass: public InstanceKlass { static const KlassID ID = InstanceRefKlassID; private: - InstanceRefKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_kind_reference, ID) {} + InstanceRefKlass(const ClassFileParser& parser) : InstanceKlass(parser, ID) {} public: InstanceRefKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index 9871036d576..f82ba4d9970 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -614,18 +614,16 @@ protected: } public: #endif - inline bool is_instance_klass() const { return assert_same_query( - layout_helper_is_instance(layout_helper()), - is_instance_klass_slow()); } - inline bool is_array_klass() const { return assert_same_query( - layout_helper_is_array(layout_helper()), - is_array_klass_slow()); } - inline bool is_objArray_klass() const { return assert_same_query( - layout_helper_is_objArray(layout_helper()), - is_objArray_klass_slow()); } - inline bool is_typeArray_klass() const { return assert_same_query( - layout_helper_is_typeArray(layout_helper()), - is_typeArray_klass_slow()); } + + bool is_instance_klass() const { return assert_same_query(_id <= InstanceClassLoaderKlassID, is_instance_klass_slow()); } + // Other is anything that is not one of the more specialized kinds of InstanceKlass. + bool is_other_instance_klass() const { return _id == InstanceKlassID; } + bool is_reference_instance_klass() const { return _id == InstanceRefKlassID; } + bool is_mirror_instance_klass() const { return _id == InstanceMirrorKlassID; } + bool is_class_loader_instance_klass() const { return _id == InstanceClassLoaderKlassID; } + bool is_array_klass() const { return assert_same_query( _id >= TypeArrayKlassID, is_array_klass_slow()); } + bool is_objArray_klass() const { return assert_same_query( _id == ObjArrayKlassID, is_objArray_klass_slow()); } + bool is_typeArray_klass() const { return assert_same_query( _id == TypeArrayKlassID, is_typeArray_klass_slow()); } #undef assert_same_query // Access flags diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 14592997091..17e96450cf2 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -134,10 +134,11 @@ void VerifyOopClosure::do_oop(oop* p) { VerifyOopClosure::do_oop_work(p); void VerifyOopClosure::do_oop(narrowOop* p) { VerifyOopClosure::do_oop_work(p); } // type test operations that doesn't require inclusion of oop.inline.hpp. -bool oopDesc::is_instance_noinline() const { return is_instance(); } -bool oopDesc::is_array_noinline() const { return is_array(); } -bool oopDesc::is_objArray_noinline() const { return is_objArray(); } -bool oopDesc::is_typeArray_noinline() const { return is_typeArray(); } +bool oopDesc::is_instance_noinline() const { return is_instance(); } +bool oopDesc::is_instanceRef_noinline() const { return is_instanceRef(); } +bool oopDesc::is_array_noinline() const { return is_array(); } +bool oopDesc::is_objArray_noinline() const { return is_objArray(); } +bool oopDesc::is_typeArray_noinline() const { return is_typeArray(); } bool oopDesc::has_klass_gap() { // Only has a klass gap when compressed class pointers are used. diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 994bb677032..08f354a905d 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -107,16 +107,18 @@ class oopDesc { inline size_t size_given_klass(Klass* klass); // type test operations (inlined in oop.inline.hpp) - inline bool is_instance() const; - inline bool is_array() const; - inline bool is_objArray() const; - inline bool is_typeArray() const; + inline bool is_instance() const; + inline bool is_instanceRef() const; + inline bool is_array() const; + inline bool is_objArray() const; + inline bool is_typeArray() const; // type test operations that don't require inclusion of oop.inline.hpp. - bool is_instance_noinline() const; - bool is_array_noinline() const; - bool is_objArray_noinline() const; - bool is_typeArray_noinline() const; + bool is_instance_noinline() const; + bool is_instanceRef_noinline() const; + bool is_array_noinline() const; + bool is_objArray_noinline() const; + bool is_typeArray_noinline() const; protected: inline oop as_oop() const { return const_cast(this); } diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index 17ce5bed561..d8ff94178c5 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.hpp @@ -195,10 +195,11 @@ size_t oopDesc::size_given_klass(Klass* klass) { return s; } -bool oopDesc::is_instance() const { return klass()->is_instance_klass(); } -bool oopDesc::is_array() const { return klass()->is_array_klass(); } -bool oopDesc::is_objArray() const { return klass()->is_objArray_klass(); } -bool oopDesc::is_typeArray() const { return klass()->is_typeArray_klass(); } +bool oopDesc::is_instance() const { return klass()->is_instance_klass(); } +bool oopDesc::is_instanceRef() const { return klass()->is_reference_instance_klass(); } +bool oopDesc::is_array() const { return klass()->is_array_klass(); } +bool oopDesc::is_objArray() const { return klass()->is_objArray_klass(); } +bool oopDesc::is_typeArray() const { return klass()->is_typeArray_klass(); } template T* oopDesc::field_addr(int offset) const { return reinterpret_cast(cast_from_oop(as_oop()) + offset); } -- GitLab From e6f707aa76ac231bef7d0abf1dd643bd7471067f Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Thu, 24 Mar 2022 06:31:12 +0000 Subject: [PATCH 148/237] 8283437: Refactor imageio classes javadoc to use @throws instead of @exception Reviewed-by: serb --- .../imageio/plugins/bmp/BMPImageReader.java | 6 +- .../plugins/common/BogusColorSpace.java | 4 +- .../imageio/plugins/common/LZWCompressor.java | 6 +- .../plugins/common/PaletteBuilder.java | 12 +- .../imageio/plugins/jpeg/JPEGImageReader.java | 4 +- .../imageio/plugins/png/PNGImageWriter.java | 2 +- .../plugins/tiff/TIFFDecompressor.java | 2 +- .../share/classes/javax/imageio/IIOImage.java | 12 +- .../share/classes/javax/imageio/IIOParam.java | 16 +- .../javax/imageio/IIOParamController.java | 2 +- .../share/classes/javax/imageio/ImageIO.java | 62 ++--- .../classes/javax/imageio/ImageReadParam.java | 8 +- .../classes/javax/imageio/ImageReader.java | 240 +++++++++--------- .../javax/imageio/ImageTranscoder.java | 4 +- .../javax/imageio/ImageTypeSpecifier.java | 74 +++--- .../javax/imageio/ImageWriteParam.java | 122 ++++----- .../classes/javax/imageio/ImageWriter.java | 228 ++++++++--------- .../javax/imageio/metadata/IIOMetadata.java | 30 +-- .../metadata/IIOMetadataController.java | 2 +- .../imageio/metadata/IIOMetadataFormat.java | 106 ++++---- .../metadata/IIOMetadataFormatImpl.java | 82 +++--- .../imageio/metadata/IIOMetadataNode.java | 8 +- .../plugins/jpeg/JPEGImageReadParam.java | 2 +- .../plugins/jpeg/JPEGImageWriteParam.java | 6 +- .../javax/imageio/spi/IIOServiceProvider.java | 4 +- .../imageio/spi/ImageInputStreamSpi.java | 14 +- .../imageio/spi/ImageOutputStreamSpi.java | 14 +- .../javax/imageio/spi/ImageReaderSpi.java | 22 +- .../imageio/spi/ImageReaderWriterSpi.java | 12 +- .../javax/imageio/spi/ImageWriterSpi.java | 22 +- .../javax/imageio/spi/ServiceRegistry.java | 44 ++-- .../stream/FileCacheImageInputStream.java | 4 +- .../stream/FileCacheImageOutputStream.java | 12 +- .../imageio/stream/FileImageInputStream.java | 10 +- .../imageio/stream/FileImageOutputStream.java | 14 +- .../imageio/stream/ImageInputStream.java | 170 ++++++------- .../imageio/stream/ImageInputStreamImpl.java | 22 +- .../imageio/stream/ImageOutputStream.java | 88 +++---- .../imageio/stream/ImageOutputStreamImpl.java | 2 +- .../javax/imageio/stream/MemoryCache.java | 14 +- .../stream/MemoryCacheImageInputStream.java | 2 +- .../stream/MemoryCacheImageOutputStream.java | 2 +- .../sun/awt/image/ByteBandedRaster.java | 4 +- .../sun/awt/image/ByteComponentRaster.java | 4 +- .../sun/awt/image/ByteInterleavedRaster.java | 4 +- .../sun/awt/image/BytePackedRaster.java | 6 +- .../sun/awt/image/IntegerComponentRaster.java | 4 +- .../awt/image/IntegerInterleavedRaster.java | 4 +- .../sun/awt/image/ShortBandedRaster.java | 4 +- .../sun/awt/image/ShortComponentRaster.java | 4 +- .../sun/awt/image/ShortInterleavedRaster.java | 4 +- 51 files changed, 775 insertions(+), 775 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java index 2e1c2db03ca..81baefe8155 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java @@ -254,11 +254,11 @@ public class BMPImageReader extends ImageReader implements BMPConstants { /** * Process the image header. * - * @exception IllegalStateException if source stream is not set. + * @throws IllegalStateException if source stream is not set. * - * @exception IOException if image stream is corrupted. + * @throws IOException if image stream is corrupted. * - * @exception IllegalArgumentException if the image stream does not contain + * @throws IllegalArgumentException if the image stream does not contain * a BMP image, or if a sample model instance to describe the * image can not be created. */ diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java index b6f73efc712..a62008dfbd4 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/BogusColorSpace.java @@ -38,7 +38,7 @@ public class BogusColorSpace extends ColorSpace { * * @param numComponents The number of components in the * {@code ColorSpace}. - * @exception IllegalArgumentException if {@code numComponents} + * @throws IllegalArgumentException if {@code numComponents} * is less than 1. */ private static int getType(int numComponents) { @@ -66,7 +66,7 @@ public class BogusColorSpace extends ColorSpace { * * @param numComponents The number of components in the * {@code ColorSpace}. - * @exception IllegalArgumentException if {@code numComponents} + * @throws IllegalArgumentException if {@code numComponents} * is less than 1. */ public BogusColorSpace(int numComponents) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/LZWCompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/LZWCompressor.java index 0177848ad80..52f66f5eafa 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/LZWCompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/LZWCompressor.java @@ -65,7 +65,7 @@ public class LZWCompressor { * @param out destination for compressed data * @param codeSize the initial code size for the LZW compressor * @param TIFF flag indicating that TIFF lzw fudge needs to be applied - * @exception IOException if underlying output stream error + * @throws IOException if underlying output stream error **/ public LZWCompressor(ImageOutputStream out, int codeSize, boolean TIFF) throws IOException @@ -90,7 +90,7 @@ public class LZWCompressor { /** * @param buf data to be compressed to output stream - * @exception IOException if underlying output stream error + * @throws IOException if underlying output stream error **/ public void compress(byte[] buf, int offset, int length) throws IOException @@ -129,7 +129,7 @@ public class LZWCompressor { * Indicate to compressor that no more data to go so write out * any remaining buffered data. * - * @exception IOException if underlying output stream error + * @throws IOException if underlying output stream error */ public void flush() throws IOException { if (prefix != -1) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/PaletteBuilder.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/PaletteBuilder.java index b4541d5c662..00d2dde0e88 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/PaletteBuilder.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/PaletteBuilder.java @@ -77,10 +77,10 @@ public class PaletteBuilder { * Result image then is an approximation constructed by octree * quantization method. * - * @exception IllegalArgumentException if {@code src} is + * @throws IllegalArgumentException if {@code src} is * {@code null}. * - * @exception UnsupportedOperationException if implemented method + * @throws UnsupportedOperationException if implemented method * is unable to create approximation of {@code src} * and {@code canCreatePalette} returns {@code false}. * @@ -98,10 +98,10 @@ public class PaletteBuilder { * {@code img}. If number of colors in the given image exceeds * maximum palette size closest colors would be merged. * - * @exception IllegalArgumentException if {@code img} is + * @throws IllegalArgumentException if {@code img} is * {@code null}. * - * @exception UnsupportedOperationException if implemented method + * @throws UnsupportedOperationException if implemented method * is unable to create approximation of {@code img} * and {@code canCreatePalette} returns {@code false}. * @@ -124,7 +124,7 @@ public class PaletteBuilder { * @return {@code true} if the {@code PaletteBuilder} * is likely to be able to create palette for this image type. * - * @exception IllegalArgumentException if {@code type} + * @throws IllegalArgumentException if {@code type} * is {@code null}. */ public static boolean canCreatePalette(ImageTypeSpecifier type) { @@ -144,7 +144,7 @@ public class PaletteBuilder { * @return {@code true} if the {@code PaletteBuilder} * is likely to be able to create palette for this image type. * - * @exception IllegalArgumentException if {@code image} + * @throws IllegalArgumentException if {@code image} * is {@code null}. */ public static boolean canCreatePalette(RenderedImage image) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index a7edf73cb80..dac1b79d4ea 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -487,9 +487,9 @@ public class JPEGImageReader extends ImageReader { /** * Sets the input stream to the start of the requested image. *

      -     * @exception IllegalStateException if the input source has not been
      +     * @throws IllegalStateException if the input source has not been
            * set.
      -     * @exception IndexOutOfBoundsException if the supplied index is
      +     * @throws IndexOutOfBoundsException if the supplied index is
            * out of bounds.
            * 
      */ diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java index ce6f771ecdc..27707613f76 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java @@ -322,7 +322,7 @@ final class PNGImageWriteParam extends ImageWriteParam { *

      The default implementation resets the compression quality * to 0.5F. * - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * MODE_EXPLICIT. */ @Override diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java index 4516ce0ad82..bd7eb568fd8 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFDecompressor.java @@ -2373,7 +2373,7 @@ public abstract class TIFFDecompressor { * and instead override the {@code decodeRaw} and/or * {@code getRawImageType} methods. * - * @exception IOException if an error occurs in + * @throws IOException if an error occurs in * {@code decodeRaw}. */ public void decode() throws IOException { diff --git a/src/java.desktop/share/classes/javax/imageio/IIOImage.java b/src/java.desktop/share/classes/javax/imageio/IIOImage.java index ad1c18444ef..c830189d0ba 100644 --- a/src/java.desktop/share/classes/javax/imageio/IIOImage.java +++ b/src/java.desktop/share/classes/javax/imageio/IIOImage.java @@ -99,7 +99,7 @@ public class IIOImage { * @param metadata an {@code IIOMetadata} object, or * {@code null}. * - * @exception IllegalArgumentException if {@code image} is + * @throws IllegalArgumentException if {@code image} is * {@code null}. */ public IIOImage(RenderedImage image, @@ -127,7 +127,7 @@ public class IIOImage { * @param metadata an {@code IIOMetadata} object, or * {@code null}. * - * @exception IllegalArgumentException if {@code raster} is + * @throws IllegalArgumentException if {@code raster} is * {@code null}. */ public IIOImage(Raster raster, @@ -163,7 +163,7 @@ public class IIOImage { * * @param image a {@code RenderedImage}. * - * @exception IllegalArgumentException if {@code image} is + * @throws IllegalArgumentException if {@code image} is * {@code null}. * * @see #getRenderedImage @@ -213,7 +213,7 @@ public class IIOImage { * * @param raster a {@code Raster}. * - * @exception IllegalArgumentException if {@code raster} is + * @throws IllegalArgumentException if {@code raster} is * {@code null}. * * @see #getRaster @@ -245,9 +245,9 @@ public class IIOImage { * * @return a thumbnail image, as a {@code BufferedImage}. * - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IndexOutOfBoundsException if the supplied index is * negative or larger than the largest valid index. - * @exception ClassCastException if a + * @throws ClassCastException if a * non-{@code BufferedImage} object is encountered in the * list of thumbnails at the given index. * diff --git a/src/java.desktop/share/classes/javax/imageio/IIOParam.java b/src/java.desktop/share/classes/javax/imageio/IIOParam.java index 360ec532895..36b10f1eacc 100644 --- a/src/java.desktop/share/classes/javax/imageio/IIOParam.java +++ b/src/java.desktop/share/classes/javax/imageio/IIOParam.java @@ -162,15 +162,15 @@ public abstract class IIOParam { * @param sourceRegion a {@code Rectangle} specifying the * source region of interest, or {@code null}. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code sourceRegion} is non-{@code null} and either * {@code sourceRegion.x} or {@code sourceRegion.y} is * negative. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code sourceRegion} is non-{@code null} and either * {@code sourceRegion.width} or * {@code sourceRegion.height} is negative or 0. - * @exception IllegalStateException if subsampling is such that + * @throws IllegalStateException if subsampling is such that * this region will have a subsampled width or height of zero. * * @see #getSourceRegion @@ -290,10 +290,10 @@ public abstract class IIOParam { * within the region, or within the image if no region is set. * @param subsamplingYOffset the horizontal offset of the first subsample * within the region, or within the image if no region is set. - * @exception IllegalArgumentException if either period is + * @throws IllegalArgumentException if either period is * negative or 0, or if either grid offset is negative or greater than * the corresponding period. - * @exception IllegalStateException if the source region is such that + * @throws IllegalStateException if the source region is such that * the subsampled output would contain no pixels. */ public void setSourceSubsampling(int sourceXSubsampling, @@ -413,7 +413,7 @@ public abstract class IIOParam { * @param sourceBands an array of integer band indices to be * used. * - * @exception IllegalArgumentException if {@code sourceBands} + * @throws IllegalArgumentException if {@code sourceBands} * contains a negative or duplicate value. * * @see #getSourceBands @@ -537,7 +537,7 @@ public abstract class IIOParam { * @param destinationOffset the offset in the destination, as a * {@code Point}. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code destinationOffset} is {@code null}. * * @see #getDestinationOffset @@ -658,7 +658,7 @@ public abstract class IIOParam { * * @return {@code true} if the controller completed normally. * - * @exception IllegalStateException if there is no controller + * @throws IllegalStateException if there is no controller * currently installed. * * @see IIOParamController diff --git a/src/java.desktop/share/classes/javax/imageio/IIOParamController.java b/src/java.desktop/share/classes/javax/imageio/IIOParamController.java index 5d8a7017ccd..9389a0093cd 100644 --- a/src/java.desktop/share/classes/javax/imageio/IIOParamController.java +++ b/src/java.desktop/share/classes/javax/imageio/IIOParamController.java @@ -111,7 +111,7 @@ public interface IIOParamController { * @return {@code true} if the {@code IIOParam} has been * modified, {@code false} otherwise. * - * @exception IllegalArgumentException if {@code param} is + * @throws IllegalArgumentException if {@code param} is * {@code null} or is not an instance of the correct class. */ boolean activate(IIOParam param); diff --git a/src/java.desktop/share/classes/javax/imageio/ImageIO.java b/src/java.desktop/share/classes/javax/imageio/ImageIO.java index 8c62ef92b11..9e87640967b 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageIO.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageIO.java @@ -277,9 +277,9 @@ public final class ImageIO { * * @see File#createTempFile(String, String, File) * - * @exception SecurityException if the security manager denies + * @throws SecurityException if the security manager denies * access to the directory. - * @exception IllegalArgumentException if {@code cacheDir} is + * @throws IllegalArgumentException if {@code cacheDir} is * non-{@code null} but is not a directory. * * @see #getCacheDirectory @@ -326,9 +326,9 @@ public final class ImageIO { * * @return an {@code ImageInputStream}, or {@code null}. * - * @exception IllegalArgumentException if {@code input} + * @throws IllegalArgumentException if {@code input} * is {@code null}. - * @exception IOException if a cache file is needed but cannot be + * @throws IOException if a cache file is needed but cannot be * created. * * @see javax.imageio.spi.ImageInputStreamSpi @@ -388,9 +388,9 @@ public final class ImageIO { * @return an {@code ImageOutputStream}, or * {@code null}. * - * @exception IllegalArgumentException if {@code output} is + * @throws IllegalArgumentException if {@code output} is * {@code null}. - * @exception IOException if a cache file is needed but cannot be + * @throws IOException if a cache file is needed but cannot be * created. * * @see javax.imageio.spi.ImageOutputStreamSpi @@ -637,7 +637,7 @@ public final class ImageIO { * * @return an {@code Iterator} containing {@code ImageReader}s. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * {@code null}. * * @see javax.imageio.spi.ImageReaderSpi#canDecodeInput @@ -697,7 +697,7 @@ public final class ImageIO { * @return an {@code Iterator} containing * {@code ImageReader}s. * - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalArgumentException if {@code formatName} * is {@code null}. * * @see javax.imageio.spi.ImageReaderSpi#getFormatNames @@ -732,7 +732,7 @@ public final class ImageIO { * @return an {@code Iterator} containing * {@code ImageReader}s. * - * @exception IllegalArgumentException if {@code fileSuffix} + * @throws IllegalArgumentException if {@code fileSuffix} * is {@code null}. * * @see javax.imageio.spi.ImageReaderSpi#getFileSuffixes @@ -767,7 +767,7 @@ public final class ImageIO { * @return an {@code Iterator} containing * {@code ImageReader}s. * - * @exception IllegalArgumentException if {@code MIMEType} is + * @throws IllegalArgumentException if {@code MIMEType} is * {@code null}. * * @see javax.imageio.spi.ImageReaderSpi#getMIMETypes @@ -880,7 +880,7 @@ public final class ImageIO { * @return an {@code Iterator} containing * {@code ImageWriter}s. * - * @exception IllegalArgumentException if {@code formatName} is + * @throws IllegalArgumentException if {@code formatName} is * {@code null}. * * @see javax.imageio.spi.ImageWriterSpi#getFormatNames @@ -914,7 +914,7 @@ public final class ImageIO { * * @return an {@code Iterator} containing {@code ImageWriter}s. * - * @exception IllegalArgumentException if {@code fileSuffix} is + * @throws IllegalArgumentException if {@code fileSuffix} is * {@code null}. * * @see javax.imageio.spi.ImageWriterSpi#getFileSuffixes @@ -948,7 +948,7 @@ public final class ImageIO { * * @return an {@code Iterator} containing {@code ImageWriter}s. * - * @exception IllegalArgumentException if {@code MIMEType} is + * @throws IllegalArgumentException if {@code MIMEType} is * {@code null}. * * @see javax.imageio.spi.ImageWriterSpi#getMIMETypes @@ -995,7 +995,7 @@ public final class ImageIO { * * @return an {@code ImageWriter}, or null. * - * @exception IllegalArgumentException if {@code reader} is + * @throws IllegalArgumentException if {@code reader} is * {@code null}. * * @see #getImageReader(ImageWriter) @@ -1075,7 +1075,7 @@ public final class ImageIO { * * @return an {@code ImageReader}, or null. * - * @exception IllegalArgumentException if {@code writer} is + * @throws IllegalArgumentException if {@code writer} is * {@code null}. * * @see #getImageWriter(ImageReader) @@ -1151,7 +1151,7 @@ public final class ImageIO { * * @return an {@code Iterator} containing {@code ImageWriter}s. * - * @exception IllegalArgumentException if any parameter is + * @throws IllegalArgumentException if any parameter is * {@code null}. * * @see javax.imageio.spi.ImageWriterSpi#canEncodeImage(ImageTypeSpecifier) @@ -1238,7 +1238,7 @@ public final class ImageIO { * @return an {@code Iterator} containing * {@code ImageTranscoder}s. * - * @exception IllegalArgumentException if {@code reader} or + * @throws IllegalArgumentException if {@code reader} or * {@code writer} is {@code null}. */ public static Iterator @@ -1295,9 +1295,9 @@ public final class ImageIO { * @return a {@code BufferedImage} containing the decoded * contents of the input, or {@code null}. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading or when not + * @throws IOException if an error occurs during reading or when not * able to create required ImageInputStream. */ public static BufferedImage read(File input) throws IOException { @@ -1346,9 +1346,9 @@ public final class ImageIO { * @return a {@code BufferedImage} containing the decoded * contents of the input, or {@code null}. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading or when not + * @throws IOException if an error occurs during reading or when not * able to create required ImageInputStream. */ public static BufferedImage read(InputStream input) throws IOException { @@ -1390,9 +1390,9 @@ public final class ImageIO { * @return a {@code BufferedImage} containing the decoded * contents of the input, or {@code null}. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * {@code null}. - * @exception IOException if an error occurs during reading or when not + * @throws IOException if an error occurs during reading or when not * able to create required ImageInputStream. */ public static BufferedImage read(URL input) throws IOException { @@ -1443,9 +1443,9 @@ public final class ImageIO { * @return a {@code BufferedImage} containing the decoded * contents of the input, or {@code null}. * - * @exception IllegalArgumentException if {@code stream} is + * @throws IllegalArgumentException if {@code stream} is * {@code null}. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public static BufferedImage read(ImageInputStream stream) throws IOException { @@ -1489,9 +1489,9 @@ public final class ImageIO { * * @return {@code false} if no appropriate writer is found. * - * @exception IllegalArgumentException if any parameter is + * @throws IllegalArgumentException if any parameter is * {@code null}. - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public static boolean write(RenderedImage im, String formatName, @@ -1522,9 +1522,9 @@ public final class ImageIO { * * @return {@code false} if no appropriate writer is found. * - * @exception IllegalArgumentException if any parameter is + * @throws IllegalArgumentException if any parameter is * {@code null}. - * @exception IOException if an error occurs during writing or when not + * @throws IOException if an error occurs during writing or when not * able to create required ImageOutputStream. */ public static boolean write(RenderedImage im, @@ -1570,9 +1570,9 @@ public final class ImageIO { * * @return {@code false} if no appropriate writer is found. * - * @exception IllegalArgumentException if any parameter is + * @throws IllegalArgumentException if any parameter is * {@code null}. - * @exception IOException if an error occurs during writing or when not + * @throws IOException if an error occurs during writing or when not * able to create required ImageOutputStream. */ public static boolean write(RenderedImage im, diff --git a/src/java.desktop/share/classes/javax/imageio/ImageReadParam.java b/src/java.desktop/share/classes/javax/imageio/ImageReadParam.java index d2181a18115..00866f60e7b 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageReadParam.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageReadParam.java @@ -272,7 +272,7 @@ public class ImageReadParam extends IIOParam { * @param destinationBands an array of integer band indices to be * used. * - * @exception IllegalArgumentException if {@code destinationBands} + * @throws IllegalArgumentException if {@code destinationBands} * contains a negative or duplicate value. * * @see #getDestinationBands @@ -360,9 +360,9 @@ public class ImageReadParam extends IIOParam { * @param size a {@code Dimension} indicating the desired * width and height. * - * @exception IllegalArgumentException if either the width or the + * @throws IllegalArgumentException if either the width or the * height is negative or 0. - * @exception UnsupportedOperationException if image resizing + * @throws UnsupportedOperationException if image resizing * is not supported by this plug-in. * * @see #getSourceRenderSize @@ -433,7 +433,7 @@ public class ImageReadParam extends IIOParam { * @param minPass the index of the first pass to be decoded. * @param numPasses the maximum number of passes to be decoded. * - * @exception IllegalArgumentException if {@code minPass} is + * @throws IllegalArgumentException if {@code minPass} is * negative, {@code numPasses} is negative or 0, or * {@code numPasses} is smaller than * {@code Integer.MAX_VALUE} but diff --git a/src/java.desktop/share/classes/javax/imageio/ImageReader.java b/src/java.desktop/share/classes/javax/imageio/ImageReader.java index e17a5f2e796..97092ec7de9 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageReader.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageReader.java @@ -196,7 +196,7 @@ public abstract class ImageReader { * provider, or which desire a different naming policy should * override this method. * - * @exception IOException if an error occurs reading the + * @throws IOException if an error occurs reading the * information from the input source. * * @return the format name, as a {@code String}. @@ -276,7 +276,7 @@ public abstract class ImageReader { * @param ignoreMetadata if {@code true}, metadata * may be ignored during reads. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * not an instance of one of the classes returned by the * originating service provider's {@code getInputTypes} * method, or is not an {@code ImageInputStream}. @@ -343,7 +343,7 @@ public abstract class ImageReader { * @param seekForwardOnly if {@code true}, images and metadata * may only be read in ascending order from this input source. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * not an instance of one of the classes returned by the * originating service provider's {@code getInputTypes} * method, or is not an {@code ImageInputStream}. @@ -369,7 +369,7 @@ public abstract class ImageReader { * @param input the {@code ImageInputStream} or other * {@code Object} to use for future decoding. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * not an instance of one of the classes returned by the * originating service provider's {@code getInputTypes} * method, or is not an {@code ImageInputStream}. @@ -470,7 +470,7 @@ public abstract class ImageReader { * @param locale the desired {@code Locale}, or * {@code null}. * - * @exception IllegalArgumentException if {@code locale} is + * @throws IllegalArgumentException if {@code locale} is * non-{@code null} but is not one of the values returned by * {@code getAvailableLocales}. * @@ -538,10 +538,10 @@ public abstract class ImageReader { * {@code -1} if {@code allowSearch} is * {@code false} and a search would be required. * - * @exception IllegalStateException if the input source has not been set, + * @throws IllegalStateException if the input source has not been set, * or if the input has been specified with {@code seekForwardOnly} * set to {@code true}. - * @exception IOException if an error occurs reading the + * @throws IOException if an error occurs reading the * information from the input source. * * @see #setInput @@ -559,10 +559,10 @@ public abstract class ImageReader { * * @return the width of the image, as an {@code int}. * - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs reading the width + * @throws IOException if an error occurs reading the width * information from the input source. */ public abstract int getWidth(int imageIndex) throws IOException; @@ -578,10 +578,10 @@ public abstract class ImageReader { * * @return the height of the image, as an {@code int}. * - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs reading the height + * @throws IOException if an error occurs reading the height * information from the input source. */ public abstract int getHeight(int imageIndex) throws IOException; @@ -617,12 +617,12 @@ public abstract class ImageReader { * @return {@code true} if reading a region of interest of * the given image is likely to be efficient. * - * @exception IllegalStateException if an input source is required + * @throws IllegalStateException if an input source is required * to determine the return value, but none has been set. - * @exception IndexOutOfBoundsException if an image must be + * @throws IndexOutOfBoundsException if an image must be * accessed to determine the return value, but the supplied index * is out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public boolean isRandomAccessEasy(int imageIndex) throws IOException { return false; @@ -644,10 +644,10 @@ public abstract class ImageReader { * @return a {@code float} indicating the aspect ratio of the * given image. * - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public float getAspectRatio(int imageIndex) throws IOException { return (float)getWidth(imageIndex)/getHeight(imageIndex); @@ -669,10 +669,10 @@ public abstract class ImageReader { * * @return an {@code ImageTypeSpecifier}. * - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs reading the format + * @throws IOException if an error occurs reading the format * information from the input source. */ public ImageTypeSpecifier getRawImageType(int imageIndex) @@ -699,10 +699,10 @@ public abstract class ImageReader { * {@code ImageTypeSpecifier} representing suggested image * types for decoding the current given image. * - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs reading the format + * @throws IOException if an error occurs reading the format * information from the input source. * * @see ImageReadParam#setDestination(BufferedImage) @@ -739,7 +739,7 @@ public abstract class ImageReader { * * @return an {@code IIOMetadata} object, or {@code null}. * - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public abstract IIOMetadata getStreamMetadata() throws IOException; @@ -778,11 +778,11 @@ public abstract class ImageReader { * * @return an {@code IIOMetadata} object, or {@code null}. * - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalArgumentException if {@code formatName} * is {@code null}. - * @exception IllegalArgumentException if {@code nodeNames} + * @throws IllegalArgumentException if {@code nodeNames} * is {@code null}. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public IIOMetadata getStreamMetadata(String formatName, Set nodeNames) @@ -839,11 +839,11 @@ public abstract class ImageReader { * @return an {@code IIOMetadata} object, or * {@code null}. * - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public abstract IIOMetadata getImageMetadata(int imageIndex) throws IOException; @@ -885,15 +885,15 @@ public abstract class ImageReader { * * @return an {@code IIOMetadata} object, or {@code null}. * - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalArgumentException if {@code formatName} * is {@code null}. - * @exception IllegalArgumentException if {@code nodeNames} + * @throws IllegalArgumentException if {@code nodeNames} * is {@code null}. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public IIOMetadata getImageMetadata(int imageIndex, String formatName, @@ -928,11 +928,11 @@ public abstract class ImageReader { * @return the desired portion of the image as a * {@code BufferedImage}. * - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public BufferedImage read(int imageIndex) throws IOException { return read(imageIndex, null); @@ -980,18 +980,18 @@ public abstract class ImageReader { * @return the desired portion of the image as a * {@code BufferedImage}. * - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IllegalArgumentException if the set of source and + * @throws IllegalArgumentException if the set of source and * destination bands specified by * {@code param.getSourceBands} and * {@code param.getDestinationBands} differ in length or * include indices that are out of bounds. - * @exception IllegalArgumentException if the resulting image would + * @throws IllegalArgumentException if the resulting image would * have a width or height less than 1. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public abstract BufferedImage read(int imageIndex, ImageReadParam param) throws IOException; @@ -1043,18 +1043,18 @@ public abstract class ImageReader { * of the image, a set of thumbnails, and associated image * metadata. * - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IllegalArgumentException if the set of source and + * @throws IllegalArgumentException if the set of source and * destination bands specified by * {@code param.getSourceBands} and * {@code param.getDestinationBands} differ in length or * include indices that are out of bounds. - * @exception IllegalArgumentException if the resulting image + * @throws IllegalArgumentException if the resulting image * would have a width or height less than 1. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public IIOImage readAll(int imageIndex, ImageReadParam param) throws IOException { @@ -1134,19 +1134,19 @@ public abstract class ImageReader { * @return an {@code Iterator} representing the * contents of the input source as {@code IIOImage}s. * - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IllegalArgumentException if any + * @throws IllegalArgumentException if any * non-{@code null} element of {@code params} is not an * {@code ImageReadParam}. - * @exception IllegalArgumentException if the set of source and + * @throws IllegalArgumentException if the set of source and * destination bands specified by * {@code param.getSourceBands} and * {@code param.getDestinationBands} differ in length or * include indices that are out of bounds. - * @exception IllegalArgumentException if a resulting image would + * @throws IllegalArgumentException if a resulting image would * have a width or height less than 1. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. * * @see ImageReadParam * @see IIOImage @@ -1267,13 +1267,13 @@ public abstract class ImageReader { * @return the desired portion of the image as a * {@code Raster}. * - * @exception UnsupportedOperationException if this plug-in does not + * @throws UnsupportedOperationException if this plug-in does not * support reading raw {@code Raster}s. - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. * * @see #canReadRaster * @see #read @@ -1310,12 +1310,12 @@ public abstract class ImageReader { * * @return {@code true} if the image is tiled. * - * @exception IllegalStateException if an input source is required + * @throws IllegalStateException if an input source is required * to determine the return value, but none has been set. - * @exception IndexOutOfBoundsException if an image must be + * @throws IndexOutOfBoundsException if an image must be * accessed to determine the return value, but the supplied index * is out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public boolean isImageTiled(int imageIndex) throws IOException { return false; @@ -1333,10 +1333,10 @@ public abstract class ImageReader { * * @param imageIndex the index of the image to be queried. * - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public int getTileWidth(int imageIndex) throws IOException { return getWidth(imageIndex); @@ -1354,10 +1354,10 @@ public abstract class ImageReader { * * @param imageIndex the index of the image to be queried. * - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public int getTileHeight(int imageIndex) throws IOException { return getHeight(imageIndex); @@ -1382,12 +1382,12 @@ public abstract class ImageReader { * * @param imageIndex the index of the image to be queried. * - * @exception IllegalStateException if an input source is required + * @throws IllegalStateException if an input source is required * to determine the return value, but none has been set. - * @exception IndexOutOfBoundsException if an image must be + * @throws IndexOutOfBoundsException if an image must be * accessed to determine the return value, but the supplied index * is out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public int getTileGridXOffset(int imageIndex) throws IOException { return 0; @@ -1412,12 +1412,12 @@ public abstract class ImageReader { * * @param imageIndex the index of the image to be queried. * - * @exception IllegalStateException if an input source is required + * @throws IllegalStateException if an input source is required * to determine the return value, but none has been set. - * @exception IndexOutOfBoundsException if an image must be + * @throws IndexOutOfBoundsException if an image must be * accessed to determine the return value, but the supplied index * is out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public int getTileGridYOffset(int imageIndex) throws IOException { return 0; @@ -1455,13 +1455,13 @@ public abstract class ImageReader { * * @return the tile as a {@code BufferedImage}. * - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if {@code imageIndex} + * @throws IndexOutOfBoundsException if {@code imageIndex} * is out of bounds. - * @exception IllegalArgumentException if the tile indices are + * @throws IllegalArgumentException if the tile indices are * out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public BufferedImage readTile(int imageIndex, int tileX, int tileY) throws IOException { @@ -1495,15 +1495,15 @@ public abstract class ImageReader { * * @return the tile as a {@code Raster}. * - * @exception UnsupportedOperationException if this plug-in does not + * @throws UnsupportedOperationException if this plug-in does not * support reading raw {@code Raster}s. - * @exception IllegalArgumentException if the tile indices are + * @throws IllegalArgumentException if the tile indices are * out of bounds. - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if {@code imageIndex} + * @throws IndexOutOfBoundsException if {@code imageIndex} * is out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. * * @see #readTile * @see #readRaster @@ -1554,18 +1554,18 @@ public abstract class ImageReader { * @return a {@code RenderedImage} object providing a view of * the image. * - * @exception IllegalStateException if the input source has not been + * @throws IllegalStateException if the input source has not been * set. - * @exception IndexOutOfBoundsException if the supplied index is + * @throws IndexOutOfBoundsException if the supplied index is * out of bounds. - * @exception IllegalArgumentException if the set of source and + * @throws IllegalArgumentException if the set of source and * destination bands specified by * {@code param.getSourceBands} and * {@code param.getDestinationBands} differ in length or * include indices that are out of bounds. - * @exception IllegalArgumentException if the resulting image + * @throws IllegalArgumentException if the resulting image * would have a width or height less than 1. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public RenderedImage readAsRenderedImage(int imageIndex, ImageReadParam param) @@ -1611,11 +1611,11 @@ public abstract class ImageReader { * * @return {@code true} if the given image has thumbnails. * - * @exception IllegalStateException if the reader supports + * @throws IllegalStateException if the reader supports * thumbnails but the input source has not been set. - * @exception IndexOutOfBoundsException if the reader supports + * @throws IndexOutOfBoundsException if the reader supports * thumbnails but {@code imageIndex} is out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public boolean hasThumbnails(int imageIndex) throws IOException { return getNumThumbnails(imageIndex) > 0; @@ -1637,11 +1637,11 @@ public abstract class ImageReader { * @return the number of thumbnails associated with the given * image. * - * @exception IllegalStateException if the reader supports + * @throws IllegalStateException if the reader supports * thumbnails but the input source has not been set. - * @exception IndexOutOfBoundsException if the reader supports + * @throws IndexOutOfBoundsException if the reader supports * thumbnails but {@code imageIndex} is out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public int getNumThumbnails(int imageIndex) throws IOException { @@ -1669,12 +1669,12 @@ public abstract class ImageReader { * * @return the width of the desired thumbnail as an {@code int}. * - * @exception UnsupportedOperationException if thumbnails are not + * @throws UnsupportedOperationException if thumbnails are not * supported. - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if either of the supplied + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if either of the supplied * indices are out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public int getThumbnailWidth(int imageIndex, int thumbnailIndex) throws IOException { @@ -1702,12 +1702,12 @@ public abstract class ImageReader { * * @return the height of the desired thumbnail as an {@code int}. * - * @exception UnsupportedOperationException if thumbnails are not + * @throws UnsupportedOperationException if thumbnails are not * supported. - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if either of the supplied + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if either of the supplied * indices are out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public int getThumbnailHeight(int imageIndex, int thumbnailIndex) throws IOException { @@ -1738,12 +1738,12 @@ public abstract class ImageReader { * * @return the desired thumbnail as a {@code BufferedImage}. * - * @exception UnsupportedOperationException if thumbnails are not + * @throws UnsupportedOperationException if thumbnails are not * supported. - * @exception IllegalStateException if the input source has not been set. - * @exception IndexOutOfBoundsException if either of the supplied + * @throws IllegalStateException if the input source has not been set. + * @throws IndexOutOfBoundsException if either of the supplied * indices are out of bounds. - * @exception IOException if an error occurs during reading. + * @throws IOException if an error occurs during reading. */ public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) @@ -2388,7 +2388,7 @@ public abstract class ImageReader { * * @param warning the warning message to send. * - * @exception IllegalArgumentException if {@code warning} + * @throws IllegalArgumentException if {@code warning} * is {@code null}. */ protected void processWarningOccurred(String warning) { @@ -2420,15 +2420,15 @@ public abstract class ImageReader { * @param keyword the keyword used to index the warning message * within the set of {@code ResourceBundle}s. * - * @exception IllegalArgumentException if {@code baseName} + * @throws IllegalArgumentException if {@code baseName} * is {@code null}. - * @exception IllegalArgumentException if {@code keyword} + * @throws IllegalArgumentException if {@code keyword} * is {@code null}. - * @exception IllegalArgumentException if no appropriate + * @throws IllegalArgumentException if no appropriate * {@code ResourceBundle} may be located. - * @exception IllegalArgumentException if the named resource is + * @throws IllegalArgumentException if the named resource is * not found in the located {@code ResourceBundle}. - * @exception IllegalArgumentException if the object retrieved + * @throws IllegalArgumentException if the object retrieved * from the {@code ResourceBundle} is not a * {@code String}. */ @@ -2594,11 +2594,11 @@ public abstract class ImageReader { * the source region of interest. * @param destRegion a {@code Rectangle} that will be filled with * the destination region of interest. - * @exception IllegalArgumentException if {@code srcRegion} + * @throws IllegalArgumentException if {@code srcRegion} * is {@code null}. - * @exception IllegalArgumentException if {@code dstRegion} + * @throws IllegalArgumentException if {@code dstRegion} * is {@code null}. - * @exception IllegalArgumentException if the resulting source or + * @throws IllegalArgumentException if the resulting source or * destination region is empty. */ protected static void computeRegions(ImageReadParam param, @@ -2720,7 +2720,7 @@ public abstract class ImageReader { * @param numDstBands the number of bands in the destination image * being written. * - * @exception IllegalArgumentException if {@code param} + * @throws IllegalArgumentException if {@code param} * contains an invalid specification of a source and/or * destination band subset. */ @@ -2797,15 +2797,15 @@ public abstract class ImageReader { * @return the {@code BufferedImage} to which decoded pixel * data should be written. * - * @exception IIOException if the {@code ImageTypeSpecifier} + * @throws IIOException if the {@code ImageTypeSpecifier} * specified by {@code param} does not match any of the legal * ones from {@code imageTypes}. - * @exception IllegalArgumentException if {@code imageTypes} + * @throws IllegalArgumentException if {@code imageTypes} * is {@code null} or empty, or if an object not of type * {@code ImageTypeSpecifier} is retrieved from it. - * @exception IllegalArgumentException if the resulting image would + * @throws IllegalArgumentException if the resulting image would * have a width or height less than 1. - * @exception IllegalArgumentException if the product of + * @throws IllegalArgumentException if the product of * {@code width} and {@code height} is greater than * {@code Integer.MAX_VALUE}. */ diff --git a/src/java.desktop/share/classes/javax/imageio/ImageTranscoder.java b/src/java.desktop/share/classes/javax/imageio/ImageTranscoder.java index 3ce8fc88710..d2832c49a1f 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageTranscoder.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageTranscoder.java @@ -109,7 +109,7 @@ public interface ImageTranscoder { * {@code null} if the plug-in does not provide metadata * encoding capabilities. * - * @exception IllegalArgumentException if {@code inData} is + * @throws IllegalArgumentException if {@code inData} is * {@code null}. */ IIOMetadata convertStreamMetadata(IIOMetadata inData, @@ -142,7 +142,7 @@ public interface ImageTranscoder { * or {@code null} if the plug-in does not provide * metadata encoding capabilities. * - * @exception IllegalArgumentException if either of + * @throws IllegalArgumentException if either of * {@code inData} or {@code imageType} is * {@code null}. */ diff --git a/src/java.desktop/share/classes/javax/imageio/ImageTypeSpecifier.java b/src/java.desktop/share/classes/javax/imageio/ImageTypeSpecifier.java index e328d7499bc..b94b7709d2b 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageTypeSpecifier.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageTypeSpecifier.java @@ -90,9 +90,9 @@ public class ImageTypeSpecifier { * @param colorModel a {@code ColorModel}. * @param sampleModel a {@code SampleModel}. * - * @exception IllegalArgumentException if either parameter is + * @throws IllegalArgumentException if either parameter is * {@code null}. - * @exception IllegalArgumentException if {@code sampleModel} + * @throws IllegalArgumentException if {@code sampleModel} * is not compatible with {@code colorModel}. */ public ImageTypeSpecifier(ColorModel colorModel, SampleModel sampleModel) { @@ -120,7 +120,7 @@ public class ImageTypeSpecifier { * * @param image a {@code RenderedImage}. * - * @exception IllegalArgumentException if the argument is + * @throws IllegalArgumentException if the argument is * {@code null}. */ public ImageTypeSpecifier(RenderedImage image) { @@ -208,13 +208,13 @@ public class ImageTypeSpecifier { * @return an {@code ImageTypeSpecifier} with the desired * characteristics. * - * @exception IllegalArgumentException if {@code colorSpace} + * @throws IllegalArgumentException if {@code colorSpace} * is {@code null}. - * @exception IllegalArgumentException if {@code colorSpace} + * @throws IllegalArgumentException if {@code colorSpace} * is not of type {@code TYPE_RGB}. - * @exception IllegalArgumentException if no mask has at least 1 + * @throws IllegalArgumentException if no mask has at least 1 * bit set. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code transferType} if not one of * {@code DataBuffer.TYPE_BYTE}, * {@code DataBuffer.TYPE_USHORT}, or @@ -375,13 +375,13 @@ public class ImageTypeSpecifier { * @return an {@code ImageTypeSpecifier} with the desired * characteristics. * - * @exception IllegalArgumentException if {@code colorSpace} + * @throws IllegalArgumentException if {@code colorSpace} * is {@code null}. - * @exception IllegalArgumentException if {@code bandOffsets} + * @throws IllegalArgumentException if {@code bandOffsets} * is {@code null}. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of the legal {@code DataBuffer.TYPE_*} constants. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code bandOffsets.length} does not equal the number of * color space components, plus 1 if {@code hasAlpha} is * {@code true}. @@ -525,19 +525,19 @@ public class ImageTypeSpecifier { * @return an {@code ImageTypeSpecifier} with the desired * characteristics. * - * @exception IllegalArgumentException if {@code colorSpace} + * @throws IllegalArgumentException if {@code colorSpace} * is {@code null}. - * @exception IllegalArgumentException if {@code bankIndices} + * @throws IllegalArgumentException if {@code bankIndices} * is {@code null}. - * @exception IllegalArgumentException if {@code bandOffsets} + * @throws IllegalArgumentException if {@code bandOffsets} * is {@code null}. - * @exception IllegalArgumentException if the lengths of + * @throws IllegalArgumentException if the lengths of * {@code bankIndices} and {@code bandOffsets} differ. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code bandOffsets.length} does not equal the number of * color space components, plus 1 if {@code hasAlpha} is * {@code true}. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of the legal {@code DataBuffer.TYPE_*} constants. */ public static ImageTypeSpecifier @@ -661,13 +661,13 @@ public class ImageTypeSpecifier { * @return an {@code ImageTypeSpecifier} with the desired * characteristics. * - * @exception IllegalArgumentException if {@code bits} is + * @throws IllegalArgumentException if {@code bits} is * not one of 1, 2, 4, 8, or 16. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of {@code DataBuffer.TYPE_BYTE}, * {@code DataBuffer.TYPE_SHORT}, or * {@code DataBuffer.TYPE_USHORT}. - * @exception IllegalArgumentException if {@code bits} is + * @throws IllegalArgumentException if {@code bits} is * larger than the bit size of the given {@code dataType}. */ public static ImageTypeSpecifier @@ -697,13 +697,13 @@ public class ImageTypeSpecifier { * @return an {@code ImageTypeSpecifier} with the desired * characteristics. * - * @exception IllegalArgumentException if {@code bits} is + * @throws IllegalArgumentException if {@code bits} is * not one of 1, 2, 4, 8, or 16. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of {@code DataBuffer.TYPE_BYTE}, * {@code DataBuffer.TYPE_SHORT}, or * {@code DataBuffer.TYPE_USHORT}. - * @exception IllegalArgumentException if {@code bits} is + * @throws IllegalArgumentException if {@code bits} is * larger than the bit size of the given {@code dataType}. */ public static ImageTypeSpecifier @@ -822,23 +822,23 @@ public class ImageTypeSpecifier { * @return an {@code ImageTypeSpecifier} with the desired * characteristics. * - * @exception IllegalArgumentException if {@code redLUT} is + * @throws IllegalArgumentException if {@code redLUT} is * {@code null}. - * @exception IllegalArgumentException if {@code greenLUT} is + * @throws IllegalArgumentException if {@code greenLUT} is * {@code null}. - * @exception IllegalArgumentException if {@code blueLUT} is + * @throws IllegalArgumentException if {@code blueLUT} is * {@code null}. - * @exception IllegalArgumentException if {@code bits} is + * @throws IllegalArgumentException if {@code bits} is * not one of 1, 2, 4, 8, or 16. - * @exception IllegalArgumentException if the + * @throws IllegalArgumentException if the * non-{@code null} LUT parameters do not have lengths of * exactly {@code 1 << bits}. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of {@code DataBuffer.TYPE_BYTE}, * {@code DataBuffer.TYPE_SHORT}, * {@code DataBuffer.TYPE_USHORT}, * or {@code DataBuffer.TYPE_INT}. - * @exception IllegalArgumentException if {@code bits} is + * @throws IllegalArgumentException if {@code bits} is * larger than the bit size of the given {@code dataType}. */ public static ImageTypeSpecifier @@ -867,7 +867,7 @@ public class ImageTypeSpecifier { * @return an {@code ImageTypeSpecifier} with the desired * characteristics. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code bufferedImageType} is not one of the standard * types, or is equal to {@code TYPE_CUSTOM}. * @@ -908,7 +908,7 @@ public class ImageTypeSpecifier { * @return an {@code ImageTypeSpecifier} with the desired * characteristics. * - * @exception IllegalArgumentException if {@code image} is + * @throws IllegalArgumentException if {@code image} is * {@code null}. */ public static @@ -985,7 +985,7 @@ public class ImageTypeSpecifier { * * @return an int specifying a number of bits. * - * @exception IllegalArgumentException if {@code band} is + * @throws IllegalArgumentException if {@code band} is * negative or greater than the largest band index. */ public int getBitsPerBand(int band) { @@ -1017,9 +1017,9 @@ public class ImageTypeSpecifier { * * @return a {@code SampleModel} with the given dimensions. * - * @exception IllegalArgumentException if either {@code width} or + * @throws IllegalArgumentException if either {@code width} or * {@code height} are negative or zero. - * @exception IllegalArgumentException if the product of + * @throws IllegalArgumentException if the product of * {@code width} and {@code height} is greater than * {@code Integer.MAX_VALUE} */ @@ -1051,9 +1051,9 @@ public class ImageTypeSpecifier { * * @return a new {@code BufferedImage} * - * @exception IllegalArgumentException if either {@code width} or + * @throws IllegalArgumentException if either {@code width} or * {@code height} are negative or zero. - * @exception IllegalArgumentException if the product of + * @throws IllegalArgumentException if the product of * {@code width} and {@code height} is greater than * {@code Integer.MAX_VALUE}, or if the number of array * elements needed to store the image is greater than diff --git a/src/java.desktop/share/classes/javax/imageio/ImageWriteParam.java b/src/java.desktop/share/classes/javax/imageio/ImageWriteParam.java index cbaa5781271..482730ba888 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageWriteParam.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageWriteParam.java @@ -474,9 +474,9 @@ public class ImageWriteParam extends IIOParam { * * @param mode The mode to use for tiling. * - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canWriteTiles} returns {@code false}. - * @exception IllegalArgumentException if {@code mode} is not + * @throws IllegalArgumentException if {@code mode} is not * one of the modes listed above. * * @see #setTiling @@ -501,7 +501,7 @@ public class ImageWriteParam extends IIOParam { * * @return the current tiling mode. * - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canWriteTiles} returns {@code false}. * * @see #setTilingMode @@ -530,7 +530,7 @@ public class ImageWriteParam extends IIOParam { *

      If no array is specified on the constructor, but tiling is * allowed, then this method returns {@code null}. * - * @exception UnsupportedOperationException if the plug-in does + * @throws UnsupportedOperationException if the plug-in does * not support tiling. * * @return an array of {@code Dimension}s with an even length @@ -559,16 +559,16 @@ public class ImageWriteParam extends IIOParam { * @param tileGridXOffset the horizontal offset of the tile grid. * @param tileGridYOffset the vertical offset of the tile grid. * - * @exception UnsupportedOperationException if the plug-in does not + * @throws UnsupportedOperationException if the plug-in does not * support tiling. - * @exception IllegalStateException if the tiling mode is not + * @throws IllegalStateException if the tiling mode is not * {@code MODE_EXPLICIT}. - * @exception UnsupportedOperationException if the plug-in does not + * @throws UnsupportedOperationException if the plug-in does not * support grid offsets, and the grid offsets are not both zero. - * @exception IllegalArgumentException if the tile size is not + * @throws IllegalArgumentException if the tile size is not * within one of the allowable ranges returned by * {@code getPreferredTileSizes}. - * @exception IllegalArgumentException if {@code tileWidth} + * @throws IllegalArgumentException if {@code tileWidth} * or {@code tileHeight} is less than or equal to 0. * * @see #canWriteTiles @@ -630,9 +630,9 @@ public class ImageWriteParam extends IIOParam { * {@code tileGridXOffset}, and * {@code tileGridYOffset} to {@code 0}. * - * @exception UnsupportedOperationException if the plug-in does not + * @throws UnsupportedOperationException if the plug-in does not * support tiling. - * @exception IllegalStateException if the tiling mode is not + * @throws IllegalStateException if the tiling mode is not * {@code MODE_EXPLICIT}. * * @see #setTiling(int, int, int, int) @@ -658,11 +658,11 @@ public class ImageWriteParam extends IIOParam { * * @return the tile width to be used for encoding. * - * @exception UnsupportedOperationException if the plug-in does not + * @throws UnsupportedOperationException if the plug-in does not * support tiling. - * @exception IllegalStateException if the tiling mode is not + * @throws IllegalStateException if the tiling mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the tiling parameters have + * @throws IllegalStateException if the tiling parameters have * not been set. * * @see #setTiling(int, int, int, int) @@ -688,11 +688,11 @@ public class ImageWriteParam extends IIOParam { * * @return the tile height to be used for encoding. * - * @exception UnsupportedOperationException if the plug-in does not + * @throws UnsupportedOperationException if the plug-in does not * support tiling. - * @exception IllegalStateException if the tiling mode is not + * @throws IllegalStateException if the tiling mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the tiling parameters have + * @throws IllegalStateException if the tiling parameters have * not been set. * * @see #setTiling(int, int, int, int) @@ -718,11 +718,11 @@ public class ImageWriteParam extends IIOParam { * * @return the tile grid X offset to be used for encoding. * - * @exception UnsupportedOperationException if the plug-in does not + * @throws UnsupportedOperationException if the plug-in does not * support tiling. - * @exception IllegalStateException if the tiling mode is not + * @throws IllegalStateException if the tiling mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the tiling parameters have + * @throws IllegalStateException if the tiling parameters have * not been set. * * @see #setTiling(int, int, int, int) @@ -748,11 +748,11 @@ public class ImageWriteParam extends IIOParam { * * @return the tile grid Y offset to be used for encoding. * - * @exception UnsupportedOperationException if the plug-in does not + * @throws UnsupportedOperationException if the plug-in does not * support tiling. - * @exception IllegalStateException if the tiling mode is not + * @throws IllegalStateException if the tiling mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the tiling parameters have + * @throws IllegalStateException if the tiling parameters have * not been set. * * @see #setTiling(int, int, int, int) @@ -818,9 +818,9 @@ public class ImageWriteParam extends IIOParam { * @param mode The mode for setting progression in the output * stream. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support progressive encoding. - * @exception IllegalArgumentException if {@code mode} is not + * @throws IllegalArgumentException if {@code mode} is not * one of the modes listed above. * * @see #getProgressiveMode @@ -846,7 +846,7 @@ public class ImageWriteParam extends IIOParam { * * @return the current mode for progressive encoding. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support progressive encoding. * * @see #setProgressiveMode @@ -902,9 +902,9 @@ public class ImageWriteParam extends IIOParam { * @param mode The mode for setting compression in the output * stream. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression, or does not support the requested mode. - * @exception IllegalArgumentException if {@code mode} is not + * @throws IllegalArgumentException if {@code mode} is not * one of the modes listed above. * * @see #getCompressionMode @@ -929,7 +929,7 @@ public class ImageWriteParam extends IIOParam { * * @return the current compression mode. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. * * @see #setCompressionMode @@ -965,7 +965,7 @@ public class ImageWriteParam extends IIOParam { * (non-localized) names of available compression types, or * {@code null}. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. */ public String[] getCompressionTypes() { @@ -998,13 +998,13 @@ public class ImageWriteParam extends IIOParam { * by {@code getCompressionTypes}, or {@code null} to * remove any previous setting. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. - * @exception UnsupportedOperationException if there are no + * @throws UnsupportedOperationException if there are no * settable compression types. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code compressionType} is non-{@code null} but is not * one of the values returned by {@code getCompressionTypes}. * @@ -1059,9 +1059,9 @@ public class ImageWriteParam extends IIOParam { * @return the current compression type as a {@code String}, * or {@code null} if no type is set. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. * * @see #setCompressionType @@ -1086,9 +1086,9 @@ public class ImageWriteParam extends IIOParam { * instance variable {@code compressionQuality} to * {@code 1.0F}. * - * @exception UnsupportedOperationException if the plug-in does not + * @throws UnsupportedOperationException if the plug-in does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. * * @see #setCompressionType @@ -1122,11 +1122,11 @@ public class ImageWriteParam extends IIOParam { * @return a {@code String} containing a localized version of * the name of the current compression type. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if no compression type is set. + * @throws IllegalStateException if no compression type is set. */ public String getLocalizedCompressionTypeName() { if (!canWriteCompressed()) { @@ -1162,11 +1162,11 @@ public class ImageWriteParam extends IIOParam { * @return {@code true} if the current compression type is * lossless. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the set of legal + * @throws IllegalStateException if the set of legal * compression types is non-{@code null} and the current * compression type is {@code null}. */ @@ -1218,14 +1218,14 @@ public class ImageWriteParam extends IIOParam { * @param quality a {@code float} between {@code 0} and * {@code 1} indicating the desired quality level. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the set of legal + * @throws IllegalStateException if the set of legal * compression types is non-{@code null} and the current * compression type is {@code null}. - * @exception IllegalArgumentException if {@code quality} is + * @throws IllegalArgumentException if {@code quality} is * not between {@code 0} and {@code 1}, inclusive. * * @see #getCompressionQuality @@ -1264,11 +1264,11 @@ public class ImageWriteParam extends IIOParam { * * @return the current compression quality setting. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the set of legal + * @throws IllegalStateException if the set of legal * compression types is non-{@code null} and the current * compression type is {@code null}. * @@ -1317,14 +1317,14 @@ public class ImageWriteParam extends IIOParam { * @return an estimate of the compressed bit rate, or * {@code -1.0F} if no estimate is available. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the set of legal + * @throws IllegalStateException if the set of legal * compression types is non-{@code null} and the current * compression type is {@code null}. - * @exception IllegalArgumentException if {@code quality} is + * @throws IllegalArgumentException if {@code quality} is * not between {@code 0} and {@code 1}, inclusive. */ public float getBitRate(float quality) { @@ -1389,11 +1389,11 @@ public class ImageWriteParam extends IIOParam { * @return an array of {@code String}s containing localized * descriptions of the compression quality levels. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the set of legal + * @throws IllegalStateException if the set of legal * compression types is non-{@code null} and the current * compression type is {@code null}. * @@ -1442,11 +1442,11 @@ public class ImageWriteParam extends IIOParam { * by the {@code String}s from * {@code getCompressionQualityDescriptions}. * - * @exception UnsupportedOperationException if the writer does not + * @throws UnsupportedOperationException if the writer does not * support compression. - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. - * @exception IllegalStateException if the set of legal + * @throws IllegalStateException if the set of legal * compression types is non-{@code null} and the current * compression type is {@code null}. * diff --git a/src/java.desktop/share/classes/javax/imageio/ImageWriter.java b/src/java.desktop/share/classes/javax/imageio/ImageWriter.java index 8723c50773e..a688d9aea91 100644 --- a/src/java.desktop/share/classes/javax/imageio/ImageWriter.java +++ b/src/java.desktop/share/classes/javax/imageio/ImageWriter.java @@ -194,7 +194,7 @@ public abstract class ImageWriter implements ImageTranscoder { * @param output the {@code ImageOutputStream} or other * {@code Object} to use for future writing. * - * @exception IllegalArgumentException if {@code output} is + * @throws IllegalArgumentException if {@code output} is * not an instance of one of the classes returned by the * originating service provider's {@code getOutputTypes} * method. @@ -276,7 +276,7 @@ public abstract class ImageWriter implements ImageTranscoder { * @param locale the desired {@code Locale}, or * {@code null}. * - * @exception IllegalArgumentException if {@code locale} is + * @throws IllegalArgumentException if {@code locale} is * non-{@code null} but is not one of the values returned by * {@code getAvailableLocales}. * @@ -561,14 +561,14 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null} to use a default * {@code ImageWriteParam}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if {@code image} + * @throws UnsupportedOperationException if {@code image} * contains a {@code Raster} and {@code canWriteRasters} * returns {@code false}. - * @exception IllegalArgumentException if {@code image} is + * @throws IllegalArgumentException if {@code image} is * {@code null}. - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public abstract void write(IIOMetadata streamMetadata, IIOImage image, @@ -582,14 +582,14 @@ public abstract class ImageWriter implements ImageTranscoder { * @param image an {@code IIOImage} object containing an * image, thumbnails, and metadata to be written. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception IllegalArgumentException if {@code image} is + * @throws IllegalArgumentException if {@code image} is * {@code null}. - * @exception UnsupportedOperationException if {@code image} + * @throws UnsupportedOperationException if {@code image} * contains a {@code Raster} and {@code canWriteRasters} * returns {@code false}. - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public void write(IIOImage image) throws IOException { write(null, image, null); @@ -603,11 +603,11 @@ public abstract class ImageWriter implements ImageTranscoder { * * @param image a {@code RenderedImage} to be written. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception IllegalArgumentException if {@code image} is + * @throws IllegalArgumentException if {@code image} is * {@code null}. - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public void write(RenderedImage image) throws IOException { write(null, new IIOImage(image, null, null), null); @@ -671,11 +671,11 @@ public abstract class ImageWriter implements ImageTranscoder { * * @param streamMetadata A stream metadata object, or {@code null}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canWriteSequence} returns {@code false}. - * @exception IOException if an error occurs writing the stream + * @throws IOException if an error occurs writing the stream * metadata. */ public void prepareWriteSequence(IIOMetadata streamMetadata) @@ -732,16 +732,16 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null} to use a default * {@code ImageWriteParam}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set, or {@code prepareWriteSequence} has not been called. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canWriteSequence} returns {@code false}. - * @exception IllegalArgumentException if {@code image} is + * @throws IllegalArgumentException if {@code image} is * {@code null}. - * @exception UnsupportedOperationException if {@code image} + * @throws UnsupportedOperationException if {@code image} * contains a {@code Raster} and {@code canWriteRasters} * returns {@code false}. - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException { @@ -767,11 +767,11 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null}, and otherwise throws an * {@code UnsupportedOperationException}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set, or {@code prepareWriteSequence} has not been called. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canWriteSequence} returns {@code false}. - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public void endWriteSequence() throws IOException { unsupported(); @@ -790,9 +790,9 @@ public abstract class ImageWriter implements ImageTranscoder { * @return {@code true} if replacement of stream metadata is * allowed. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception IOException if an I/O error occurs during the query. + * @throws IOException if an I/O error occurs during the query. */ public boolean canReplaceStreamMetadata() throws IOException { if (getOutput() == null) { @@ -821,12 +821,12 @@ public abstract class ImageWriter implements ImageTranscoder { * @param streamMetadata an {@code IIOMetadata} object representing * stream metadata, or {@code null} to use default values. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if the + * @throws UnsupportedOperationException if the * {@code canReplaceStreamMetadata} returns * {@code false}. modes do not include - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public void replaceStreamMetadata(IIOMetadata streamMetadata) throws IOException { @@ -856,13 +856,13 @@ public abstract class ImageWriter implements ImageTranscoder { * @return {@code true} if the image metadata of the given * image can be replaced. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception IndexOutOfBoundsException if the writer supports + * @throws IndexOutOfBoundsException if the writer supports * image metadata replacement in general, but * {@code imageIndex} is less than 0 or greater than the * largest available index. - * @exception IOException if an I/O error occurs during the query. + * @throws IOException if an I/O error occurs during the query. */ public boolean canReplaceImageMetadata(int imageIndex) throws IOException { @@ -889,14 +889,14 @@ public abstract class ImageWriter implements ImageTranscoder { * @param imageMetadata an {@code IIOMetadata} object * representing image metadata, or {@code null}. * - * @exception IllegalStateException if the output has not been + * @throws IllegalStateException if the output has not been * set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canReplaceImageMetadata} returns * {@code false}. - * @exception IndexOutOfBoundsException if {@code imageIndex} + * @throws IndexOutOfBoundsException if {@code imageIndex} * is less than 0 or greater than the largest available index. - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public void replaceImageMetadata(int imageIndex, IIOMetadata imageMetadata) @@ -929,12 +929,12 @@ public abstract class ImageWriter implements ImageTranscoder { * @return {@code true} if an image may be inserted at the * given index. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception IndexOutOfBoundsException if the writer supports + * @throws IndexOutOfBoundsException if the writer supports * image insertion in general, but {@code imageIndex} is less * than -1 or greater than the largest available index. - * @exception IOException if an I/O error occurs during the query. + * @throws IOException if an I/O error occurs during the query. */ public boolean canInsertImage(int imageIndex) throws IOException { if (getOutput() == null) { @@ -978,18 +978,18 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null} to use a default * {@code ImageWriteParam}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canInsertImage(imageIndex)} returns {@code false}. - * @exception IllegalArgumentException if {@code image} is + * @throws IllegalArgumentException if {@code image} is * {@code null}. - * @exception IndexOutOfBoundsException if {@code imageIndex} + * @throws IndexOutOfBoundsException if {@code imageIndex} * is less than -1 or greater than the largest available index. - * @exception UnsupportedOperationException if {@code image} + * @throws UnsupportedOperationException if {@code image} * contains a {@code Raster} and {@code canWriteRasters} * returns {@code false}. - * @exception IOException if an error occurs during writing. + * @throws IOException if an error occurs during writing. */ public void writeInsert(int imageIndex, IIOImage image, @@ -1019,12 +1019,12 @@ public abstract class ImageWriter implements ImageTranscoder { * @return {@code true} if it is possible to remove the given * image. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception IndexOutOfBoundsException if the writer supports + * @throws IndexOutOfBoundsException if the writer supports * image removal in general, but {@code imageIndex} is less * than 0 or greater than the largest available index. - * @exception IOException if an I/O error occurs during the + * @throws IOException if an I/O error occurs during the * query. */ public boolean canRemoveImage(int imageIndex) throws IOException { @@ -1050,13 +1050,13 @@ public abstract class ImageWriter implements ImageTranscoder { * * @param imageIndex the index of the image to be removed. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canRemoveImage(imageIndex)} returns {@code false}. - * @exception IndexOutOfBoundsException if {@code imageIndex} + * @throws IndexOutOfBoundsException if {@code imageIndex} * is less than 0 or greater than the largest available index. - * @exception IOException if an I/O error occurs during the + * @throws IOException if an I/O error occurs during the * removal. */ public void removeImage(int imageIndex) throws IOException { @@ -1082,9 +1082,9 @@ public abstract class ImageWriter implements ImageTranscoder { * @return {@code true} if the writing of complete image * stream with contents to be defined later is supported. * - * @exception IllegalStateException if the output has not been + * @throws IllegalStateException if the output has not been * set. - * @exception IOException if an I/O error occurs during the + * @throws IOException if an I/O error occurs during the * query. */ public boolean canWriteEmpty() throws IOException { @@ -1144,23 +1144,23 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null} to use a default * {@code ImageWriteParam}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canWriteEmpty} returns {@code false}. - * @exception IllegalStateException if a previous call to + * @throws IllegalStateException if a previous call to * {@code prepareWriteEmpty} has been made without a * corresponding call to {@code endWriteEmpty}. - * @exception IllegalStateException if a previous call to + * @throws IllegalStateException if a previous call to * {@code prepareInsertEmpty} has been made without a * corresponding call to {@code endInsertEmpty}. - * @exception IllegalArgumentException if {@code imageType} + * @throws IllegalArgumentException if {@code imageType} * is {@code null} or {@code thumbnails} contains * {@code null} references or objects other than * {@code BufferedImage}s. - * @exception IllegalArgumentException if width or height are less + * @throws IllegalArgumentException if width or height are less * than 1. - * @exception IOException if an I/O error occurs during writing. + * @throws IOException if an I/O error occurs during writing. */ public void prepareWriteEmpty(IIOMetadata streamMetadata, ImageTypeSpecifier imageType, @@ -1183,21 +1183,21 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null}, and otherwise throws an * {@code UnsupportedOperationException}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canWriteEmpty(imageIndex)} returns * {@code false}. - * @exception IllegalStateException if a previous call to + * @throws IllegalStateException if a previous call to * {@code prepareWriteEmpty} without a corresponding call to * {@code endWriteEmpty} has not been made. - * @exception IllegalStateException if a previous call to + * @throws IllegalStateException if a previous call to * {@code prepareInsertEmpty} without a corresponding call to * {@code endInsertEmpty} has been made. - * @exception IllegalStateException if a call to + * @throws IllegalStateException if a call to * {@code prepareReiplacePixels} has been made without a * matching call to {@code endReplacePixels}. - * @exception IOException if an I/O error occurs during writing. + * @throws IOException if an I/O error occurs during writing. */ public void endWriteEmpty() throws IOException { if (getOutput() == null) { @@ -1231,12 +1231,12 @@ public abstract class ImageWriter implements ImageTranscoder { * @return {@code true} if an empty image may be inserted at * the given index. * - * @exception IllegalStateException if the output has not been + * @throws IllegalStateException if the output has not been * set. - * @exception IndexOutOfBoundsException if the writer supports + * @throws IndexOutOfBoundsException if the writer supports * empty image insertion in general, but {@code imageIndex} * is less than -1 or greater than the largest available index. - * @exception IOException if an I/O error occurs during the + * @throws IOException if an I/O error occurs during the * query. */ public boolean canInsertEmpty(int imageIndex) throws IOException { @@ -1301,26 +1301,26 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null} to use a default * {@code ImageWriteParam}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canInsertEmpty(imageIndex)} returns * {@code false}. - * @exception IndexOutOfBoundsException if {@code imageIndex} + * @throws IndexOutOfBoundsException if {@code imageIndex} * is less than -1 or greater than the largest available index. - * @exception IllegalStateException if a previous call to + * @throws IllegalStateException if a previous call to * {@code prepareInsertEmpty} has been made without a * corresponding call to {@code endInsertEmpty}. - * @exception IllegalStateException if a previous call to + * @throws IllegalStateException if a previous call to * {@code prepareWriteEmpty} has been made without a * corresponding call to {@code endWriteEmpty}. - * @exception IllegalArgumentException if {@code imageType} + * @throws IllegalArgumentException if {@code imageType} * is {@code null} or {@code thumbnails} contains * {@code null} references or objects other than * {@code BufferedImage}s. - * @exception IllegalArgumentException if width or height are less + * @throws IllegalArgumentException if width or height are less * than 1. - * @exception IOException if an I/O error occurs during writing. + * @throws IOException if an I/O error occurs during writing. */ public void prepareInsertEmpty(int imageIndex, ImageTypeSpecifier imageType, @@ -1340,21 +1340,21 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null}, and otherwise throws an * {@code UnsupportedOperationException}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canInsertEmpty(imageIndex)} returns * {@code false}. - * @exception IllegalStateException if a previous call to + * @throws IllegalStateException if a previous call to * {@code prepareInsertEmpty} without a corresponding call to * {@code endInsertEmpty} has not been made. - * @exception IllegalStateException if a previous call to + * @throws IllegalStateException if a previous call to * {@code prepareWriteEmpty} without a corresponding call to * {@code endWriteEmpty} has been made. - * @exception IllegalStateException if a call to + * @throws IllegalStateException if a call to * {@code prepareReplacePixels} has been made without a * matching call to {@code endReplacePixels}. - * @exception IOException if an I/O error occurs during writing. + * @throws IOException if an I/O error occurs during writing. */ public void endInsertEmpty() throws IOException { unsupported(); @@ -1382,12 +1382,12 @@ public abstract class ImageWriter implements ImageTranscoder { * @return {@code true} if the pixels of the given * image can be replaced. * - * @exception IllegalStateException if the output has not been + * @throws IllegalStateException if the output has not been * set. - * @exception IndexOutOfBoundsException if the writer supports + * @throws IndexOutOfBoundsException if the writer supports * pixel replacement in general, but {@code imageIndex} is * less than 0 or greater than the largest available index. - * @exception IOException if an I/O error occurs during the query. + * @throws IOException if an I/O error occurs during the query. */ public boolean canReplacePixels(int imageIndex) throws IOException { if (getOutput() == null) { @@ -1415,20 +1415,20 @@ public abstract class ImageWriter implements ImageTranscoder { * @param region a {@code Rectangle} that will be used to clip * future pixel regions. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canReplacePixels(imageIndex)} returns * {@code false}. - * @exception IndexOutOfBoundsException if {@code imageIndex} + * @throws IndexOutOfBoundsException if {@code imageIndex} * is less than 0 or greater than the largest available index. - * @exception IllegalStateException if there is a previous call to + * @throws IllegalStateException if there is a previous call to * {@code prepareReplacePixels} without a matching call to * {@code endReplacePixels} (i.e., nesting is not * allowed). - * @exception IllegalArgumentException if {@code region} is + * @throws IllegalArgumentException if {@code region} is * {@code null} or has a width or height less than 1. - * @exception IOException if an I/O error occurs during the + * @throws IOException if an I/O error occurs during the * preparation. */ public void prepareReplacePixels(int imageIndex, @@ -1471,22 +1471,22 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null} to use a default * {@code ImageWriteParam}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canReplacePixels(imageIndex)} returns * {@code false}. - * @exception IllegalStateException if there is no previous call to + * @throws IllegalStateException if there is no previous call to * {@code prepareReplacePixels} without a matching call to * {@code endReplacePixels}. - * @exception IllegalArgumentException if any of the following are true: + * @throws IllegalArgumentException if any of the following are true: *

        *
      • {@code image} is {@code null}. *
      • the intersected region does not contain at least one pixel. *
      • the layout of {@code image} does not match, or this * writer cannot convert it to, the existing image layout. *
      - * @exception IOException if an I/O error occurs during writing. + * @throws IOException if an I/O error occurs during writing. */ public void replacePixels(RenderedImage image, ImageWriteParam param) throws IOException { @@ -1529,24 +1529,24 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null} to use a default * {@code ImageWriteParam}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canReplacePixels(imageIndex)} returns * {@code false}. - * @exception IllegalStateException if there is no previous call to + * @throws IllegalStateException if there is no previous call to * {@code prepareReplacePixels} without a matching call to * {@code endReplacePixels}. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canWriteRasters} returns {@code false}. - * @exception IllegalArgumentException if any of the following are true: + * @throws IllegalArgumentException if any of the following are true: *
        *
      • {@code raster} is {@code null}. *
      • the intersected region does not contain at least one pixel. *
      • the layout of {@code raster} does not match, or this * writer cannot convert it to, the existing image layout. *
      - * @exception IOException if an I/O error occurs during writing. + * @throws IOException if an I/O error occurs during writing. */ public void replacePixels(Raster raster, ImageWriteParam param) throws IOException { @@ -1565,15 +1565,15 @@ public abstract class ImageWriter implements ImageTranscoder { * {@code null}, and otherwise throws an * {@code UnsupportedOperationException}. * - * @exception IllegalStateException if the output has not + * @throws IllegalStateException if the output has not * been set. - * @exception UnsupportedOperationException if + * @throws UnsupportedOperationException if * {@code canReplacePixels(imageIndex)} returns * {@code false}. - * @exception IllegalStateException if there is no previous call + * @throws IllegalStateException if there is no previous call * to {@code prepareReplacePixels} without a matching call to * {@code endReplacePixels}. - * @exception IOException if an I/O error occurs during writing. + * @throws IOException if an I/O error occurs during writing. */ public void endReplacePixels() throws IOException { unsupported(); @@ -1886,7 +1886,7 @@ public abstract class ImageWriter implements ImageTranscoder { * occurred. * @param warning the warning message. * - * @exception IllegalArgumentException if {@code warning} + * @throws IllegalArgumentException if {@code warning} * is {@code null}. */ protected void processWarningOccurred(int imageIndex, @@ -1921,15 +1921,15 @@ public abstract class ImageWriter implements ImageTranscoder { * @param keyword the keyword used to index the warning message * within the set of {@code ResourceBundle}s. * - * @exception IllegalArgumentException if {@code baseName} + * @throws IllegalArgumentException if {@code baseName} * is {@code null}. - * @exception IllegalArgumentException if {@code keyword} + * @throws IllegalArgumentException if {@code keyword} * is {@code null}. - * @exception IllegalArgumentException if no appropriate + * @throws IllegalArgumentException if no appropriate * {@code ResourceBundle} may be located. - * @exception IllegalArgumentException if the named resource is + * @throws IllegalArgumentException if the named resource is * not found in the located {@code ResourceBundle}. - * @exception IllegalArgumentException if the object retrieved + * @throws IllegalArgumentException if the object retrieved * from the {@code ResourceBundle} is not a * {@code String}. */ diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java index 9952544b487..3954f886f47 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java +++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadata.java @@ -165,9 +165,9 @@ public abstract class IIOMetadata { * indicating the class names of any additional formats supported by * this object, or {@code null} if there are none. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code extraMetadataFormatNames} has length 0. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code extraMetadataFormatNames} and * {@code extraMetadataFormatClassNames} are neither both * {@code null}, nor of the same length. @@ -368,10 +368,10 @@ public abstract class IIOMetadata { * * @return an {@code IIOMetadataFormat} object. * - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalArgumentException if {@code formatName} * is {@code null} or is not one of the names recognized by * the plug-in. - * @exception IllegalStateException if the class corresponding to + * @throws IllegalStateException if the class corresponding to * the format name cannot be loaded. */ public IIOMetadataFormat getMetadataFormat(String formatName) { @@ -452,7 +452,7 @@ public abstract class IIOMetadata { * @return an XML DOM {@code Node} object forming the * root of a tree. * - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalArgumentException if {@code formatName} * is {@code null} or is not one of the names returned by * {@code getMetadataFormatNames}. * @@ -481,13 +481,13 @@ public abstract class IIOMetadata { * @param root an XML DOM {@code Node} object forming the * root of a tree. * - * @exception IllegalStateException if this object is read-only. - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalStateException if this object is read-only. + * @throws IllegalArgumentException if {@code formatName} * is {@code null} or is not one of the names returned by * {@code getMetadataFormatNames}. - * @exception IllegalArgumentException if {@code root} is + * @throws IllegalArgumentException if {@code root} is * {@code null}. - * @exception IIOInvalidTreeException if the tree cannot be parsed + * @throws IIOInvalidTreeException if the tree cannot be parsed * successfully using the rules of the given format. * * @see #getMetadataFormatNames @@ -731,13 +731,13 @@ public abstract class IIOMetadata { * @param root an XML DOM {@code Node} object forming the * root of a tree. * - * @exception IllegalStateException if this object is read-only. - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalStateException if this object is read-only. + * @throws IllegalArgumentException if {@code formatName} * is {@code null} or is not one of the names returned by * {@code getMetadataFormatNames}. - * @exception IllegalArgumentException if {@code root} is + * @throws IllegalArgumentException if {@code root} is * {@code null}. - * @exception IIOInvalidTreeException if the tree cannot be parsed + * @throws IIOInvalidTreeException if the tree cannot be parsed * successfully using the rules of the given format. * * @see #getMetadataFormatNames @@ -757,7 +757,7 @@ public abstract class IIOMetadata { * Note that there are many possible default values, depending on * how the object was created. * - * @exception IllegalStateException if this object is read-only. + * @throws IllegalStateException if this object is read-only. * * @see javax.imageio.ImageReader#getStreamMetadata * @see javax.imageio.ImageReader#getImageMetadata @@ -873,7 +873,7 @@ public abstract class IIOMetadata { * * @return {@code true} if the controller completed normally. * - * @exception IllegalStateException if there is no controller + * @throws IllegalStateException if there is no controller * currently installed. * * @see IIOMetadataController diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataController.java b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataController.java index ddf105763f0..88f8727aad5 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataController.java +++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataController.java @@ -79,7 +79,7 @@ public interface IIOMetadataController { * @return {@code true} if the {@code IIOMetadata} has been * modified, {@code false} otherwise. * - * @exception IllegalArgumentException if {@code metadata} is + * @throws IllegalArgumentException if {@code metadata} is * {@code null} or is not an instance of the correct class. */ boolean activate(IIOMetadata metadata); diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java index 797ecc56180..b0cd40b6f6e 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java +++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormat.java @@ -319,10 +319,10 @@ public interface IIOMetadataFormat { * * @return an {@code int}. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element does + * @throws IllegalArgumentException if the named element does * not have a child policy of {@code CHILD_POLICY_REPEAT}. */ int getElementMinChildren(String elementName); @@ -339,10 +339,10 @@ public interface IIOMetadataFormat { * * @return an {@code int}. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element does + * @throws IllegalArgumentException if the named element does * not have a child policy of {@code CHILD_POLICY_REPEAT}. */ int getElementMaxChildren(String elementName); @@ -362,7 +362,7 @@ public interface IIOMetadataFormat { * * @return the element description. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this format. */ String getElementDescription(String elementName, Locale locale); @@ -378,7 +378,7 @@ public interface IIOMetadataFormat { * * @return one of the {@code CHILD_POLICY_*} constants. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. */ @@ -394,7 +394,7 @@ public interface IIOMetadataFormat { * * @return an array of {@code String}s, or null. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. */ @@ -410,7 +410,7 @@ public interface IIOMetadataFormat { * * @return an array of {@code String}s. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. */ @@ -428,10 +428,10 @@ public interface IIOMetadataFormat { * * @return one of the {@code VALUE_*} constants. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. */ @@ -450,10 +450,10 @@ public interface IIOMetadataFormat { * * @return one of the {@code DATATYPE_*} constants. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. */ @@ -468,10 +468,10 @@ public interface IIOMetadataFormat { * * @return {@code true} if the attribute must be present. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. */ @@ -489,10 +489,10 @@ public interface IIOMetadataFormat { * @return a {@code String} containing the default value, or * {@code null}. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. */ @@ -510,13 +510,13 @@ public interface IIOMetadataFormat { * * @return an array of {@code String}s. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. - * @exception IllegalArgumentException if the given attribute is + * @throws IllegalArgumentException if the given attribute is * not defined as an enumeration. */ String[] getAttributeEnumerations(String elementName, String attrName); @@ -537,13 +537,13 @@ public interface IIOMetadataFormat { * @return a {@code String} containing the smallest legal * value for the attribute. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. - * @exception IllegalArgumentException if the given attribute is + * @throws IllegalArgumentException if the given attribute is * not defined as a range. */ String getAttributeMinValue(String elementName, String attrName); @@ -565,13 +565,13 @@ public interface IIOMetadataFormat { * @return a {@code String} containing the largest legal * value for the attribute. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. - * @exception IllegalArgumentException if the given attribute is + * @throws IllegalArgumentException if the given attribute is * not defined as a range. */ String getAttributeMaxValue(String elementName, String attrName); @@ -590,13 +590,13 @@ public interface IIOMetadataFormat { * @return the smallest legal number of list items for the * attribute. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. - * @exception IllegalArgumentException if the given attribute is + * @throws IllegalArgumentException if the given attribute is * not defined as a list. */ int getAttributeListMinLength(String elementName, String attrName); @@ -617,13 +617,13 @@ public interface IIOMetadataFormat { * @return the largest legal number of list items for the * attribute. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. - * @exception IllegalArgumentException if the given attribute is + * @throws IllegalArgumentException if the given attribute is * not defined as a list. */ int getAttributeListMaxLength(String elementName, String attrName); @@ -644,9 +644,9 @@ public interface IIOMetadataFormat { * * @return the attribute description. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. */ @@ -671,7 +671,7 @@ public interface IIOMetadataFormat { * * @return one of the {@code VALUE_*} constants. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. * @@ -696,10 +696,10 @@ public interface IIOMetadataFormat { * * @return a {@code Class} object. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element cannot + * @throws IllegalArgumentException if the named element cannot * contain an object value (i.e., if * {@code getObjectValueType(elementName) == VALUE_NONE}). */ @@ -714,10 +714,10 @@ public interface IIOMetadataFormat { * * @return an {@code Object}. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element cannot + * @throws IllegalArgumentException if the named element cannot * contain an object value (i.e., if * {@code getObjectValueType(elementName) == VALUE_NONE}). */ @@ -739,13 +739,13 @@ public interface IIOMetadataFormat { * * @return an array of {@code Object}s. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element cannot + * @throws IllegalArgumentException if the named element cannot * contain an object value (i.e., if * {@code getObjectValueType(elementName) == VALUE_NONE}). - * @exception IllegalArgumentException if the {@code Object} + * @throws IllegalArgumentException if the {@code Object} * is not defined as an enumeration. */ Object[] getObjectEnumerations(String elementName); @@ -762,13 +762,13 @@ public interface IIOMetadataFormat { * * @return the smallest legal value for the attribute. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element cannot + * @throws IllegalArgumentException if the named element cannot * contain an object value (i.e., if * {@code getObjectValueType(elementName) == VALUE_NONE}). - * @exception IllegalArgumentException if the {@code Object} + * @throws IllegalArgumentException if the {@code Object} * is not defined as a range. */ Comparable getObjectMinValue(String elementName); @@ -785,13 +785,13 @@ public interface IIOMetadataFormat { * * @param elementName the name of the element being queried. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element cannot + * @throws IllegalArgumentException if the named element cannot * contain an object value (i.e., if * {@code getObjectValueType(elementName) == VALUE_NONE}). - * @exception IllegalArgumentException if the {@code Object} + * @throws IllegalArgumentException if the {@code Object} * is not defined as a range. */ Comparable getObjectMaxValue(String elementName); @@ -808,13 +808,13 @@ public interface IIOMetadataFormat { * @return the smallest valid array length for the * {@code Object} reference. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element cannot + * @throws IllegalArgumentException if the named element cannot * contain an object value (i.e., if * {@code getObjectValueType(elementName) == VALUE_NONE}). - * @exception IllegalArgumentException if the {@code Object} is not + * @throws IllegalArgumentException if the {@code Object} is not * an array. */ int getObjectArrayMinLength(String elementName); @@ -832,13 +832,13 @@ public interface IIOMetadataFormat { * @return the largest valid array length for the * {@code Object} reference. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null} or is not a legal element name for this * format. - * @exception IllegalArgumentException if the named element cannot + * @throws IllegalArgumentException if the named element cannot * contain an object value (i.e., if * {@code getObjectValueType(elementName) == VALUE_NONE}). - * @exception IllegalArgumentException if the {@code Object} is not + * @throws IllegalArgumentException if the {@code Object} is not * an array. */ int getObjectArrayMaxLength(String elementName); diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java index 8b5de4089ef..d81b0df3c87 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java +++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataFormatImpl.java @@ -160,9 +160,9 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param childPolicy one of the {@code CHILD_POLICY_*} constants, * other than {@code CHILD_POLICY_REPEAT}. * - * @exception IllegalArgumentException if {@code rootName} is + * @throws IllegalArgumentException if {@code rootName} is * {@code null}. - * @exception IllegalArgumentException if {@code childPolicy} is + * @throws IllegalArgumentException if {@code childPolicy} is * not one of the predefined constants. */ public IIOMetadataFormatImpl(String rootName, @@ -196,9 +196,9 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param minChildren the minimum number of children of the node. * @param maxChildren the maximum number of children of the node. * - * @exception IllegalArgumentException if {@code rootName} is + * @throws IllegalArgumentException if {@code rootName} is * {@code null}. - * @exception IllegalArgumentException if {@code minChildren} + * @throws IllegalArgumentException if {@code minChildren} * is negative or larger than {@code maxChildren}. */ public IIOMetadataFormatImpl(String rootName, @@ -236,7 +236,7 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param resourceBaseName a {@code String} containing the new * base name. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code resourceBaseName} is {@code null}. * * @see #getResourceBaseName @@ -307,10 +307,10 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * constants, other than {@code CHILD_POLICY_REPEAT}, * indicating the child policy of the new element. * - * @exception IllegalArgumentException if {@code parentName} + * @throws IllegalArgumentException if {@code parentName} * is {@code null}, or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code childPolicy} + * @throws IllegalArgumentException if {@code childPolicy} * is not one of the predefined constants. */ protected void addElement(String elementName, @@ -344,10 +344,10 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param minChildren the minimum number of children of the node. * @param maxChildren the maximum number of children of the node. * - * @exception IllegalArgumentException if {@code parentName} + * @throws IllegalArgumentException if {@code parentName} * is {@code null}, or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code minChildren} + * @throws IllegalArgumentException if {@code minChildren} * is negative or larger than {@code maxChildren}. */ protected void addElement(String elementName, @@ -383,10 +383,10 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param elementName the name of the element to be added as a * child. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code parentName} + * @throws IllegalArgumentException if {@code parentName} * is {@code null}, or is not a legal element name for this * format. */ @@ -429,12 +429,12 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param defaultValue the default value for the attribute, or * {@code null}. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null}. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of the predefined constants. */ protected void addAttribute(String elementName, @@ -476,19 +476,19 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * {@code String}s containing the legal values for the * attribute. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null}. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of the predefined constants. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code enumeratedValues} is {@code null}. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code enumeratedValues} does not contain at least one * entry. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code enumeratedValues} contains an element that is not a * {@code String} or is {@code null}. */ @@ -556,12 +556,12 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param maxInclusive {@code true} if {@code maxValue} * is inclusive. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null}. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of the predefined constants. */ protected void addAttribute(String elementName, @@ -612,14 +612,14 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param listMinLength the smallest legal number of list items. * @param listMaxLength the largest legal number of list items. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null}. - * @exception IllegalArgumentException if {@code dataType} is + * @throws IllegalArgumentException if {@code dataType} is * not one of the predefined constants. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code listMinLength} is negative or larger than * {@code listMaxLength}. */ @@ -666,10 +666,10 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * {@code boolean}, ignored if {@code hasDefaultValue} * is {@code false}. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this * format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null}. */ protected void addBooleanAttribute(String elementName, @@ -700,7 +700,7 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param elementName the name of the element. * @param attrName the name of the attribute being removed. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this format. */ protected void removeAttribute(String elementName, String attrName) { @@ -726,7 +726,7 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * {@code Object} reference, or {@code null}. * @param the type of the object. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this format. */ protected void addObjectValue(String elementName, @@ -763,14 +763,14 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * object reference. * @param the type of the object. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this format. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code enumeratedValues} is {@code null}. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code enumeratedValues} does not contain at least one * entry. - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code enumeratedValues} contains an element that is not * an instance of the class type denoted by {@code classType} * or is {@code null}. @@ -833,7 +833,7 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * is inclusive. * @param the type of the object. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this * format. */ @@ -880,7 +880,7 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * @param arrayMinLength the smallest legal length for the array. * @param arrayMaxLength the largest legal length for the array. * - * @exception IllegalArgumentException if {@code elementName} is + * @throws IllegalArgumentException if {@code elementName} is * not a legal element name for this format. */ protected void addObjectValue(String elementName, @@ -903,7 +903,7 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * * @param elementName the name of the element. * - * @exception IllegalArgumentException if {@code elementName} is + * @throws IllegalArgumentException if {@code elementName} is * not a legal element name for this format. */ protected void removeObjectValue(String elementName) { @@ -990,7 +990,7 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * * @return the element description. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this format. * * @see #setResourceBaseName @@ -1130,9 +1130,9 @@ public abstract class IIOMetadataFormatImpl implements IIOMetadataFormat { * * @return the attribute description. * - * @exception IllegalArgumentException if {@code elementName} + * @throws IllegalArgumentException if {@code elementName} * is {@code null}, or is not a legal element name for this format. - * @exception IllegalArgumentException if {@code attrName} is + * @throws IllegalArgumentException if {@code attrName} is * {@code null} or is not a legal attribute name for this * element. * diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java index 227bc8dcb31..e57d0ba00fd 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java +++ b/src/java.desktop/share/classes/javax/imageio/metadata/IIOMetadataNode.java @@ -464,7 +464,7 @@ public class IIOMetadataNode implements Element, NodeList { * * @return the node being inserted. * - * @exception IllegalArgumentException if {@code newChild} is + * @throws IllegalArgumentException if {@code newChild} is * {@code null}. */ public Node insertBefore(Node newChild, @@ -522,7 +522,7 @@ public class IIOMetadataNode implements Element, NodeList { * * @return the node replaced. * - * @exception IllegalArgumentException if {@code newChild} is + * @throws IllegalArgumentException if {@code newChild} is * {@code null}. */ public Node replaceChild(Node newChild, @@ -573,7 +573,7 @@ public class IIOMetadataNode implements Element, NodeList { * * @return the node removed. * - * @exception IllegalArgumentException if {@code oldChild} is + * @throws IllegalArgumentException if {@code oldChild} is * {@code null}. */ public Node removeChild(Node oldChild) { @@ -617,7 +617,7 @@ public class IIOMetadataNode implements Element, NodeList { * * @return the node added. * - * @exception IllegalArgumentException if {@code newChild} is + * @throws IllegalArgumentException if {@code newChild} is * {@code null}. */ public Node appendChild(Node newChild) { diff --git a/src/java.desktop/share/classes/javax/imageio/plugins/jpeg/JPEGImageReadParam.java b/src/java.desktop/share/classes/javax/imageio/plugins/jpeg/JPEGImageReadParam.java index 8904c89fff2..507d2c28041 100644 --- a/src/java.desktop/share/classes/javax/imageio/plugins/jpeg/JPEGImageReadParam.java +++ b/src/java.desktop/share/classes/javax/imageio/plugins/jpeg/JPEGImageReadParam.java @@ -113,7 +113,7 @@ public class JPEGImageReadParam extends ImageReadParam { * @param DCHuffmanTables an array of Huffman table objects. * @param ACHuffmanTables an array of Huffman table objects. * - * @exception IllegalArgumentException if any of the arguments + * @throws IllegalArgumentException if any of the arguments * is {@code null}, has more than 4 elements, or if the * numbers of DC and AC tables differ. * diff --git a/src/java.desktop/share/classes/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java b/src/java.desktop/share/classes/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java index 986d302decc..de9c077d8c7 100644 --- a/src/java.desktop/share/classes/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java +++ b/src/java.desktop/share/classes/javax/imageio/plugins/jpeg/JPEGImageWriteParam.java @@ -130,7 +130,7 @@ public class JPEGImageWriteParam extends ImageWriteParam { *

      The default implementation resets the compression quality * to {@code 0.75F}. * - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. */ public void unsetCompression() { @@ -147,7 +147,7 @@ public class JPEGImageWriteParam extends ImageWriteParam { * * @return {@code false}. * - * @exception IllegalStateException if the compression mode is not + * @throws IllegalStateException if the compression mode is not * {@code MODE_EXPLICIT}. */ public boolean isCompressionLossless() { @@ -204,7 +204,7 @@ public class JPEGImageWriteParam extends ImageWriteParam { * @param DCHuffmanTables An array of Huffman table objects. * @param ACHuffmanTables An array of Huffman table objects. * - * @exception IllegalArgumentException if any of the arguments + * @throws IllegalArgumentException if any of the arguments * is {@code null} or has more than 4 elements, or if the * numbers of DC and AC tables differ. * diff --git a/src/java.desktop/share/classes/javax/imageio/spi/IIOServiceProvider.java b/src/java.desktop/share/classes/javax/imageio/spi/IIOServiceProvider.java index 95f0ec0edab..9bb3cbac97e 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/IIOServiceProvider.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/IIOServiceProvider.java @@ -65,9 +65,9 @@ public abstract class IIOServiceProvider implements RegisterableService { * @param vendorName the vendor name. * @param version a version identifier. * - * @exception IllegalArgumentException if {@code vendorName} + * @throws IllegalArgumentException if {@code vendorName} * is {@code null}. - * @exception IllegalArgumentException if {@code version} + * @throws IllegalArgumentException if {@code version} * is {@code null}. */ public IIOServiceProvider(String vendorName, diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ImageInputStreamSpi.java b/src/java.desktop/share/classes/javax/imageio/spi/ImageInputStreamSpi.java index e7f7264287c..fb3b8d58e31 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ImageInputStreamSpi.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ImageInputStreamSpi.java @@ -79,9 +79,9 @@ public abstract class ImageInputStreamSpi extends IIOServiceProvider { * legal object type for use by the * {@code createInputStreamInstance} method. * - * @exception IllegalArgumentException if {@code vendorName} + * @throws IllegalArgumentException if {@code vendorName} * is {@code null}. - * @exception IllegalArgumentException if {@code version} + * @throws IllegalArgumentException if {@code version} * is {@code null}. */ public ImageInputStreamSpi(String vendorName, @@ -159,12 +159,12 @@ public abstract class ImageInputStreamSpi extends IIOServiceProvider { * * @return an {@code ImageInputStream} instance. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * not an instance of the correct class or is {@code null}. - * @exception IllegalArgumentException if a cache file is needed + * @throws IllegalArgumentException if a cache file is needed * but {@code cacheDir} is non-{@code null} and is not a * directory. - * @exception IOException if a cache file is needed but cannot be + * @throws IOException if a cache file is needed but cannot be * created. * * @see #getInputClass @@ -187,9 +187,9 @@ public abstract class ImageInputStreamSpi extends IIOServiceProvider { * * @return an {@code ImageInputStream} instance. * - * @exception IllegalArgumentException if {@code input} is + * @throws IllegalArgumentException if {@code input} is * not an instance of the correct class or is {@code null}. - * @exception IOException if a cache file is needed but cannot be + * @throws IOException if a cache file is needed but cannot be * created. * * @see #getInputClass() diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ImageOutputStreamSpi.java b/src/java.desktop/share/classes/javax/imageio/spi/ImageOutputStreamSpi.java index d3cf9593d04..a8fcf7ef19f 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ImageOutputStreamSpi.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ImageOutputStreamSpi.java @@ -80,9 +80,9 @@ public abstract class ImageOutputStreamSpi extends IIOServiceProvider { * legal object type for use by the * {@code createOutputStreamInstance} method. * - * @exception IllegalArgumentException if {@code vendorName} + * @throws IllegalArgumentException if {@code vendorName} * is {@code null}. - * @exception IllegalArgumentException if {@code version} + * @throws IllegalArgumentException if {@code version} * is {@code null}. */ public ImageOutputStreamSpi(String vendorName, @@ -159,12 +159,12 @@ public abstract class ImageOutputStreamSpi extends IIOServiceProvider { * * @return an {@code ImageOutputStream} instance. * - * @exception IllegalArgumentException if {@code output} is + * @throws IllegalArgumentException if {@code output} is * not an instance of the correct class or is {@code null}. - * @exception IllegalArgumentException if a cache file is needed, + * @throws IllegalArgumentException if a cache file is needed, * but {@code cacheDir} is non-{@code null} and is not a * directory. - * @exception IOException if a cache file is needed but cannot be + * @throws IOException if a cache file is needed but cannot be * created. * * @see #getOutputClass @@ -186,9 +186,9 @@ public abstract class ImageOutputStreamSpi extends IIOServiceProvider { * * @return an {@code ImageOutputStream} instance. * - * @exception IllegalArgumentException if {@code output} is + * @throws IllegalArgumentException if {@code output} is * not an instance of the correct class or is {@code null}. - * @exception IOException if a cache file is needed but cannot be + * @throws IOException if a cache file is needed but cannot be * created. * * @see #getOutputClass() diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderSpi.java b/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderSpi.java index 4777f989c4b..f20f1bd6eb0 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderSpi.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderSpi.java @@ -180,15 +180,15 @@ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { * {@code getImageMetadataFormat}. An array of length * 0 is normalized to {@code null}. * - * @exception IllegalArgumentException if {@code vendorName} + * @throws IllegalArgumentException if {@code vendorName} * is {@code null}. - * @exception IllegalArgumentException if {@code version} + * @throws IllegalArgumentException if {@code version} * is {@code null}. - * @exception IllegalArgumentException if {@code names} + * @throws IllegalArgumentException if {@code names} * is {@code null} or has length 0. - * @exception IllegalArgumentException if {@code readerClassName} + * @throws IllegalArgumentException if {@code readerClassName} * is {@code null}. - * @exception IllegalArgumentException if {@code inputTypes} + * @throws IllegalArgumentException if {@code inputTypes} * is {@code null} or has length 0. */ public ImageReaderSpi(String vendorName, @@ -294,9 +294,9 @@ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { * @return {@code true} if it is likely that this stream can * be decoded. * - * @exception IllegalArgumentException if {@code source} is + * @throws IllegalArgumentException if {@code source} is * {@code null}. - * @exception IOException if an I/O error occurs while reading the + * @throws IOException if an I/O error occurs while reading the * stream. */ public abstract boolean canDecodeInput(Object source) throws IOException; @@ -312,7 +312,7 @@ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { * * @return an {@code ImageReader} instance. * - * @exception IOException if an error occurs during loading, + * @throws IOException if an error occurs during loading, * or initialization of the reader class, or during instantiation * or initialization of the reader object. */ @@ -338,9 +338,9 @@ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { * * @return an {@code ImageReader} instance. * - * @exception IOException if the attempt to instantiate + * @throws IOException if the attempt to instantiate * the reader fails. - * @exception IllegalArgumentException if the + * @throws IllegalArgumentException if the * {@code ImageReader}'s constructor throws an * {@code IllegalArgumentException} to indicate that the * extension object is unsuitable. @@ -362,7 +362,7 @@ public abstract class ImageReaderSpi extends ImageReaderWriterSpi { * * @return {@code true} if {@code reader} is recognized. * - * @exception IllegalArgumentException if {@code reader} is + * @throws IllegalArgumentException if {@code reader} is * {@code null}. */ public boolean isOwnReader(ImageReader reader) { diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java b/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java index 29ed6de0d50..7abefdd9431 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ImageReaderWriterSpi.java @@ -199,13 +199,13 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider { * {@code getImageMetadataFormat}. An array of length * 0 is normalized to {@code null}. * - * @exception IllegalArgumentException if {@code vendorName} + * @throws IllegalArgumentException if {@code vendorName} * is {@code null}. - * @exception IllegalArgumentException if {@code version} + * @throws IllegalArgumentException if {@code version} * is {@code null}. - * @exception IllegalArgumentException if {@code names} + * @throws IllegalArgumentException if {@code names} * is {@code null} or has length 0. - * @exception IllegalArgumentException if {@code pluginClassName} + * @throws IllegalArgumentException if {@code pluginClassName} * is {@code null}. */ public ImageReaderWriterSpi(String vendorName, @@ -518,7 +518,7 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider { * * @return an {@code IIOMetadataFormat} object. * - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalArgumentException if {@code formatName} * is {@code null} or is not a supported name. */ public IIOMetadataFormat getStreamMetadataFormat(String formatName) { @@ -542,7 +542,7 @@ public abstract class ImageReaderWriterSpi extends IIOServiceProvider { * * @return an {@code IIOMetadataFormat} object. * - * @exception IllegalArgumentException if {@code formatName} + * @throws IllegalArgumentException if {@code formatName} * is {@code null} or is not a supported name. */ public IIOMetadataFormat getImageMetadataFormat(String formatName) { diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ImageWriterSpi.java b/src/java.desktop/share/classes/javax/imageio/spi/ImageWriterSpi.java index 604de8d7b22..de2195988b4 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ImageWriterSpi.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ImageWriterSpi.java @@ -181,15 +181,15 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { * {@code getImageMetadataFormat}. An array of length * 0 is normalized to {@code null}. * - * @exception IllegalArgumentException if {@code vendorName} + * @throws IllegalArgumentException if {@code vendorName} * is {@code null}. - * @exception IllegalArgumentException if {@code version} + * @throws IllegalArgumentException if {@code version} * is {@code null}. - * @exception IllegalArgumentException if {@code names} + * @throws IllegalArgumentException if {@code names} * is {@code null} or has length 0. - * @exception IllegalArgumentException if {@code writerClassName} + * @throws IllegalArgumentException if {@code writerClassName} * is {@code null}. - * @exception IllegalArgumentException if {@code outputTypes} + * @throws IllegalArgumentException if {@code outputTypes} * is {@code null} or has length 0. */ public ImageWriterSpi(String vendorName, @@ -304,7 +304,7 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { * @return {@code true} if this writer is likely to be able * to encode images with the given layout. * - * @exception IllegalArgumentException if {@code type} + * @throws IllegalArgumentException if {@code type} * is {@code null}. */ public abstract boolean canEncodeImage(ImageTypeSpecifier type); @@ -325,7 +325,7 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { * @return {@code true} if this writer is likely to be able * to encode this image. * - * @exception IllegalArgumentException if {@code im} + * @throws IllegalArgumentException if {@code im} * is {@code null}. */ public boolean canEncodeImage(RenderedImage im) { @@ -343,7 +343,7 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { * * @return an {@code ImageWriter} instance. * - * @exception IOException if an error occurs during loading, + * @throws IOException if an error occurs during loading, * or initialization of the writer class, or during instantiation * or initialization of the writer object. */ @@ -369,9 +369,9 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { * * @return an {@code ImageWriter} instance. * - * @exception IOException if the attempt to instantiate + * @throws IOException if the attempt to instantiate * the writer fails. - * @exception IllegalArgumentException if the + * @throws IllegalArgumentException if the * {@code ImageWriter}'s constructor throws an * {@code IllegalArgumentException} to indicate that the * extension object is unsuitable. @@ -388,7 +388,7 @@ public abstract class ImageWriterSpi extends ImageReaderWriterSpi { * * @return {@code true} if {@code writer} is recognized * - * @exception IllegalArgumentException if {@code writer} is + * @throws IllegalArgumentException if {@code writer} is * {@code null}. */ public boolean isOwnWriter(ImageWriter writer) { diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java index 4a43ca8133a..64f71f734a9 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java @@ -104,7 +104,7 @@ public class ServiceRegistry { * @param categories an {@code Iterator} containing * {@code Class} objects to be used to define categories. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code categories} is {@code null}, or if * one of the categories is not an allowed service type. */ @@ -157,7 +157,7 @@ public class ServiceRegistry { * file violates the specified format or if a provider class * cannot be found and instantiated. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code providerClass} is {@code null}, or if it is * not one of the allowed service types. */ @@ -196,7 +196,7 @@ public class ServiceRegistry { * file violates the specified format or if a provider class * cannot be found and instantiated. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code providerClass} is {@code null}, or if it is * not one of the allowed service types. */ @@ -254,11 +254,11 @@ public class ServiceRegistry { * @return true if no provider of the same class was previously * registered in the same category category. * - * @exception IllegalArgumentException if {@code provider} is + * @throws IllegalArgumentException if {@code provider} is * {@code null}. - * @exception IllegalArgumentException if there is no category + * @throws IllegalArgumentException if there is no category * corresponding to {@code category}. - * @exception ClassCastException if provider does not implement + * @throws ClassCastException if provider does not implement * the {@code Class} defined by {@code category}. */ public boolean registerServiceProvider(T provider, @@ -292,7 +292,7 @@ public class ServiceRegistry { * * @param provider the service provider object to be registered. * - * @exception IllegalArgumentException if + * @throws IllegalArgumentException if * {@code provider} is {@code null}. */ public void registerServiceProvider(Object provider) { @@ -323,7 +323,7 @@ public class ServiceRegistry { * @param providers an Iterator containing service provider * objects to be registered. * - * @exception IllegalArgumentException if {@code providers} + * @throws IllegalArgumentException if {@code providers} * is {@code null} or contains a {@code null} entry. */ public void registerServiceProviders(Iterator providers) { @@ -357,11 +357,11 @@ public class ServiceRegistry { * registered in the same category category, * {@code false} otherwise. * - * @exception IllegalArgumentException if {@code provider} is + * @throws IllegalArgumentException if {@code provider} is * {@code null}. - * @exception IllegalArgumentException if there is no category + * @throws IllegalArgumentException if there is no category * corresponding to {@code category}. - * @exception ClassCastException if provider does not implement + * @throws ClassCastException if provider does not implement * the class defined by {@code category}. */ public boolean deregisterServiceProvider(T provider, @@ -385,7 +385,7 @@ public class ServiceRegistry { * * @param provider the service provider object to be deregistered. * - * @exception IllegalArgumentException if {@code provider} is + * @throws IllegalArgumentException if {@code provider} is * {@code null}. */ public void deregisterServiceProvider(Object provider) { @@ -408,7 +408,7 @@ public class ServiceRegistry { * @return {@code true} if the given provider has been * registered. * - * @exception IllegalArgumentException if {@code provider} is + * @throws IllegalArgumentException if {@code provider} is * {@code null}. */ public boolean contains(Object provider) { @@ -444,7 +444,7 @@ public class ServiceRegistry { * @return an {@code Iterator} containing service provider * objects from the given category, possibly in order. * - * @exception IllegalArgumentException if there is no category + * @throws IllegalArgumentException if there is no category * corresponding to {@code category}. */ public Iterator getServiceProviders(Class category, @@ -502,7 +502,7 @@ public class ServiceRegistry { * @return an {@code Iterator} containing service provider * objects from the given category, possibly in order. * - * @exception IllegalArgumentException if there is no category + * @throws IllegalArgumentException if there is no category * corresponding to {@code category}. */ public Iterator getServiceProviders(Class category, @@ -531,7 +531,7 @@ public class ServiceRegistry { * desired {@code Class} type, or {@code null} is none is * present. * - * @exception IllegalArgumentException if {@code providerClass} is + * @throws IllegalArgumentException if {@code providerClass} is * {@code null}. */ public T getServiceProviderByClass(Class providerClass) { @@ -573,9 +573,9 @@ public class ServiceRegistry { * @return {@code true} if a previously unset ordering * was established. * - * @exception IllegalArgumentException if either provider is + * @throws IllegalArgumentException if either provider is * {@code null} or they are the same object. - * @exception IllegalArgumentException if there is no category + * @throws IllegalArgumentException if there is no category * corresponding to {@code category}. */ public boolean setOrdering(Class category, @@ -619,9 +619,9 @@ public class ServiceRegistry { * @return {@code true} if a previously set ordering was * disestablished. * - * @exception IllegalArgumentException if either provider is + * @throws IllegalArgumentException if either provider is * {@code null} or they are the same object. - * @exception IllegalArgumentException if there is no category + * @throws IllegalArgumentException if there is no category * corresponding to {@code category}. */ public boolean unsetOrdering(Class category, @@ -650,7 +650,7 @@ public class ServiceRegistry { * * @param category the category to be emptied. * - * @exception IllegalArgumentException if there is no category + * @throws IllegalArgumentException if there is no category * corresponding to {@code category}. */ public void deregisterAll(Class category) { @@ -677,7 +677,7 @@ public class ServiceRegistry { * currently registered service providers. This method should not * be called from application code. * - * @exception Throwable if an error occurs during superclass + * @throws Throwable if an error occurs during superclass * finalization. * * @deprecated Finalization has been deprecated for removal. See diff --git a/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageInputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageInputStream.java index 6bf14838b7f..d5c1ff18e5a 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageInputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageInputStream.java @@ -83,9 +83,9 @@ public class FileCacheImageInputStream extends ImageInputStreamImpl { * cache file should be created, or {@code null} to use the * system directory. * - * @exception IllegalArgumentException if {@code stream} is + * @throws IllegalArgumentException if {@code stream} is * {@code null}. - * @exception IllegalArgumentException if {@code cacheDir} is + * @throws IllegalArgumentException if {@code cacheDir} is * non-{@code null} but is not a directory. * @throws IOException if a cache file cannot be created. */ diff --git a/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageOutputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageOutputStream.java index 5a2a54abcaa..904515b6f82 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageOutputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/FileCacheImageOutputStream.java @@ -69,11 +69,11 @@ public class FileCacheImageOutputStream extends ImageOutputStreamImpl { * cache file should be created, or {@code null} to use the * system directory. * - * @exception IllegalArgumentException if {@code stream} + * @throws IllegalArgumentException if {@code stream} * is {@code null}. - * @exception IllegalArgumentException if {@code cacheDir} is + * @throws IllegalArgumentException if {@code cacheDir} is * non-{@code null} but is not a directory. - * @exception IOException if a cache file cannot be created. + * @throws IOException if a cache file cannot be created. */ public FileCacheImageOutputStream(OutputStream stream, File cacheDir) throws IOException { @@ -159,9 +159,9 @@ public class FileCacheImageOutputStream extends ImageOutputStreamImpl { * performed. The file length will not be increased until a write * is performed. * - * @exception IndexOutOfBoundsException if {@code pos} is smaller + * @throws IndexOutOfBoundsException if {@code pos} is smaller * than the flushed position. - * @exception IOException if any other I/O error occurs. + * @throws IOException if any other I/O error occurs. */ public void seek(long pos) throws IOException { checkClosed(); @@ -223,7 +223,7 @@ public class FileCacheImageOutputStream extends ImageOutputStreamImpl { * is closed and removed. The destination {@code OutputStream} * is not closed. * - * @exception IOException if an error occurs. + * @throws IOException if an error occurs. */ public void close() throws IOException { maxStreamPos = cache.length(); diff --git a/src/java.desktop/share/classes/javax/imageio/stream/FileImageInputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/FileImageInputStream.java index b1cce6fae4c..ef127ddfa2e 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/FileImageInputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/FileImageInputStream.java @@ -60,13 +60,13 @@ public class FileImageInputStream extends ImageInputStreamImpl { * * @param f a {@code File} to read from. * - * @exception IllegalArgumentException if {@code f} is + * @throws IllegalArgumentException if {@code f} is * {@code null}. - * @exception SecurityException if a security manager exists + * @throws SecurityException if a security manager exists * and does not allow read access to the file. - * @exception FileNotFoundException if {@code f} is a + * @throws FileNotFoundException if {@code f} is a * directory or cannot be opened for reading for any other reason. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ public FileImageInputStream(File f) throws FileNotFoundException, IOException { @@ -83,7 +83,7 @@ public class FileImageInputStream extends ImageInputStreamImpl { * * @param raf a {@code RandomAccessFile} to read from. * - * @exception IllegalArgumentException if {@code raf} is + * @throws IllegalArgumentException if {@code raf} is * {@code null}. */ public FileImageInputStream(RandomAccessFile raf) { diff --git a/src/java.desktop/share/classes/javax/imageio/stream/FileImageOutputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/FileImageOutputStream.java index 715b43f40fb..96d84ef652f 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/FileImageOutputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/FileImageOutputStream.java @@ -55,14 +55,14 @@ public class FileImageOutputStream extends ImageOutputStreamImpl { * * @param f a {@code File} to write to. * - * @exception IllegalArgumentException if {@code f} is + * @throws IllegalArgumentException if {@code f} is * {@code null}. - * @exception SecurityException if a security manager exists + * @throws SecurityException if a security manager exists * and does not allow write access to the file. - * @exception FileNotFoundException if {@code f} does not denote + * @throws FileNotFoundException if {@code f} does not denote * a regular file or it cannot be opened for reading and writing for any * other reason. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ public FileImageOutputStream(File f) throws FileNotFoundException, IOException { @@ -75,7 +75,7 @@ public class FileImageOutputStream extends ImageOutputStreamImpl { * * @param raf a {@code RandomAccessFile} to write to. * - * @exception IllegalArgumentException if {@code raf} is + * @throws IllegalArgumentException if {@code raf} is * {@code null}. */ public FileImageOutputStream(RandomAccessFile raf) { @@ -141,9 +141,9 @@ public class FileImageOutputStream extends ImageOutputStreamImpl { * performed. The file length will not be increased until a write * is performed. * - * @exception IndexOutOfBoundsException if {@code pos} is smaller + * @throws IndexOutOfBoundsException if {@code pos} is smaller * than the flushed position. - * @exception IOException if any other I/O error occurs. + * @throws IOException if any other I/O error occurs. */ public void seek(long pos) throws IOException { checkClosed(); diff --git a/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStream.java index d8999d4a884..11251ac5938 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStream.java @@ -100,7 +100,7 @@ public interface ImageInputStream extends DataInput, Closeable { * @return a byte value from the stream, as an int, or -1 to * indicate EOF. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ int read() throws IOException; @@ -118,10 +118,10 @@ public interface ImageInputStream extends DataInput, Closeable { * @return the number of bytes actually read, or {@code -1} * to indicate EOF. * - * @exception NullPointerException if {@code b} is + * @throws NullPointerException if {@code b} is * {@code null}. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ int read(byte[] b) throws IOException; @@ -142,12 +142,12 @@ public interface ImageInputStream extends DataInput, Closeable { * @return the number of bytes actually read, or {@code -1} * to indicate EOF. * - * @exception NullPointerException if {@code b} is + * @throws NullPointerException if {@code b} is * {@code null}. - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code b.length}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ int read(byte[] b, int off, int len) throws IOException; @@ -164,12 +164,12 @@ public interface ImageInputStream extends DataInput, Closeable { * @param buf an IIOByteBuffer object to be modified. * @param len the maximum number of {@code byte}s to read. * - * @exception IndexOutOfBoundsException if {@code len} is + * @throws IndexOutOfBoundsException if {@code len} is * negative. - * @exception NullPointerException if {@code buf} is + * @throws NullPointerException if {@code buf} is * {@code null}. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readBytes(IIOByteBuffer buf, int len) throws IOException; @@ -183,8 +183,8 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a boolean value from the stream. * - * @exception java.io.EOFException if the end of the stream is reached. - * @exception IOException if an I/O error occurs. + * @throws java.io.EOFException if the end of the stream is reached. + * @throws IOException if an I/O error occurs. */ boolean readBoolean() throws IOException; @@ -201,8 +201,8 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a signed byte value from the stream. * - * @exception java.io.EOFException if the end of the stream is reached. - * @exception IOException if an I/O error occurs. + * @throws java.io.EOFException if the end of the stream is reached. + * @throws IOException if an I/O error occurs. */ byte readByte() throws IOException; @@ -225,8 +225,8 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return an unsigned byte value from the stream. * - * @exception java.io.EOFException if the end of the stream is reached. - * @exception IOException if an I/O error occurs. + * @throws java.io.EOFException if the end of the stream is reached. + * @throws IOException if an I/O error occurs. */ int readUnsignedByte() throws IOException; @@ -240,9 +240,9 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a signed short value from the stream. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #getByteOrder */ @@ -261,9 +261,9 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return an unsigned short value from the stream, as an int. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #getByteOrder */ @@ -278,9 +278,9 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return an unsigned char value from the stream. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #readUnsignedShort */ @@ -296,9 +296,9 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a signed int value from the stream. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #getByteOrder */ @@ -316,9 +316,9 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return an unsigned int value from the stream, as a long. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #getByteOrder */ @@ -334,9 +334,9 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a signed long value from the stream. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #getByteOrder */ @@ -352,9 +352,9 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a float value from the stream. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #getByteOrder */ @@ -370,9 +370,9 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a double value from the stream. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #getByteOrder */ @@ -408,7 +408,7 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a String containing a line of text from the stream. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ String readLine() throws IOException; @@ -488,11 +488,11 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a String read from the stream. * - * @exception java.io.EOFException if this stream reaches the end + * @throws java.io.EOFException if this stream reaches the end * before reading all the bytes. - * @exception java.io.UTFDataFormatException if the bytes do not represent + * @throws java.io.UTFDataFormatException if the bytes do not represent * a valid modified UTF-8 encoding of a string. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ String readUTF() throws IOException; @@ -509,14 +509,14 @@ public interface ImageInputStream extends DataInput, Closeable { * @param off the starting position within {@code b} to write to. * @param len the maximum number of {@code byte}s to read. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code b.length}. - * @exception NullPointerException if {@code b} is + * @throws NullPointerException if {@code b} is * {@code null}. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readFully(byte[] b, int off, int len) throws IOException; @@ -531,11 +531,11 @@ public interface ImageInputStream extends DataInput, Closeable { * * @param b an array of {@code byte}s. * - * @exception NullPointerException if {@code b} is + * @throws NullPointerException if {@code b} is * {@code null}. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readFully(byte[] b) throws IOException; @@ -553,14 +553,14 @@ public interface ImageInputStream extends DataInput, Closeable { * @param off the starting position within {@code s} to write to. * @param len the maximum number of {@code short}s to read. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code s.length}. - * @exception NullPointerException if {@code s} is + * @throws NullPointerException if {@code s} is * {@code null}. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readFully(short[] s, int off, int len) throws IOException; @@ -578,14 +578,14 @@ public interface ImageInputStream extends DataInput, Closeable { * @param off the starting position within {@code c} to write to. * @param len the maximum number of {@code char}s to read. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code c.length}. - * @exception NullPointerException if {@code c} is + * @throws NullPointerException if {@code c} is * {@code null}. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readFully(char[] c, int off, int len) throws IOException; @@ -603,14 +603,14 @@ public interface ImageInputStream extends DataInput, Closeable { * @param off the starting position within {@code i} to write to. * @param len the maximum number of {@code int}s to read. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code i.length}. - * @exception NullPointerException if {@code i} is + * @throws NullPointerException if {@code i} is * {@code null}. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readFully(int[] i, int off, int len) throws IOException; @@ -628,14 +628,14 @@ public interface ImageInputStream extends DataInput, Closeable { * @param off the starting position within {@code l} to write to. * @param len the maximum number of {@code long}s to read. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code l.length}. - * @exception NullPointerException if {@code l} is + * @throws NullPointerException if {@code l} is * {@code null}. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readFully(long[] l, int off, int len) throws IOException; @@ -653,14 +653,14 @@ public interface ImageInputStream extends DataInput, Closeable { * @param off the starting position within {@code f} to write to. * @param len the maximum number of {@code float}s to read. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code f.length}. - * @exception NullPointerException if {@code f} is + * @throws NullPointerException if {@code f} is * {@code null}. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readFully(float[] f, int off, int len) throws IOException; @@ -678,14 +678,14 @@ public interface ImageInputStream extends DataInput, Closeable { * @param off the starting position within {@code d} to write to. * @param len the maximum number of {@code double}s to read. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code d.length}. - * @exception NullPointerException if {@code d} is + * @throws NullPointerException if {@code d} is * {@code null}. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void readFully(double[] d, int off, int len) throws IOException; @@ -695,7 +695,7 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return a long containing the position of the stream. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ long getStreamPosition() throws IOException; @@ -714,7 +714,7 @@ public interface ImageInputStream extends DataInput, Closeable { * @return an {@code int} containing the bit offset between * 0 and 7, inclusive. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #setBitOffset */ @@ -731,9 +731,9 @@ public interface ImageInputStream extends DataInput, Closeable { * @param bitOffset the desired offset, as an {@code int} * between 0 and 7, inclusive. * - * @exception IllegalArgumentException if {@code bitOffset} + * @throws IllegalArgumentException if {@code bitOffset} * is not between 0 and 7, inclusive. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #getBitOffset */ @@ -748,9 +748,9 @@ public interface ImageInputStream extends DataInput, Closeable { * @return an {@code int} containing the value {@code 0} * or {@code 1}. * - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bits. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ int readBit() throws IOException; @@ -788,11 +788,11 @@ public interface ImageInputStream extends DataInput, Closeable { * @return the bitstring, as a {@code long} with the last bit * read stored in the least significant bit. * - * @exception IllegalArgumentException if {@code numBits} + * @throws IllegalArgumentException if {@code numBits} * is not between 0 and 64, inclusive. - * @exception java.io.EOFException if the stream reaches the end before + * @throws java.io.EOFException if the stream reaches the end before * reading all the bits. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ long readBits(int numBits) throws IOException; @@ -803,7 +803,7 @@ public interface ImageInputStream extends DataInput, Closeable { * @return a {@code long} containing the length of the * stream, if known, or else {@code -1}. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ long length() throws IOException; @@ -820,7 +820,7 @@ public interface ImageInputStream extends DataInput, Closeable { * * @return an {@code int} representing the number of bytes skipped. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ int skipBytes(int n) throws IOException; @@ -835,7 +835,7 @@ public interface ImageInputStream extends DataInput, Closeable { * @return a {@code long} representing the number of bytes * skipped. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ long skipBytes(long n) throws IOException; @@ -855,9 +855,9 @@ public interface ImageInputStream extends DataInput, Closeable { * @param pos a {@code long} containing the desired file * pointer position. * - * @exception IndexOutOfBoundsException if {@code pos} is smaller + * @throws IndexOutOfBoundsException if {@code pos} is smaller * than the flushed position. - * @exception IOException if any other I/O error occurs. + * @throws IOException if any other I/O error occurs. */ void seek(long pos) throws IOException; @@ -897,7 +897,7 @@ public interface ImageInputStream extends DataInput, Closeable { *

      An {@code IOException} will be thrown if the previous * marked position lies in the discarded portion of the stream. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void reset() throws IOException; @@ -915,10 +915,10 @@ public interface ImageInputStream extends DataInput, Closeable { * @param pos a {@code long} containing the length of the * stream prefix that may be flushed. * - * @exception IndexOutOfBoundsException if {@code pos} lies + * @throws IndexOutOfBoundsException if {@code pos} lies * in the flushed portion of the stream or past the current stream * position. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void flushBefore(long pos) throws IOException; @@ -927,7 +927,7 @@ public interface ImageInputStream extends DataInput, Closeable { * stream position. Equivalent to * {@code flushBefore(getStreamPosition())}. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void flush() throws IOException; @@ -993,7 +993,7 @@ public interface ImageInputStream extends DataInput, Closeable { * this interface to release resources associated with the stream * such as memory, disk space, or file descriptors. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void close() throws IOException; } diff --git a/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStreamImpl.java b/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStreamImpl.java index 053bbf74918..f9bb1235660 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStreamImpl.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/ImageInputStreamImpl.java @@ -103,7 +103,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { * Subclasses may call this method from any of their methods that * require the stream not to be closed. * - * @exception IOException if the stream is closed. + * @throws IOException if the stream is closed. */ protected final void checkClosed() throws IOException { if (isClosed) { @@ -134,7 +134,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { * @return the value of the next byte in the stream, or {@code -1} * if EOF is reached. * - * @exception IOException if the stream has been closed. + * @throws IOException if the stream has been closed. */ public abstract int read() throws IOException; @@ -147,9 +147,9 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { * @return the number of bytes actually read, or {@code -1} * to indicate EOF. * - * @exception NullPointerException if {@code b} is + * @throws NullPointerException if {@code b} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ public int read(byte[] b) throws IOException { return read(b, 0, b.length); @@ -175,12 +175,12 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { * @return the number of bytes actually read, or {@code -1} * to indicate EOF. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code b.length}. - * @exception NullPointerException if {@code b} is + * @throws NullPointerException if {@code b} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ public abstract int read(byte[] b, int off, int len) throws IOException; @@ -729,7 +729,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { * @return an {@code int} representing the number of bytes * skipped. * - * @exception IOException if {@code getStreamPosition} + * @throws IOException if {@code getStreamPosition} * throws an {@code IOException} when computing either * the starting or ending position. */ @@ -750,7 +750,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { * @return a {@code long} representing the number of bytes * skipped. * - * @exception IOException if {@code getStreamPosition} + * @throws IOException if {@code getStreamPosition} * throws an {@code IOException} when computing either * the starting or ending position. */ @@ -791,7 +791,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { *

      An {@code IOException} will be thrown if the previous * marked position lies in the discarded portion of the stream. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ public void reset() throws IOException { if (markByteStack.empty()) { @@ -865,7 +865,7 @@ public abstract class ImageInputStreamImpl implements ImageInputStream { * source. This method should not be called from application * code. * - * @exception Throwable if an error occurs during superclass + * @throws Throwable if an error occurs during superclass * finalization. * * @deprecated Finalization has been deprecated for removal. See diff --git a/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStream.java index 5c261754c91..e88fb00e9cf 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStream.java @@ -66,7 +66,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param b an {@code int} whose lower 8 bits are to be * written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void write(int b) throws IOException; @@ -83,9 +83,9 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * * @param b an array of {@code byte}s to be written. * - * @exception NullPointerException if {@code b} is + * @throws NullPointerException if {@code b} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void write(byte[] b) throws IOException; @@ -107,12 +107,12 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param off the start offset in the data. * @param len the number of {@code byte}s to write. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code b.length}. - * @exception NullPointerException if {@code b} is + * @throws NullPointerException if {@code b} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void write(byte[] b, int off, int len) throws IOException; @@ -129,7 +129,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * * @param v the {@code boolean} to be written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeBoolean(boolean v) throws IOException; @@ -147,7 +147,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param v an {@code int} containing the byte value to be * written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeByte(int v) throws IOException; @@ -177,7 +177,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param v an {@code int} containing the short value to be * written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeShort(int v) throws IOException; @@ -187,7 +187,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param v an {@code int} containing the char (unsigned * short) value to be written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * * @see #writeShort(int) */ @@ -222,7 +222,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param v an {@code int} containing the value to be * written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeInt(int v) throws IOException; @@ -263,7 +263,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param v a {@code long} containing the value to be * written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeLong(long v) throws IOException; @@ -283,7 +283,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param v a {@code float} containing the value to be * written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeFloat(float v) throws IOException; @@ -304,7 +304,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param v a {@code double} containing the value to be * written. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeDouble(double v) throws IOException; @@ -330,9 +330,9 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param s a {@code String} containing the value to be * written. * - * @exception NullPointerException if {@code s} is + * @throws NullPointerException if {@code s} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeBytes(String s) throws IOException; @@ -358,9 +358,9 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param s a {@code String} containing the value to be * written. * - * @exception NullPointerException if {@code s} is + * @throws NullPointerException if {@code s} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeChars(String s) throws IOException; @@ -427,11 +427,11 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param s a {@code String} containing the value to be * written. * - * @exception NullPointerException if {@code s} is + * @throws NullPointerException if {@code s} is * {@code null}. - * @exception java.io.UTFDataFormatException if the modified UTF-8 + * @throws java.io.UTFDataFormatException if the modified UTF-8 * representation of {@code s} requires more than 65536 bytes. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeUTF(String s) throws IOException; @@ -452,12 +452,12 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param off the start offset in the data. * @param len the number of {@code short}s to write. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code s.length}. - * @exception NullPointerException if {@code s} is + * @throws NullPointerException if {@code s} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeShorts(short[] s, int off, int len) throws IOException; @@ -478,12 +478,12 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param off the start offset in the data. * @param len the number of {@code char}s to write. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code c.length}. - * @exception NullPointerException if {@code c} is + * @throws NullPointerException if {@code c} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeChars(char[] c, int off, int len) throws IOException; @@ -504,12 +504,12 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param off the start offset in the data. * @param len the number of {@code int}s to write. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code i.length}. - * @exception NullPointerException if {@code i} is + * @throws NullPointerException if {@code i} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeInts(int[] i, int off, int len) throws IOException; @@ -530,12 +530,12 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param off the start offset in the data. * @param len the number of {@code long}s to write. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code l.length}. - * @exception NullPointerException if {@code l} is + * @throws NullPointerException if {@code l} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeLongs(long[] l, int off, int len) throws IOException; @@ -556,12 +556,12 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param off the start offset in the data. * @param len the number of {@code float}s to write. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code f.length}. - * @exception NullPointerException if {@code f} is + * @throws NullPointerException if {@code f} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeFloats(float[] f, int off, int len) throws IOException; @@ -582,12 +582,12 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param off the start offset in the data. * @param len the number of {@code double}s to write. * - * @exception IndexOutOfBoundsException if {@code off} is + * @throws IndexOutOfBoundsException if {@code off} is * negative, {@code len} is negative, or {@code off + len} * is greater than {@code d.length}. - * @exception NullPointerException if {@code d} is + * @throws NullPointerException if {@code d} is * {@code null}. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeDoubles(double[] d, int off, int len) throws IOException; @@ -606,7 +606,7 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param bit an {@code int} whose least significant bit * is to be written to the stream. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeBit(int bit) throws IOException; @@ -637,9 +637,9 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * * @param numBits an {@code int} between 0 and 64, inclusive. * - * @exception IllegalArgumentException if {@code numBits} is + * @throws IllegalArgumentException if {@code numBits} is * not between 0 and 64, inclusive. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void writeBits(long bits, int numBits) throws IOException; @@ -653,10 +653,10 @@ public interface ImageOutputStream extends ImageInputStream, DataOutput { * @param pos a {@code long} containing the length of the * stream prefix that may be flushed to the destination. * - * @exception IndexOutOfBoundsException if {@code pos} lies + * @throws IndexOutOfBoundsException if {@code pos} lies * in the flushed portion of the stream or past the current stream * position. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ void flushBefore(long pos) throws IOException; } diff --git a/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java b/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java index 29e55a9a745..0bee5c7a240 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/ImageOutputStreamImpl.java @@ -484,7 +484,7 @@ public abstract class ImageOutputStreamImpl * beginning of the {@code write(int)} and * {@code write(byte[], int, int)} methods. * - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ protected final void flushBits() throws IOException { checkClosed(); diff --git a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCache.java b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCache.java index 2b0fdd98d60..260a0242546 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCache.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCache.java @@ -141,7 +141,7 @@ class MemoryCache { * not dispose of any blocks containing bytes written. To dispose * blocks, use {@link #disposeBefore disposeBefore()}. * - * @exception IndexOutOfBoundsException if any portion of + * @throws IndexOutOfBoundsException if any portion of * the requested data is not in the cache (including if {@code pos} * is in a block already disposed), or if either {@code pos} or * {@code len} is < 0. @@ -207,8 +207,8 @@ class MemoryCache { * @param len the number of bytes to be written. * @param pos the cache position at which to begin writing. * - * @exception NullPointerException if {@code b} is {@code null}. - * @exception IndexOutOfBoundsException if {@code off}, + * @throws NullPointerException if {@code b} is {@code null}. + * @throws IndexOutOfBoundsException if {@code off}, * {@code len}, or {@code pos} are negative, * or if {@code off+len > b.length}. * @throws IOException if there is an I/O error while writing to the cache @@ -254,7 +254,7 @@ class MemoryCache { * will be written. * @param pos the cache position at which to begin writing. * - * @exception IndexOutOfBoundsException if {@code pos} is negative. + * @throws IndexOutOfBoundsException if {@code pos} is negative. * @throws IOException if there is an I/O error while writing to the cache */ public void write(int b, long pos) throws IOException { @@ -309,8 +309,8 @@ class MemoryCache { * at cache position {@code pos}, into the array * {@code b} at offset {@code off}. * - * @exception NullPointerException if b is {@code null} - * @exception IndexOutOfBoundsException if {@code off}, + * @throws NullPointerException if b is {@code null} + * @throws IndexOutOfBoundsException if {@code off}, * {@code len} or {@code pos} are negative or if * {@code off + len > b.length} or if any portion of the * requested data is not in the cache (including if @@ -349,7 +349,7 @@ class MemoryCache { * Free the blocks up to the position {@code pos}. * The byte at {@code pos} remains available. * - * @exception IndexOutOfBoundsException if {@code pos} + * @throws IndexOutOfBoundsException if {@code pos} * is in a block that has already been disposed. */ public void disposeBefore(long pos) { diff --git a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java index 44b9d8cd5fb..ecb30ddba52 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageInputStream.java @@ -61,7 +61,7 @@ public class MemoryCacheImageInputStream extends ImageInputStreamImpl { * * @param stream an {@code InputStream} to read from. * - * @exception IllegalArgumentException if {@code stream} is + * @throws IllegalArgumentException if {@code stream} is * {@code null}. */ public MemoryCacheImageInputStream(InputStream stream) { diff --git a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageOutputStream.java b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageOutputStream.java index b90b7f33eac..676e3c829e3 100644 --- a/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageOutputStream.java +++ b/src/java.desktop/share/classes/javax/imageio/stream/MemoryCacheImageOutputStream.java @@ -51,7 +51,7 @@ public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl { * * @param stream an {@code OutputStream} to write to. * - * @exception IllegalArgumentException if {@code stream} is + * @throws IllegalArgumentException if {@code stream} is * {@code null}. */ public MemoryCacheImageOutputStream(OutputStream stream) { diff --git a/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java b/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java index 882881f13b9..0afae4060c0 100644 --- a/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java @@ -634,7 +634,7 @@ public class ByteBandedRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public WritableRaster createWritableChild (int x, int y, @@ -689,7 +689,7 @@ public class ByteBandedRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild (int x, int y, diff --git a/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java b/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java index 6a92748330c..3ec93b741e7 100644 --- a/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java @@ -759,7 +759,7 @@ public class ByteComponentRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild(int x, int y, @@ -788,7 +788,7 @@ public class ByteComponentRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent Raster. */ public WritableRaster createWritableChild(int x, int y, diff --git a/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java b/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java index 796f0835972..f0dedd9775a 100644 --- a/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java @@ -1195,7 +1195,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild(int x, int y, @@ -1224,7 +1224,7 @@ public class ByteInterleavedRaster extends ByteComponentRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent Raster. */ public WritableRaster createWritableChild(int x, int y, diff --git a/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java b/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java index d721eee5739..cadc390e6e9 100644 --- a/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java @@ -143,7 +143,7 @@ public class BytePackedRaster extends SunWritableRaster { * @param origin The Point that specifies the origin. * @param parent The parent (if any) of this raster. * - * @exception RasterFormatException if the parameters do not conform + * @throws RasterFormatException if the parameters do not conform * to requirements of this Raster type. */ public BytePackedRaster(SampleModel sampleModel, @@ -1258,7 +1258,7 @@ public class BytePackedRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild(int x, int y, @@ -1286,7 +1286,7 @@ public class BytePackedRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent Raster. */ public WritableRaster createWritableChild(int x, int y, diff --git a/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java b/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java index 3b110e77eca..e918a285aaa 100644 --- a/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java @@ -535,7 +535,7 @@ public class IntegerComponentRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public WritableRaster createWritableChild (int x, int y, @@ -589,7 +589,7 @@ public class IntegerComponentRaster extends SunWritableRaster { * @param x0 Translated X origin of the subRaster. * @param y0 Translated Y origin of the subRaster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild (int x, int y, diff --git a/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java b/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java index cb84024ae22..b00b0301130 100644 --- a/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java @@ -447,7 +447,7 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public WritableRaster createWritableChild (int x, int y, @@ -501,7 +501,7 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster { * @param x0 Translated X origin of the subRaster. * @param y0 Translated Y origin of the subRaster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild (int x, int y, diff --git a/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java b/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java index d8403926567..17d24e27686 100644 --- a/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java @@ -633,7 +633,7 @@ public class ShortBandedRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent Raster. */ public WritableRaster createWritableChild(int x, int y, @@ -689,7 +689,7 @@ public class ShortBandedRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild (int x, int y, diff --git a/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java b/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java index 3e95f652d33..b24b664826f 100644 --- a/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java @@ -693,7 +693,7 @@ public class ShortComponentRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild (int x, int y, @@ -722,7 +722,7 @@ public class ShortComponentRaster extends SunWritableRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent Raster. */ public WritableRaster createWritableChild(int x, int y, diff --git a/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java b/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java index d4926bb295e..327adf9ac98 100644 --- a/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java +++ b/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java @@ -666,7 +666,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent raster. */ public Raster createChild (int x, int y, @@ -695,7 +695,7 @@ public class ShortInterleavedRaster extends ShortComponentRaster { * @param x0 Translated X origin of the subraster. * @param y0 Translated Y origin of the subraster. * @param bandList Array of band indices. - * @exception RasterFormatException + * @throws RasterFormatException * if the specified bounding box is outside of the parent Raster. */ public WritableRaster createWritableChild(int x, int y, -- GitLab From a35afe84c3032cb10720bcd16498e2969cea0b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 24 Mar 2022 07:53:14 +0000 Subject: [PATCH 149/237] 8283519: Hsdis with capstone should annotate output Reviewed-by: jvernee --- src/utils/hsdis/capstone/hsdis-capstone.c | 43 ++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/utils/hsdis/capstone/hsdis-capstone.c b/src/utils/hsdis/capstone/hsdis-capstone.c index d71330ee6a7..075b4c67b14 100644 --- a/src/utils/hsdis/capstone/hsdis-capstone.c +++ b/src/utils/hsdis/capstone/hsdis-capstone.c @@ -61,6 +61,26 @@ typedef decode_instructions_printf_callback_ftype printf_callback_t; #define print(...) (*printf_callback) (printf_stream, __VA_ARGS__) +static void* null_event_callback(void* ignore_stream, const char* ignore_event, void* arg) { + return NULL; +} + +/* print all events as XML markup */ +static void* xml_event_callback(void* stream, const char* event, void* arg) { + FILE* fp = (FILE*) stream; +#define NS_PFX "dis:" + if (event[0] != '/') { + /* issue the tag, with or without a formatted argument */ + fprintf(fp, "<"NS_PFX); + fprintf(fp, event, arg); + fprintf(fp, ">"); + } else { + ++event; /* skip slash */ + fprintf(fp, "", event); + } + return NULL; +} + #ifdef _WIN32 __declspec(dllexport) #endif @@ -74,6 +94,21 @@ void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, int newline /* bool value for nice new line */) { csh cs_handle; + if (printf_callback == NULL) { + int (*fprintf_callback)(FILE*, const char*, ...) = &fprintf; + FILE* fprintf_stream = stdout; + printf_callback = (printf_callback_t) fprintf_callback; + if (printf_stream == NULL) + printf_stream = (void*) fprintf_stream; + } + if (event_callback == NULL) { + if (event_stream == NULL) + event_callback = &null_event_callback; + else + event_callback = &xml_event_callback; + } + + if (cs_open(CAPSTONE_ARCH, CAPSTONE_MODE, &cs_handle) != CS_ERR_OK) { print("Could not open cs_handle"); return NULL; @@ -86,7 +121,13 @@ void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, size_t count = cs_disasm(cs_handle, buffer, length, (uintptr_t) buffer, 0 , &insn); if (count) { for (unsigned int j = 0; j < count; j++) { - print(" 0x%" PRIx64 ":\t%s\t\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + (*event_callback)(event_stream, "insn", (void*) insn[j].address); + print("%s\t\t%s", insn[j].mnemonic, insn[j].op_str); + (*event_callback)(event_stream, "/insn", (void*) (insn[j].address + insn[j].size)); + if (newline) { + /* follow each complete insn by a nice newline */ + print("\n"); + } } cs_free(insn, count); } -- GitLab From b05d4ccf8e54635c16bc2c26aa7a8fcc2e3b3dde Mon Sep 17 00:00:00 2001 From: Yoshiki Sato Date: Thu, 24 Mar 2022 09:13:25 +0000 Subject: [PATCH 150/237] 8283350: (tz) Update Timezone Data to 2022a Reviewed-by: coffeys --- src/java.base/share/data/tzdata/VERSION | 2 +- src/java.base/share/data/tzdata/africa | 4 ++ src/java.base/share/data/tzdata/asia | 13 +++-- src/java.base/share/data/tzdata/europe | 56 +++++++++++++++++--- src/java.base/share/data/tzdata/leapseconds | 8 +-- src/java.base/share/data/tzdata/southamerica | 47 ++++++++++++---- 6 files changed, 103 insertions(+), 27 deletions(-) diff --git a/src/java.base/share/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION index 3a40c910333..bc830a3a5ef 100644 --- a/src/java.base/share/data/tzdata/VERSION +++ b/src/java.base/share/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2021e +tzdata2022a diff --git a/src/java.base/share/data/tzdata/africa b/src/java.base/share/data/tzdata/africa index 0f367713ea9..5466bbcc87b 100644 --- a/src/java.base/share/data/tzdata/africa +++ b/src/java.base/share/data/tzdata/africa @@ -941,6 +941,10 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis # (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a)) # (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b))))) # (setq islamic-year (+ 1 islamic-year)))) +# +# From Milamber (2021-03-31, 2022-03-10), confirming these predictions: +# https://www.mmsp.gov.ma/fr/actualites.aspx?id=2076 +# https://www.ecoactu.ma/horaires-administration-ramadan-gmtheure-gmt-a-partir-de-dimanche-27-mars/ # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Morocco 1939 only - Sep 12 0:00 1:00 - diff --git a/src/java.base/share/data/tzdata/asia b/src/java.base/share/data/tzdata/asia index cfe48745e24..4aaaf146b0f 100644 --- a/src/java.base/share/data/tzdata/asia +++ b/src/java.base/share/data/tzdata/asia @@ -3429,8 +3429,12 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # ... winter time will begin in Palestine from Friday 10-29, 01:00 AM # by 60 minutes backwards. # -# From Paul Eggert (2021-10-20): -# Guess future fall transitions on October's last Friday at 01:00. +# From Tim Parenti (2021-10-25), per Paul Eggert (2021-10-24): +# Guess future fall transitions at 01:00 on the Friday preceding October's +# last Sunday (i.e., Fri>=23), as this is more consistent with recent practice. + +# From Heba Hamad (2022-03-10): +# summer time will begin in Palestine from Sunday 03-27-2022, 00:00 AM. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -3466,9 +3470,10 @@ Rule Palestine 2016 2018 - Mar Sat>=24 1:00 1:00 S Rule Palestine 2016 2018 - Oct Sat>=24 1:00 0 - Rule Palestine 2019 only - Mar 29 0:00 1:00 S Rule Palestine 2019 only - Oct Sat>=24 0:00 0 - -Rule Palestine 2020 max - Mar Sat>=24 0:00 1:00 S +Rule Palestine 2020 2021 - Mar Sat>=24 0:00 1:00 S Rule Palestine 2020 only - Oct 24 1:00 0 - -Rule Palestine 2021 max - Oct lastFri 1:00 0 - +Rule Palestine 2021 max - Oct Fri>=23 1:00 0 - +Rule Palestine 2022 max - Mar Sun>=25 0:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct diff --git a/src/java.base/share/data/tzdata/europe b/src/java.base/share/data/tzdata/europe index 9b0b64aa3eb..bc57e94e44f 100644 --- a/src/java.base/share/data/tzdata/europe +++ b/src/java.base/share/data/tzdata/europe @@ -2808,8 +2808,26 @@ Zone Europe/Kaliningrad 1:22:00 - LMT 1893 Apr # says he remembers that Samara opted out of the 1992-01-19 exception # 2 days before the switch. # -# -# From Paul Eggert (2016-03-18): +# From Alois Treindl (2022-02-15): +# the Russian wikipedia page +# https://ru.wikipedia.org/wiki/Московское_время#Перемещение_границы_применения_московского_времени_на_восток +# contains the sentence (in Google translation) "In the autumn of +# 1981, Arkhangelsk, Vologda, Yaroslavl, Ivanovo, Vladimir, Ryazan, +# Lipetsk, Voronezh, Rostov-on-Don, Krasnodar and regions to the east +# of those named (about 30 in total) parted ways with Moscow time. +# However, the convenience of common time with Moscow turned out to be +# decisive - in 1982, these regions again switched to Moscow time." +# Shanks International atlas has similar information, and also the +# Russian book Zaitsev A., Kutalev D. A new astrologer's reference +# book. Coordinates of cities and time corrections, - The World of +# Urania, 2012 (Russian: Зайцев А., Куталёв Д., Новый справочник +# астролога. Координаты городов и временные поправки). +# To me it seems that an extra zone is needed, which starts with LMT +# util 1919, later follows Moscow since 1930, but deviates from it +# between 1 October 1981 until 1 April 1982. +# +# +# From Paul Eggert (2022-02-15): # Given the above, we appear to be missing some Zone entries for the # chaotic early 1980s in Russia. It's not clear what these entries # should be. For now, sweep this under the rug and just document the @@ -2856,7 +2874,7 @@ Zone Europe/Simferopol 2:16:24 - LMT 1880 1:00 C-Eur CE%sT 1944 Apr 13 3:00 Russia MSK/MSD 1990 3:00 - MSK 1990 Jul 1 2:00 - 2:00 - EET 1992 + 2:00 - EET 1992 Mar 20 # Central Crimea used Moscow time 1994/1997. # # From Paul Eggert (2006-03-22): @@ -2866,7 +2884,7 @@ Zone Europe/Simferopol 2:16:24 - LMT 1880 # sometime between the 1994 DST switches. Shanks & Pottenger simply say # 1994-09-25 03:00, but that can't be right. For now, guess it # changed in May. - 2:00 E-Eur EE%sT 1994 May + 2:00 C-Eur EE%sT 1994 May # From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev. 3:00 E-Eur MSK/MSD 1996 Mar 31 0:00s 3:00 1:00 MSD 1996 Oct 27 3:00s @@ -4033,6 +4051,27 @@ Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. # Ukraine # +# From Alois Triendl (2014-03-01): +# REGULATION A N O V A on March 20, 1992 N 139 ... means that from +# 1992 on, Ukraine had DST with begin time at 02:00 am, on last Sunday +# in March, and end time 03:00 am, last Sunday in September.... +# CABINET OF MINISTERS OF UKRAINE RESOLUTION on May 13, 1996 N 509 +# "On the order of computation time on the territory of Ukraine" .... +# As this cabinet decision is from May 1996, it seems likely that the +# transition in March 1996, which predates it, was still at 2:00 am +# and not at 3:00 as would have been under EU rules. +# This is why I have set the change to EU rules into May 1996, +# so that the change in March is stil covered by the Ukraine rule. +# The next change in October 1996 happened under EU rules.... +# TZ database holds three other zones for Ukraine.... I have not yet +# worked out the consequences for these three zones, as we (me and my +# US colleague David Cochrane) are still trying to get more +# information upon these local deviations from Kiev rules. +# +# From Paul Eggert (2022-02-08): +# For now, assume that Ukraine's other three zones followed the same rules, +# except that Crimea switched to Moscow time in 1994 as described elsewhere. + # From Igor Karpov, who works for the Ukrainian Ministry of Justice, # via Garrett Wollman (2003-01-27): # BTW, I've found the official document on this matter. It's government @@ -4122,7 +4161,7 @@ Zone Europe/Kiev 2:02:04 - LMT 1880 1:00 C-Eur CE%sT 1943 Nov 6 3:00 Russia MSK/MSD 1990 Jul 1 2:00 2:00 1:00 EEST 1991 Sep 29 3:00 - 2:00 E-Eur EE%sT 1995 + 2:00 C-Eur EE%sT 1996 May 13 2:00 EU EE%sT # Transcarpathia used CET 1990/1991. # "Uzhhorod" is the transliteration of the Rusyn/Ukrainian pronunciation, but @@ -4135,8 +4174,8 @@ Zone Europe/Uzhgorod 1:29:12 - LMT 1890 Oct 3:00 Russia MSK/MSD 1990 3:00 - MSK 1990 Jul 1 2:00 1:00 - CET 1991 Mar 31 3:00 - 2:00 - EET 1992 - 2:00 E-Eur EE%sT 1995 + 2:00 - EET 1992 Mar 20 + 2:00 C-Eur EE%sT 1996 May 13 2:00 EU EE%sT # Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991. # "Zaporizhia" is the transliteration of the Ukrainian name, but @@ -4149,7 +4188,8 @@ Zone Europe/Zaporozhye 2:20:40 - LMT 1880 3:00 - MSK 1941 Aug 25 1:00 C-Eur CE%sT 1943 Oct 25 3:00 Russia MSK/MSD 1991 Mar 31 2:00 - 2:00 E-Eur EE%sT 1995 + 2:00 E-Eur EE%sT 1992 Mar 20 + 2:00 C-Eur EE%sT 1996 May 13 2:00 EU EE%sT # Vatican City diff --git a/src/java.base/share/data/tzdata/leapseconds b/src/java.base/share/data/tzdata/leapseconds index cc514561ff1..776d25ab367 100644 --- a/src/java.base/share/data/tzdata/leapseconds +++ b/src/java.base/share/data/tzdata/leapseconds @@ -95,11 +95,11 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2022 Jun 28 00:00:00 +#Expires 2022 Dec 28 00:00:00 # POSIX timestamps for the data in this file: #updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1656374400 (2022-06-28 00:00:00 UTC) +#expires 1672185600 (2022-12-28 00:00:00 UTC) -# Updated through IERS Bulletin C62 -# File expires on: 28 June 2022 +# Updated through IERS Bulletin C63 +# File expires on: 28 December 2022 diff --git a/src/java.base/share/data/tzdata/southamerica b/src/java.base/share/data/tzdata/southamerica index 503ed65f580..b6e401ac252 100644 --- a/src/java.base/share/data/tzdata/southamerica +++ b/src/java.base/share/data/tzdata/southamerica @@ -1109,7 +1109,7 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 # Chile -# From Paul Eggert (2015-04-03): +# From Paul Eggert (2022-03-15): # Shanks & Pottenger says America/Santiago introduced standard time in # 1890 and rounds its UT offset to 70W40; guess that in practice this # was the same offset as in 1916-1919. It also says Pacific/Easter @@ -1132,7 +1132,7 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 # Historia de la hora oficial de Chile (retrieved 2012-10-24). See: # https://web.archive.org/web/20121024234627/http://www.horaoficial.cl/horaof.htm # A fancier Spanish version (requiring mouse-clicking) is at: -# http://www.horaoficial.cl/historia_hora.html +# http://www.horaoficial.cl/historia_hora.php # Conflicts between [1] and [2] were resolved as follows: # # - [1] says the 1910 transition was Jan 1, [2] says Jan 10 and cites @@ -1141,7 +1141,8 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 # - [1] says SMT was -4:42:45, [2] says Chile's official time from # 1916 to 1919 was -4:42:46.3, the meridian of Chile's National # Astronomical Observatory (OAN), then located in what is now -# Quinta Normal in Santiago. Go with [2], rounding it to -4:42:46. +# Quinta Normal in Santiago. Go with [1], as this matches the meridian +# referred to by the relevant Chilean laws to this day. # # - [1] says the 1918 transition was Sep 1, [2] says Sep 10 and cites # Boletín No. 22, Aviso No. 129/1918 (1918-08-23). Go with [2]. @@ -1163,6 +1164,32 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 # this is known to work for DST transitions starting in 2008 and # may well be true for earlier transitions. +# From Tim Parenti (2022-03-15): +# For a brief period of roughly six weeks in 1946, DST was only observed on an +# emergency basis in specific regions of central Chile; namely, "the national +# territory between the provinces of Coquimbo and Concepción, inclusive". +# This was enacted by Decree 3,891, dated 1946-07-13, and took effect +# 1946-07-14 24:00, advancing these central regions to -03. +# https://www.diariooficial.interior.gob.cl/versiones-anteriores/do-h/19460715/#page/1 +# The decree contemplated "[t]hat this advancement of the Official Time, even +# though it has been proposed for the cities of Santiago and Valparaíso only, +# must be agreed with that of other cities, due to the connection of various +# activities that require it, such as, for example, the operation of rail +# services". It was originally set to expire after 30 days but was extended +# through 1946-08-31 by Decree 4,506, dated 1946-08-13. +# https://www.diariooficial.interior.gob.cl/versiones-anteriores/do-h/19460814/#page/1 +# +# Law Number 8,522, promulgated 1946-08-27, reunified Chilean clocks at their +# new "Summer Time" of -04, reckoned as that of "the meridian of the +# Astronomical Observatory of Lo Espejo, advanced by 42 minutes and 45 +# seconds". +# https://www.diariooficial.interior.gob.cl/versiones-anteriores/do-h/19460828/#page/1 +# After a brief "Winter Time" stint at -05 beginning 1947-04-01, Law Number +# 8,777, promulgated 1947-05-17, established year-round -04 "from 23:00 on the +# second day after it is published in the 'Diario Oficial'." It was published +# on Monday 1947-05-19 and so took effect from Wednesday 1947-05-21 23:00. +# https://www.diariooficial.interior.gob.cl/versiones-anteriores/do-h/19470519/#page/1 + # From Eduardo Krell (1995-10-19): # The law says to switch to DST at midnight [24:00] on the second SATURDAY # of October.... The law is the same for March and October. @@ -1321,12 +1348,12 @@ Rule Chile 2019 max - Sep Sun>=2 4:00u 1:00 - # IATA SSIM anomalies: (1992-02) says 1992-03-14; # (1996-09) says 1998-03-08. Ignore these. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Santiago -4:42:46 - LMT 1890 - -4:42:46 - SMT 1910 Jan 10 # Santiago Mean Time +Zone America/Santiago -4:42:45 - LMT 1890 + -4:42:45 - SMT 1910 Jan 10 # Santiago Mean Time -5:00 - -05 1916 Jul 1 - -4:42:46 - SMT 1918 Sep 10 + -4:42:45 - SMT 1918 Sep 10 -4:00 - -04 1919 Jul 1 - -4:42:46 - SMT 1927 Sep 1 + -4:42:45 - SMT 1927 Sep 1 -5:00 Chile -05/-04 1932 Sep 1 -4:00 - -04 1942 Jun 1 -5:00 - -05 1942 Aug 1 @@ -1336,11 +1363,11 @@ Zone America/Santiago -4:42:46 - LMT 1890 -5:00 - -05 1947 May 21 23:00 -4:00 Chile -04/-03 Zone America/Punta_Arenas -4:43:40 - LMT 1890 - -4:42:46 - SMT 1910 Jan 10 + -4:42:45 - SMT 1910 Jan 10 -5:00 - -05 1916 Jul 1 - -4:42:46 - SMT 1918 Sep 10 + -4:42:45 - SMT 1918 Sep 10 -4:00 - -04 1919 Jul 1 - -4:42:46 - SMT 1927 Sep 1 + -4:42:45 - SMT 1927 Sep 1 -5:00 Chile -05/-04 1932 Sep 1 -4:00 - -04 1942 Jun 1 -5:00 - -05 1942 Aug 1 -- GitLab From 5905b02c0e2643ae8d097562f181953f6c88fc89 Mon Sep 17 00:00:00 2001 From: Fei Yang Date: Thu, 24 Mar 2022 09:22:46 +0000 Subject: [PATCH 151/237] 8276799: Implementation of JEP 422: Linux/RISC-V Port Co-authored-by: Yadong Wang Co-authored-by: Yanhong Zhu Co-authored-by: Feilong Jiang Co-authored-by: Kun Wang Co-authored-by: Zhuxuan Ni Co-authored-by: Taiping Guo Co-authored-by: Kang He Co-authored-by: Aleksey Shipilev Co-authored-by: Xiaolin Zheng Co-authored-by: Kuai Wei Co-authored-by: Magnus Ihse Bursie Reviewed-by: ihse, dholmes, rriggs, kvn, shade --- make/autoconf/build-aux/config.guess | 11 +- make/autoconf/jvm-features.m4 | 6 +- make/autoconf/libraries.m4 | 8 +- make/autoconf/platform.m4 | 6 +- make/hotspot/gensrc/GensrcAdlc.gmk | 9 +- .../cpu/aarch64/c1_LIRAssembler_aarch64.cpp | 6 +- src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp | 7 +- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 6 +- .../cpu/riscv/abstractInterpreter_riscv.cpp | 177 + src/hotspot/cpu/riscv/assembler_riscv.cpp | 372 + src/hotspot/cpu/riscv/assembler_riscv.hpp | 3047 +++++ .../cpu/riscv/assembler_riscv.inline.hpp | 47 + src/hotspot/cpu/riscv/bytes_riscv.hpp | 167 + src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp | 353 + src/hotspot/cpu/riscv/c1_Defs_riscv.hpp | 84 + .../cpu/riscv/c1_FpuStackSim_riscv.cpp | 30 + .../cpu/riscv/c1_FpuStackSim_riscv.hpp | 32 + src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp | 388 + src/hotspot/cpu/riscv/c1_FrameMap_riscv.hpp | 148 + .../cpu/riscv/c1_LIRAssembler_arith_riscv.cpp | 281 + .../cpu/riscv/c1_LIRAssembler_arith_riscv.hpp | 37 + .../riscv/c1_LIRAssembler_arraycopy_riscv.cpp | 388 + .../riscv/c1_LIRAssembler_arraycopy_riscv.hpp | 52 + .../cpu/riscv/c1_LIRAssembler_riscv.cpp | 2267 ++++ .../cpu/riscv/c1_LIRAssembler_riscv.hpp | 132 + .../cpu/riscv/c1_LIRGenerator_riscv.cpp | 1075 ++ src/hotspot/cpu/riscv/c1_LIR_riscv.cpp | 55 + src/hotspot/cpu/riscv/c1_LinearScan_riscv.cpp | 33 + src/hotspot/cpu/riscv/c1_LinearScan_riscv.hpp | 83 + .../cpu/riscv/c1_MacroAssembler_riscv.cpp | 432 + .../cpu/riscv/c1_MacroAssembler_riscv.hpp | 120 + src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp | 1172 ++ src/hotspot/cpu/riscv/c1_globals_riscv.hpp | 65 + .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 1646 +++ .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 193 + src/hotspot/cpu/riscv/c2_globals_riscv.hpp | 83 + src/hotspot/cpu/riscv/c2_init_riscv.cpp | 38 + .../riscv/c2_safepointPollStubTable_riscv.cpp | 47 + src/hotspot/cpu/riscv/codeBuffer_riscv.hpp | 36 + src/hotspot/cpu/riscv/compiledIC_riscv.cpp | 149 + src/hotspot/cpu/riscv/copy_riscv.hpp | 136 + src/hotspot/cpu/riscv/disassembler_riscv.hpp | 58 + .../cpu/riscv/foreign_globals_riscv.cpp | 44 + .../cpu/riscv/foreign_globals_riscv.hpp | 32 + src/hotspot/cpu/riscv/frame_riscv.cpp | 697 + src/hotspot/cpu/riscv/frame_riscv.hpp | 202 + src/hotspot/cpu/riscv/frame_riscv.inline.hpp | 248 + .../gc/g1/g1BarrierSetAssembler_riscv.cpp | 484 + .../gc/g1/g1BarrierSetAssembler_riscv.hpp | 78 + .../cpu/riscv/gc/g1/g1Globals_riscv.hpp | 31 + .../gc/shared/barrierSetAssembler_riscv.cpp | 302 + .../gc/shared/barrierSetAssembler_riscv.hpp | 79 + .../gc/shared/barrierSetNMethod_riscv.cpp | 171 + .../cardTableBarrierSetAssembler_riscv.cpp | 111 + .../cardTableBarrierSetAssembler_riscv.hpp | 42 + .../modRefBarrierSetAssembler_riscv.cpp | 55 + .../modRefBarrierSetAssembler_riscv.hpp | 55 + .../c1/shenandoahBarrierSetC1_riscv.cpp | 117 + .../shenandoahBarrierSetAssembler_riscv.cpp | 712 ++ .../shenandoahBarrierSetAssembler_riscv.hpp | 88 + .../riscv/gc/shenandoah/shenandoah_riscv64.ad | 285 + .../riscv/gc/z/zBarrierSetAssembler_riscv.cpp | 441 + .../riscv/gc/z/zBarrierSetAssembler_riscv.hpp | 101 + src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.cpp | 212 + src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.hpp | 36 + src/hotspot/cpu/riscv/gc/z/z_riscv64.ad | 233 + .../cpu/riscv/globalDefinitions_riscv.hpp | 52 + src/hotspot/cpu/riscv/globals_riscv.hpp | 99 + src/hotspot/cpu/riscv/icBuffer_riscv.cpp | 79 + src/hotspot/cpu/riscv/icache_riscv.cpp | 51 + src/hotspot/cpu/riscv/icache_riscv.hpp | 42 + src/hotspot/cpu/riscv/interp_masm_riscv.cpp | 1940 +++ src/hotspot/cpu/riscv/interp_masm_riscv.hpp | 285 + src/hotspot/cpu/riscv/interpreterRT_riscv.cpp | 295 + src/hotspot/cpu/riscv/interpreterRT_riscv.hpp | 68 + .../cpu/riscv/javaFrameAnchor_riscv.hpp | 86 + .../cpu/riscv/jniFastGetField_riscv.cpp | 214 + src/hotspot/cpu/riscv/jniTypes_riscv.hpp | 106 + .../cpu/riscv/macroAssembler_riscv.cpp | 4016 ++++++ .../cpu/riscv/macroAssembler_riscv.hpp | 858 ++ .../cpu/riscv/macroAssembler_riscv.inline.hpp | 31 + src/hotspot/cpu/riscv/matcher_riscv.hpp | 169 + src/hotspot/cpu/riscv/methodHandles_riscv.cpp | 461 + src/hotspot/cpu/riscv/methodHandles_riscv.hpp | 57 + src/hotspot/cpu/riscv/nativeInst_riscv.cpp | 429 + src/hotspot/cpu/riscv/nativeInst_riscv.hpp | 572 + src/hotspot/cpu/riscv/registerMap_riscv.cpp | 45 + src/hotspot/cpu/riscv/registerMap_riscv.hpp | 43 + src/hotspot/cpu/riscv/register_riscv.cpp | 73 + src/hotspot/cpu/riscv/register_riscv.hpp | 324 + src/hotspot/cpu/riscv/relocInfo_riscv.cpp | 113 + src/hotspot/cpu/riscv/relocInfo_riscv.hpp | 44 + src/hotspot/cpu/riscv/riscv.ad | 10611 ++++++++++++++++ src/hotspot/cpu/riscv/riscv_b.ad | 527 + src/hotspot/cpu/riscv/riscv_v.ad | 2065 +++ src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp | 2761 ++++ src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 3864 ++++++ src/hotspot/cpu/riscv/stubRoutines_riscv.cpp | 58 + src/hotspot/cpu/riscv/stubRoutines_riscv.hpp | 161 + .../templateInterpreterGenerator_riscv.cpp | 1794 +++ src/hotspot/cpu/riscv/templateTable_riscv.cpp | 3951 ++++++ src/hotspot/cpu/riscv/templateTable_riscv.hpp | 42 + .../riscv/universalNativeInvoker_riscv.cpp | 33 + .../cpu/riscv/universalUpcallHandle_riscv.cpp | 42 + src/hotspot/cpu/riscv/vmStructs_riscv.hpp | 42 + src/hotspot/cpu/riscv/vm_version_riscv.cpp | 230 + src/hotspot/cpu/riscv/vm_version_riscv.hpp | 72 + src/hotspot/cpu/riscv/vmreg_riscv.cpp | 64 + src/hotspot/cpu/riscv/vmreg_riscv.hpp | 68 + src/hotspot/cpu/riscv/vmreg_riscv.inline.hpp | 46 + src/hotspot/cpu/riscv/vtableStubs_riscv.cpp | 260 + src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp | 7 +- src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp | 7 +- src/hotspot/os/linux/os_linux.cpp | 2 + .../linux_riscv/assembler_linux_riscv.cpp | 26 + .../os_cpu/linux_riscv/atomic_linux_riscv.hpp | 134 + .../os_cpu/linux_riscv/bytes_linux_riscv.hpp | 45 + .../os_cpu/linux_riscv/copy_linux_riscv.hpp | 31 + .../linux_riscv/gc/z/zSyscall_linux_riscv.hpp | 42 + .../linux_riscv/globals_linux_riscv.hpp | 43 + .../linux_riscv/orderAccess_linux_riscv.hpp | 63 + .../os_cpu/linux_riscv/os_linux_riscv.cpp | 466 + .../os_cpu/linux_riscv/os_linux_riscv.hpp | 59 + .../prefetch_linux_riscv.inline.hpp | 38 + .../os_cpu/linux_riscv/thread_linux_riscv.cpp | 92 + .../os_cpu/linux_riscv/thread_linux_riscv.hpp | 48 + .../linux_riscv/vmStructs_linux_riscv.hpp | 55 + .../linux_riscv/vm_version_linux_riscv.cpp | 118 + src/hotspot/share/c1/c1_LIR.cpp | 109 +- src/hotspot/share/c1/c1_LIR.hpp | 191 +- src/hotspot/share/c1/c1_LIRAssembler.cpp | 15 +- src/hotspot/share/c1/c1_LIRAssembler.hpp | 5 +- src/hotspot/share/c1/c1_LinearScan.cpp | 18 +- .../gc/shenandoah/shenandoahArguments.cpp | 4 +- src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp | 4 +- .../share/jfr/utilities/jfrBigEndian.hpp | 2 +- src/hotspot/share/opto/regmask.hpp | 4 +- .../share/runtime/abstract_vm_version.cpp | 3 +- src/hotspot/share/runtime/arguments.cpp | 2 +- src/hotspot/share/runtime/synchronizer.cpp | 4 +- src/hotspot/share/runtime/thread.inline.hpp | 4 +- src/hotspot/share/utilities/macros.hpp | 26 + .../native/libsaproc/LinuxDebuggerLocal.cpp | 49 +- .../linux/native/libsaproc/libproc.h | 4 +- .../classes/sun/jvm/hotspot/HotSpotAgent.java | 3 + .../debugger/MachineDescriptionRISCV64.java | 40 + .../debugger/linux/LinuxCDebugger.java | 13 +- .../linux/riscv64/LinuxRISCV64CFrame.java | 90 + .../riscv64/LinuxRISCV64ThreadContext.java | 48 + .../proc/riscv64/ProcRISCV64Thread.java | 88 + .../riscv64/ProcRISCV64ThreadContext.java | 48 + .../riscv64/ProcRISCV64ThreadFactory.java | 46 + .../remote/riscv64/RemoteRISCV64Thread.java | 55 + .../riscv64/RemoteRISCV64ThreadContext.java | 48 + .../riscv64/RemoteRISCV64ThreadFactory.java | 46 + .../debugger/risv64/RISCV64ThreadContext.java | 172 + .../sun/jvm/hotspot/runtime/Threads.java | 5 +- .../LinuxRISCV64JavaThreadPDAccess.java | 134 + .../riscv64/RISCV64CurrentFrameGuess.java | 223 + .../hotspot/runtime/riscv64/RISCV64Frame.java | 556 + .../riscv64/RISCV64JavaCallWrapper.java | 61 + .../runtime/riscv64/RISCV64RegisterMap.java | 53 + .../jvm/hotspot/utilities/PlatformInfo.java | 4 +- test/hotspot/jtreg/compiler/c2/TestBit.java | 7 +- ...eSHA1IntrinsicsOptionOnUnsupportedCPU.java | 5 +- ...HA256IntrinsicsOptionOnUnsupportedCPU.java | 5 +- ...HA512IntrinsicsOptionOnUnsupportedCPU.java | 5 +- .../cli/TestUseSHAOptionOnUnsupportedCPU.java | 5 +- .../testcases/GenericTestCaseForOtherCPU.java | 11 +- ...nericTestCaseForUnsupportedRISCV64CPU.java | 115 + .../loopopts/superword/ProdRed_Double.java | 4 +- .../loopopts/superword/ProdRed_Float.java | 4 +- .../loopopts/superword/ProdRed_Int.java | 4 +- .../loopopts/superword/ReductionPerf.java | 4 +- .../superword/SumRedAbsNeg_Double.java | 4 +- .../superword/SumRedAbsNeg_Float.java | 4 +- .../loopopts/superword/SumRedSqrt_Double.java | 4 +- .../loopopts/superword/SumRed_Double.java | 4 +- .../loopopts/superword/SumRed_Float.java | 4 +- .../loopopts/superword/SumRed_Int.java | 4 +- .../sha/predicate/IntrinsicPredicates.java | 11 +- .../NMT/CheckForProperDetailStackTrace.java | 4 +- .../ReservedStack/ReservedStackTest.java | 4 +- .../MyPackage/ASGCTBaseTest.java | 4 +- .../ConcurrentHashMap/MapLoops.java | 2 +- .../jdk/jfr/event/os/TestCPUInformation.java | 6 +- ...stMutuallyExclusivePlatformPredicates.java | 2 +- test/lib/jdk/test/lib/Platform.java | 4 + 188 files changed, 59087 insertions(+), 177 deletions(-) create mode 100644 src/hotspot/cpu/riscv/abstractInterpreter_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/assembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/assembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/assembler_riscv.inline.hpp create mode 100644 src/hotspot/cpu/riscv/bytes_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_Defs_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_FpuStackSim_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_FpuStackSim_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_FrameMap_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_LIRAssembler_arith_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_LIRAssembler_arith_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_LIR_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_LinearScan_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_LinearScan_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c1_globals_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c2_globals_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/c2_init_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/c2_safepointPollStubTable_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/codeBuffer_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/compiledIC_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/copy_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/disassembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/foreign_globals_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/foreign_globals_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/frame_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/frame_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/frame_riscv.inline.hpp create mode 100644 src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/gc/g1/g1Globals_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/gc/shared/modRefBarrierSetAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/shared/modRefBarrierSetAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/gc/shenandoah/shenandoah_riscv64.ad create mode 100644 src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/gc/z/z_riscv64.ad create mode 100644 src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/globals_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/icBuffer_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/icache_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/icache_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/interp_masm_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/interp_masm_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/interpreterRT_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/interpreterRT_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/javaFrameAnchor_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/jniTypes_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/macroAssembler_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/macroAssembler_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/macroAssembler_riscv.inline.hpp create mode 100644 src/hotspot/cpu/riscv/matcher_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/methodHandles_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/methodHandles_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/nativeInst_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/nativeInst_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/registerMap_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/registerMap_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/register_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/register_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/relocInfo_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/relocInfo_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/riscv.ad create mode 100644 src/hotspot/cpu/riscv/riscv_b.ad create mode 100644 src/hotspot/cpu/riscv/riscv_v.ad create mode 100644 src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/stubGenerator_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/stubRoutines_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/stubRoutines_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/templateTable_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/templateTable_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/universalNativeInvoker_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/universalUpcallHandle_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/vmStructs_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/vm_version_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/vm_version_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/vmreg_riscv.cpp create mode 100644 src/hotspot/cpu/riscv/vmreg_riscv.hpp create mode 100644 src/hotspot/cpu/riscv/vmreg_riscv.inline.hpp create mode 100644 src/hotspot/cpu/riscv/vtableStubs_riscv.cpp create mode 100644 src/hotspot/os_cpu/linux_riscv/assembler_linux_riscv.cpp create mode 100644 src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/bytes_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/copy_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/gc/z/zSyscall_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/globals_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp create mode 100644 src/hotspot/os_cpu/linux_riscv/os_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/prefetch_linux_riscv.inline.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/thread_linux_riscv.cpp create mode 100644 src/hotspot/os_cpu/linux_riscv/thread_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp create mode 100644 src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionRISCV64.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64ThreadContext.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64Thread.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64ThreadContext.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64ThreadFactory.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64Thread.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64ThreadContext.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64ThreadFactory.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/risv64/RISCV64ThreadContext.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_riscv64/LinuxRISCV64JavaThreadPDAccess.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64CurrentFrameGuess.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64JavaCallWrapper.java create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64RegisterMap.java create mode 100644 test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForUnsupportedRISCV64CPU.java diff --git a/make/autoconf/build-aux/config.guess b/make/autoconf/build-aux/config.guess index d589529f35a..6ae31e8ae22 100644 --- a/make/autoconf/build-aux/config.guess +++ b/make/autoconf/build-aux/config.guess @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2021, Azul Systems, Inc. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # @@ -111,6 +111,15 @@ if [ "x$OUT" = x ]; then fi fi +# Test and fix RISC-V. +if [ "x$OUT" = x ]; then + if [ `uname -s` = Linux ]; then + if [ `uname -m` = riscv64 ]; then + OUT=riscv64-unknown-linux-gnu + fi + fi +fi + # Test and fix cpu on macos-aarch64, uname -p reports arm, buildsys expects aarch64 echo $OUT | grep arm-apple-darwin > /dev/null 2> /dev/null if test $? != 0; then diff --git a/make/autoconf/jvm-features.m4 b/make/autoconf/jvm-features.m4 index 8dfc0d362b9..ee1d19ecce8 100644 --- a/make/autoconf/jvm-features.m4 +++ b/make/autoconf/jvm-features.m4 @@ -291,7 +291,8 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_SHENANDOAHGC], AC_MSG_CHECKING([if platform is supported by Shenandoah]) if test "x$OPENJDK_TARGET_CPU_ARCH" = "xx86" || \ test "x$OPENJDK_TARGET_CPU" = "xaarch64" || \ - test "x$OPENJDK_TARGET_CPU" = "xppc64le"; then + test "x$OPENJDK_TARGET_CPU" = "xppc64le" || \ + test "x$OPENJDK_TARGET_CPU" = "xriscv64"; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no, $OPENJDK_TARGET_CPU]) @@ -341,7 +342,8 @@ AC_DEFUN_ONCE([JVM_FEATURES_CHECK_ZGC], AC_MSG_RESULT([no, $OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU]) AVAILABLE=false fi - elif test "x$OPENJDK_TARGET_CPU" = "xppc64le"; then + elif test "x$OPENJDK_TARGET_CPU" = "xppc64le" || \ + test "x$OPENJDK_TARGET_CPU" = "xriscv64"; then if test "x$OPENJDK_TARGET_OS" = "xlinux"; then AC_MSG_RESULT([yes]) else diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 index fbc8ee7b9c8..b901d77c5c5 100644 --- a/make/autoconf/libraries.m4 +++ b/make/autoconf/libraries.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -149,6 +149,12 @@ AC_DEFUN_ONCE([LIB_SETUP_LIBRARIES], fi fi + # Because RISC-V only has word-sized atomics, it requries libatomic where + # other common architectures do not. So link libatomic by default. + if test "x$OPENJDK_TARGET_OS" = xlinux && test "x$OPENJDK_TARGET_CPU" = xriscv64; then + BASIC_JVM_LIBS="$BASIC_JVM_LIBS -latomic" + fi + # perfstat lib if test "x$OPENJDK_TARGET_OS" = xaix; then BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lperfstat" diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4 index 205d64f566d..a48aabe06f3 100644 --- a/make/autoconf/platform.m4 +++ b/make/autoconf/platform.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2022, 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 @@ -561,6 +561,8 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], HOTSPOT_$1_CPU_DEFINE=PPC64 elif test "x$OPENJDK_$1_CPU" = xppc64le; then HOTSPOT_$1_CPU_DEFINE=PPC64 + elif test "x$OPENJDK_$1_CPU" = xriscv64; then + HOTSPOT_$1_CPU_DEFINE=RISCV64 # The cpu defines below are for zero, we don't support them directly. elif test "x$OPENJDK_$1_CPU" = xsparc; then @@ -571,8 +573,6 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], HOTSPOT_$1_CPU_DEFINE=S390 elif test "x$OPENJDK_$1_CPU" = xs390x; then HOTSPOT_$1_CPU_DEFINE=S390 - elif test "x$OPENJDK_$1_CPU" = xriscv64; then - HOTSPOT_$1_CPU_DEFINE=RISCV elif test "x$OPENJDK_$1_CPU" != x; then HOTSPOT_$1_CPU_DEFINE=$(echo $OPENJDK_$1_CPU | tr a-z A-Z) fi diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index 25c13272914..73496bc6586 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 2022, 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 @@ -146,6 +146,13 @@ ifeq ($(call check-jvm-feature, compiler2), true) ))) endif + ifeq ($(HOTSPOT_TARGET_CPU_ARCH), riscv) + AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_CPU_ARCH)_v.ad \ + $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_CPU_ARCH)_b.ad \ + ))) + endif + ifeq ($(call check-jvm-feature, shenandoahgc), true) AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \ $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/shenandoah/shenandoah_$(HOTSPOT_TARGET_CPU).ad \ diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 6f91b1539a6..b7e6ccc28d9 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1582,7 +1582,9 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { } -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type, + LIR_Opr cmp_opr1, LIR_Opr cmp_opr2) { + assert(cmp_opr1 == LIR_OprFact::illegalOpr && cmp_opr2 == LIR_OprFact::illegalOpr, "unnecessary cmp oprs on aarch64"); Assembler::Condition acond, ncond; switch (condition) { diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp index f7ffe84618d..b92167fb6a0 100644 --- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -1412,7 +1412,10 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { } -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type, + LIR_Opr cmp_opr1, LIR_Opr cmp_opr2) { + assert(cmp_opr1 == LIR_OprFact::illegalOpr && cmp_opr2 == LIR_OprFact::illegalOpr, "unnecessary cmp oprs on arm"); + AsmCondition acond = al; AsmCondition ncond = nv; if (opr1 != opr2) { diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index b04c49152f3..730e95ae775 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1547,8 +1547,10 @@ inline void load_to_reg(LIR_Assembler *lasm, LIR_Opr src, LIR_Opr dst) { } } +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type, + LIR_Opr cmp_opr1, LIR_Opr cmp_opr2) { + assert(cmp_opr1 == LIR_OprFact::illegalOpr && cmp_opr2 == LIR_OprFact::illegalOpr, "unnecessary cmp oprs on ppc"); -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { if (opr1->is_equal(opr2) || opr1->is_same_register(opr2)) { load_to_reg(this, opr1, result); // Condition doesn't matter. return; diff --git a/src/hotspot/cpu/riscv/abstractInterpreter_riscv.cpp b/src/hotspot/cpu/riscv/abstractInterpreter_riscv.cpp new file mode 100644 index 00000000000..31c63abe71d --- /dev/null +++ b/src/hotspot/cpu/riscv/abstractInterpreter_riscv.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "interpreter/interpreter.hpp" +#include "oops/constMethod.hpp" +#include "oops/klass.inline.hpp" +#include "oops/method.hpp" +#include "runtime/frame.inline.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" +#include "utilities/macros.hpp" + +int AbstractInterpreter::BasicType_as_index(BasicType type) { + int i = 0; + switch (type) { + case T_BOOLEAN: i = 0; break; + case T_CHAR : i = 1; break; + case T_BYTE : i = 2; break; + case T_SHORT : i = 3; break; + case T_INT : i = 4; break; + case T_LONG : i = 5; break; + case T_VOID : i = 6; break; + case T_FLOAT : i = 7; break; + case T_DOUBLE : i = 8; break; + case T_OBJECT : i = 9; break; + case T_ARRAY : i = 9; break; + default : ShouldNotReachHere(); + } + assert(0 <= i && i < AbstractInterpreter::number_of_result_handlers, + "index out of bounds"); + return i; +} + +// How much stack a method activation needs in words. +int AbstractInterpreter::size_top_interpreter_activation(Method* method) { + const int entry_size = frame::interpreter_frame_monitor_size(); + + // total overhead size: entry_size + (saved fp thru expr stack + // bottom). be sure to change this if you add/subtract anything + // to/from the overhead area + const int overhead_size = + -(frame::interpreter_frame_initial_sp_offset) + entry_size; + + const int stub_code = frame::entry_frame_after_call_words; + assert_cond(method != NULL); + const int method_stack = (method->max_locals() + method->max_stack()) * + Interpreter::stackElementWords; + return (overhead_size + method_stack + stub_code); +} + +// asm based interpreter deoptimization helpers +int AbstractInterpreter::size_activation(int max_stack, + int temps, + int extra_args, + int monitors, + int callee_params, + int callee_locals, + bool is_top_frame) { + // Note: This calculation must exactly parallel the frame setup + // in TemplateInterpreterGenerator::generate_method_entry. + + // fixed size of an interpreter frame: + int overhead = frame::sender_sp_offset - + frame::interpreter_frame_initial_sp_offset; + // Our locals were accounted for by the caller (or last_frame_adjust + // on the transistion) Since the callee parameters already account + // for the callee's params we only need to account for the extra + // locals. + int size = overhead + + (callee_locals - callee_params) + + monitors * frame::interpreter_frame_monitor_size() + + // On the top frame, at all times SP <= ESP, and SP is + // 16-aligned. We ensure this by adjusting SP on method + // entry and re-entry to allow room for the maximum size of + // the expression stack. When we call another method we bump + // SP so that no stack space is wasted. So, only on the top + // frame do we need to allow max_stack words. + (is_top_frame ? max_stack : temps + extra_args); + + // On riscv we always keep the stack pointer 16-aligned, so we + // must round up here. + size = align_up(size, 2); + + return size; +} + +void AbstractInterpreter::layout_activation(Method* method, + int tempcount, + int popframe_extra_args, + int moncount, + int caller_actual_parameters, + int callee_param_count, + int callee_locals, + frame* caller, + frame* interpreter_frame, + bool is_top_frame, + bool is_bottom_frame) { + // The frame interpreter_frame is guaranteed to be the right size, + // as determined by a previous call to the size_activation() method. + // It is also guaranteed to be walkable even though it is in a + // skeletal state + assert_cond(method != NULL && caller != NULL && interpreter_frame != NULL); + int max_locals = method->max_locals() * Interpreter::stackElementWords; + int extra_locals = (method->max_locals() - method->size_of_parameters()) * + Interpreter::stackElementWords; + +#ifdef ASSERT + assert(caller->sp() == interpreter_frame->sender_sp(), "Frame not properly walkable"); +#endif + + interpreter_frame->interpreter_frame_set_method(method); + // NOTE the difference in using sender_sp and interpreter_frame_sender_sp + // interpreter_frame_sender_sp is the original sp of the caller (the unextended_sp) + // and sender_sp is fp + intptr_t* locals = NULL; + if (caller->is_interpreted_frame()) { + locals = caller->interpreter_frame_last_sp() + caller_actual_parameters - 1; + } else { + locals = interpreter_frame->sender_sp() + max_locals - 1; + } + +#ifdef ASSERT + if (caller->is_interpreted_frame()) { + assert(locals < caller->fp() + frame::interpreter_frame_initial_sp_offset, "bad placement"); + } +#endif + + interpreter_frame->interpreter_frame_set_locals(locals); + BasicObjectLock* montop = interpreter_frame->interpreter_frame_monitor_begin(); + BasicObjectLock* monbot = montop - moncount; + interpreter_frame->interpreter_frame_set_monitor_end(monbot); + + // Set last_sp + intptr_t* last_sp = (intptr_t*) monbot - + tempcount*Interpreter::stackElementWords - + popframe_extra_args; + interpreter_frame->interpreter_frame_set_last_sp(last_sp); + + // All frames but the initial (oldest) interpreter frame we fill in have + // a value for sender_sp that allows walking the stack but isn't + // truly correct. Correct the value here. + if (extra_locals != 0 && + interpreter_frame->sender_sp() == + interpreter_frame->interpreter_frame_sender_sp()) { + interpreter_frame->set_interpreter_frame_sender_sp(caller->sp() + + extra_locals); + } + + *interpreter_frame->interpreter_frame_cache_addr() = + method->constants()->cache(); + *interpreter_frame->interpreter_frame_mirror_addr() = + method->method_holder()->java_mirror(); +} diff --git a/src/hotspot/cpu/riscv/assembler_riscv.cpp b/src/hotspot/cpu/riscv/assembler_riscv.cpp new file mode 100644 index 00000000000..f15ef5304c5 --- /dev/null +++ b/src/hotspot/cpu/riscv/assembler_riscv.cpp @@ -0,0 +1,372 @@ +/* + * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include +#include + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "compiler/disassembler.hpp" +#include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/sharedRuntime.hpp" + +int AbstractAssembler::code_fill_byte() { + return 0; +} + +void Assembler::add(Register Rd, Register Rn, int64_t increment, Register temp) { + if (is_imm_in_range(increment, 12, 0)) { + addi(Rd, Rn, increment); + } else { + assert_different_registers(Rn, temp); + li(temp, increment); + add(Rd, Rn, temp); + } +} + +void Assembler::addw(Register Rd, Register Rn, int64_t increment, Register temp) { + if (is_imm_in_range(increment, 12, 0)) { + addiw(Rd, Rn, increment); + } else { + assert_different_registers(Rn, temp); + li(temp, increment); + addw(Rd, Rn, temp); + } +} + +void Assembler::sub(Register Rd, Register Rn, int64_t decrement, Register temp) { + if (is_imm_in_range(-decrement, 12, 0)) { + addi(Rd, Rn, -decrement); + } else { + assert_different_registers(Rn, temp); + li(temp, decrement); + sub(Rd, Rn, temp); + } +} + +void Assembler::subw(Register Rd, Register Rn, int64_t decrement, Register temp) { + if (is_imm_in_range(-decrement, 12, 0)) { + addiw(Rd, Rn, -decrement); + } else { + assert_different_registers(Rn, temp); + li(temp, decrement); + subw(Rd, Rn, temp); + } +} + +void Assembler::zext_w(Register Rd, Register Rs) { + add_uw(Rd, Rs, zr); +} + +void Assembler::_li(Register Rd, int64_t imm) { + // int64_t is in range 0x8000 0000 0000 0000 ~ 0x7fff ffff ffff ffff + int shift = 12; + int64_t upper = imm, lower = imm; + // Split imm to a lower 12-bit sign-extended part and the remainder, + // because addi will sign-extend the lower imm. + lower = ((int32_t)imm << 20) >> 20; + upper -= lower; + + // Test whether imm is a 32-bit integer. + if (!(((imm) & ~(int64_t)0x7fffffff) == 0 || + (((imm) & ~(int64_t)0x7fffffff) == ~(int64_t)0x7fffffff))) { + while (((upper >> shift) & 1) == 0) { shift++; } + upper >>= shift; + li(Rd, upper); + slli(Rd, Rd, shift); + if (lower != 0) { + addi(Rd, Rd, lower); + } + } else { + // 32-bit integer + Register hi_Rd = zr; + if (upper != 0) { + lui(Rd, (int32_t)upper); + hi_Rd = Rd; + } + if (lower != 0 || hi_Rd == zr) { + addiw(Rd, hi_Rd, lower); + } + } +} + +void Assembler::li64(Register Rd, int64_t imm) { + // Load upper 32 bits. upper = imm[63:32], but if imm[31] == 1 or + // (imm[31:28] == 0x7ff && imm[19] == 1), upper = imm[63:32] + 1. + int64_t lower = imm & 0xffffffff; + lower -= ((lower << 44) >> 44); + int64_t tmp_imm = ((uint64_t)(imm & 0xffffffff00000000)) + (uint64_t)lower; + int32_t upper = (tmp_imm - (int32_t)lower) >> 32; + + // Load upper 32 bits + int64_t up = upper, lo = upper; + lo = (lo << 52) >> 52; + up -= lo; + up = (int32_t)up; + lui(Rd, up); + addi(Rd, Rd, lo); + + // Load the rest 32 bits. + slli(Rd, Rd, 12); + addi(Rd, Rd, (int32_t)lower >> 20); + slli(Rd, Rd, 12); + lower = ((int32_t)imm << 12) >> 20; + addi(Rd, Rd, lower); + slli(Rd, Rd, 8); + lower = imm & 0xff; + addi(Rd, Rd, lower); +} + +void Assembler::li32(Register Rd, int32_t imm) { + // int32_t is in range 0x8000 0000 ~ 0x7fff ffff, and imm[31] is the sign bit + int64_t upper = imm, lower = imm; + lower = (imm << 20) >> 20; + upper -= lower; + upper = (int32_t)upper; + // lui Rd, imm[31:12] + imm[11] + lui(Rd, upper); + // use addiw to distinguish li32 to li64 + addiw(Rd, Rd, lower); +} + +#define INSN(NAME, REGISTER) \ + void Assembler::NAME(const address &dest, Register temp) { \ + assert_cond(dest != NULL); \ + int64_t distance = dest - pc(); \ + if (is_imm_in_range(distance, 20, 1)) { \ + jal(REGISTER, distance); \ + } else { \ + assert(temp != noreg, "temp must not be empty register!"); \ + int32_t offset = 0; \ + movptr_with_offset(temp, dest, offset); \ + jalr(REGISTER, temp, offset); \ + } \ + } \ + void Assembler::NAME(Label &l, Register temp) { \ + jal(REGISTER, l, temp); \ + } \ + + INSN(j, x0); + INSN(jal, x1); + +#undef INSN + +#define INSN(NAME, REGISTER) \ + void Assembler::NAME(Register Rs) { \ + jalr(REGISTER, Rs, 0); \ + } + + INSN(jr, x0); + INSN(jalr, x1); + +#undef INSN + +void Assembler::ret() { + jalr(x0, x1, 0); +} + +#define INSN(NAME, REGISTER) \ + void Assembler::NAME(const address &dest, Register temp) { \ + assert_cond(dest != NULL); \ + assert(temp != noreg, "temp must not be empty register!"); \ + int64_t distance = dest - pc(); \ + if (is_offset_in_range(distance, 32)) { \ + auipc(temp, distance + 0x800); \ + jalr(REGISTER, temp, ((int32_t)distance << 20) >> 20); \ + } else { \ + int32_t offset = 0; \ + movptr_with_offset(temp, dest, offset); \ + jalr(REGISTER, temp, offset); \ + } \ + } + + INSN(call, x1); + INSN(tail, x0); + +#undef INSN + +#define INSN(NAME, REGISTER) \ + void Assembler::NAME(const Address &adr, Register temp) { \ + switch (adr.getMode()) { \ + case Address::literal: { \ + code_section()->relocate(pc(), adr.rspec()); \ + NAME(adr.target(), temp); \ + break; \ + } \ + case Address::base_plus_offset: { \ + int32_t offset = 0; \ + baseOffset(temp, adr, offset); \ + jalr(REGISTER, temp, offset); \ + break; \ + } \ + default: \ + ShouldNotReachHere(); \ + } \ + } + + INSN(j, x0); + INSN(jal, x1); + INSN(call, x1); + INSN(tail, x0); + +#undef INSN + +void Assembler::wrap_label(Register r1, Register r2, Label &L, compare_and_branch_insn insn, + compare_and_branch_label_insn neg_insn, bool is_far) { + if (is_far) { + Label done; + (this->*neg_insn)(r1, r2, done, /* is_far */ false); + j(L); + bind(done); + } else { + if (L.is_bound()) { + (this->*insn)(r1, r2, target(L)); + } else { + L.add_patch_at(code(), locator()); + (this->*insn)(r1, r2, pc()); + } + } +} + +void Assembler::wrap_label(Register Rt, Label &L, Register tmp, load_insn_by_temp insn) { + if (L.is_bound()) { + (this->*insn)(Rt, target(L), tmp); + } else { + L.add_patch_at(code(), locator()); + (this->*insn)(Rt, pc(), tmp); + } +} + +void Assembler::wrap_label(Register Rt, Label &L, jal_jalr_insn insn) { + if (L.is_bound()) { + (this->*insn)(Rt, target(L)); + } else { + L.add_patch_at(code(), locator()); + (this->*insn)(Rt, pc()); + } +} + +void Assembler::movptr_with_offset(Register Rd, address addr, int32_t &offset) { + uintptr_t imm64 = (uintptr_t)addr; +#ifndef PRODUCT + { + char buffer[64]; + snprintf(buffer, sizeof(buffer), "0x%" PRIx64, imm64); + block_comment(buffer); + } +#endif + assert(is_unsigned_imm_in_range(imm64, 47, 0) || (imm64 == (uintptr_t)-1), + "48-bit overflow in address constant"); + // Load upper 32 bits + int32_t imm = imm64 >> 16; + int64_t upper = imm, lower = imm; + lower = (lower << 52) >> 52; + upper -= lower; + upper = (int32_t)upper; + lui(Rd, upper); + addi(Rd, Rd, lower); + + // Load the rest 16 bits. + slli(Rd, Rd, 11); + addi(Rd, Rd, (imm64 >> 5) & 0x7ff); + slli(Rd, Rd, 5); + + // This offset will be used by following jalr/ld. + offset = imm64 & 0x1f; +} + +void Assembler::movptr(Register Rd, uintptr_t imm64) { + movptr(Rd, (address)imm64); +} + +void Assembler::movptr(Register Rd, address addr) { + int offset = 0; + movptr_with_offset(Rd, addr, offset); + addi(Rd, Rd, offset); +} + +void Assembler::ifence() { + fence_i(); + if (UseConservativeFence) { + fence(ir, ir); + } +} + +#define INSN(NAME, NEG_INSN) \ + void Assembler::NAME(Register Rs, Register Rt, const address &dest) { \ + NEG_INSN(Rt, Rs, dest); \ + } \ + void Assembler::NAME(Register Rs, Register Rt, Label &l, bool is_far) { \ + NEG_INSN(Rt, Rs, l, is_far); \ + } + + INSN(bgt, blt); + INSN(ble, bge); + INSN(bgtu, bltu); + INSN(bleu, bgeu); +#undef INSN + +#undef __ + +Address::Address(address target, relocInfo::relocType rtype) : _base(noreg), _offset(0), _mode(literal) { + _target = target; + switch (rtype) { + case relocInfo::oop_type: + case relocInfo::metadata_type: + // Oops are a special case. Normally they would be their own section + // but in cases like icBuffer they are literals in the code stream that + // we don't have a section for. We use none so that we get a literal address + // which is always patchable. + break; + case relocInfo::external_word_type: + _rspec = external_word_Relocation::spec(target); + break; + case relocInfo::internal_word_type: + _rspec = internal_word_Relocation::spec(target); + break; + case relocInfo::opt_virtual_call_type: + _rspec = opt_virtual_call_Relocation::spec(); + break; + case relocInfo::static_call_type: + _rspec = static_call_Relocation::spec(); + break; + case relocInfo::runtime_call_type: + _rspec = runtime_call_Relocation::spec(); + break; + case relocInfo::poll_type: + case relocInfo::poll_return_type: + _rspec = Relocation::spec_simple(rtype); + break; + case relocInfo::none: + _rspec = RelocationHolder::none; + break; + default: + ShouldNotReachHere(); + } +} diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp new file mode 100644 index 00000000000..4923962a496 --- /dev/null +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -0,0 +1,3047 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_ASSEMBLER_RISCV_HPP +#define CPU_RISCV_ASSEMBLER_RISCV_HPP + +#include "asm/register.hpp" +#include "assembler_riscv.inline.hpp" +#include "metaprogramming/enableIf.hpp" + +#define XLEN 64 + +// definitions of various symbolic names for machine registers + +// First intercalls between C and Java which use 8 general registers +// and 8 floating registers + +class Argument { + public: + enum { + n_int_register_parameters_c = 8, // x10, x11, ... x17 (c_rarg0, c_rarg1, ...) + n_float_register_parameters_c = 8, // f10, f11, ... f17 (c_farg0, c_farg1, ... ) + + n_int_register_parameters_j = 8, // x11, ... x17, x10 (j_rarg0, j_rarg1, ...) + n_float_register_parameters_j = 8 // f10, f11, ... f17 (j_farg0, j_farg1, ...) + }; +}; + +// function argument(caller-save registers) +REGISTER_DECLARATION(Register, c_rarg0, x10); +REGISTER_DECLARATION(Register, c_rarg1, x11); +REGISTER_DECLARATION(Register, c_rarg2, x12); +REGISTER_DECLARATION(Register, c_rarg3, x13); +REGISTER_DECLARATION(Register, c_rarg4, x14); +REGISTER_DECLARATION(Register, c_rarg5, x15); +REGISTER_DECLARATION(Register, c_rarg6, x16); +REGISTER_DECLARATION(Register, c_rarg7, x17); + +REGISTER_DECLARATION(FloatRegister, c_farg0, f10); +REGISTER_DECLARATION(FloatRegister, c_farg1, f11); +REGISTER_DECLARATION(FloatRegister, c_farg2, f12); +REGISTER_DECLARATION(FloatRegister, c_farg3, f13); +REGISTER_DECLARATION(FloatRegister, c_farg4, f14); +REGISTER_DECLARATION(FloatRegister, c_farg5, f15); +REGISTER_DECLARATION(FloatRegister, c_farg6, f16); +REGISTER_DECLARATION(FloatRegister, c_farg7, f17); + +// Symbolically name the register arguments used by the Java calling convention. +// We have control over the convention for java so we can do what we please. +// What pleases us is to offset the java calling convention so that when +// we call a suitable jni method the arguments are lined up and we don't +// have to do much shuffling. A suitable jni method is non-static and a +// small number of arguments. +// +// |------------------------------------------------------------------------| +// | c_rarg0 c_rarg1 c_rarg2 c_rarg3 c_rarg4 c_rarg5 c_rarg6 c_rarg7 | +// |------------------------------------------------------------------------| +// | x10 x11 x12 x13 x14 x15 x16 x17 | +// |------------------------------------------------------------------------| +// | j_rarg7 j_rarg0 j_rarg1 j_rarg2 j_rarg3 j_rarg4 j_rarg5 j_rarg6 | +// |------------------------------------------------------------------------| + +REGISTER_DECLARATION(Register, j_rarg0, c_rarg1); +REGISTER_DECLARATION(Register, j_rarg1, c_rarg2); +REGISTER_DECLARATION(Register, j_rarg2, c_rarg3); +REGISTER_DECLARATION(Register, j_rarg3, c_rarg4); +REGISTER_DECLARATION(Register, j_rarg4, c_rarg5); +REGISTER_DECLARATION(Register, j_rarg5, c_rarg6); +REGISTER_DECLARATION(Register, j_rarg6, c_rarg7); +REGISTER_DECLARATION(Register, j_rarg7, c_rarg0); + +// Java floating args are passed as per C + +REGISTER_DECLARATION(FloatRegister, j_farg0, f10); +REGISTER_DECLARATION(FloatRegister, j_farg1, f11); +REGISTER_DECLARATION(FloatRegister, j_farg2, f12); +REGISTER_DECLARATION(FloatRegister, j_farg3, f13); +REGISTER_DECLARATION(FloatRegister, j_farg4, f14); +REGISTER_DECLARATION(FloatRegister, j_farg5, f15); +REGISTER_DECLARATION(FloatRegister, j_farg6, f16); +REGISTER_DECLARATION(FloatRegister, j_farg7, f17); + +// zero rigster +REGISTER_DECLARATION(Register, zr, x0); +// global pointer +REGISTER_DECLARATION(Register, gp, x3); +// thread pointer +REGISTER_DECLARATION(Register, tp, x4); + +// registers used to hold VM data either temporarily within a method +// or across method calls + +// volatile (caller-save) registers + +// current method -- must be in a call-clobbered register +REGISTER_DECLARATION(Register, xmethod, x31); +// return address +REGISTER_DECLARATION(Register, ra, x1); + +// non-volatile (callee-save) registers + +// stack pointer +REGISTER_DECLARATION(Register, sp, x2); +// frame pointer +REGISTER_DECLARATION(Register, fp, x8); +// base of heap +REGISTER_DECLARATION(Register, xheapbase, x27); +// constant pool cache +REGISTER_DECLARATION(Register, xcpool, x26); +// monitors allocated on stack +REGISTER_DECLARATION(Register, xmonitors, x25); +// locals on stack +REGISTER_DECLARATION(Register, xlocals, x24); + +// java thread pointer +REGISTER_DECLARATION(Register, xthread, x23); +// bytecode pointer +REGISTER_DECLARATION(Register, xbcp, x22); +// Dispatch table base +REGISTER_DECLARATION(Register, xdispatch, x21); +// Java stack pointer +REGISTER_DECLARATION(Register, esp, x20); + +// temporary register(caller-save registers) +REGISTER_DECLARATION(Register, t0, x5); +REGISTER_DECLARATION(Register, t1, x6); +REGISTER_DECLARATION(Register, t2, x7); + +const Register g_INTArgReg[Argument::n_int_register_parameters_c] = { + c_rarg0, c_rarg1, c_rarg2, c_rarg3, c_rarg4, c_rarg5, c_rarg6, c_rarg7 +}; + +const FloatRegister g_FPArgReg[Argument::n_float_register_parameters_c] = { + c_farg0, c_farg1, c_farg2, c_farg3, c_farg4, c_farg5, c_farg6, c_farg7 +}; + +#define assert_cond(ARG1) assert(ARG1, #ARG1) + +// Addressing modes +class Address { + public: + + enum mode { no_mode, base_plus_offset, pcrel, literal }; + + private: + Register _base; + Register _index; + int64_t _offset; + enum mode _mode; + + RelocationHolder _rspec; + + // If the target is far we'll need to load the ea of this to a + // register to reach it. Otherwise if near we can do PC-relative + // addressing. + address _target; + + public: + Address() + : _base(noreg), _index(noreg), _offset(0), _mode(no_mode), _target(NULL) { } + Address(Register r) + : _base(r), _index(noreg), _offset(0), _mode(base_plus_offset), _target(NULL) { } + + template::value)> + Address(Register r, T o) + : _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(NULL) {} + + Address(Register r, ByteSize disp) + : Address(r, in_bytes(disp)) {} + Address(address target, RelocationHolder const& rspec) + : _base(noreg), + _index(noreg), + _offset(0), + _mode(literal), + _rspec(rspec), + _target(target) { } + Address(address target, relocInfo::relocType rtype = relocInfo::external_word_type); + + const Register base() const { + guarantee((_mode == base_plus_offset | _mode == pcrel | _mode == literal), "wrong mode"); + return _base; + } + long offset() const { + return _offset; + } + Register index() const { + return _index; + } + mode getMode() const { + return _mode; + } + + bool uses(Register reg) const { return _base == reg; } + const address target() const { return _target; } + const RelocationHolder& rspec() const { return _rspec; } + ~Address() { + _target = NULL; + _base = NULL; + } +}; + +// Convience classes +class RuntimeAddress: public Address { + + public: + + RuntimeAddress(address target) : Address(target, relocInfo::runtime_call_type) {} + ~RuntimeAddress() {} +}; + +class OopAddress: public Address { + + public: + + OopAddress(address target) : Address(target, relocInfo::oop_type) {} + ~OopAddress() {} +}; + +class ExternalAddress: public Address { + private: + static relocInfo::relocType reloc_for_target(address target) { + // Sometimes ExternalAddress is used for values which aren't + // exactly addresses, like the card table base. + // external_word_type can't be used for values in the first page + // so just skip the reloc in that case. + return external_word_Relocation::can_be_relocated(target) ? relocInfo::external_word_type : relocInfo::none; + } + + public: + + ExternalAddress(address target) : Address(target, reloc_for_target(target)) {} + ~ExternalAddress() {} +}; + +class InternalAddress: public Address { + + public: + + InternalAddress(address target) : Address(target, relocInfo::internal_word_type) {} + ~InternalAddress() {} +}; + +class Assembler : public AbstractAssembler { +public: + + enum { instruction_size = 4 }; + + //---< calculate length of instruction >--- + // We just use the values set above. + // instruction must start at passed address + static unsigned int instr_len(unsigned char *instr) { return instruction_size; } + + //---< longest instructions >--- + static unsigned int instr_maxlen() { return instruction_size; } + + enum RoundingMode { + rne = 0b000, // round to Nearest, ties to Even + rtz = 0b001, // round towards Zero + rdn = 0b010, // round Down (towards eegative infinity) + rup = 0b011, // round Up (towards infinity) + rmm = 0b100, // round to Nearest, ties to Max Magnitude + rdy = 0b111, // in instruction's rm field, selects dynamic rounding mode.In Rounding Mode register, Invalid. + }; + + void baseOffset32(Register Rd, const Address &adr, int32_t &offset) { + assert(Rd != noreg, "Rd must not be empty register!"); + guarantee(Rd != adr.base(), "should use different registers!"); + if (is_offset_in_range(adr.offset(), 32)) { + int32_t imm = adr.offset(); + int32_t upper = imm, lower = imm; + lower = (imm << 20) >> 20; + upper -= lower; + lui(Rd, upper); + offset = lower; + } else { + movptr_with_offset(Rd, (address)(uintptr_t)adr.offset(), offset); + } + add(Rd, Rd, adr.base()); + } + + void baseOffset(Register Rd, const Address &adr, int32_t &offset) { + if (is_offset_in_range(adr.offset(), 12)) { + assert(Rd != noreg, "Rd must not be empty register!"); + addi(Rd, adr.base(), adr.offset()); + offset = 0; + } else { + baseOffset32(Rd, adr, offset); + } + } + + void _li(Register Rd, int64_t imm); // optimized load immediate + void li32(Register Rd, int32_t imm); + void li64(Register Rd, int64_t imm); + void movptr(Register Rd, address addr); + void movptr_with_offset(Register Rd, address addr, int32_t &offset); + void movptr(Register Rd, uintptr_t imm64); + void ifence(); + void j(const address &dest, Register temp = t0); + void j(const Address &adr, Register temp = t0); + void j(Label &l, Register temp = t0); + void jal(Label &l, Register temp = t0); + void jal(const address &dest, Register temp = t0); + void jal(const Address &adr, Register temp = t0); + void jr(Register Rs); + void jalr(Register Rs); + void ret(); + void call(const address &dest, Register temp = t0); + void call(const Address &adr, Register temp = t0); + void tail(const address &dest, Register temp = t0); + void tail(const Address &adr, Register temp = t0); + void call(Label &l, Register temp) { + call(target(l), temp); + } + void tail(Label &l, Register temp) { + tail(target(l), temp); + } + + static inline uint32_t extract(uint32_t val, unsigned msb, unsigned lsb) { + assert_cond(msb >= lsb && msb <= 31); + unsigned nbits = msb - lsb + 1; + uint32_t mask = (1U << nbits) - 1; + uint32_t result = val >> lsb; + result &= mask; + return result; + } + + static inline int32_t sextract(uint32_t val, unsigned msb, unsigned lsb) { + assert_cond(msb >= lsb && msb <= 31); + int32_t result = val << (31 - msb); + result >>= (31 - msb + lsb); + return result; + } + + static void patch(address a, unsigned msb, unsigned lsb, unsigned val) { + assert_cond(a != NULL); + assert_cond(msb >= lsb && msb <= 31); + unsigned nbits = msb - lsb + 1; + guarantee(val < (1U << nbits), "Field too big for insn"); + unsigned mask = (1U << nbits) - 1; + val <<= lsb; + mask <<= lsb; + unsigned target = *(unsigned *)a; + target &= ~mask; + target |= val; + *(unsigned *)a = target; + } + + static void patch(address a, unsigned bit, unsigned val) { + patch(a, bit, bit, val); + } + + static void patch_reg(address a, unsigned lsb, Register reg) { + patch(a, lsb + 4, lsb, reg->encoding_nocheck()); + } + + static void patch_reg(address a, unsigned lsb, FloatRegister reg) { + patch(a, lsb + 4, lsb, reg->encoding_nocheck()); + } + + static void patch_reg(address a, unsigned lsb, VectorRegister reg) { + patch(a, lsb + 4, lsb, reg->encoding_nocheck()); + } + + void emit(unsigned insn) { + emit_int32((jint)insn); + } + + void _halt() { + emit_int32(0); + } + +// Register Instruction +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + emit(insn); \ + } + + INSN(_add, 0b0110011, 0b000, 0b0000000); + INSN(_sub, 0b0110011, 0b000, 0b0100000); + INSN(_andr, 0b0110011, 0b111, 0b0000000); + INSN(_orr, 0b0110011, 0b110, 0b0000000); + INSN(_xorr, 0b0110011, 0b100, 0b0000000); + INSN(sll, 0b0110011, 0b001, 0b0000000); + INSN(sra, 0b0110011, 0b101, 0b0100000); + INSN(srl, 0b0110011, 0b101, 0b0000000); + INSN(slt, 0b0110011, 0b010, 0b0000000); + INSN(sltu, 0b0110011, 0b011, 0b0000000); + INSN(_addw, 0b0111011, 0b000, 0b0000000); + INSN(_subw, 0b0111011, 0b000, 0b0100000); + INSN(sllw, 0b0111011, 0b001, 0b0000000); + INSN(sraw, 0b0111011, 0b101, 0b0100000); + INSN(srlw, 0b0111011, 0b101, 0b0000000); + INSN(mul, 0b0110011, 0b000, 0b0000001); + INSN(mulh, 0b0110011, 0b001, 0b0000001); + INSN(mulhsu,0b0110011, 0b010, 0b0000001); + INSN(mulhu, 0b0110011, 0b011, 0b0000001); + INSN(mulw, 0b0111011, 0b000, 0b0000001); + INSN(div, 0b0110011, 0b100, 0b0000001); + INSN(divu, 0b0110011, 0b101, 0b0000001); + INSN(divw, 0b0111011, 0b100, 0b0000001); + INSN(divuw, 0b0111011, 0b101, 0b0000001); + INSN(rem, 0b0110011, 0b110, 0b0000001); + INSN(remu, 0b0110011, 0b111, 0b0000001); + INSN(remw, 0b0111011, 0b110, 0b0000001); + INSN(remuw, 0b0111011, 0b111, 0b0000001); + +#undef INSN + +#define INSN_ENTRY_RELOC(result_type, header) \ + result_type header { \ + InstructionMark im(this); \ + guarantee(rtype == relocInfo::internal_word_type, \ + "only internal_word_type relocs make sense here"); \ + code_section()->relocate(inst_mark(), InternalAddress(dest).rspec()); + + // Load/store register (all modes) +#define INSN(NAME, op, funct3) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + unsigned insn = 0; \ + int32_t val = offset & 0xfff; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 15, Rs); \ + patch_reg((address)&insn, 7, Rd); \ + patch((address)&insn, 31, 20, val); \ + emit(insn); \ + } + + INSN(lb, 0b0000011, 0b000); + INSN(lbu, 0b0000011, 0b100); + INSN(lh, 0b0000011, 0b001); + INSN(lhu, 0b0000011, 0b101); + INSN(_lw, 0b0000011, 0b010); + INSN(lwu, 0b0000011, 0b110); + INSN(_ld, 0b0000011, 0b011); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, address dest) { \ + assert_cond(dest != NULL); \ + int64_t distance = (dest - pc()); \ + if (is_offset_in_range(distance, 32)) { \ + auipc(Rd, (int32_t)distance + 0x800); \ + NAME(Rd, Rd, ((int32_t)distance << 20) >> 20); \ + } else { \ + int32_t offset = 0; \ + movptr_with_offset(Rd, dest, offset); \ + NAME(Rd, Rd, offset); \ + } \ + } \ + INSN_ENTRY_RELOC(void, NAME(Register Rd, address dest, relocInfo::relocType rtype)) \ + NAME(Rd, dest); \ + } \ + void NAME(Register Rd, const Address &adr, Register temp = t0) { \ + switch (adr.getMode()) { \ + case Address::literal: { \ + code_section()->relocate(pc(), adr.rspec()); \ + NAME(Rd, adr.target()); \ + break; \ + } \ + case Address::base_plus_offset: { \ + if (is_offset_in_range(adr.offset(), 12)) { \ + NAME(Rd, adr.base(), adr.offset()); \ + } else { \ + int32_t offset = 0; \ + if (Rd == adr.base()) { \ + baseOffset32(temp, adr, offset); \ + NAME(Rd, temp, offset); \ + } else { \ + baseOffset32(Rd, adr, offset); \ + NAME(Rd, Rd, offset); \ + } \ + } \ + break; \ + } \ + default: \ + ShouldNotReachHere(); \ + } \ + } \ + void NAME(Register Rd, Label &L) { \ + wrap_label(Rd, L, &Assembler::NAME); \ + } + + INSN(lb); + INSN(lbu); + INSN(lh); + INSN(lhu); + INSN(lw); + INSN(lwu); + INSN(ld); + +#undef INSN + +#define INSN(NAME, op, funct3) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + unsigned insn = 0; \ + uint32_t val = offset & 0xfff; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 15, Rs); \ + patch_reg((address)&insn, 7, Rd); \ + patch((address)&insn, 31, 20, val); \ + emit(insn); \ + } + + INSN(flw, 0b0000111, 0b010); + INSN(_fld, 0b0000111, 0b011); + +#undef INSN + +#define INSN(NAME) \ + void NAME(FloatRegister Rd, address dest, Register temp = t0) { \ + assert_cond(dest != NULL); \ + int64_t distance = (dest - pc()); \ + if (is_offset_in_range(distance, 32)) { \ + auipc(temp, (int32_t)distance + 0x800); \ + NAME(Rd, temp, ((int32_t)distance << 20) >> 20); \ + } else { \ + int32_t offset = 0; \ + movptr_with_offset(temp, dest, offset); \ + NAME(Rd, temp, offset); \ + } \ + } \ + INSN_ENTRY_RELOC(void, NAME(FloatRegister Rd, address dest, relocInfo::relocType rtype, Register temp = t0)) \ + NAME(Rd, dest, temp); \ + } \ + void NAME(FloatRegister Rd, const Address &adr, Register temp = t0) { \ + switch (adr.getMode()) { \ + case Address::literal: { \ + code_section()->relocate(pc(), adr.rspec()); \ + NAME(Rd, adr.target(), temp); \ + break; \ + } \ + case Address::base_plus_offset: { \ + if (is_offset_in_range(adr.offset(), 12)) { \ + NAME(Rd, adr.base(), adr.offset()); \ + } else { \ + int32_t offset = 0; \ + baseOffset32(temp, adr, offset); \ + NAME(Rd, temp, offset); \ + } \ + break; \ + } \ + default: \ + ShouldNotReachHere(); \ + } \ + } + + INSN(flw); + INSN(fld); +#undef INSN + +#define INSN(NAME, op, funct3) \ + void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ + guarantee(is_imm_in_range(offset, 12, 1), "offset is invalid."); \ + unsigned insn = 0; \ + uint32_t val = offset & 0x1fff; \ + uint32_t val11 = (val >> 11) & 0x1; \ + uint32_t val12 = (val >> 12) & 0x1; \ + uint32_t low = (val >> 1) & 0xf; \ + uint32_t high = (val >> 5) & 0x3f; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + patch((address)&insn, 7, val11); \ + patch((address)&insn, 11, 8, low); \ + patch((address)&insn, 30, 25, high); \ + patch((address)&insn, 31, val12); \ + emit(insn); \ + } + + INSN(_beq, 0b1100011, 0b000); + INSN(_bne, 0b1100011, 0b001); + INSN(bge, 0b1100011, 0b101); + INSN(bgeu, 0b1100011, 0b111); + INSN(blt, 0b1100011, 0b100); + INSN(bltu, 0b1100011, 0b110); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rs1, Register Rs2, const address dest) { \ + assert_cond(dest != NULL); \ + int64_t offset = (dest - pc()); \ + guarantee(is_imm_in_range(offset, 12, 1), "offset is invalid."); \ + NAME(Rs1, Rs2, offset); \ + } \ + INSN_ENTRY_RELOC(void, NAME(Register Rs1, Register Rs2, address dest, relocInfo::relocType rtype)) \ + NAME(Rs1, Rs2, dest); \ + } + + INSN(beq); + INSN(bne); + INSN(bge); + INSN(bgeu); + INSN(blt); + INSN(bltu); + +#undef INSN + +#define INSN(NAME, NEG_INSN) \ + void NAME(Register Rs1, Register Rs2, Label &L, bool is_far = false) { \ + wrap_label(Rs1, Rs2, L, &Assembler::NAME, &Assembler::NEG_INSN, is_far); \ + } + + INSN(beq, bne); + INSN(bne, beq); + INSN(blt, bge); + INSN(bge, blt); + INSN(bltu, bgeu); + INSN(bgeu, bltu); + +#undef INSN + +#define INSN(NAME, REGISTER, op, funct3) \ + void NAME(REGISTER Rs1, Register Rs2, const int32_t offset) { \ + guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + unsigned insn = 0; \ + uint32_t val = offset & 0xfff; \ + uint32_t low = val & 0x1f; \ + uint32_t high = (val >> 5) & 0x7f; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 15, Rs2); \ + patch_reg((address)&insn, 20, Rs1); \ + patch((address)&insn, 11, 7, low); \ + patch((address)&insn, 31, 25, high); \ + emit(insn); \ + } \ + + INSN(sb, Register, 0b0100011, 0b000); + INSN(sh, Register, 0b0100011, 0b001); + INSN(_sw, Register, 0b0100011, 0b010); + INSN(_sd, Register, 0b0100011, 0b011); + INSN(fsw, FloatRegister, 0b0100111, 0b010); + INSN(_fsd, FloatRegister, 0b0100111, 0b011); + +#undef INSN + +#define INSN(NAME, REGISTER) \ + INSN_ENTRY_RELOC(void, NAME(REGISTER Rs, address dest, relocInfo::relocType rtype, Register temp = t0)) \ + NAME(Rs, dest, temp); \ + } + + INSN(sb, Register); + INSN(sh, Register); + INSN(sw, Register); + INSN(sd, Register); + INSN(fsw, FloatRegister); + INSN(fsd, FloatRegister); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rs, address dest, Register temp = t0) { \ + assert_cond(dest != NULL); \ + assert_different_registers(Rs, temp); \ + int64_t distance = (dest - pc()); \ + if (is_offset_in_range(distance, 32)) { \ + auipc(temp, (int32_t)distance + 0x800); \ + NAME(Rs, temp, ((int32_t)distance << 20) >> 20); \ + } else { \ + int32_t offset = 0; \ + movptr_with_offset(temp, dest, offset); \ + NAME(Rs, temp, offset); \ + } \ + } \ + void NAME(Register Rs, const Address &adr, Register temp = t0) { \ + switch (adr.getMode()) { \ + case Address::literal: { \ + assert_different_registers(Rs, temp); \ + code_section()->relocate(pc(), adr.rspec()); \ + NAME(Rs, adr.target(), temp); \ + break; \ + } \ + case Address::base_plus_offset: { \ + if (is_offset_in_range(adr.offset(), 12)) { \ + NAME(Rs, adr.base(), adr.offset()); \ + } else { \ + int32_t offset= 0; \ + assert_different_registers(Rs, temp); \ + baseOffset32(temp, adr, offset); \ + NAME(Rs, temp, offset); \ + } \ + break; \ + } \ + default: \ + ShouldNotReachHere(); \ + } \ + } + + INSN(sb); + INSN(sh); + INSN(sw); + INSN(sd); + +#undef INSN + +#define INSN(NAME) \ + void NAME(FloatRegister Rs, address dest, Register temp = t0) { \ + assert_cond(dest != NULL); \ + int64_t distance = (dest - pc()); \ + if (is_offset_in_range(distance, 32)) { \ + auipc(temp, (int32_t)distance + 0x800); \ + NAME(Rs, temp, ((int32_t)distance << 20) >> 20); \ + } else { \ + int32_t offset = 0; \ + movptr_with_offset(temp, dest, offset); \ + NAME(Rs, temp, offset); \ + } \ + } \ + void NAME(FloatRegister Rs, const Address &adr, Register temp = t0) { \ + switch (adr.getMode()) { \ + case Address::literal: { \ + code_section()->relocate(pc(), adr.rspec()); \ + NAME(Rs, adr.target(), temp); \ + break; \ + } \ + case Address::base_plus_offset: { \ + if (is_offset_in_range(adr.offset(), 12)) { \ + NAME(Rs, adr.base(), adr.offset()); \ + } else { \ + int32_t offset = 0; \ + baseOffset32(temp, adr, offset); \ + NAME(Rs, temp, offset); \ + } \ + break; \ + } \ + default: \ + ShouldNotReachHere(); \ + } \ + } + + INSN(fsw); + INSN(fsd); + +#undef INSN + +#define INSN(NAME, op, funct3) \ + void NAME(Register Rd, const uint32_t csr, Register Rs1) { \ + guarantee(is_unsigned_imm_in_range(csr, 12, 0), "csr is invalid"); \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch((address)&insn, 31, 20, csr); \ + emit(insn); \ + } + + INSN(csrrw, 0b1110011, 0b001); + INSN(csrrs, 0b1110011, 0b010); + INSN(csrrc, 0b1110011, 0b011); + +#undef INSN + +#define INSN(NAME, op, funct3) \ + void NAME(Register Rd, const uint32_t csr, const uint32_t uimm) { \ + guarantee(is_unsigned_imm_in_range(csr, 12, 0), "csr is invalid"); \ + guarantee(is_unsigned_imm_in_range(uimm, 5, 0), "uimm is invalid"); \ + unsigned insn = 0; \ + uint32_t val = uimm & 0x1f; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 7, Rd); \ + patch((address)&insn, 19, 15, val); \ + patch((address)&insn, 31, 20, csr); \ + emit(insn); \ + } + + INSN(csrrwi, 0b1110011, 0b101); + INSN(csrrsi, 0b1110011, 0b110); + INSN(csrrci, 0b1110011, 0b111); + +#undef INSN + +#define INSN(NAME, op) \ + void NAME(Register Rd, const int32_t offset) { \ + guarantee(is_imm_in_range(offset, 20, 1), "offset is invalid."); \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch_reg((address)&insn, 7, Rd); \ + patch((address)&insn, 19, 12, (uint32_t)((offset >> 12) & 0xff)); \ + patch((address)&insn, 20, (uint32_t)((offset >> 11) & 0x1)); \ + patch((address)&insn, 30, 21, (uint32_t)((offset >> 1) & 0x3ff)); \ + patch((address)&insn, 31, (uint32_t)((offset >> 20) & 0x1)); \ + emit(insn); \ + } + + INSN(_jal, 0b1101111); + +#undef INSN + +#define INSN(NAME) \ + void NAME(Register Rd, const address dest, Register temp = t0) { \ + assert_cond(dest != NULL); \ + int64_t offset = dest - pc(); \ + if (is_imm_in_range(offset, 20, 1)) { \ + NAME(Rd, offset); \ + } else { \ + assert_different_registers(Rd, temp); \ + int32_t off = 0; \ + movptr_with_offset(temp, dest, off); \ + jalr(Rd, temp, off); \ + } \ + } \ + void NAME(Register Rd, Label &L, Register temp = t0) { \ + assert_different_registers(Rd, temp); \ + wrap_label(Rd, L, temp, &Assembler::NAME); \ + } + + INSN(jal); + +#undef INSN + +#undef INSN_ENTRY_RELOC + +#define INSN(NAME, op, funct) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + guarantee(is_offset_in_range(offset, 12), "offset is invalid."); \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch_reg((address)&insn, 7, Rd); \ + patch((address)&insn, 14, 12, funct); \ + patch_reg((address)&insn, 15, Rs); \ + int32_t val = offset & 0xfff; \ + patch((address)&insn, 31, 20, val); \ + emit(insn); \ + } + + INSN(_jalr, 0b1100111, 0b000); + +#undef INSN + + enum barrier { + i = 0b1000, o = 0b0100, r = 0b0010, w = 0b0001, + ir = i | r, ow = o | w, iorw = i | o | r | w + }; + + void fence(const uint32_t predecessor, const uint32_t successor) { + unsigned insn = 0; + guarantee(predecessor < 16, "predecessor is invalid"); + guarantee(successor < 16, "successor is invalid"); + patch((address)&insn, 6, 0, 0b001111); + patch((address)&insn, 11, 7, 0b00000); + patch((address)&insn, 14, 12, 0b000); + patch((address)&insn, 19, 15, 0b00000); + patch((address)&insn, 23, 20, successor); + patch((address)&insn, 27, 24, predecessor); + patch((address)&insn, 31, 28, 0b0000); + emit(insn); + } + +#define INSN(NAME, op, funct3, funct7) \ + void NAME() { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 11, 7, 0b00000); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 19, 15, 0b00000); \ + patch((address)&insn, 31, 20, funct7); \ + emit(insn); \ + } + + INSN(fence_i, 0b0001111, 0b001, 0b000000000000); + INSN(ecall, 0b1110011, 0b000, 0b000000000000); + INSN(_ebreak, 0b1110011, 0b000, 0b000000000001); + +#undef INSN + +enum Aqrl {relaxed = 0b00, rl = 0b01, aq = 0b10, aqrl = 0b11}; + +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = aqrl) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + patch((address)&insn, 31, 27, funct7); \ + patch((address)&insn, 26, 25, memory_order); \ + emit(insn); \ + } + + INSN(amoswap_w, 0b0101111, 0b010, 0b00001); + INSN(amoadd_w, 0b0101111, 0b010, 0b00000); + INSN(amoxor_w, 0b0101111, 0b010, 0b00100); + INSN(amoand_w, 0b0101111, 0b010, 0b01100); + INSN(amoor_w, 0b0101111, 0b010, 0b01000); + INSN(amomin_w, 0b0101111, 0b010, 0b10000); + INSN(amomax_w, 0b0101111, 0b010, 0b10100); + INSN(amominu_w, 0b0101111, 0b010, 0b11000); + INSN(amomaxu_w, 0b0101111, 0b010, 0b11100); + INSN(amoswap_d, 0b0101111, 0b011, 0b00001); + INSN(amoadd_d, 0b0101111, 0b011, 0b00000); + INSN(amoxor_d, 0b0101111, 0b011, 0b00100); + INSN(amoand_d, 0b0101111, 0b011, 0b01100); + INSN(amoor_d, 0b0101111, 0b011, 0b01000); + INSN(amomin_d, 0b0101111, 0b011, 0b10000); + INSN(amomax_d , 0b0101111, 0b011, 0b10100); + INSN(amominu_d, 0b0101111, 0b011, 0b11000); + INSN(amomaxu_d, 0b0101111, 0b011, 0b11100); +#undef INSN + +enum operand_size { int8, int16, int32, uint32, int64 }; + +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, Register Rs1, Aqrl memory_order = relaxed) { \ + unsigned insn = 0; \ + uint32_t val = memory_order & 0x3; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch((address)&insn, 25, 20, 0b00000); \ + patch((address)&insn, 31, 27, funct7); \ + patch((address)&insn, 26, 25, val); \ + emit(insn); \ + } + + INSN(lr_w, 0b0101111, 0b010, 0b00010); + INSN(lr_d, 0b0101111, 0b011, 0b00010); + +#undef INSN + +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, Register Rs1, Register Rs2, Aqrl memory_order = relaxed) { \ + unsigned insn = 0; \ + uint32_t val = memory_order & 0x3; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs2); \ + patch_reg((address)&insn, 20, Rs1); \ + patch((address)&insn, 31, 27, funct7); \ + patch((address)&insn, 26, 25, val); \ + emit(insn); \ + } + + INSN(sc_w, 0b0101111, 0b010, 0b00011); + INSN(sc_d, 0b0101111, 0b011, 0b00011); +#undef INSN + +#define INSN(NAME, op, funct5, funct7) \ + void NAME(FloatRegister Rd, FloatRegister Rs1, RoundingMode rm = rne) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, rm); \ + patch((address)&insn, 24, 20, funct5); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(fsqrt_s, 0b1010011, 0b00000, 0b0101100); + INSN(fsqrt_d, 0b1010011, 0b00000, 0b0101101); + INSN(fcvt_s_d, 0b1010011, 0b00001, 0b0100000); + INSN(fcvt_d_s, 0b1010011, 0b00000, 0b0100001); +#undef INSN + +// Immediate Instruction +#define INSN(NAME, op, funct3) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + guarantee(is_imm_in_range(imm, 12, 0), "Immediate is out of validity"); \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 31, 20, imm & 0x00000fff); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(_addi, 0b0010011, 0b000); + INSN(slti, 0b0010011, 0b010); + INSN(_addiw, 0b0011011, 0b000); + INSN(_and_imm12, 0b0010011, 0b111); + INSN(ori, 0b0010011, 0b110); + INSN(xori, 0b0010011, 0b100); + +#undef INSN + +#define INSN(NAME, op, funct3) \ + void NAME(Register Rd, Register Rs1, uint32_t imm) { \ + guarantee(is_unsigned_imm_in_range(imm, 12, 0), "Immediate is out of validity"); \ + unsigned insn = 0; \ + patch((address)&insn,6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 31, 20, imm & 0x00000fff); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(sltiu, 0b0010011, 0b011); + +#undef INSN + +// Shift Immediate Instruction +#define INSN(NAME, op, funct3, funct6) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + guarantee(shamt <= 0x3f, "Shamt is invalid"); \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 25, 20, shamt); \ + patch((address)&insn, 31, 26, funct6); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(_slli, 0b0010011, 0b001, 0b000000); + INSN(_srai, 0b0010011, 0b101, 0b010000); + INSN(_srli, 0b0010011, 0b101, 0b000000); + +#undef INSN + +// Shift Word Immediate Instruction +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + guarantee(shamt <= 0x1f, "Shamt is invalid"); \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 24, 20, shamt); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(slliw, 0b0011011, 0b001, 0b0000000); + INSN(sraiw, 0b0011011, 0b101, 0b0100000); + INSN(srliw, 0b0011011, 0b101, 0b0000000); + +#undef INSN + +// Upper Immediate Instruction +#define INSN(NAME, op) \ + void NAME(Register Rd, int32_t imm) { \ + int32_t upperImm = imm >> 12; \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch_reg((address)&insn, 7, Rd); \ + upperImm &= 0x000fffff; \ + patch((address)&insn, 31, 12, upperImm); \ + emit(insn); \ + } + + INSN(_lui, 0b0110111); + INSN(auipc, 0b0010111); + +#undef INSN + +// Float and Double Rigster Instruction +#define INSN(NAME, op, funct2) \ + void NAME(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, FloatRegister Rs3, RoundingMode rm = rne) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, rm); \ + patch((address)&insn, 26, 25, funct2); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + patch_reg((address)&insn, 27, Rs3); \ + emit(insn); \ + } + + INSN(fmadd_s, 0b1000011, 0b00); + INSN(fmsub_s, 0b1000111, 0b00); + INSN(fnmsub_s, 0b1001011, 0b00); + INSN(fnmadd_s, 0b1001111, 0b00); + INSN(fmadd_d, 0b1000011, 0b01); + INSN(fmsub_d, 0b1000111, 0b01); + INSN(fnmsub_d, 0b1001011, 0b01); + INSN(fnmadd_d, 0b1001111, 0b01); + +#undef INSN + +// Float and Double Rigster Instruction +#define INSN(NAME, op, funct3, funct7) \ + void NAME(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + emit(insn); \ + } + + INSN(fsgnj_s, 0b1010011, 0b000, 0b0010000); + INSN(fsgnjn_s, 0b1010011, 0b001, 0b0010000); + INSN(fsgnjx_s, 0b1010011, 0b010, 0b0010000); + INSN(fmin_s, 0b1010011, 0b000, 0b0010100); + INSN(fmax_s, 0b1010011, 0b001, 0b0010100); + INSN(fsgnj_d, 0b1010011, 0b000, 0b0010001); + INSN(fsgnjn_d, 0b1010011, 0b001, 0b0010001); + INSN(fsgnjx_d, 0b1010011, 0b010, 0b0010001); + INSN(fmin_d, 0b1010011, 0b000, 0b0010101); + INSN(fmax_d, 0b1010011, 0b001, 0b0010101); + +#undef INSN + +// Float and Double Rigster Arith Instruction +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, FloatRegister Rs1, FloatRegister Rs2) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + emit(insn); \ + } + + INSN(feq_s, 0b1010011, 0b010, 0b1010000); + INSN(flt_s, 0b1010011, 0b001, 0b1010000); + INSN(fle_s, 0b1010011, 0b000, 0b1010000); + INSN(feq_d, 0b1010011, 0b010, 0b1010001); + INSN(fle_d, 0b1010011, 0b000, 0b1010001); + INSN(flt_d, 0b1010011, 0b001, 0b1010001); +#undef INSN + +// Float and Double Arith Instruction +#define INSN(NAME, op, funct7) \ + void NAME(FloatRegister Rd, FloatRegister Rs1, FloatRegister Rs2, RoundingMode rm = rne) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, rm); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + emit(insn); \ + } + + INSN(fadd_s, 0b1010011, 0b0000000); + INSN(fsub_s, 0b1010011, 0b0000100); + INSN(fmul_s, 0b1010011, 0b0001000); + INSN(fdiv_s, 0b1010011, 0b0001100); + INSN(fadd_d, 0b1010011, 0b0000001); + INSN(fsub_d, 0b1010011, 0b0000101); + INSN(fmul_d, 0b1010011, 0b0001001); + INSN(fdiv_d, 0b1010011, 0b0001101); + +#undef INSN + +// Whole Float and Double Conversion Instruction +#define INSN(NAME, op, funct5, funct7) \ + void NAME(FloatRegister Rd, Register Rs1, RoundingMode rm = rne) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, rm); \ + patch((address)&insn, 24, 20, funct5); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(fcvt_s_w, 0b1010011, 0b00000, 0b1101000); + INSN(fcvt_s_wu, 0b1010011, 0b00001, 0b1101000); + INSN(fcvt_s_l, 0b1010011, 0b00010, 0b1101000); + INSN(fcvt_s_lu, 0b1010011, 0b00011, 0b1101000); + INSN(fcvt_d_w, 0b1010011, 0b00000, 0b1101001); + INSN(fcvt_d_wu, 0b1010011, 0b00001, 0b1101001); + INSN(fcvt_d_l, 0b1010011, 0b00010, 0b1101001); + INSN(fcvt_d_lu, 0b1010011, 0b00011, 0b1101001); + +#undef INSN + +// Float and Double Conversion Instruction +#define INSN(NAME, op, funct5, funct7) \ + void NAME(Register Rd, FloatRegister Rs1, RoundingMode rm = rtz) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, rm); \ + patch((address)&insn, 24, 20, funct5); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(fcvt_w_s, 0b1010011, 0b00000, 0b1100000); + INSN(fcvt_l_s, 0b1010011, 0b00010, 0b1100000); + INSN(fcvt_wu_s, 0b1010011, 0b00001, 0b1100000); + INSN(fcvt_lu_s, 0b1010011, 0b00011, 0b1100000); + INSN(fcvt_w_d, 0b1010011, 0b00000, 0b1100001); + INSN(fcvt_wu_d, 0b1010011, 0b00001, 0b1100001); + INSN(fcvt_l_d, 0b1010011, 0b00010, 0b1100001); + INSN(fcvt_lu_d, 0b1010011, 0b00011, 0b1100001); + +#undef INSN + +// Float and Double Move Instruction +#define INSN(NAME, op, funct3, funct5, funct7) \ + void NAME(FloatRegister Rd, Register Rs1) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 20, funct5); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(fmv_w_x, 0b1010011, 0b000, 0b00000, 0b1111000); + INSN(fmv_d_x, 0b1010011, 0b000, 0b00000, 0b1111001); + +#undef INSN + +// Float and Double Conversion Instruction +#define INSN(NAME, op, funct3, funct5, funct7) \ + void NAME(Register Rd, FloatRegister Rs1) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 20, funct5); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(fclass_s, 0b1010011, 0b001, 0b00000, 0b1110000); + INSN(fclass_d, 0b1010011, 0b001, 0b00000, 0b1110001); + INSN(fmv_x_w, 0b1010011, 0b000, 0b00000, 0b1110000); + INSN(fmv_x_d, 0b1010011, 0b000, 0b00000, 0b1110001); + +#undef INSN + +// ========================== +// RISC-V Vector Extension +// ========================== +enum SEW { + e8, + e16, + e32, + e64, + RESERVED, +}; + +enum LMUL { + mf8 = 0b101, + mf4 = 0b110, + mf2 = 0b111, + m1 = 0b000, + m2 = 0b001, + m4 = 0b010, + m8 = 0b011, +}; + +enum VMA { + mu, // undisturbed + ma, // agnostic +}; + +enum VTA { + tu, // undisturbed + ta, // agnostic +}; + +static Assembler::SEW elembytes_to_sew(int ebytes) { + assert(ebytes > 0 && ebytes <= 8, "unsupported element size"); + return (Assembler::SEW) exact_log2(ebytes); +} + +static Assembler::SEW elemtype_to_sew(BasicType etype) { + return Assembler::elembytes_to_sew(type2aelembytes(etype)); +} + +#define patch_vtype(hsb, lsb, vlmul, vsew, vta, vma, vill) \ + if (vill == 1) { \ + guarantee((vlmul | vsew | vta | vma == 0), \ + "the other bits in vtype shall be zero"); \ + } \ + patch((address)&insn, lsb + 2, lsb, vlmul); \ + patch((address)&insn, lsb + 5, lsb + 3, vsew); \ + patch((address)&insn, lsb + 6, vta); \ + patch((address)&insn, lsb + 7, vma); \ + patch((address)&insn, hsb - 1, lsb + 8, 0); \ + patch((address)&insn, hsb, vill) + +#define INSN(NAME, op, funct3) \ + void NAME(Register Rd, Register Rs1, SEW sew, LMUL lmul = m1, \ + VMA vma = mu, VTA vta = tu, bool vill = false) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch_vtype(30, 20, lmul, sew, vta, vma, vill); \ + patch((address)&insn, 31, 0); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(vsetvli, 0b1010111, 0b111); + +#undef INSN + +#define INSN(NAME, op, funct3) \ + void NAME(Register Rd, uint32_t imm, SEW sew, LMUL lmul = m1, \ + VMA vma = mu, VTA vta = tu, bool vill = false) { \ + unsigned insn = 0; \ + guarantee(is_unsigned_imm_in_range(imm, 5, 0), "imm is invalid"); \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 19, 15, imm); \ + patch_vtype(29, 20, lmul, sew, vta, vma, vill); \ + patch((address)&insn, 31, 30, 0b11); \ + patch_reg((address)&insn, 7, Rd); \ + emit(insn); \ + } + + INSN(vsetivli, 0b1010111, 0b111); + +#undef INSN + +#undef patch_vtype + +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + emit(insn); \ + } + + // Vector Configuration Instruction + INSN(vsetvl, 0b1010111, 0b111, 0b1000000); + +#undef INSN + +enum VectorMask { + v0_t = 0b0, + unmasked = 0b1 +}; + +#define patch_VArith(op, Reg, funct3, Reg_or_Imm5, Vs2, vm, funct6) \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 19, 15, Reg_or_Imm5); \ + patch((address)&insn, 25, vm); \ + patch((address)&insn, 31, 26, funct6); \ + patch_reg((address)&insn, 7, Reg); \ + patch_reg((address)&insn, 20, Vs2); \ + emit(insn) + +// r2_vm +#define INSN(NAME, op, funct3, Vs1, funct6) \ + void NAME(Register Rd, VectorRegister Vs2, VectorMask vm = unmasked) { \ + patch_VArith(op, Rd, funct3, Vs1, Vs2, vm, funct6); \ + } + + // Vector Mask + INSN(vpopc_m, 0b1010111, 0b010, 0b10000, 0b010000); + INSN(vfirst_m, 0b1010111, 0b010, 0b10001, 0b010000); +#undef INSN + +#define INSN(NAME, op, funct3, Vs1, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, VectorMask vm = unmasked) { \ + patch_VArith(op, Vd, funct3, Vs1, Vs2, vm, funct6); \ + } + + // Vector Integer Extension + INSN(vzext_vf2, 0b1010111, 0b010, 0b00110, 0b010010); + INSN(vzext_vf4, 0b1010111, 0b010, 0b00100, 0b010010); + INSN(vzext_vf8, 0b1010111, 0b010, 0b00010, 0b010010); + INSN(vsext_vf2, 0b1010111, 0b010, 0b00111, 0b010010); + INSN(vsext_vf4, 0b1010111, 0b010, 0b00101, 0b010010); + INSN(vsext_vf8, 0b1010111, 0b010, 0b00011, 0b010010); + + // Vector Mask + INSN(vmsbf_m, 0b1010111, 0b010, 0b00001, 0b010100); + INSN(vmsif_m, 0b1010111, 0b010, 0b00011, 0b010100); + INSN(vmsof_m, 0b1010111, 0b010, 0b00010, 0b010100); + INSN(viota_m, 0b1010111, 0b010, 0b10000, 0b010100); + + // Vector Single-Width Floating-Point/Integer Type-Convert Instructions + INSN(vfcvt_xu_f_v, 0b1010111, 0b001, 0b00000, 0b010010); + INSN(vfcvt_x_f_v, 0b1010111, 0b001, 0b00001, 0b010010); + INSN(vfcvt_f_xu_v, 0b1010111, 0b001, 0b00010, 0b010010); + INSN(vfcvt_f_x_v, 0b1010111, 0b001, 0b00011, 0b010010); + INSN(vfcvt_rtz_xu_f_v, 0b1010111, 0b001, 0b00110, 0b010010); + INSN(vfcvt_rtz_x_f_v, 0b1010111, 0b001, 0b00111, 0b010010); + + // Vector Floating-Point Instruction + INSN(vfsqrt_v, 0b1010111, 0b001, 0b00000, 0b010011); + INSN(vfclass_v, 0b1010111, 0b001, 0b10000, 0b010011); + +#undef INSN + +// r2rd +#define INSN(NAME, op, funct3, simm5, vm, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2) { \ + patch_VArith(op, Vd, funct3, simm5, Vs2, vm, funct6); \ + } + + // Vector Whole Vector Register Move + INSN(vmv1r_v, 0b1010111, 0b011, 0b00000, 0b1, 0b100111); + INSN(vmv2r_v, 0b1010111, 0b011, 0b00001, 0b1, 0b100111); + INSN(vmv4r_v, 0b1010111, 0b011, 0b00011, 0b1, 0b100111); + INSN(vmv8r_v, 0b1010111, 0b011, 0b00111, 0b1, 0b100111); + +#undef INSN + +#define INSN(NAME, op, funct3, Vs1, vm, funct6) \ + void NAME(FloatRegister Rd, VectorRegister Vs2) { \ + patch_VArith(op, Rd, funct3, Vs1, Vs2, vm, funct6); \ + } + + // Vector Floating-Point Move Instruction + INSN(vfmv_f_s, 0b1010111, 0b001, 0b00000, 0b1, 0b010000); + +#undef INSN + +#define INSN(NAME, op, funct3, Vs1, vm, funct6) \ + void NAME(Register Rd, VectorRegister Vs2) { \ + patch_VArith(op, Rd, funct3, Vs1, Vs2, vm, funct6); \ + } + + // Vector Integer Scalar Move Instructions + INSN(vmv_x_s, 0b1010111, 0b010, 0b00000, 0b1, 0b010000); + +#undef INSN + +// r_vm +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, uint32_t imm, VectorMask vm = unmasked) { \ + guarantee(is_unsigned_imm_in_range(imm, 5, 0), "imm is invalid"); \ + patch_VArith(op, Vd, funct3, (uint32_t)(imm & 0x1f), Vs2, vm, funct6); \ + } + + // Vector Single-Width Bit Shift Instructions + INSN(vsra_vi, 0b1010111, 0b011, 0b101001); + INSN(vsrl_vi, 0b1010111, 0b011, 0b101000); + INSN(vsll_vi, 0b1010111, 0b011, 0b100101); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs1, VectorRegister Vs2, VectorMask vm = unmasked) { \ + patch_VArith(op, Vd, funct3, Vs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Vector Single-Width Floating-Point Fused Multiply-Add Instructions + INSN(vfnmsub_vv, 0b1010111, 0b001, 0b101011); + INSN(vfmsub_vv, 0b1010111, 0b001, 0b101010); + INSN(vfnmadd_vv, 0b1010111, 0b001, 0b101001); + INSN(vfmadd_vv, 0b1010111, 0b001, 0b101000); + INSN(vfnmsac_vv, 0b1010111, 0b001, 0b101111); + INSN(vfmsac_vv, 0b1010111, 0b001, 0b101110); + INSN(vfmacc_vv, 0b1010111, 0b001, 0b101100); + INSN(vfnmacc_vv, 0b1010111, 0b001, 0b101101); + + // Vector Single-Width Integer Multiply-Add Instructions + INSN(vnmsub_vv, 0b1010111, 0b010, 0b101011); + INSN(vmadd_vv, 0b1010111, 0b010, 0b101001); + INSN(vnmsac_vv, 0b1010111, 0b010, 0b101111); + INSN(vmacc_vv, 0b1010111, 0b010, 0b101101); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, Register Rs1, VectorRegister Vs2, VectorMask vm = unmasked) { \ + patch_VArith(op, Vd, funct3, Rs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Vector Single-Width Integer Multiply-Add Instructions + INSN(vnmsub_vx, 0b1010111, 0b110, 0b101011); + INSN(vmadd_vx, 0b1010111, 0b110, 0b101001); + INSN(vnmsac_vx, 0b1010111, 0b110, 0b101111); + INSN(vmacc_vx, 0b1010111, 0b110, 0b101101); + + INSN(vrsub_vx, 0b1010111, 0b100, 0b000011); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, FloatRegister Rs1, VectorRegister Vs2, VectorMask vm = unmasked) { \ + patch_VArith(op, Vd, funct3, Rs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Vector Single-Width Floating-Point Fused Multiply-Add Instructions + INSN(vfnmsub_vf, 0b1010111, 0b101, 0b101011); + INSN(vfmsub_vf, 0b1010111, 0b101, 0b101010); + INSN(vfnmadd_vf, 0b1010111, 0b101, 0b101001); + INSN(vfmadd_vf, 0b1010111, 0b101, 0b101000); + INSN(vfnmsac_vf, 0b1010111, 0b101, 0b101111); + INSN(vfmsac_vf, 0b1010111, 0b101, 0b101110); + INSN(vfmacc_vf, 0b1010111, 0b101, 0b101100); + INSN(vfnmacc_vf, 0b1010111, 0b101, 0b101101); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, VectorRegister Vs1, VectorMask vm = unmasked) { \ + patch_VArith(op, Vd, funct3, Vs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Vector Single-Width Floating-Point Reduction Instructions + INSN(vfredsum_vs, 0b1010111, 0b001, 0b000001); + INSN(vfredosum_vs, 0b1010111, 0b001, 0b000011); + INSN(vfredmin_vs, 0b1010111, 0b001, 0b000101); + INSN(vfredmax_vs, 0b1010111, 0b001, 0b000111); + + // Vector Single-Width Integer Reduction Instructions + INSN(vredsum_vs, 0b1010111, 0b010, 0b000000); + INSN(vredand_vs, 0b1010111, 0b010, 0b000001); + INSN(vredor_vs, 0b1010111, 0b010, 0b000010); + INSN(vredxor_vs, 0b1010111, 0b010, 0b000011); + INSN(vredminu_vs, 0b1010111, 0b010, 0b000100); + INSN(vredmin_vs, 0b1010111, 0b010, 0b000101); + INSN(vredmaxu_vs, 0b1010111, 0b010, 0b000110); + INSN(vredmax_vs, 0b1010111, 0b010, 0b000111); + + // Vector Floating-Point Compare Instructions + INSN(vmfle_vv, 0b1010111, 0b001, 0b011001); + INSN(vmflt_vv, 0b1010111, 0b001, 0b011011); + INSN(vmfne_vv, 0b1010111, 0b001, 0b011100); + INSN(vmfeq_vv, 0b1010111, 0b001, 0b011000); + + // Vector Floating-Point Sign-Injection Instructions + INSN(vfsgnjx_vv, 0b1010111, 0b001, 0b001010); + INSN(vfsgnjn_vv, 0b1010111, 0b001, 0b001001); + INSN(vfsgnj_vv, 0b1010111, 0b001, 0b001000); + + // Vector Floating-Point MIN/MAX Instructions + INSN(vfmax_vv, 0b1010111, 0b001, 0b000110); + INSN(vfmin_vv, 0b1010111, 0b001, 0b000100); + + // Vector Single-Width Floating-Point Multiply/Divide Instructions + INSN(vfdiv_vv, 0b1010111, 0b001, 0b100000); + INSN(vfmul_vv, 0b1010111, 0b001, 0b100100); + + // Vector Single-Width Floating-Point Add/Subtract Instructions + INSN(vfsub_vv, 0b1010111, 0b001, 0b000010); + INSN(vfadd_vv, 0b1010111, 0b001, 0b000000); + + // Vector Single-Width Fractional Multiply with Rounding and Saturation + INSN(vsmul_vv, 0b1010111, 0b000, 0b100111); + + // Vector Integer Divide Instructions + INSN(vrem_vv, 0b1010111, 0b010, 0b100011); + INSN(vremu_vv, 0b1010111, 0b010, 0b100010); + INSN(vdiv_vv, 0b1010111, 0b010, 0b100001); + INSN(vdivu_vv, 0b1010111, 0b010, 0b100000); + + // Vector Single-Width Integer Multiply Instructions + INSN(vmulhsu_vv, 0b1010111, 0b010, 0b100110); + INSN(vmulhu_vv, 0b1010111, 0b010, 0b100100); + INSN(vmulh_vv, 0b1010111, 0b010, 0b100111); + INSN(vmul_vv, 0b1010111, 0b010, 0b100101); + + // Vector Integer Min/Max Instructions + INSN(vmax_vv, 0b1010111, 0b000, 0b000111); + INSN(vmaxu_vv, 0b1010111, 0b000, 0b000110); + INSN(vmin_vv, 0b1010111, 0b000, 0b000101); + INSN(vminu_vv, 0b1010111, 0b000, 0b000100); + + // Vector Integer Comparison Instructions + INSN(vmsle_vv, 0b1010111, 0b000, 0b011101); + INSN(vmsleu_vv, 0b1010111, 0b000, 0b011100); + INSN(vmslt_vv, 0b1010111, 0b000, 0b011011); + INSN(vmsltu_vv, 0b1010111, 0b000, 0b011010); + INSN(vmsne_vv, 0b1010111, 0b000, 0b011001); + INSN(vmseq_vv, 0b1010111, 0b000, 0b011000); + + // Vector Single-Width Bit Shift Instructions + INSN(vsra_vv, 0b1010111, 0b000, 0b101001); + INSN(vsrl_vv, 0b1010111, 0b000, 0b101000); + INSN(vsll_vv, 0b1010111, 0b000, 0b100101); + + // Vector Bitwise Logical Instructions + INSN(vxor_vv, 0b1010111, 0b000, 0b001011); + INSN(vor_vv, 0b1010111, 0b000, 0b001010); + INSN(vand_vv, 0b1010111, 0b000, 0b001001); + + // Vector Single-Width Integer Add and Subtract + INSN(vsub_vv, 0b1010111, 0b000, 0b000010); + INSN(vadd_vv, 0b1010111, 0b000, 0b000000); + +#undef INSN + + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, Register Rs1, VectorMask vm = unmasked) { \ + patch_VArith(op, Vd, funct3, Rs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Vector Integer Divide Instructions + INSN(vrem_vx, 0b1010111, 0b110, 0b100011); + INSN(vremu_vx, 0b1010111, 0b110, 0b100010); + INSN(vdiv_vx, 0b1010111, 0b110, 0b100001); + INSN(vdivu_vx, 0b1010111, 0b110, 0b100000); + + // Vector Single-Width Integer Multiply Instructions + INSN(vmulhsu_vx, 0b1010111, 0b110, 0b100110); + INSN(vmulhu_vx, 0b1010111, 0b110, 0b100100); + INSN(vmulh_vx, 0b1010111, 0b110, 0b100111); + INSN(vmul_vx, 0b1010111, 0b110, 0b100101); + + // Vector Integer Min/Max Instructions + INSN(vmax_vx, 0b1010111, 0b100, 0b000111); + INSN(vmaxu_vx, 0b1010111, 0b100, 0b000110); + INSN(vmin_vx, 0b1010111, 0b100, 0b000101); + INSN(vminu_vx, 0b1010111, 0b100, 0b000100); + + // Vector Integer Comparison Instructions + INSN(vmsgt_vx, 0b1010111, 0b100, 0b011111); + INSN(vmsgtu_vx, 0b1010111, 0b100, 0b011110); + INSN(vmsle_vx, 0b1010111, 0b100, 0b011101); + INSN(vmsleu_vx, 0b1010111, 0b100, 0b011100); + INSN(vmslt_vx, 0b1010111, 0b100, 0b011011); + INSN(vmsltu_vx, 0b1010111, 0b100, 0b011010); + INSN(vmsne_vx, 0b1010111, 0b100, 0b011001); + INSN(vmseq_vx, 0b1010111, 0b100, 0b011000); + + // Vector Narrowing Integer Right Shift Instructions + INSN(vnsra_wx, 0b1010111, 0b100, 0b101101); + INSN(vnsrl_wx, 0b1010111, 0b100, 0b101100); + + // Vector Single-Width Bit Shift Instructions + INSN(vsra_vx, 0b1010111, 0b100, 0b101001); + INSN(vsrl_vx, 0b1010111, 0b100, 0b101000); + INSN(vsll_vx, 0b1010111, 0b100, 0b100101); + + // Vector Bitwise Logical Instructions + INSN(vxor_vx, 0b1010111, 0b100, 0b001011); + INSN(vor_vx, 0b1010111, 0b100, 0b001010); + INSN(vand_vx, 0b1010111, 0b100, 0b001001); + + // Vector Single-Width Integer Add and Subtract + INSN(vsub_vx, 0b1010111, 0b100, 0b000010); + INSN(vadd_vx, 0b1010111, 0b100, 0b000000); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, FloatRegister Rs1, VectorMask vm = unmasked) { \ + patch_VArith(op, Vd, funct3, Rs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Vector Floating-Point Compare Instructions + INSN(vmfge_vf, 0b1010111, 0b101, 0b011111); + INSN(vmfgt_vf, 0b1010111, 0b101, 0b011101); + INSN(vmfle_vf, 0b1010111, 0b101, 0b011001); + INSN(vmflt_vf, 0b1010111, 0b101, 0b011011); + INSN(vmfne_vf, 0b1010111, 0b101, 0b011100); + INSN(vmfeq_vf, 0b1010111, 0b101, 0b011000); + + // Vector Floating-Point Sign-Injection Instructions + INSN(vfsgnjx_vf, 0b1010111, 0b101, 0b001010); + INSN(vfsgnjn_vf, 0b1010111, 0b101, 0b001001); + INSN(vfsgnj_vf, 0b1010111, 0b101, 0b001000); + + // Vector Floating-Point MIN/MAX Instructions + INSN(vfmax_vf, 0b1010111, 0b101, 0b000110); + INSN(vfmin_vf, 0b1010111, 0b101, 0b000100); + + // Vector Single-Width Floating-Point Multiply/Divide Instructions + INSN(vfdiv_vf, 0b1010111, 0b101, 0b100000); + INSN(vfmul_vf, 0b1010111, 0b101, 0b100100); + INSN(vfrdiv_vf, 0b1010111, 0b101, 0b100001); + + // Vector Single-Width Floating-Point Add/Subtract Instructions + INSN(vfsub_vf, 0b1010111, 0b101, 0b000010); + INSN(vfadd_vf, 0b1010111, 0b101, 0b000000); + INSN(vfrsub_vf, 0b1010111, 0b101, 0b100111); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, int32_t imm, VectorMask vm = unmasked) { \ + guarantee(is_imm_in_range(imm, 5, 0), "imm is invalid"); \ + patch_VArith(op, Vd, funct3, (uint32_t)imm & 0x1f, Vs2, vm, funct6); \ + } + + INSN(vmsgt_vi, 0b1010111, 0b011, 0b011111); + INSN(vmsgtu_vi, 0b1010111, 0b011, 0b011110); + INSN(vmsle_vi, 0b1010111, 0b011, 0b011101); + INSN(vmsleu_vi, 0b1010111, 0b011, 0b011100); + INSN(vmsne_vi, 0b1010111, 0b011, 0b011001); + INSN(vmseq_vi, 0b1010111, 0b011, 0b011000); + INSN(vxor_vi, 0b1010111, 0b011, 0b001011); + INSN(vor_vi, 0b1010111, 0b011, 0b001010); + INSN(vand_vi, 0b1010111, 0b011, 0b001001); + INSN(vadd_vi, 0b1010111, 0b011, 0b000000); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(VectorRegister Vd, int32_t imm, VectorRegister Vs2, VectorMask vm = unmasked) { \ + guarantee(is_imm_in_range(imm, 5, 0), "imm is invalid"); \ + patch_VArith(op, Vd, funct3, (uint32_t)(imm & 0x1f), Vs2, vm, funct6); \ + } + + INSN(vrsub_vi, 0b1010111, 0b011, 0b000011); + +#undef INSN + +#define INSN(NAME, op, funct3, vm, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs2, VectorRegister Vs1) { \ + patch_VArith(op, Vd, funct3, Vs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Vector Compress Instruction + INSN(vcompress_vm, 0b1010111, 0b010, 0b1, 0b010111); + + // Vector Mask-Register Logical Instructions + INSN(vmxnor_mm, 0b1010111, 0b010, 0b1, 0b011111); + INSN(vmornot_mm, 0b1010111, 0b010, 0b1, 0b011100); + INSN(vmnor_mm, 0b1010111, 0b010, 0b1, 0b011110); + INSN(vmor_mm, 0b1010111, 0b010, 0b1, 0b011010); + INSN(vmxor_mm, 0b1010111, 0b010, 0b1, 0b011011); + INSN(vmandnot_mm, 0b1010111, 0b010, 0b1, 0b011000); + INSN(vmnand_mm, 0b1010111, 0b010, 0b1, 0b011101); + INSN(vmand_mm, 0b1010111, 0b010, 0b1, 0b011001); + +#undef INSN + +#define INSN(NAME, op, funct3, Vs2, vm, funct6) \ + void NAME(VectorRegister Vd, int32_t imm) { \ + guarantee(is_imm_in_range(imm, 5, 0), "imm is invalid"); \ + patch_VArith(op, Vd, funct3, (uint32_t)(imm & 0x1f), Vs2, vm, funct6); \ + } + + // Vector Integer Move Instructions + INSN(vmv_v_i, 0b1010111, 0b011, v0, 0b1, 0b010111); + +#undef INSN + +#define INSN(NAME, op, funct3, Vs2, vm, funct6) \ + void NAME(VectorRegister Vd, FloatRegister Rs1) { \ + patch_VArith(op, Vd, funct3, Rs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Floating-Point Scalar Move Instructions + INSN(vfmv_s_f, 0b1010111, 0b101, v0, 0b1, 0b010000); + // Vector Floating-Point Move Instruction + INSN(vfmv_v_f, 0b1010111, 0b101, v0, 0b1, 0b010111); + +#undef INSN + +#define INSN(NAME, op, funct3, Vs2, vm, funct6) \ + void NAME(VectorRegister Vd, VectorRegister Vs1) { \ + patch_VArith(op, Vd, funct3, Vs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Vector Integer Move Instructions + INSN(vmv_v_v, 0b1010111, 0b000, v0, 0b1, 0b010111); + +#undef INSN + +#define INSN(NAME, op, funct3, Vs2, vm, funct6) \ + void NAME(VectorRegister Vd, Register Rs1) { \ + patch_VArith(op, Vd, funct3, Rs1->encoding_nocheck(), Vs2, vm, funct6); \ + } + + // Integer Scalar Move Instructions + INSN(vmv_s_x, 0b1010111, 0b110, v0, 0b1, 0b010000); + + // Vector Integer Move Instructions + INSN(vmv_v_x, 0b1010111, 0b100, v0, 0b1, 0b010111); + +#undef INSN +#undef patch_VArith + +#define INSN(NAME, op, funct13, funct6) \ + void NAME(VectorRegister Vd, VectorMask vm = unmasked) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 24, 12, funct13); \ + patch((address)&insn, 25, vm); \ + patch((address)&insn, 31, 26, funct6); \ + patch_reg((address)&insn, 7, Vd); \ + emit(insn); \ + } + + // Vector Element Index Instruction + INSN(vid_v, 0b1010111, 0b0000010001010, 0b010100); + +#undef INSN + +enum Nf { + g1 = 0b000, + g2 = 0b001, + g3 = 0b010, + g4 = 0b011, + g5 = 0b100, + g6 = 0b101, + g7 = 0b110, + g8 = 0b111 +}; + +#define patch_VLdSt(op, VReg, width, Rs1, Reg_or_umop, vm, mop, mew, nf) \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, width); \ + patch((address)&insn, 24, 20, Reg_or_umop); \ + patch((address)&insn, 25, vm); \ + patch((address)&insn, 27, 26, mop); \ + patch((address)&insn, 28, mew); \ + patch((address)&insn, 31, 29, nf); \ + patch_reg((address)&insn, 7, VReg); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn) + +#define INSN(NAME, op, lumop, vm, mop, nf) \ + void NAME(VectorRegister Vd, Register Rs1, uint32_t width = 0, bool mew = false) { \ + guarantee(is_unsigned_imm_in_range(width, 3, 0), "width is invalid"); \ + patch_VLdSt(op, Vd, width, Rs1, lumop, vm, mop, mew, nf); \ + } + + // Vector Load/Store Instructions + INSN(vl1r_v, 0b0000111, 0b01000, 0b1, 0b00, g1); + +#undef INSN + +#define INSN(NAME, op, width, sumop, vm, mop, mew, nf) \ + void NAME(VectorRegister Vs3, Register Rs1) { \ + patch_VLdSt(op, Vs3, width, Rs1, sumop, vm, mop, mew, nf); \ + } + + // Vector Load/Store Instructions + INSN(vs1r_v, 0b0100111, 0b000, 0b01000, 0b1, 0b00, 0b0, g1); + +#undef INSN + +// r2_nfvm +#define INSN(NAME, op, width, umop, mop, mew) \ + void NAME(VectorRegister Vd_or_Vs3, Register Rs1, Nf nf = g1) { \ + patch_VLdSt(op, Vd_or_Vs3, width, Rs1, umop, 1, mop, mew, nf); \ + } + + // Vector Unit-Stride Instructions + INSN(vle1_v, 0b0000111, 0b000, 0b01011, 0b00, 0b0); + INSN(vse1_v, 0b0100111, 0b000, 0b01011, 0b00, 0b0); + +#undef INSN + +#define INSN(NAME, op, width, umop, mop, mew) \ + void NAME(VectorRegister Vd_or_Vs3, Register Rs1, VectorMask vm = unmasked, Nf nf = g1) { \ + patch_VLdSt(op, Vd_or_Vs3, width, Rs1, umop, vm, mop, mew, nf); \ + } + + // Vector Unit-Stride Instructions + INSN(vle8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0); + INSN(vle16_v, 0b0000111, 0b101, 0b00000, 0b00, 0b0); + INSN(vle32_v, 0b0000111, 0b110, 0b00000, 0b00, 0b0); + INSN(vle64_v, 0b0000111, 0b111, 0b00000, 0b00, 0b0); + + // Vector unit-stride fault-only-first Instructions + INSN(vle8ff_v, 0b0000111, 0b000, 0b10000, 0b00, 0b0); + INSN(vle16ff_v, 0b0000111, 0b101, 0b10000, 0b00, 0b0); + INSN(vle32ff_v, 0b0000111, 0b110, 0b10000, 0b00, 0b0); + INSN(vle64ff_v, 0b0000111, 0b111, 0b10000, 0b00, 0b0); + + INSN(vse8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0); + INSN(vse16_v, 0b0100111, 0b101, 0b00000, 0b00, 0b0); + INSN(vse32_v, 0b0100111, 0b110, 0b00000, 0b00, 0b0); + INSN(vse64_v, 0b0100111, 0b111, 0b00000, 0b00, 0b0); + +#undef INSN + +#define INSN(NAME, op, width, mop, mew) \ + void NAME(VectorRegister Vd, Register Rs1, VectorRegister Vs2, VectorMask vm = unmasked, Nf nf = g1) { \ + patch_VLdSt(op, Vd, width, Rs1, Vs2->encoding_nocheck(), vm, mop, mew, nf); \ + } + + // Vector unordered indexed load instructions + INSN(vluxei8_v, 0b0000111, 0b000, 0b01, 0b0); + INSN(vluxei16_v, 0b0000111, 0b101, 0b01, 0b0); + INSN(vluxei32_v, 0b0000111, 0b110, 0b01, 0b0); + INSN(vluxei64_v, 0b0000111, 0b111, 0b01, 0b0); + + // Vector ordered indexed load instructions + INSN(vloxei8_v, 0b0000111, 0b000, 0b11, 0b0); + INSN(vloxei16_v, 0b0000111, 0b101, 0b11, 0b0); + INSN(vloxei32_v, 0b0000111, 0b110, 0b11, 0b0); + INSN(vloxei64_v, 0b0000111, 0b111, 0b11, 0b0); +#undef INSN + +#define INSN(NAME, op, width, mop, mew) \ + void NAME(VectorRegister Vd, Register Rs1, Register Rs2, VectorMask vm = unmasked, Nf nf = g1) { \ + patch_VLdSt(op, Vd, width, Rs1, Rs2->encoding_nocheck(), vm, mop, mew, nf); \ + } + + // Vector Strided Instructions + INSN(vlse8_v, 0b0000111, 0b000, 0b10, 0b0); + INSN(vlse16_v, 0b0000111, 0b101, 0b10, 0b0); + INSN(vlse32_v, 0b0000111, 0b110, 0b10, 0b0); + INSN(vlse64_v, 0b0000111, 0b111, 0b10, 0b0); + +#undef INSN +#undef patch_VLdSt + +// ==================================== +// RISC-V Bit-Manipulation Extension +// ==================================== +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + patch_reg((address)&insn, 20, Rs2); \ + emit(insn); \ + } + + INSN(add_uw, 0b0111011, 0b000, 0b0000100); + INSN(rol, 0b0110011, 0b001, 0b0110000); + INSN(rolw, 0b0111011, 0b001, 0b0110000); + INSN(ror, 0b0110011, 0b101, 0b0110000); + INSN(rorw, 0b0111011, 0b101, 0b0110000); + INSN(sh1add, 0b0110011, 0b010, 0b0010000); + INSN(sh2add, 0b0110011, 0b100, 0b0010000); + INSN(sh3add, 0b0110011, 0b110, 0b0010000); + INSN(sh1add_uw, 0b0111011, 0b010, 0b0010000); + INSN(sh2add_uw, 0b0111011, 0b100, 0b0010000); + INSN(sh3add_uw, 0b0111011, 0b110, 0b0010000); + INSN(andn, 0b0110011, 0b111, 0b0100000); + INSN(orn, 0b0110011, 0b110, 0b0100000); + INSN(xnor, 0b0110011, 0b100, 0b0100000); + INSN(max, 0b0110011, 0b110, 0b0000101); + INSN(maxu, 0b0110011, 0b111, 0b0000101); + INSN(min, 0b0110011, 0b100, 0b0000101); + INSN(minu, 0b0110011, 0b101, 0b0000101); + +#undef INSN + +#define INSN(NAME, op, funct3, funct12) \ + void NAME(Register Rd, Register Rs1) { \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 31, 20, funct12); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(rev8, 0b0010011, 0b101, 0b011010111000); + INSN(sext_b, 0b0010011, 0b001, 0b011000000100); + INSN(sext_h, 0b0010011, 0b001, 0b011000000101); + INSN(zext_h, 0b0111011, 0b100, 0b000010000000); + INSN(clz, 0b0010011, 0b001, 0b011000000000); + INSN(clzw, 0b0011011, 0b001, 0b011000000000); + INSN(ctz, 0b0010011, 0b001, 0b011000000001); + INSN(ctzw, 0b0011011, 0b001, 0b011000000001); + INSN(cpop, 0b0010011, 0b001, 0b011000000010); + INSN(cpopw, 0b0011011, 0b001, 0b011000000010); + INSN(orc_b, 0b0010011, 0b101, 0b001010000111); + +#undef INSN + +#define INSN(NAME, op, funct3, funct6) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) {\ + guarantee(shamt <= 0x3f, "Shamt is invalid"); \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 25, 20, shamt); \ + patch((address)&insn, 31, 26, funct6); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(rori, 0b0010011, 0b101, 0b011000); + INSN(slli_uw, 0b0011011, 0b001, 0b000010); + +#undef INSN + +#define INSN(NAME, op, funct3, funct7) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) {\ + guarantee(shamt <= 0x1f, "Shamt is invalid"); \ + unsigned insn = 0; \ + patch((address)&insn, 6, 0, op); \ + patch((address)&insn, 14, 12, funct3); \ + patch((address)&insn, 24, 20, shamt); \ + patch((address)&insn, 31, 25, funct7); \ + patch_reg((address)&insn, 7, Rd); \ + patch_reg((address)&insn, 15, Rs1); \ + emit(insn); \ + } + + INSN(roriw, 0b0011011, 0b101, 0b0110000); + +#undef INSN + +// ======================================== +// RISC-V Compressed Instructions Extension +// ======================================== +// Note: +// 1. When UseRVC is enabled, 32-bit instructions under 'CompressibleRegion's will be +// transformed to 16-bit instructions if compressible. +// 2. RVC instructions in Assembler always begin with 'c_' prefix, as 'c_li', +// but most of time we have no need to explicitly use these instructions. +// 3. 'CompressibleRegion' is introduced to hint instructions in this Region's RTTI range +// are qualified to be compressed with their 2-byte versions. +// An example: +// +// CompressibleRegion cr(_masm); +// __ andr(...); // this instruction could change to c.and if able to +// +// 4. Using -XX:PrintAssemblyOptions=no-aliases could distinguish RVC instructions from +// normal ones. +// + +private: + bool _in_compressible_region; +public: + bool in_compressible_region() const { return _in_compressible_region; } + void set_in_compressible_region(bool b) { _in_compressible_region = b; } +public: + + // a compressible region + class CompressibleRegion : public StackObj { + protected: + Assembler *_masm; + bool _saved_in_compressible_region; + public: + CompressibleRegion(Assembler *_masm) + : _masm(_masm) + , _saved_in_compressible_region(_masm->in_compressible_region()) { + _masm->set_in_compressible_region(true); + } + ~CompressibleRegion() { + _masm->set_in_compressible_region(_saved_in_compressible_region); + } + }; + + // patch a 16-bit instruction. + static void c_patch(address a, unsigned msb, unsigned lsb, uint16_t val) { + assert_cond(a != NULL); + assert_cond(msb >= lsb && msb <= 15); + unsigned nbits = msb - lsb + 1; + guarantee(val < (1U << nbits), "Field too big for insn"); + uint16_t mask = (1U << nbits) - 1; + val <<= lsb; + mask <<= lsb; + uint16_t target = *(uint16_t *)a; + target &= ~mask; + target |= val; + *(uint16_t *)a = target; + } + + static void c_patch(address a, unsigned bit, uint16_t val) { + c_patch(a, bit, bit, val); + } + + // patch a 16-bit instruction with a general purpose register ranging [0, 31] (5 bits) + static void c_patch_reg(address a, unsigned lsb, Register reg) { + c_patch(a, lsb + 4, lsb, reg->encoding_nocheck()); + } + + // patch a 16-bit instruction with a general purpose register ranging [8, 15] (3 bits) + static void c_patch_compressed_reg(address a, unsigned lsb, Register reg) { + c_patch(a, lsb + 2, lsb, reg->compressed_encoding_nocheck()); + } + + // patch a 16-bit instruction with a float register ranging [0, 31] (5 bits) + static void c_patch_reg(address a, unsigned lsb, FloatRegister reg) { + c_patch(a, lsb + 4, lsb, reg->encoding_nocheck()); + } + + // patch a 16-bit instruction with a float register ranging [8, 15] (3 bits) + static void c_patch_compressed_reg(address a, unsigned lsb, FloatRegister reg) { + c_patch(a, lsb + 2, lsb, reg->compressed_encoding_nocheck()); + } + +// -------------- RVC Instruction Definitions -------------- + + void c_nop() { + c_addi(x0, 0); + } + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd_Rs1, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 6, 0)); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (imm & right_n_bits(5))); \ + c_patch_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_addi, 0b000, 0b01); + INSN(c_addiw, 0b001, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 10, 0)); \ + assert_cond((imm & 0b1111) == 0); \ + assert_cond(imm != 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 2, 2, (imm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 4, 3, (imm & right_n_bits(9)) >> 7); \ + c_patch((address)&insn, 5, 5, (imm & nth_bit(6)) >> 6); \ + c_patch((address)&insn, 6, 6, (imm & nth_bit(4)) >> 4); \ + c_patch_reg((address)&insn, 7, sp); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(9)) >> 9); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_addi16sp, 0b011, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 10, 0)); \ + assert_cond((uimm & 0b11) == 0); \ + assert_cond(uimm != 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_compressed_reg((address)&insn, 2, Rd); \ + c_patch((address)&insn, 5, 5, (uimm & nth_bit(3)) >> 3); \ + c_patch((address)&insn, 6, 6, (uimm & nth_bit(2)) >> 2); \ + c_patch((address)&insn, 10, 7, (uimm & right_n_bits(10)) >> 6); \ + c_patch((address)&insn, 12, 11, (uimm & right_n_bits(6)) >> 4); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_addi4spn, 0b000, 0b00); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd_Rs1, uint32_t shamt) { \ + assert_cond(is_unsigned_imm_in_range(shamt, 6, 0)); \ + assert_cond(shamt != 0); \ + assert_cond(Rd_Rs1 != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (shamt & right_n_bits(5))); \ + c_patch_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 12, 12, (shamt & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_slli, 0b000, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, funct2, op) \ + void NAME(Register Rd_Rs1, uint32_t shamt) { \ + assert_cond(is_unsigned_imm_in_range(shamt, 6, 0)); \ + assert_cond(shamt != 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (shamt & right_n_bits(5))); \ + c_patch_compressed_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 11, 10, funct2); \ + c_patch((address)&insn, 12, 12, (shamt & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_srli, 0b100, 0b00, 0b01); + INSN(c_srai, 0b100, 0b01, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, funct2, op) \ + void NAME(Register Rd_Rs1, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 6, 0)); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (imm & right_n_bits(5))); \ + c_patch_compressed_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 11, 10, funct2); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_andi, 0b100, 0b10, 0b01); + +#undef INSN + +#define INSN(NAME, funct6, funct2, op) \ + void NAME(Register Rd_Rs1, Register Rs2) { \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_compressed_reg((address)&insn, 2, Rs2); \ + c_patch((address)&insn, 6, 5, funct2); \ + c_patch_compressed_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 15, 10, funct6); \ + emit_int16(insn); \ + } + + INSN(c_sub, 0b100011, 0b00, 0b01); + INSN(c_xor, 0b100011, 0b01, 0b01); + INSN(c_or, 0b100011, 0b10, 0b01); + INSN(c_and, 0b100011, 0b11, 0b01); + INSN(c_subw, 0b100111, 0b00, 0b01); + INSN(c_addw, 0b100111, 0b01, 0b01); + +#undef INSN + +#define INSN(NAME, funct4, op) \ + void NAME(Register Rd_Rs1, Register Rs2) { \ + assert_cond(Rd_Rs1 != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_reg((address)&insn, 2, Rs2); \ + c_patch_reg((address)&insn, 7, Rd_Rs1); \ + c_patch((address)&insn, 15, 12, funct4); \ + emit_int16(insn); \ + } + + INSN(c_mv, 0b1000, 0b10); + INSN(c_add, 0b1001, 0b10); + +#undef INSN + +#define INSN(NAME, funct4, op) \ + void NAME(Register Rs1) { \ + assert_cond(Rs1 != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_reg((address)&insn, 2, x0); \ + c_patch_reg((address)&insn, 7, Rs1); \ + c_patch((address)&insn, 15, 12, funct4); \ + emit_int16(insn); \ + } + + INSN(c_jr, 0b1000, 0b10); + INSN(c_jalr, 0b1001, 0b10); + +#undef INSN + + typedef void (Assembler::* j_c_insn)(address dest); + typedef void (Assembler::* compare_and_branch_c_insn)(Register Rs1, address dest); + + void wrap_label(Label &L, j_c_insn insn) { + if (L.is_bound()) { + (this->*insn)(target(L)); + } else { + L.add_patch_at(code(), locator()); + (this->*insn)(pc()); + } + } + + void wrap_label(Label &L, Register r, compare_and_branch_c_insn insn) { + if (L.is_bound()) { + (this->*insn)(r, target(L)); + } else { + L.add_patch_at(code(), locator()); + (this->*insn)(r, pc()); + } + } + +#define INSN(NAME, funct3, op) \ + void NAME(int32_t offset) { \ + assert_cond(is_imm_in_range(offset, 11, 1)); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 2, 2, (offset & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 5, 3, (offset & right_n_bits(4)) >> 1); \ + c_patch((address)&insn, 6, 6, (offset & nth_bit(7)) >> 7); \ + c_patch((address)&insn, 7, 7, (offset & nth_bit(6)) >> 6); \ + c_patch((address)&insn, 8, 8, (offset & nth_bit(10)) >> 10); \ + c_patch((address)&insn, 10, 9, (offset & right_n_bits(10)) >> 8); \ + c_patch((address)&insn, 11, 11, (offset & nth_bit(4)) >> 4); \ + c_patch((address)&insn, 12, 12, (offset & nth_bit(11)) >> 11); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } \ + void NAME(address dest) { \ + assert_cond(dest != NULL); \ + int64_t distance = dest - pc(); \ + assert_cond(is_imm_in_range(distance, 11, 1)); \ + c_j(distance); \ + } \ + void NAME(Label &L) { \ + wrap_label(L, &Assembler::NAME); \ + } + + INSN(c_j, 0b101, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rs1, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 8, 1)); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 2, 2, (imm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 4, 3, (imm & right_n_bits(3)) >> 1); \ + c_patch((address)&insn, 6, 5, (imm & right_n_bits(8)) >> 6); \ + c_patch_compressed_reg((address)&insn, 7, Rs1); \ + c_patch((address)&insn, 11, 10, (imm & right_n_bits(5)) >> 3); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(8)) >> 8); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } \ + void NAME(Register Rs1, address dest) { \ + assert_cond(dest != NULL); \ + int64_t distance = dest - pc(); \ + assert_cond(is_imm_in_range(distance, 8, 1)); \ + NAME(Rs1, distance); \ + } \ + void NAME(Register Rs1, Label &L) { \ + wrap_label(L, Rs1, &Assembler::NAME); \ + } + + INSN(c_beqz, 0b110, 0b01); + INSN(c_bnez, 0b111, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 18, 0)); \ + assert_cond((imm & 0xfff) == 0); \ + assert_cond(imm != 0); \ + assert_cond(Rd != x0 && Rd != x2); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (imm & right_n_bits(17)) >> 12); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (imm & nth_bit(17)) >> 17); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_lui, 0b011, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, int32_t imm) { \ + assert_cond(is_imm_in_range(imm, 6, 0)); \ + assert_cond(Rd != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 6, 2, (imm & right_n_bits(5))); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (imm & right_n_bits(6)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_li, 0b010, 0b01); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + assert_cond(Rd != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 4, 2, (uimm & right_n_bits(9)) >> 6); \ + c_patch((address)&insn, 6, 5, (uimm & right_n_bits(5)) >> 3); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (uimm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_ldsp, 0b011, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(FloatRegister Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 4, 2, (uimm & right_n_bits(9)) >> 6); \ + c_patch((address)&insn, 6, 5, (uimm & right_n_bits(5)) >> 3); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (uimm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_fldsp, 0b001, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, op, REGISTER_TYPE) \ + void NAME(REGISTER_TYPE Rd_Rs2, Register Rs1, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 8, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_compressed_reg((address)&insn, 2, Rd_Rs2); \ + c_patch((address)&insn, 6, 5, (uimm & right_n_bits(8)) >> 6); \ + c_patch_compressed_reg((address)&insn, 7, Rs1); \ + c_patch((address)&insn, 12, 10, (uimm & right_n_bits(6)) >> 3); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_ld, 0b011, 0b00, Register); + INSN(c_sd, 0b111, 0b00, Register); + INSN(c_fld, 0b001, 0b00, FloatRegister); + INSN(c_fsd, 0b101, 0b00, FloatRegister); + +#undef INSN + +#define INSN(NAME, funct3, op, REGISTER_TYPE) \ + void NAME(REGISTER_TYPE Rs2, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 9, 0)); \ + assert_cond((uimm & 0b111) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_reg((address)&insn, 2, Rs2); \ + c_patch((address)&insn, 9, 7, (uimm & right_n_bits(9)) >> 6); \ + c_patch((address)&insn, 12, 10, (uimm & right_n_bits(6)) >> 3); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_sdsp, 0b111, 0b10, Register); + INSN(c_fsdsp, 0b101, 0b10, FloatRegister); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rs2, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 8, 0)); \ + assert_cond((uimm & 0b11) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_reg((address)&insn, 2, Rs2); \ + c_patch((address)&insn, 8, 7, (uimm & right_n_bits(8)) >> 6); \ + c_patch((address)&insn, 12, 9, (uimm & right_n_bits(6)) >> 2); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_swsp, 0b110, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 8, 0)); \ + assert_cond((uimm & 0b11) == 0); \ + assert_cond(Rd != x0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 3, 2, (uimm & right_n_bits(8)) >> 6); \ + c_patch((address)&insn, 6, 4, (uimm & right_n_bits(5)) >> 2); \ + c_patch_reg((address)&insn, 7, Rd); \ + c_patch((address)&insn, 12, 12, (uimm & nth_bit(5)) >> 5); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_lwsp, 0b010, 0b10); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME(Register Rd_Rs2, Register Rs1, uint32_t uimm) { \ + assert_cond(is_unsigned_imm_in_range(uimm, 7, 0)); \ + assert_cond((uimm & 0b11) == 0); \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch_compressed_reg((address)&insn, 2, Rd_Rs2); \ + c_patch((address)&insn, 5, 5, (uimm & nth_bit(6)) >> 6); \ + c_patch((address)&insn, 6, 6, (uimm & nth_bit(2)) >> 2); \ + c_patch_compressed_reg((address)&insn, 7, Rs1); \ + c_patch((address)&insn, 12, 10, (uimm & right_n_bits(6)) >> 3); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_lw, 0b010, 0b00); + INSN(c_sw, 0b110, 0b00); + +#undef INSN + +#define INSN(NAME, funct3, op) \ + void NAME() { \ + uint16_t insn = 0; \ + c_patch((address)&insn, 1, 0, op); \ + c_patch((address)&insn, 11, 2, 0x0); \ + c_patch((address)&insn, 12, 12, 0b1); \ + c_patch((address)&insn, 15, 13, funct3); \ + emit_int16(insn); \ + } + + INSN(c_ebreak, 0b100, 0b10); + +#undef INSN + +// -------------- RVC Transformation Functions -------------- + +// -------------------------- +// Register instructions +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + /* add -> c.add */ \ + if (do_compress()) { \ + Register src = noreg; \ + if (Rs1 != x0 && Rs2 != x0 && ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) { \ + c_add(Rd, src); \ + return; \ + } \ + } \ + _add(Rd, Rs1, Rs2); \ + } + + INSN(add); + +#undef INSN + +// -------------------------- +#define INSN(NAME, C_NAME, NORMAL_NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + /* sub/subw -> c.sub/c.subw */ \ + if (do_compress() && \ + (Rd == Rs1 && Rd->is_compressed_valid() && Rs2->is_compressed_valid())) { \ + C_NAME(Rd, Rs2); \ + return; \ + } \ + NORMAL_NAME(Rd, Rs1, Rs2); \ + } + + INSN(sub, c_sub, _sub); + INSN(subw, c_subw, _subw); + +#undef INSN + +// -------------------------- +#define INSN(NAME, C_NAME, NORMAL_NAME) \ + void NAME(Register Rd, Register Rs1, Register Rs2) { \ + /* and/or/xor/addw -> c.and/c.or/c.xor/c.addw */ \ + if (do_compress()) { \ + Register src = noreg; \ + if (Rs1->is_compressed_valid() && Rs2->is_compressed_valid() && \ + ((src = Rs1, Rs2 == Rd) || (src = Rs2, Rs1 == Rd))) { \ + C_NAME(Rd, src); \ + return; \ + } \ + } \ + NORMAL_NAME(Rd, Rs1, Rs2); \ + } + + INSN(andr, c_and, _andr); + INSN(orr, c_or, _orr); + INSN(xorr, c_xor, _xorr); + INSN(addw, c_addw, _addw); + +#undef INSN + +private: +// some helper functions + bool do_compress() const { + return UseRVC && in_compressible_region(); + } + +#define FUNC(NAME, funct3, bits) \ + bool NAME(Register rs1, Register rd_rs2, int32_t imm12, bool ld) { \ + return rs1 == sp && \ + is_unsigned_imm_in_range(imm12, bits, 0) && \ + (intx(imm12) & funct3) == 0x0 && \ + (!ld || rd_rs2 != x0); \ + } \ + + FUNC(is_c_ldsdsp, 0b111, 9); + FUNC(is_c_lwswsp, 0b011, 8); + +#undef FUNC + +#define FUNC(NAME, funct3, bits) \ + bool NAME(Register rs1, int32_t imm12) { \ + return rs1 == sp && \ + is_unsigned_imm_in_range(imm12, bits, 0) && \ + (intx(imm12) & funct3) == 0x0; \ + } \ + + FUNC(is_c_fldsdsp, 0b111, 9); + +#undef FUNC + +#define FUNC(NAME, REG_TYPE, funct3, bits) \ + bool NAME(Register rs1, REG_TYPE rd_rs2, int32_t imm12) { \ + return rs1->is_compressed_valid() && \ + rd_rs2->is_compressed_valid() && \ + is_unsigned_imm_in_range(imm12, bits, 0) && \ + (intx(imm12) & funct3) == 0x0; \ + } \ + + FUNC(is_c_ldsd, Register, 0b111, 8); + FUNC(is_c_lwsw, Register, 0b011, 7); + FUNC(is_c_fldsd, FloatRegister, 0b111, 8); + +#undef FUNC + +public: +// -------------------------- +// Load/store register +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* lw -> c.lwsp/c.lw */ \ + if (do_compress()) { \ + if (is_c_lwswsp(Rs, Rd, offset, true)) { \ + c_lwsp(Rd, offset); \ + return; \ + } else if (is_c_lwsw(Rs, Rd, offset)) { \ + c_lw(Rd, Rs, offset); \ + return; \ + } \ + } \ + _lw(Rd, Rs, offset); \ + } + + INSN(lw); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* ld -> c.ldsp/c.ld */ \ + if (do_compress()) { \ + if (is_c_ldsdsp(Rs, Rd, offset, true)) { \ + c_ldsp(Rd, offset); \ + return; \ + } else if (is_c_ldsd(Rs, Rd, offset)) { \ + c_ld(Rd, Rs, offset); \ + return; \ + } \ + } \ + _ld(Rd, Rs, offset); \ + } + + INSN(ld); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + /* fld -> c.fldsp/c.fld */ \ + if (do_compress()) { \ + if (is_c_fldsdsp(Rs, offset)) { \ + c_fldsp(Rd, offset); \ + return; \ + } else if (is_c_fldsd(Rs, Rd, offset)) { \ + c_fld(Rd, Rs, offset); \ + return; \ + } \ + } \ + _fld(Rd, Rs, offset); \ + } + + INSN(fld); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* sd -> c.sdsp/c.sd */ \ + if (do_compress()) { \ + if (is_c_ldsdsp(Rs, Rd, offset, false)) { \ + c_sdsp(Rd, offset); \ + return; \ + } else if (is_c_ldsd(Rs, Rd, offset)) { \ + c_sd(Rd, Rs, offset); \ + return; \ + } \ + } \ + _sd(Rd, Rs, offset); \ + } + + INSN(sd); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* sw -> c.swsp/c.sw */ \ + if (do_compress()) { \ + if (is_c_lwswsp(Rs, Rd, offset, false)) { \ + c_swsp(Rd, offset); \ + return; \ + } else if (is_c_lwsw(Rs, Rd, offset)) { \ + c_sw(Rd, Rs, offset); \ + return; \ + } \ + } \ + _sw(Rd, Rs, offset); \ + } + + INSN(sw); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(FloatRegister Rd, Register Rs, const int32_t offset) { \ + /* fsd -> c.fsdsp/c.fsd */ \ + if (do_compress()) { \ + if (is_c_fldsdsp(Rs, offset)) { \ + c_fsdsp(Rd, offset); \ + return; \ + } else if (is_c_fldsd(Rs, Rd, offset)) { \ + c_fsd(Rd, Rs, offset); \ + return; \ + } \ + } \ + _fsd(Rd, Rs, offset); \ + } + + INSN(fsd); + +#undef INSN + +// -------------------------- +// Conditional branch instructions +// -------------------------- +#define INSN(NAME, C_NAME, NORMAL_NAME) \ + void NAME(Register Rs1, Register Rs2, const int64_t offset) { \ + /* beq/bne -> c.beqz/c.bnez */ \ + if (do_compress() && \ + (offset != 0 && Rs2 == x0 && Rs1->is_compressed_valid() && \ + is_imm_in_range(offset, 8, 1))) { \ + C_NAME(Rs1, offset); \ + return; \ + } \ + NORMAL_NAME(Rs1, Rs2, offset); \ + } + + INSN(beq, c_beqz, _beq); + INSN(bne, c_beqz, _bne); + +#undef INSN + +// -------------------------- +// Unconditional branch instructions +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, const int32_t offset) { \ + /* jal -> c.j */ \ + if (do_compress() && offset != 0 && Rd == x0 && is_imm_in_range(offset, 11, 1)) { \ + c_j(offset); \ + return; \ + } \ + _jal(Rd, offset); \ + } + + INSN(jal); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs, const int32_t offset) { \ + /* jalr -> c.jr/c.jalr */ \ + if (do_compress() && (offset == 0 && Rs != x0)) { \ + if (Rd == x1) { \ + c_jalr(Rs); \ + return; \ + } else if (Rd == x0) { \ + c_jr(Rs); \ + return; \ + } \ + } \ + _jalr(Rd, Rs, offset); \ + } + + INSN(jalr); + +#undef INSN + +// -------------------------- +// Miscellaneous Instructions +// -------------------------- +#define INSN(NAME) \ + void NAME() { \ + /* ebreak -> c.ebreak */ \ + if (do_compress()) { \ + c_ebreak(); \ + return; \ + } \ + _ebreak(); \ + } + + INSN(ebreak); + +#undef INSN + +#define INSN(NAME) \ + void NAME() { \ + /* The illegal instruction in RVC is presented by a 16-bit 0. */ \ + if (do_compress()) { \ + emit_int16(0); \ + return; \ + } \ + _halt(); \ + } + + INSN(halt); + +#undef INSN + +// -------------------------- +// Immediate Instructions +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, int64_t imm) { \ + /* li -> c.li */ \ + if (do_compress() && (is_imm_in_range(imm, 6, 0) && Rd != x0)) { \ + c_li(Rd, imm); \ + return; \ + } \ + _li(Rd, imm); \ + } + + INSN(li); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + /* addi -> c.addi/c.nop/c.mv/c.addi16sp/c.addi4spn */ \ + if (do_compress()) { \ + if (Rd == Rs1 && is_imm_in_range(imm, 6, 0)) { \ + c_addi(Rd, imm); \ + return; \ + } else if (imm == 0 && Rd != x0 && Rs1 != x0) { \ + c_mv(Rd, Rs1); \ + return; \ + } else if (Rs1 == sp && imm != 0) { \ + if (Rd == Rs1 && (imm & 0b1111) == 0x0 && is_imm_in_range(imm, 10, 0)) { \ + c_addi16sp(imm); \ + return; \ + } else if (Rd->is_compressed_valid() && (imm & 0b11) == 0x0 && is_unsigned_imm_in_range(imm, 10, 0)) { \ + c_addi4spn(Rd, imm); \ + return; \ + } \ + } \ + } \ + _addi(Rd, Rs1, imm); \ + } + + INSN(addi); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + /* addiw -> c.addiw */ \ + if (do_compress() && (Rd == Rs1 && Rd != x0 && is_imm_in_range(imm, 6, 0))) { \ + c_addiw(Rd, imm); \ + return; \ + } \ + _addiw(Rd, Rs1, imm); \ + } + + INSN(addiw); + +#undef INSN + +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, int32_t imm) { \ + /* and_imm12 -> c.andi */ \ + if (do_compress() && \ + (Rd == Rs1 && Rd->is_compressed_valid() && is_imm_in_range(imm, 6, 0))) { \ + c_andi(Rd, imm); \ + return; \ + } \ + _and_imm12(Rd, Rs1, imm); \ + } + + INSN(and_imm12); + +#undef INSN + +// -------------------------- +// Shift Immediate Instructions +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + /* slli -> c.slli */ \ + if (do_compress() && (Rd == Rs1 && Rd != x0 && shamt != 0)) { \ + c_slli(Rd, shamt); \ + return; \ + } \ + _slli(Rd, Rs1, shamt); \ + } + + INSN(slli); + +#undef INSN + +// -------------------------- +#define INSN(NAME, C_NAME, NORMAL_NAME) \ + void NAME(Register Rd, Register Rs1, unsigned shamt) { \ + /* srai/srli -> c.srai/c.srli */ \ + if (do_compress() && (Rd == Rs1 && Rd->is_compressed_valid() && shamt != 0)) { \ + C_NAME(Rd, shamt); \ + return; \ + } \ + NORMAL_NAME(Rd, Rs1, shamt); \ + } + + INSN(srai, c_srai, _srai); + INSN(srli, c_srli, _srli); + +#undef INSN + +// -------------------------- +// Upper Immediate Instruction +// -------------------------- +#define INSN(NAME) \ + void NAME(Register Rd, int32_t imm) { \ + /* lui -> c.lui */ \ + if (do_compress() && (Rd != x0 && Rd != x2 && imm != 0 && is_imm_in_range(imm, 18, 0))) { \ + c_lui(Rd, imm); \ + return; \ + } \ + _lui(Rd, imm); \ + } + + INSN(lui); + +#undef INSN + +// --------------------------------------------------------------------------------------- + + void bgt(Register Rs, Register Rt, const address &dest); + void ble(Register Rs, Register Rt, const address &dest); + void bgtu(Register Rs, Register Rt, const address &dest); + void bleu(Register Rs, Register Rt, const address &dest); + void bgt(Register Rs, Register Rt, Label &l, bool is_far = false); + void ble(Register Rs, Register Rt, Label &l, bool is_far = false); + void bgtu(Register Rs, Register Rt, Label &l, bool is_far = false); + void bleu(Register Rs, Register Rt, Label &l, bool is_far = false); + + typedef void (Assembler::* jal_jalr_insn)(Register Rt, address dest); + typedef void (Assembler::* load_insn_by_temp)(Register Rt, address dest, Register temp); + typedef void (Assembler::* compare_and_branch_insn)(Register Rs1, Register Rs2, const address dest); + typedef void (Assembler::* compare_and_branch_label_insn)(Register Rs1, Register Rs2, Label &L, bool is_far); + + void wrap_label(Register r1, Register r2, Label &L, compare_and_branch_insn insn, + compare_and_branch_label_insn neg_insn, bool is_far); + void wrap_label(Register r, Label &L, Register t, load_insn_by_temp insn); + void wrap_label(Register r, Label &L, jal_jalr_insn insn); + + // calculate pseudoinstruction + void add(Register Rd, Register Rn, int64_t increment, Register temp = t0); + void addw(Register Rd, Register Rn, int64_t increment, Register temp = t0); + void sub(Register Rd, Register Rn, int64_t decrement, Register temp = t0); + void subw(Register Rd, Register Rn, int64_t decrement, Register temp = t0); + + // RVB pseudo instructions + // zero extend word + void zext_w(Register Rd, Register Rs); + + Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(false) { + } + + // Stack overflow checking + virtual void bang_stack_with_offset(int offset) { Unimplemented(); } + + static bool operand_valid_for_add_immediate(long imm) { + return is_imm_in_range(imm, 12, 0); + } + + // The maximum range of a branch is fixed for the RISCV architecture. + static const unsigned long branch_range = 1 * M; + + static bool reachable_from_branch_at(address branch, address target) { + return uabs(target - branch) < branch_range; + } + + virtual ~Assembler() {} +}; + +#endif // CPU_RISCV_ASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/assembler_riscv.inline.hpp b/src/hotspot/cpu/riscv/assembler_riscv.inline.hpp new file mode 100644 index 00000000000..7ffe8803985 --- /dev/null +++ b/src/hotspot/cpu/riscv/assembler_riscv.inline.hpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_ASSEMBLER_RISCV_INLINE_HPP +#define CPU_RISCV_ASSEMBLER_RISCV_INLINE_HPP + +#include "asm/assembler.inline.hpp" +#include "asm/codeBuffer.hpp" +#include "code/codeCache.hpp" + +inline bool is_imm_in_range(long value, unsigned bits, unsigned align_bits) { + intx sign_bits = (value >> (bits + align_bits - 1)); + return ((value & right_n_bits(align_bits)) == 0) && ((sign_bits == 0) || (sign_bits == -1)); +} + +inline bool is_unsigned_imm_in_range(intx value, unsigned bits, unsigned align_bits) { + return (value >= 0) && ((value & right_n_bits(align_bits)) == 0) && ((value >> (align_bits + bits)) == 0); +} + +inline bool is_offset_in_range(intx offset, unsigned bits) { + return is_imm_in_range(offset, bits, 0); +} + +#endif // CPU_RISCV_ASSEMBLER_RISCV_INLINE_HPP diff --git a/src/hotspot/cpu/riscv/bytes_riscv.hpp b/src/hotspot/cpu/riscv/bytes_riscv.hpp new file mode 100644 index 00000000000..23d982f9abd --- /dev/null +++ b/src/hotspot/cpu/riscv/bytes_riscv.hpp @@ -0,0 +1,167 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2016 SAP SE. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_BYTES_RISCV_HPP +#define CPU_RISCV_BYTES_RISCV_HPP + +#include "memory/allStatic.hpp" + +class Bytes: AllStatic { + public: + // Efficient reading and writing of unaligned unsigned data in platform-specific byte ordering + // RISCV needs to check for alignment. + + // Forward declarations of the compiler-dependent implementation + static inline u2 swap_u2(u2 x); + static inline u4 swap_u4(u4 x); + static inline u8 swap_u8(u8 x); + + static inline u2 get_native_u2(address p) { + if ((intptr_t(p) & 1) == 0) { + return *(u2*)p; + } else { + return ((u2)(p[1]) << 8) | + ((u2)(p[0])); + } + } + + static inline u4 get_native_u4(address p) { + switch (intptr_t(p) & 3) { + case 0: + return *(u4*)p; + + case 2: + return ((u4)(((u2*)p)[1]) << 16) | + ((u4)(((u2*)p)[0])); + + default: + return ((u4)(p[3]) << 24) | + ((u4)(p[2]) << 16) | + ((u4)(p[1]) << 8) | + ((u4)(p[0])); + } + } + + static inline u8 get_native_u8(address p) { + switch (intptr_t(p) & 7) { + case 0: + return *(u8*)p; + + case 4: + return ((u8)(((u4*)p)[1]) << 32) | + ((u8)(((u4*)p)[0])); + + case 2: + return ((u8)(((u2*)p)[3]) << 48) | + ((u8)(((u2*)p)[2]) << 32) | + ((u8)(((u2*)p)[1]) << 16) | + ((u8)(((u2*)p)[0])); + + default: + return ((u8)(p[7]) << 56) | + ((u8)(p[6]) << 48) | + ((u8)(p[5]) << 40) | + ((u8)(p[4]) << 32) | + ((u8)(p[3]) << 24) | + ((u8)(p[2]) << 16) | + ((u8)(p[1]) << 8) | + ((u8)(p[0])); + } + } + + static inline void put_native_u2(address p, u2 x) { + if ((intptr_t(p) & 1) == 0) { + *(u2*)p = x; + } else { + p[1] = x >> 8; + p[0] = x; + } + } + + static inline void put_native_u4(address p, u4 x) { + switch (intptr_t(p) & 3) { + case 0: + *(u4*)p = x; + break; + + case 2: + ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: + ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + break; + } + } + + static inline void put_native_u8(address p, u8 x) { + switch (intptr_t(p) & 7) { + case 0: + *(u8*)p = x; + break; + + case 4: + ((u4*)p)[1] = x >> 32; + ((u4*)p)[0] = x; + break; + + case 2: + ((u2*)p)[3] = x >> 48; + ((u2*)p)[2] = x >> 32; + ((u2*)p)[1] = x >> 16; + ((u2*)p)[0] = x; + break; + + default: + ((u1*)p)[7] = x >> 56; + ((u1*)p)[6] = x >> 48; + ((u1*)p)[5] = x >> 40; + ((u1*)p)[4] = x >> 32; + ((u1*)p)[3] = x >> 24; + ((u1*)p)[2] = x >> 16; + ((u1*)p)[1] = x >> 8; + ((u1*)p)[0] = x; + break; + } + } + + // Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering) + static inline u2 get_Java_u2(address p) { return swap_u2(get_native_u2(p)); } + static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); } + static inline u8 get_Java_u8(address p) { return swap_u8(get_native_u8(p)); } + + static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, swap_u2(x)); } + static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, swap_u4(x)); } + static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, swap_u8(x)); } +}; + +#include OS_CPU_HEADER(bytes) + +#endif // CPU_RISCV_BYTES_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp new file mode 100644 index 00000000000..dcd0472c540 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_CodeStubs_riscv.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "c1/c1_CodeStubs.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "classfile/javaClasses.hpp" +#include "nativeInst_riscv.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_riscv.inline.hpp" + + +#define __ ce->masm()-> + +void C1SafepointPollStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + InternalAddress safepoint_pc(__ pc() - __ offset() + safepoint_offset()); + __ code_section()->relocate(__ pc(), safepoint_pc.rspec()); + __ la(t0, safepoint_pc.target()); + __ sd(t0, Address(xthread, JavaThread::saved_exception_pc_offset())); + + assert(SharedRuntime::polling_page_return_handler_blob() != NULL, + "polling page return stub not created yet"); + address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); + + __ far_jump(RuntimeAddress(stub)); +} + +void CounterOverflowStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + Metadata *m = _method->as_constant_ptr()->as_metadata(); + __ mov_metadata(t0, m); + ce->store_parameter(t0, 1); + ce->store_parameter(_bci, 0); + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::counter_overflow_id))); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ j(_continuation); +} + +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index, LIR_Opr array) + : _index(index), _array(array), _throw_index_out_of_bounds_exception(false) { + assert(info != NULL, "must have info"); + _info = new CodeEmitInfo(info); +} + +RangeCheckStub::RangeCheckStub(CodeEmitInfo* info, LIR_Opr index) + : _index(index), _array(), _throw_index_out_of_bounds_exception(true) { + assert(info != NULL, "must have info"); + _info = new CodeEmitInfo(info); +} + +void RangeCheckStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + if (_info->deoptimize_on_exception()) { + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + __ far_call(RuntimeAddress(a)); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); + return; + } + + if (_index->is_cpu_register()) { + __ mv(t0, _index->as_register()); + } else { + __ mv(t0, _index->as_jint()); + } + Runtime1::StubID stub_id; + if (_throw_index_out_of_bounds_exception) { + stub_id = Runtime1::throw_index_exception_id; + } else { + assert(_array != LIR_Opr::nullOpr(), "sanity"); + __ mv(t1, _array->as_pointer_register()); + stub_id = Runtime1::throw_range_check_failed_id; + } + int32_t off = 0; + __ la_patchable(ra, RuntimeAddress(Runtime1::entry_for(stub_id)), off); + __ jalr(ra, ra, off); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); +} + +PredicateFailedStub::PredicateFailedStub(CodeEmitInfo* info) { + _info = new CodeEmitInfo(info); +} + +void PredicateFailedStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + address a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + __ far_call(RuntimeAddress(a)); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); +} + +void DivByZeroStub::emit_code(LIR_Assembler* ce) { + if (_offset != -1) { + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); + } + __ bind(_entry); + __ far_call(Address(Runtime1::entry_for(Runtime1::throw_div0_exception_id), relocInfo::runtime_call_type)); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); +#ifdef ASSERT + __ should_not_reach_here(); +#endif +} + +// Implementation of NewInstanceStub +NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) { + _result = result; + _klass = klass; + _klass_reg = klass_reg; + _info = new CodeEmitInfo(info); + assert(stub_id == Runtime1::new_instance_id || + stub_id == Runtime1::fast_new_instance_id || + stub_id == Runtime1::fast_new_instance_init_check_id, + "need new_instance id"); + _stub_id = stub_id; +} + +void NewInstanceStub::emit_code(LIR_Assembler* ce) { + assert(__ rsp_offset() == 0, "frame size should be fixed"); + __ bind(_entry); + __ mv(x13, _klass_reg->as_register()); + __ far_call(RuntimeAddress(Runtime1::entry_for(_stub_id))); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + assert(_result->as_register() == x10, "result must in x10"); + __ j(_continuation); +} + +// Implementation of NewTypeArrayStub +NewTypeArrayStub::NewTypeArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { + _klass_reg = klass_reg; + _length = length; + _result = result; + _info = new CodeEmitInfo(info); +} + +void NewTypeArrayStub::emit_code(LIR_Assembler* ce) { + assert(__ rsp_offset() == 0, "frame size should be fixed"); + __ bind(_entry); + assert(_length->as_register() == x9, "length must in x9"); + assert(_klass_reg->as_register() == x13, "klass_reg must in x13"); + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_type_array_id))); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + assert(_result->as_register() == x10, "result must in x10"); + __ j(_continuation); +} + +// Implementation of NewObjectArrayStub +NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { + _klass_reg = klass_reg; + _result = result; + _length = length; + _info = new CodeEmitInfo(info); +} + +void NewObjectArrayStub::emit_code(LIR_Assembler* ce) { + assert(__ rsp_offset() == 0, "frame size should be fixed"); + __ bind(_entry); + assert(_length->as_register() == x9, "length must in x9"); + assert(_klass_reg->as_register() == x13, "klass_reg must in x13"); + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id))); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + assert(_result->as_register() == x10, "result must in x10"); + __ j(_continuation); +} + +// Implementation of MonitorAccessStubs +MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info) +: MonitorAccessStub(obj_reg, lock_reg) { + _info = new CodeEmitInfo(info); +} + +void MonitorEnterStub::emit_code(LIR_Assembler* ce) { + assert(__ rsp_offset() == 0, "frame size should be fixed"); + __ bind(_entry); + ce->store_parameter(_obj_reg->as_register(), 1); + ce->store_parameter(_lock_reg->as_register(), 0); + Runtime1::StubID enter_id; + if (ce->compilation()->has_fpu_code()) { + enter_id = Runtime1::monitorenter_id; + } else { + enter_id = Runtime1::monitorenter_nofpu_id; + } + __ far_call(RuntimeAddress(Runtime1::entry_for(enter_id))); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + __ j(_continuation); +} + +void MonitorExitStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + if (_compute_lock) { + // lock_reg was destroyed by fast unlocking attempt => recompute it + ce->monitor_address(_monitor_ix, _lock_reg); + } + ce->store_parameter(_lock_reg->as_register(), 0); + // note: non-blocking leaf routine => no call info needed + Runtime1::StubID exit_id; + if (ce->compilation()->has_fpu_code()) { + exit_id = Runtime1::monitorexit_id; + } else { + exit_id = Runtime1::monitorexit_nofpu_id; + } + __ la(ra, _continuation); + __ far_jump(RuntimeAddress(Runtime1::entry_for(exit_id))); +} + +// Implementation of patching: +// - Copy the code at given offset to an inlined buffer (first the bytes, then the number of bytes) +// - Replace original code with a call to the stub +// At Runtime: +// - call to stub, jump to runtime +// - in runtime: preserve all registers (rspecially objects, i.e., source and destination object) +// - in runtime: after initializing class, restore original code, reexecute instruction + +int PatchingStub::_patch_info_offset = -NativeGeneralJump::instruction_size; + +void PatchingStub::align_patch_site(MacroAssembler* masm) {} + +void PatchingStub::emit_code(LIR_Assembler* ce) { + assert(false, "RISCV should not use C1 runtime patching"); +} + +void DeoptimizeStub::emit_code(LIR_Assembler* ce) { + __ bind(_entry); + ce->store_parameter(_trap_request, 0); + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::deoptimize_id))); + ce->add_call_info_here(_info); + DEBUG_ONLY(__ should_not_reach_here()); +} + +void ImplicitNullCheckStub::emit_code(LIR_Assembler* ce) { + address a = NULL; + if (_info->deoptimize_on_exception()) { + // Deoptimize, do not throw the exception, because it is probably wrong to do it here. + a = Runtime1::entry_for(Runtime1::predicate_failed_trap_id); + } else { + a = Runtime1::entry_for(Runtime1::throw_null_pointer_exception_id); + } + + ce->compilation()->implicit_exception_table()->append(_offset, __ offset()); + __ bind(_entry); + __ far_call(RuntimeAddress(a)); + ce->add_call_info_here(_info); + ce->verify_oop_map(_info); + debug_only(__ should_not_reach_here()); +} + +void SimpleExceptionStub::emit_code(LIR_Assembler* ce) { + assert(__ rsp_offset() == 0, "frame size should be fixed"); + + __ bind(_entry); + // pass the object in a tmp register because all other registers + // must be preserved + if (_obj->is_cpu_register()) { + __ mv(t0, _obj->as_register()); + } + __ far_call(RuntimeAddress(Runtime1::entry_for(_stub)), NULL, t1); + ce->add_call_info_here(_info); + debug_only(__ should_not_reach_here()); +} + +void ArrayCopyStub::emit_code(LIR_Assembler* ce) { + // ---------------slow case: call to native----------------- + __ bind(_entry); + // Figure out where the args should go + // This should really convert the IntrinsicID to the Method* and signature + // but I don't know how to do that. + const int args_num = 5; + VMRegPair args[args_num]; + BasicType signature[args_num] = { T_OBJECT, T_INT, T_OBJECT, T_INT, T_INT }; + SharedRuntime::java_calling_convention(signature, args, args_num); + + // push parameters + Register r[args_num]; + r[0] = src()->as_register(); + r[1] = src_pos()->as_register(); + r[2] = dst()->as_register(); + r[3] = dst_pos()->as_register(); + r[4] = length()->as_register(); + + // next registers will get stored on the stack + for (int j = 0; j < args_num; j++) { + VMReg r_1 = args[j].first(); + if (r_1->is_stack()) { + int st_off = r_1->reg2stack() * wordSize; + __ sd(r[j], Address(sp, st_off)); + } else { + assert(r[j] == args[j].first()->as_Register(), "Wrong register for arg"); + } + } + + ce->align_call(lir_static_call); + + ce->emit_static_call_stub(); + if (ce->compilation()->bailed_out()) { + return; // CodeCache is full + } + Address resolve(SharedRuntime::get_resolve_static_call_stub(), + relocInfo::static_call_type); + address call = __ trampoline_call(resolve); + if (call == NULL) { + ce->bailout("trampoline stub overflow"); + return; + } + ce->add_call_info_here(info()); + +#ifndef PRODUCT + if (PrintC1Statistics) { + __ la(t1, ExternalAddress((address)&Runtime1::_arraycopy_slowcase_cnt)); + __ add_memory_int32(Address(t1), 1); + } +#endif + + __ j(_continuation); +} + +#undef __ diff --git a/src/hotspot/cpu/riscv/c1_Defs_riscv.hpp b/src/hotspot/cpu/riscv/c1_Defs_riscv.hpp new file mode 100644 index 00000000000..4417ad63091 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_Defs_riscv.hpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_DEFS_RISCV_HPP +#define CPU_RISCV_C1_DEFS_RISCV_HPP + +// native word offsets from memory address (little endian) +enum { + pd_lo_word_offset_in_bytes = 0, + pd_hi_word_offset_in_bytes = BytesPerWord +}; + +// explicit rounding operations are required to implement the strictFP mode +enum { + pd_strict_fp_requires_explicit_rounding = false +}; + +// registers +enum { + pd_nof_cpu_regs_frame_map = RegisterImpl::number_of_registers, // number of registers used during code emission + pd_nof_fpu_regs_frame_map = FloatRegisterImpl::number_of_registers, // number of float registers used during code emission + + // caller saved + pd_nof_caller_save_cpu_regs_frame_map = 13, // number of registers killed by calls + pd_nof_caller_save_fpu_regs_frame_map = 32, // number of float registers killed by calls + + pd_first_callee_saved_reg = pd_nof_caller_save_cpu_regs_frame_map, + pd_last_callee_saved_reg = 21, + + pd_last_allocatable_cpu_reg = pd_nof_caller_save_cpu_regs_frame_map - 1, + + pd_nof_cpu_regs_reg_alloc + = pd_nof_caller_save_cpu_regs_frame_map, // number of registers that are visible to register allocator + pd_nof_fpu_regs_reg_alloc = 32, // number of float registers that are visible to register allocator + + pd_nof_cpu_regs_linearscan = 32, // number of registers visible to linear scan + pd_nof_fpu_regs_linearscan = pd_nof_fpu_regs_frame_map, // number of float registers visible to linear scan + pd_nof_xmm_regs_linearscan = 0, // don't have vector registers + + pd_first_cpu_reg = 0, + pd_last_cpu_reg = pd_nof_cpu_regs_reg_alloc - 1, + pd_first_byte_reg = 0, + pd_last_byte_reg = pd_nof_cpu_regs_reg_alloc - 1, + + pd_first_fpu_reg = pd_nof_cpu_regs_frame_map, + pd_last_fpu_reg = pd_first_fpu_reg + 31, + + pd_first_callee_saved_fpu_reg_1 = 8 + pd_first_fpu_reg, + pd_last_callee_saved_fpu_reg_1 = 9 + pd_first_fpu_reg, + pd_first_callee_saved_fpu_reg_2 = 18 + pd_first_fpu_reg, + pd_last_callee_saved_fpu_reg_2 = 27 + pd_first_fpu_reg +}; + + +// Encoding of float value in debug info. This is true on x86 where +// floats are extended to doubles when stored in the stack, false for +// RISCV where floats and doubles are stored in their native form. +enum { + pd_float_saved_as_double = false +}; + +#endif // CPU_RISCV_C1_DEFS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_FpuStackSim_riscv.cpp b/src/hotspot/cpu/riscv/c1_FpuStackSim_riscv.cpp new file mode 100644 index 00000000000..e3a2606c532 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_FpuStackSim_riscv.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +//-------------------------------------------------------- +// FpuStackSim +//-------------------------------------------------------- + +// No FPU stack on RISCV diff --git a/src/hotspot/cpu/riscv/c1_FpuStackSim_riscv.hpp b/src/hotspot/cpu/riscv/c1_FpuStackSim_riscv.hpp new file mode 100644 index 00000000000..7bc3d311501 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_FpuStackSim_riscv.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_FPUSTACKSIM_RISCV_HPP +#define CPU_RISCV_C1_FPUSTACKSIM_RISCV_HPP + +// No FPU stack on RISCV +class FpuStackSim; + +#endif // CPU_RISCV_C1_FPUSTACKSIM_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp new file mode 100644 index 00000000000..172031941b2 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.cpp @@ -0,0 +1,388 @@ +/* + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_LIR.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_riscv.inline.hpp" + +LIR_Opr FrameMap::map_to_opr(BasicType type, VMRegPair* reg, bool) { + LIR_Opr opr = LIR_OprFact::illegalOpr; + VMReg r_1 = reg->first(); + VMReg r_2 = reg->second(); + if (r_1->is_stack()) { + // Convert stack slot to an SP offset + // The calling convention does not count the SharedRuntime::out_preserve_stack_slots() value + // so we must add it in here. + int st_off = (r_1->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size; + opr = LIR_OprFact::address(new LIR_Address(sp_opr, st_off, type)); + } else if (r_1->is_Register()) { + Register reg1 = r_1->as_Register(); + if (r_2->is_Register() && (type == T_LONG || type == T_DOUBLE)) { + Register reg2 = r_2->as_Register(); + assert(reg2 == reg1, "must be same register"); + opr = as_long_opr(reg1); + } else if (is_reference_type(type)) { + opr = as_oop_opr(reg1); + } else if (type == T_METADATA) { + opr = as_metadata_opr(reg1); + } else if (type == T_ADDRESS) { + opr = as_address_opr(reg1); + } else { + opr = as_opr(reg1); + } + } else if (r_1->is_FloatRegister()) { + assert(type == T_DOUBLE || type == T_FLOAT, "wrong type"); + int num = r_1->as_FloatRegister()->encoding(); + if (type == T_FLOAT) { + opr = LIR_OprFact::single_fpu(num); + } else { + opr = LIR_OprFact::double_fpu(num); + } + } else { + ShouldNotReachHere(); + } + return opr; +} + +LIR_Opr FrameMap::zr_opr; +LIR_Opr FrameMap::r1_opr; +LIR_Opr FrameMap::r2_opr; +LIR_Opr FrameMap::r3_opr; +LIR_Opr FrameMap::r4_opr; +LIR_Opr FrameMap::r5_opr; +LIR_Opr FrameMap::r6_opr; +LIR_Opr FrameMap::r7_opr; +LIR_Opr FrameMap::r8_opr; +LIR_Opr FrameMap::r9_opr; +LIR_Opr FrameMap::r10_opr; +LIR_Opr FrameMap::r11_opr; +LIR_Opr FrameMap::r12_opr; +LIR_Opr FrameMap::r13_opr; +LIR_Opr FrameMap::r14_opr; +LIR_Opr FrameMap::r15_opr; +LIR_Opr FrameMap::r16_opr; +LIR_Opr FrameMap::r17_opr; +LIR_Opr FrameMap::r18_opr; +LIR_Opr FrameMap::r19_opr; +LIR_Opr FrameMap::r20_opr; +LIR_Opr FrameMap::r21_opr; +LIR_Opr FrameMap::r22_opr; +LIR_Opr FrameMap::r23_opr; +LIR_Opr FrameMap::r24_opr; +LIR_Opr FrameMap::r25_opr; +LIR_Opr FrameMap::r26_opr; +LIR_Opr FrameMap::r27_opr; +LIR_Opr FrameMap::r28_opr; +LIR_Opr FrameMap::r29_opr; +LIR_Opr FrameMap::r30_opr; +LIR_Opr FrameMap::r31_opr; + +LIR_Opr FrameMap::fp_opr; +LIR_Opr FrameMap::sp_opr; + +LIR_Opr FrameMap::receiver_opr; + +LIR_Opr FrameMap::zr_oop_opr; +LIR_Opr FrameMap::r1_oop_opr; +LIR_Opr FrameMap::r2_oop_opr; +LIR_Opr FrameMap::r3_oop_opr; +LIR_Opr FrameMap::r4_oop_opr; +LIR_Opr FrameMap::r5_oop_opr; +LIR_Opr FrameMap::r6_oop_opr; +LIR_Opr FrameMap::r7_oop_opr; +LIR_Opr FrameMap::r8_oop_opr; +LIR_Opr FrameMap::r9_oop_opr; +LIR_Opr FrameMap::r10_oop_opr; +LIR_Opr FrameMap::r11_oop_opr; +LIR_Opr FrameMap::r12_oop_opr; +LIR_Opr FrameMap::r13_oop_opr; +LIR_Opr FrameMap::r14_oop_opr; +LIR_Opr FrameMap::r15_oop_opr; +LIR_Opr FrameMap::r16_oop_opr; +LIR_Opr FrameMap::r17_oop_opr; +LIR_Opr FrameMap::r18_oop_opr; +LIR_Opr FrameMap::r19_oop_opr; +LIR_Opr FrameMap::r20_oop_opr; +LIR_Opr FrameMap::r21_oop_opr; +LIR_Opr FrameMap::r22_oop_opr; +LIR_Opr FrameMap::r23_oop_opr; +LIR_Opr FrameMap::r24_oop_opr; +LIR_Opr FrameMap::r25_oop_opr; +LIR_Opr FrameMap::r26_oop_opr; +LIR_Opr FrameMap::r27_oop_opr; +LIR_Opr FrameMap::r28_oop_opr; +LIR_Opr FrameMap::r29_oop_opr; +LIR_Opr FrameMap::r30_oop_opr; +LIR_Opr FrameMap::r31_oop_opr; + +LIR_Opr FrameMap::t0_opr; +LIR_Opr FrameMap::t1_opr; +LIR_Opr FrameMap::t0_long_opr; +LIR_Opr FrameMap::t1_long_opr; + +LIR_Opr FrameMap::r10_metadata_opr; +LIR_Opr FrameMap::r11_metadata_opr; +LIR_Opr FrameMap::r12_metadata_opr; +LIR_Opr FrameMap::r13_metadata_opr; +LIR_Opr FrameMap::r14_metadata_opr; +LIR_Opr FrameMap::r15_metadata_opr; + +LIR_Opr FrameMap::long10_opr; +LIR_Opr FrameMap::long11_opr; +LIR_Opr FrameMap::fpu10_float_opr; +LIR_Opr FrameMap::fpu10_double_opr; + +LIR_Opr FrameMap::_caller_save_cpu_regs[] = {}; +LIR_Opr FrameMap::_caller_save_fpu_regs[] = {}; + +//-------------------------------------------------------- +// FrameMap +//-------------------------------------------------------- +// |---f31--| +// |---..---| +// |---f28--| +// |---f27--|<---pd_last_callee_saved_fpu_reg_2 +// |---..---| +// |---f18--|<---pd_first_callee_saved_fpu_reg_2 +// |---f17--| +// |---..---| +// |---f10--| +// |---f9---|<---pd_last_callee_saved_fpu_reg_1 +// |---f8---|<---pd_first_callee_saved_fpu_reg_1 +// |---f7---| +// |---..---| +// |---f0---| +// |---x27--| +// |---x23--| +// |---x8---| +// |---x4---| +// |---x3---| +// |---x2---| +// |---x1---| +// |---x0---| +// |---x26--|<---pd_last_callee_saved_reg +// |---..---| +// |---x18--| +// |---x9---|<---pd_first_callee_saved_reg +// |---x31--| +// |---..---| +// |---x28--| +// |---x17--| +// |---..---| +// |---x10--| +// |---x7---| + +void FrameMap::initialize() { + assert(!_init_done, "once"); + + int i = 0; + + // caller save register + map_register(i, x7); r7_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x10); r10_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x11); r11_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x12); r12_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x13); r13_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x14); r14_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x15); r15_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x16); r16_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x17); r17_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x28); r28_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x29); r29_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x30); r30_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x31); r31_opr = LIR_OprFact::single_cpu(i); i++; + + // callee save register + map_register(i, x9); r9_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x18); r18_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x19); r19_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x20); r20_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x21); r21_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x22); r22_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x24); r24_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x25); r25_opr = LIR_OprFact::single_cpu(i); i++; + map_register(i, x26); r26_opr = LIR_OprFact::single_cpu(i); i++; + + // special register + map_register(i, x0); zr_opr = LIR_OprFact::single_cpu(i); i++; // zr + map_register(i, x1); r1_opr = LIR_OprFact::single_cpu(i); i++; // ra + map_register(i, x2); r2_opr = LIR_OprFact::single_cpu(i); i++; // sp + map_register(i, x3); r3_opr = LIR_OprFact::single_cpu(i); i++; // gp + map_register(i, x4); r4_opr = LIR_OprFact::single_cpu(i); i++; // thread + map_register(i, x8); r8_opr = LIR_OprFact::single_cpu(i); i++; // fp + map_register(i, x23); r23_opr = LIR_OprFact::single_cpu(i); i++; // java thread + map_register(i, x27); r27_opr = LIR_OprFact::single_cpu(i); i++; // heapbase + + // tmp register + map_register(i, x5); r5_opr = LIR_OprFact::single_cpu(i); i++; // t0 + map_register(i, x6); r6_opr = LIR_OprFact::single_cpu(i); i++; // t1 + + t0_opr = r5_opr; + t1_opr = r6_opr; + t0_long_opr = LIR_OprFact::double_cpu(r5_opr->cpu_regnr(), r5_opr->cpu_regnr()); + t1_long_opr = LIR_OprFact::double_cpu(r6_opr->cpu_regnr(), r6_opr->cpu_regnr()); + + long10_opr = LIR_OprFact::double_cpu(r10_opr->cpu_regnr(), r10_opr->cpu_regnr()); + long11_opr = LIR_OprFact::double_cpu(r11_opr->cpu_regnr(), r11_opr->cpu_regnr()); + + fpu10_float_opr = LIR_OprFact::single_fpu(10); + fpu10_double_opr = LIR_OprFact::double_fpu(10); + + i = 0; + _caller_save_cpu_regs[i++] = r7_opr; + _caller_save_cpu_regs[i++] = r10_opr; + _caller_save_cpu_regs[i++] = r11_opr; + _caller_save_cpu_regs[i++] = r12_opr; + _caller_save_cpu_regs[i++] = r13_opr; + _caller_save_cpu_regs[i++] = r14_opr; + _caller_save_cpu_regs[i++] = r15_opr; + _caller_save_cpu_regs[i++] = r16_opr; + _caller_save_cpu_regs[i++] = r17_opr; + _caller_save_cpu_regs[i++] = r28_opr; + _caller_save_cpu_regs[i++] = r29_opr; + _caller_save_cpu_regs[i++] = r30_opr; + _caller_save_cpu_regs[i++] = r31_opr; + + _init_done = true; + + zr_oop_opr = as_oop_opr(x0); + r1_oop_opr = as_oop_opr(x1); + r2_oop_opr = as_oop_opr(x2); + r3_oop_opr = as_oop_opr(x3); + r4_oop_opr = as_oop_opr(x4); + r5_oop_opr = as_oop_opr(x5); + r6_oop_opr = as_oop_opr(x6); + r7_oop_opr = as_oop_opr(x7); + r8_oop_opr = as_oop_opr(x8); + r9_oop_opr = as_oop_opr(x9); + r10_oop_opr = as_oop_opr(x10); + r11_oop_opr = as_oop_opr(x11); + r12_oop_opr = as_oop_opr(x12); + r13_oop_opr = as_oop_opr(x13); + r14_oop_opr = as_oop_opr(x14); + r15_oop_opr = as_oop_opr(x15); + r16_oop_opr = as_oop_opr(x16); + r17_oop_opr = as_oop_opr(x17); + r18_oop_opr = as_oop_opr(x18); + r19_oop_opr = as_oop_opr(x19); + r20_oop_opr = as_oop_opr(x20); + r21_oop_opr = as_oop_opr(x21); + r22_oop_opr = as_oop_opr(x22); + r23_oop_opr = as_oop_opr(x23); + r24_oop_opr = as_oop_opr(x24); + r25_oop_opr = as_oop_opr(x25); + r26_oop_opr = as_oop_opr(x26); + r27_oop_opr = as_oop_opr(x27); + r28_oop_opr = as_oop_opr(x28); + r29_oop_opr = as_oop_opr(x29); + r30_oop_opr = as_oop_opr(x30); + r31_oop_opr = as_oop_opr(x31); + + r10_metadata_opr = as_metadata_opr(x10); + r11_metadata_opr = as_metadata_opr(x11); + r12_metadata_opr = as_metadata_opr(x12); + r13_metadata_opr = as_metadata_opr(x13); + r14_metadata_opr = as_metadata_opr(x14); + r15_metadata_opr = as_metadata_opr(x15); + + sp_opr = as_pointer_opr(sp); + fp_opr = as_pointer_opr(fp); + + VMRegPair regs; + BasicType sig_bt = T_OBJECT; + SharedRuntime::java_calling_convention(&sig_bt, ®s, 1); + receiver_opr = as_oop_opr(regs.first()->as_Register()); + + for (i = 0; i < nof_caller_save_fpu_regs; i++) { + _caller_save_fpu_regs[i] = LIR_OprFact::single_fpu(i); + } +} + + +Address FrameMap::make_new_address(ByteSize sp_offset) const { + return Address(sp, in_bytes(sp_offset)); +} + + +// ----------------mapping----------------------- +// all mapping is based on fp addressing, except for simple leaf methods where we access +// the locals sp based (and no frame is built) + + +// Frame for simple leaf methods (quick entries) +// +// +----------+ +// | ret addr | <- TOS +// +----------+ +// | args | +// | ...... | + +// Frame for standard methods +// +// | .........| <- TOS +// | locals | +// +----------+ +// | old fp, | +// +----------+ +// | ret addr | +// +----------+ +// | args | <- FP +// | .........| + + +// For OopMaps, map a local variable or spill index to an VMRegImpl name. +// This is the offset from sp() in the frame of the slot for the index, +// skewed by VMRegImpl::stack0 to indicate a stack location (vs.a register.) +// +// framesize + +// stack0 stack0 0 <- VMReg +// | | | +// ...........|..............|.............| +// 0 1 2 3 x x 4 5 6 ... | <- local indices +// ^ ^ sp() ( x x indicate link +// | | and return addr) +// arguments non-argument locals + + +VMReg FrameMap::fpu_regname (int n) { + // Return the OptoReg name for the fpu stack slot "n" + // A spilled fpu stack slot comprises to two single-word OptoReg's. + return as_FloatRegister(n)->as_VMReg(); +} + +LIR_Opr FrameMap::stack_pointer() { + return FrameMap::sp_opr; +} + +// JSR 292 +LIR_Opr FrameMap::method_handle_invoke_SP_save_opr() { + return LIR_OprFact::illegalOpr; // Not needed on riscv +} + +bool FrameMap::validate_frame() { + return true; +} diff --git a/src/hotspot/cpu/riscv/c1_FrameMap_riscv.hpp b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.hpp new file mode 100644 index 00000000000..01281f5c9e1 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_FrameMap_riscv.hpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_FRAMEMAP_RISCV_HPP +#define CPU_RISCV_C1_FRAMEMAP_RISCV_HPP + +// On RISCV the frame looks as follows: +// +// +-----------------------------+---------+----------------------------------------+----------------+----------- +// | size_arguments-nof_reg_args | 2 words | size_locals-size_arguments+numreg_args | _size_monitors | spilling . +// +-----------------------------+---------+----------------------------------------+----------------+----------- + + public: + static const int pd_c_runtime_reserved_arg_size; + + enum { + first_available_sp_in_frame = 0, + frame_pad_in_bytes = 16, + nof_reg_args = 8 + }; + + public: + static LIR_Opr receiver_opr; + + static LIR_Opr zr_opr; + static LIR_Opr r1_opr; + static LIR_Opr r2_opr; + static LIR_Opr r3_opr; + static LIR_Opr r4_opr; + static LIR_Opr r5_opr; + static LIR_Opr r6_opr; + static LIR_Opr r7_opr; + static LIR_Opr r8_opr; + static LIR_Opr r9_opr; + static LIR_Opr r10_opr; + static LIR_Opr r11_opr; + static LIR_Opr r12_opr; + static LIR_Opr r13_opr; + static LIR_Opr r14_opr; + static LIR_Opr r15_opr; + static LIR_Opr r16_opr; + static LIR_Opr r17_opr; + static LIR_Opr r18_opr; + static LIR_Opr r19_opr; + static LIR_Opr r20_opr; + static LIR_Opr r21_opr; + static LIR_Opr r22_opr; + static LIR_Opr r23_opr; + static LIR_Opr r24_opr; + static LIR_Opr r25_opr; + static LIR_Opr r26_opr; + static LIR_Opr r27_opr; + static LIR_Opr r28_opr; + static LIR_Opr r29_opr; + static LIR_Opr r30_opr; + static LIR_Opr r31_opr; + static LIR_Opr fp_opr; + static LIR_Opr sp_opr; + + static LIR_Opr zr_oop_opr; + static LIR_Opr r1_oop_opr; + static LIR_Opr r2_oop_opr; + static LIR_Opr r3_oop_opr; + static LIR_Opr r4_oop_opr; + static LIR_Opr r5_oop_opr; + static LIR_Opr r6_oop_opr; + static LIR_Opr r7_oop_opr; + static LIR_Opr r8_oop_opr; + static LIR_Opr r9_oop_opr; + static LIR_Opr r10_oop_opr; + static LIR_Opr r11_oop_opr; + static LIR_Opr r12_oop_opr; + static LIR_Opr r13_oop_opr; + static LIR_Opr r14_oop_opr; + static LIR_Opr r15_oop_opr; + static LIR_Opr r16_oop_opr; + static LIR_Opr r17_oop_opr; + static LIR_Opr r18_oop_opr; + static LIR_Opr r19_oop_opr; + static LIR_Opr r20_oop_opr; + static LIR_Opr r21_oop_opr; + static LIR_Opr r22_oop_opr; + static LIR_Opr r23_oop_opr; + static LIR_Opr r24_oop_opr; + static LIR_Opr r25_oop_opr; + static LIR_Opr r26_oop_opr; + static LIR_Opr r27_oop_opr; + static LIR_Opr r28_oop_opr; + static LIR_Opr r29_oop_opr; + static LIR_Opr r30_oop_opr; + static LIR_Opr r31_oop_opr; + + static LIR_Opr t0_opr; + static LIR_Opr t1_opr; + static LIR_Opr t0_long_opr; + static LIR_Opr t1_long_opr; + + static LIR_Opr r10_metadata_opr; + static LIR_Opr r11_metadata_opr; + static LIR_Opr r12_metadata_opr; + static LIR_Opr r13_metadata_opr; + static LIR_Opr r14_metadata_opr; + static LIR_Opr r15_metadata_opr; + + static LIR_Opr long10_opr; + static LIR_Opr long11_opr; + static LIR_Opr fpu10_float_opr; + static LIR_Opr fpu10_double_opr; + + static LIR_Opr as_long_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + } + static LIR_Opr as_pointer_opr(Register r) { + return LIR_OprFact::double_cpu(cpu_reg2rnr(r), cpu_reg2rnr(r)); + } + + // VMReg name for spilled physical FPU stack slot n + static VMReg fpu_regname(int n); + + static bool is_caller_save_register(LIR_Opr opr) { return true; } + static bool is_caller_save_register(Register r) { return true; } + + static int nof_caller_save_cpu_regs() { return pd_nof_caller_save_cpu_regs_frame_map; } + static int last_cpu_reg() { return pd_last_cpu_reg; } + +#endif // CPU_RISCV_C1_FRAMEMAP_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arith_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arith_riscv.cpp new file mode 100644 index 00000000000..4c1c13dc290 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arith_riscv.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" + +#ifndef PRODUCT +#define COMMENT(x) do { __ block_comment(x); } while (0) +#else +#define COMMENT(x) +#endif + +#define __ _masm-> + +void LIR_Assembler::arithmetic_idiv(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr illegal, + LIR_Opr result, CodeEmitInfo* info) { + // opcode check + assert((code == lir_idiv) || (code == lir_irem), "opcode must be idiv or irem"); + bool is_irem = (code == lir_irem); + // opreand check + assert(left->is_single_cpu(), "left must be a register"); + assert(right->is_single_cpu() || right->is_constant(), "right must be a register or constant"); + assert(result->is_single_cpu(), "result must be a register"); + Register lreg = left->as_register(); + Register dreg = result->as_register(); + + // power-of-2 constant check and codegen + if (right->is_constant()) { + int c = right->as_constant_ptr()->as_jint(); + assert(c > 0 && is_power_of_2(c), "divisor must be power-of-2 constant"); + if (is_irem) { + if (c == 1) { + // move 0 to dreg if divisor is 1 + __ mv(dreg, zr); + } else { + unsigned int shift = exact_log2(c); + __ sraiw(t0, lreg, 0x1f); + __ srliw(t0, t0, BitsPerInt - shift); + __ addw(t1, lreg, t0); + if (is_imm_in_range(c - 1, 12, 0)) { + __ andi(t1, t1, c - 1); + } else { + __ zero_extend(t1, t1, shift); + } + __ subw(dreg, t1, t0); + } + } else { + if (c == 1) { + // move lreg to dreg if divisor is 1 + __ mv(dreg, lreg); + } else { + unsigned int shift = exact_log2(c); + __ sraiw(t0, lreg, 0x1f); + if (is_imm_in_range(c - 1, 12, 0)) { + __ andi(t0, t0, c - 1); + } else { + __ zero_extend(t0, t0, shift); + } + __ addw(dreg, t0, lreg); + __ sraiw(dreg, dreg, shift); + } + } + } else { + Register rreg = right->as_register(); + __ corrected_idivl(dreg, lreg, rreg, is_irem); + } +} + +void LIR_Assembler::arith_op_single_cpu_right_constant(LIR_Code code, LIR_Opr left, LIR_Opr right, + Register lreg, Register dreg) { + // cpu register - constant + jlong c; + + switch (right->type()) { + case T_LONG: + c = right->as_constant_ptr()->as_jlong(); break; + case T_INT: // fall through + case T_ADDRESS: + c = right->as_constant_ptr()->as_jint(); break; + default: + ShouldNotReachHere(); + c = 0; // unreachable + } + + assert(code == lir_add || code == lir_sub, "mismatched arithmetic op"); + if (c == 0 && dreg == lreg) { + COMMENT("effective nop elided"); + return; + } + switch (left->type()) { + case T_INT: + switch (code) { + case lir_add: __ addw(dreg, lreg, c); break; + case lir_sub: __ subw(dreg, lreg, c); break; + default: ShouldNotReachHere(); + } + break; + case T_OBJECT: // fall through + case T_ADDRESS: + switch (code) { + case lir_add: __ add(dreg, lreg, c); break; + case lir_sub: __ sub(dreg, lreg, c); break; + default: ShouldNotReachHere(); + } + break; + default: + ShouldNotReachHere(); + } +} + +void LIR_Assembler::arith_op_single_cpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) { + Register lreg = left->as_register(); + Register dreg = as_reg(dest); + + if (right->is_single_cpu()) { + // cpu register - cpu register + assert(left->type() == T_INT && right->type() == T_INT && dest->type() == T_INT, "should be"); + Register rreg = right->as_register(); + switch (code) { + case lir_add: __ addw(dest->as_register(), lreg, rreg); break; + case lir_sub: __ subw(dest->as_register(), lreg, rreg); break; + case lir_mul: __ mulw(dest->as_register(), lreg, rreg); break; + default: ShouldNotReachHere(); + } + } else if (right->is_double_cpu()) { + Register rreg = right->as_register_lo(); + // sigle_cpu + double_cpu; can happen with obj_long + assert(code == lir_add || code == lir_sub, "mismatched arithmetic op"); + switch (code) { + case lir_add: __ add(dreg, lreg, rreg); break; + case lir_sub: __ sub(dreg, lreg, rreg); break; + default: ShouldNotReachHere(); + } + } else if (right->is_constant()) { + arith_op_single_cpu_right_constant(code, left, right, lreg, dreg); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::arith_op_double_cpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) { + Register lreg_lo = left->as_register_lo(); + + if (right->is_double_cpu()) { + // cpu register - cpu register + Register rreg_lo = right->as_register_lo(); + switch (code) { + case lir_add: __ add(dest->as_register_lo(), lreg_lo, rreg_lo); break; + case lir_sub: __ sub(dest->as_register_lo(), lreg_lo, rreg_lo); break; + case lir_mul: __ mul(dest->as_register_lo(), lreg_lo, rreg_lo); break; + case lir_div: __ corrected_idivq(dest->as_register_lo(), lreg_lo, rreg_lo, false); break; + case lir_rem: __ corrected_idivq(dest->as_register_lo(), lreg_lo, rreg_lo, true); break; + default: + ShouldNotReachHere(); + } + } else if (right->is_constant()) { + jlong c = right->as_constant_ptr()->as_jlong(); + Register dreg = as_reg(dest); + switch (code) { + case lir_add: // fall through + case lir_sub: + if (c == 0 && dreg == lreg_lo) { + COMMENT("effective nop elided"); + return; + } + code == lir_add ? __ add(dreg, lreg_lo, c) : __ sub(dreg, lreg_lo, c); + break; + case lir_div: + assert(c > 0 && is_power_of_2(c), "divisor must be power-of-2 constant"); + if (c == 1) { + // move lreg_lo to dreg if divisor is 1 + __ mv(dreg, lreg_lo); + } else { + unsigned int shift = exact_log2_long(c); + // use t0 as intermediate result register + __ srai(t0, lreg_lo, 0x3f); + if (is_imm_in_range(c - 1, 12, 0)) { + __ andi(t0, t0, c - 1); + } else { + __ zero_extend(t0, t0, shift); + } + __ add(dreg, t0, lreg_lo); + __ srai(dreg, dreg, shift); + } + break; + case lir_rem: + assert(c > 0 && is_power_of_2(c), "divisor must be power-of-2 constant"); + if (c == 1) { + // move 0 to dreg if divisor is 1 + __ mv(dreg, zr); + } else { + unsigned int shift = exact_log2_long(c); + __ srai(t0, lreg_lo, 0x3f); + __ srli(t0, t0, BitsPerLong - shift); + __ add(t1, lreg_lo, t0); + if (is_imm_in_range(c - 1, 12, 0)) { + __ andi(t1, t1, c - 1); + } else { + __ zero_extend(t1, t1, shift); + } + __ sub(dreg, t1, t0); + } + break; + default: + ShouldNotReachHere(); + } + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::arith_op_single_fpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) { + assert(right->is_single_fpu(), "right hand side of float arithmetics needs to be float register"); + switch (code) { + case lir_add: __ fadd_s(dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break; + case lir_sub: __ fsub_s(dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break; + case lir_mul: __ fmul_s(dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break; + case lir_div: __ fdiv_s(dest->as_float_reg(), left->as_float_reg(), right->as_float_reg()); break; + default: + ShouldNotReachHere(); + } +} + +void LIR_Assembler::arith_op_double_fpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest) { + if (right->is_double_fpu()) { + // fpu register - fpu register + switch (code) { + case lir_add: __ fadd_d(dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break; + case lir_sub: __ fsub_d(dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break; + case lir_mul: __ fmul_d(dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break; + case lir_div: __ fdiv_d(dest->as_double_reg(), left->as_double_reg(), right->as_double_reg()); break; + default: + ShouldNotReachHere(); + } + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::arith_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest, + CodeEmitInfo* info, bool pop_fpu_stack) { + assert(info == NULL, "should never be used, idiv/irem and ldiv/lrem not handled by this method"); + + if (left->is_single_cpu()) { + arith_op_single_cpu(code, left, right, dest); + } else if (left->is_double_cpu()) { + arith_op_double_cpu(code, left, right, dest); + } else if (left->is_single_fpu()) { + arith_op_single_fpu(code, left, right, dest); + } else if (left->is_double_fpu()) { + arith_op_double_fpu(code, left, right, dest); + } else { + ShouldNotReachHere(); + } +} + +#undef __ diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arith_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arith_riscv.hpp new file mode 100644 index 00000000000..ab0a9963fc1 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arith_riscv.hpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_LIRASSEMBLER_ARITH_RISCV_HPP +#define CPU_RISCV_C1_LIRASSEMBLER_ARITH_RISCV_HPP + + // arith_op sub functions + void arith_op_single_cpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest); + void arith_op_double_cpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest); + void arith_op_single_fpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest); + void arith_op_double_fpu(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dest); + void arith_op_single_cpu_right_constant(LIR_Code code, LIR_Opr left, LIR_Opr right, Register lreg, Register dreg); + void arithmetic_idiv(LIR_Op3* op, bool is_irem); + +#endif // CPU_RISCV_C1_LIRASSEMBLER_ARITH_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp new file mode 100644 index 00000000000..b7f53e395f3 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.cpp @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "ci/ciArrayKlass.hpp" +#include "oops/objArrayKlass.hpp" +#include "runtime/stubRoutines.hpp" + +#define __ _masm-> + + +void LIR_Assembler::generic_arraycopy(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, CodeStub *stub) { + assert(src == x11 && src_pos == x12, "mismatch in calling convention"); + // Save the arguments in case the generic arraycopy fails and we + // have to fall back to the JNI stub + arraycopy_store_args(src, src_pos, length, dst, dst_pos); + + address copyfunc_addr = StubRoutines::generic_arraycopy(); + assert(copyfunc_addr != NULL, "generic arraycopy stub required"); + + // The arguments are in java calling convention so we shift them + // to C convention + assert_different_registers(c_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4); + __ mv(c_rarg0, j_rarg0); + assert_different_registers(c_rarg1, j_rarg2, j_rarg3, j_rarg4); + __ mv(c_rarg1, j_rarg1); + assert_different_registers(c_rarg2, j_rarg3, j_rarg4); + __ mv(c_rarg2, j_rarg2); + assert_different_registers(c_rarg3, j_rarg4); + __ mv(c_rarg3, j_rarg3); + __ mv(c_rarg4, j_rarg4); +#ifndef PRODUCT + if (PrintC1Statistics) { + __ add_memory_int32(ExternalAddress((address)&Runtime1::_generic_arraycopystub_cnt), 1); + } +#endif + __ far_call(RuntimeAddress(copyfunc_addr)); + __ beqz(x10, *stub->continuation()); + // Reload values from the stack so they are where the stub + // expects them. + arraycopy_load_args(src, src_pos, length, dst, dst_pos); + + // x10 is -1^K where K == partial copied count + __ xori(t0, x10, -1); + // adjust length down and src/end pos up by partial copied count + __ subw(length, length, t0); + __ addw(src_pos, src_pos, t0); + __ addw(dst_pos, dst_pos, t0); + __ j(*stub->entry()); + + __ bind(*stub->continuation()); +} + +void LIR_Assembler::arraycopy_simple_check(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, Register tmp, + CodeStub *stub, int flags) { + // test for NULL + if (flags & LIR_OpArrayCopy::src_null_check) { + __ beqz(src, *stub->entry(), /* is_far */ true); + } + if (flags & LIR_OpArrayCopy::dst_null_check) { + __ beqz(dst, *stub->entry(), /* is_far */ true); + } + + // If the compiler was not able to prove that exact type of the source or the destination + // of the arraycopy is an array type, check at runtime if the source or the destination is + // an instance type. + if (flags & LIR_OpArrayCopy::type_check) { + if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::dst_objarray)) { + __ load_klass(tmp, dst); + __ lw(t0, Address(tmp, in_bytes(Klass::layout_helper_offset()))); + __ li(t1, Klass::_lh_neutral_value); + __ bge(t0, t1, *stub->entry(), /* is_far */ true); + } + + if (!(flags & LIR_OpArrayCopy::LIR_OpArrayCopy::src_objarray)) { + __ load_klass(tmp, src); + __ lw(t0, Address(tmp, in_bytes(Klass::layout_helper_offset()))); + __ li(t1, Klass::_lh_neutral_value); + __ bge(t0, t1, *stub->entry(), /* is_far */ true); + } + } + + // check if negative + if (flags & LIR_OpArrayCopy::src_pos_positive_check) { + __ bltz(src_pos, *stub->entry(), /* is_far */ true); + } + if (flags & LIR_OpArrayCopy::dst_pos_positive_check) { + __ bltz(dst_pos, *stub->entry(), /* is_far */ true); + } + if (flags & LIR_OpArrayCopy::length_positive_check) { + __ bltz(length, *stub->entry(), /* is_far */ true); + } + + if (flags & LIR_OpArrayCopy::src_range_check) { + __ addw(tmp, src_pos, length); + __ lwu(t0, Address(src, arrayOopDesc::length_offset_in_bytes())); + __ bgtu(tmp, t0, *stub->entry(), /* is_far */ true); + } + if (flags & LIR_OpArrayCopy::dst_range_check) { + __ addw(tmp, dst_pos, length); + __ lwu(t0, Address(dst, arrayOopDesc::length_offset_in_bytes())); + __ bgtu(tmp, t0, *stub->entry(), /* is_far */ true); + } +} + +void LIR_Assembler::arraycopy_checkcast(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, Register tmp, + CodeStub *stub, BasicType basic_type, + address copyfunc_addr, int flags) { + // src is not a sub class of dst so we have to do a + // per-element check. + int mask = LIR_OpArrayCopy::src_objarray | LIR_OpArrayCopy::dst_objarray; + if ((flags & mask) != mask) { + // Check that at least both of them object arrays. + assert(flags & mask, "one of the two should be known to be an object array"); + + if (!(flags & LIR_OpArrayCopy::src_objarray)) { + __ load_klass(tmp, src); + } else if (!(flags & LIR_OpArrayCopy::dst_objarray)) { + __ load_klass(tmp, dst); + } + int lh_offset = in_bytes(Klass::layout_helper_offset()); + Address klass_lh_addr(tmp, lh_offset); + jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ lw(t0, klass_lh_addr); + __ mvw(t1, objArray_lh); + __ bne(t0, t1, *stub->entry(), /* is_far */ true); + } + + // Spill because stubs can use any register they like and it's + // easier to restore just those that we care about. + arraycopy_store_args(src, src_pos, length, dst, dst_pos); + arraycopy_checkcast_prepare_params(src, src_pos, length, dst, dst_pos, basic_type); + __ far_call(RuntimeAddress(copyfunc_addr)); + +#ifndef PRODUCT + if (PrintC1Statistics) { + Label failed; + __ bnez(x10, failed); + __ add_memory_int32(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_cnt), 1); + __ bind(failed); + } +#endif + + __ beqz(x10, *stub->continuation()); + +#ifndef PRODUCT + if (PrintC1Statistics) { + __ add_memory_int32(ExternalAddress((address)&Runtime1::_arraycopy_checkcast_attempt_cnt), 1); + } +#endif + assert_different_registers(dst, dst_pos, length, src_pos, src, x10, t0); + + // Restore previously spilled arguments + arraycopy_load_args(src, src_pos, length, dst, dst_pos); + + // return value is -1^K where K is partial copied count + __ xori(t0, x10, -1); + // adjust length down and src/end pos up by partial copied count + __ subw(length, length, t0); + __ addw(src_pos, src_pos, t0); + __ addw(dst_pos, dst_pos, t0); +} + +void LIR_Assembler::arraycopy_type_check(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, Register tmp, + CodeStub *stub, BasicType basic_type, int flags) { + // We don't know the array types are compatible + if (basic_type != T_OBJECT) { + // Simple test for basic type arrays + if (UseCompressedClassPointers) { + __ lwu(tmp, Address(src, oopDesc::klass_offset_in_bytes())); + __ lwu(t0, Address(dst, oopDesc::klass_offset_in_bytes())); + } else { + __ ld(tmp, Address(src, oopDesc::klass_offset_in_bytes())); + __ ld(t0, Address(dst, oopDesc::klass_offset_in_bytes())); + } + __ bne(tmp, t0, *stub->entry(), /* is_far */ true); + } else { + // For object arrays, if src is a sub class of dst then we can + // safely do the copy. + Label cont, slow; + +#define PUSH(r1, r2) \ + __ addi(sp, sp, -2 * wordSize); \ + __ sd(r1, Address(sp, 1 * wordSize)); \ + __ sd(r2, Address(sp, 0)); + +#define POP(r1, r2) \ + __ ld(r1, Address(sp, 1 * wordSize)); \ + __ ld(r2, Address(sp, 0)); \ + __ addi(sp, sp, 2 * wordSize); + + PUSH(src, dst); + __ load_klass(src, src); + __ load_klass(dst, dst); + __ check_klass_subtype_fast_path(src, dst, tmp, &cont, &slow, NULL); + + PUSH(src, dst); + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); + POP(src, dst); + __ bnez(dst, cont); + + __ bind(slow); + POP(src, dst); + + address copyfunc_addr = StubRoutines::checkcast_arraycopy(); + if (copyfunc_addr != NULL) { // use stub if available + arraycopy_checkcast(src, src_pos, length, dst, dst_pos, tmp, stub, basic_type, copyfunc_addr, flags); + } + + __ j(*stub->entry()); + __ bind(cont); + POP(src, dst); + } +} + +void LIR_Assembler::arraycopy_assert(Register src, Register dst, Register tmp, ciArrayKlass *default_type, int flags) { + assert(default_type != NULL, "NULL default_type!"); + BasicType basic_type = default_type->element_type()->basic_type(); + + if (basic_type == T_ARRAY) { basic_type = T_OBJECT; } + if (basic_type != T_OBJECT || !(flags & LIR_OpArrayCopy::type_check)) { + // Sanity check the known type with the incoming class. For the + // primitive case the types must match exactly with src.klass and + // dst.klass each exactly matching the default type. For the + // object array case, if no type check is needed then either the + // dst type is exactly the expected type and the src type is a + // subtype which we can't check or src is the same array as dst + // but not necessarily exactly of type default_type. + Label known_ok, halt; + __ mov_metadata(tmp, default_type->constant_encoding()); + if (UseCompressedClassPointers) { + __ encode_klass_not_null(tmp); + } + + if (basic_type != T_OBJECT) { + if (UseCompressedClassPointers) { + __ lwu(t0, Address(dst, oopDesc::klass_offset_in_bytes())); + } else { + __ ld(t0, Address(dst, oopDesc::klass_offset_in_bytes())); + } + __ bne(tmp, t0, halt); + if (UseCompressedClassPointers) { + __ lwu(t0, Address(src, oopDesc::klass_offset_in_bytes())); + } else { + __ ld(t0, Address(src, oopDesc::klass_offset_in_bytes())); + } + __ beq(tmp, t0, known_ok); + } else { + if (UseCompressedClassPointers) { + __ lwu(t0, Address(dst, oopDesc::klass_offset_in_bytes())); + } else { + __ ld(t0, Address(dst, oopDesc::klass_offset_in_bytes())); + } + __ beq(tmp, t0, known_ok); + __ beq(src, dst, known_ok); + } + __ bind(halt); + __ stop("incorrect type information in arraycopy"); + __ bind(known_ok); + } +} + +void LIR_Assembler::emit_arraycopy(LIR_OpArrayCopy* op) { + ciArrayKlass *default_type = op->expected_type(); + Register src = op->src()->as_register(); + Register dst = op->dst()->as_register(); + Register src_pos = op->src_pos()->as_register(); + Register dst_pos = op->dst_pos()->as_register(); + Register length = op->length()->as_register(); + Register tmp = op->tmp()->as_register(); + + CodeStub* stub = op->stub(); + int flags = op->flags(); + BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL; + if (is_reference_type(basic_type)) { basic_type = T_OBJECT; } + + // if we don't know anything, just go through the generic arraycopy + if (default_type == NULL) { + generic_arraycopy(src, src_pos, length, dst, dst_pos, stub); + return; + } + + assert(default_type != NULL && default_type->is_array_klass() && default_type->is_loaded(), + "must be true at this point"); + + arraycopy_simple_check(src, src_pos, length, dst, dst_pos, tmp, stub, flags); + + if (flags & LIR_OpArrayCopy::type_check) { + arraycopy_type_check(src, src_pos, length, dst, dst_pos, tmp, stub, basic_type, flags); + } + +#ifdef ASSERT + arraycopy_assert(src, dst, tmp, default_type, flags); +#endif + +#ifndef PRODUCT + if (PrintC1Statistics) { + __ add_memory_int32(ExternalAddress(Runtime1::arraycopy_count_address(basic_type)), 1); + } +#endif + arraycopy_prepare_params(src, src_pos, length, dst, dst_pos, basic_type); + + bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0; + bool aligned = (flags & LIR_OpArrayCopy::unaligned) == 0; + const char *name = NULL; + address entry = StubRoutines::select_arraycopy_function(basic_type, aligned, disjoint, name, false); + + CodeBlob *cb = CodeCache::find_blob(entry); + if (cb != NULL) { + __ far_call(RuntimeAddress(entry)); + } else { + const int args_num = 3; + __ call_VM_leaf(entry, args_num); + } + + __ bind(*stub->continuation()); +} + + +void LIR_Assembler::arraycopy_prepare_params(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, BasicType basic_type) { + int scale = array_element_size(basic_type); + __ shadd(c_rarg0, src_pos, src, t0, scale); + __ add(c_rarg0, c_rarg0, arrayOopDesc::base_offset_in_bytes(basic_type)); + assert_different_registers(c_rarg0, dst, dst_pos, length); + __ shadd(c_rarg1, dst_pos, dst, t0, scale); + __ add(c_rarg1, c_rarg1, arrayOopDesc::base_offset_in_bytes(basic_type)); + assert_different_registers(c_rarg1, dst, length); + __ mv(c_rarg2, length); + assert_different_registers(c_rarg2, dst); +} + +void LIR_Assembler::arraycopy_checkcast_prepare_params(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, BasicType basic_type) { + arraycopy_prepare_params(src, src_pos, length, dst, dst_pos, basic_type); + __ load_klass(c_rarg4, dst); + __ ld(c_rarg4, Address(c_rarg4, ObjArrayKlass::element_klass_offset())); + __ lwu(c_rarg3, Address(c_rarg4, Klass::super_check_offset_offset())); +} + +void LIR_Assembler::arraycopy_store_args(Register src, Register src_pos, Register length, + Register dst, Register dst_pos) { + __ sd(dst_pos, Address(sp, 0)); // 0: dst_pos sp offset + __ sd(dst, Address(sp, 1 * BytesPerWord)); // 1: dst sp offset + __ sd(length, Address(sp, 2 * BytesPerWord)); // 2: length sp offset + __ sd(src_pos, Address(sp, 3 * BytesPerWord)); // 3: src_pos sp offset + __ sd(src, Address(sp, 4 * BytesPerWord)); // 4: src sp offset +} + +void LIR_Assembler::arraycopy_load_args(Register src, Register src_pos, Register length, + Register dst, Register dst_pos) { + __ ld(dst_pos, Address(sp, 0)); // 0: dst_pos sp offset + __ ld(dst, Address(sp, 1 * BytesPerWord)); // 1: dst sp offset + __ ld(length, Address(sp, 2 * BytesPerWord)); // 2: length sp offset + __ ld(src_pos, Address(sp, 3 * BytesPerWord)); // 3: src_pos sp offset + __ ld(src, Address(sp, 4 * BytesPerWord)); // 4: src sp offset +} + +#undef __ diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp new file mode 100644 index 00000000000..06a0f248ca6 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_arraycopy_riscv.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_LIRASSEMBLER_ARRAYCOPY_RISCV_HPP +#define CPU_RISCV_C1_LIRASSEMBLER_ARRAYCOPY_RISCV_HPP + + // arraycopy sub functions + void generic_arraycopy(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, CodeStub *stub); + void arraycopy_simple_check(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, Register tmp, + CodeStub *stub, int flags); + void arraycopy_checkcast(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, Register tmp, + CodeStub *stub, BasicType basic_type, + address copyfunc_addr, int flags); + void arraycopy_type_check(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, Register tmp, + CodeStub *stub, BasicType basic_type, int flags); + void arraycopy_assert(Register src, Register dst, Register tmp, ciArrayKlass *default_type, int flags); + void arraycopy_prepare_params(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, BasicType basic_type); + void arraycopy_checkcast_prepare_params(Register src, Register src_pos, Register length, + Register dst, Register dst_pos, BasicType basic_type); + void arraycopy_store_args(Register src, Register src_pos, Register length, + Register dst, Register dst_pos); + void arraycopy_load_args(Register src, Register src_pos, Register length, + Register dst, Register dst_pos); + +#endif // CPU_RISCV_C1_LIRASSEMBLER_ARRAYCOPY_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp new file mode 100644 index 00000000000..742c2126e60 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.cpp @@ -0,0 +1,2267 @@ +/* + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "c1/c1_CodeStubs.hpp" +#include "c1/c1_Compilation.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "c1/c1_ValueStack.hpp" +#include "ci/ciArrayKlass.hpp" +#include "ci/ciInstance.hpp" +#include "code/compiledIC.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "nativeInst_riscv.hpp" +#include "oops/objArrayKlass.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/powerOfTwo.hpp" +#include "vmreg_riscv.inline.hpp" + +#ifndef PRODUCT +#define COMMENT(x) do { __ block_comment(x); } while (0) +#else +#define COMMENT(x) +#endif + +NEEDS_CLEANUP // remove this definitions ? +const Register IC_Klass = t1; // where the IC klass is cached +const Register SYNC_header = x10; // synchronization header +const Register SHIFT_count = x10; // where count for shift operations must be + +#define __ _masm-> + +static void select_different_registers(Register preserve, + Register extra, + Register &tmp1, + Register &tmp2) { + if (tmp1 == preserve) { + assert_different_registers(tmp1, tmp2, extra); + tmp1 = extra; + } else if (tmp2 == preserve) { + assert_different_registers(tmp1, tmp2, extra); + tmp2 = extra; + } + assert_different_registers(preserve, tmp1, tmp2); +} + +static void select_different_registers(Register preserve, + Register extra, + Register &tmp1, + Register &tmp2, + Register &tmp3) { + if (tmp1 == preserve) { + assert_different_registers(tmp1, tmp2, tmp3, extra); + tmp1 = extra; + } else if (tmp2 == preserve) { + assert_different_registers(tmp1, tmp2, tmp3, extra); + tmp2 = extra; + } else if (tmp3 == preserve) { + assert_different_registers(tmp1, tmp2, tmp3, extra); + tmp3 = extra; + } + assert_different_registers(preserve, tmp1, tmp2, tmp3); +} + +bool LIR_Assembler::is_small_constant(LIR_Opr opr) { Unimplemented(); return false; } + +void LIR_Assembler::clinit_barrier(ciMethod* method) { + assert(VM_Version::supports_fast_class_init_checks(), "sanity"); + assert(!method->holder()->is_not_initialized(), "initialization should have been started"); + + Label L_skip_barrier; + + __ mov_metadata(t1, method->holder()->constant_encoding()); + __ clinit_barrier(t1, t0, &L_skip_barrier /* L_fast_path */); + __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + __ bind(L_skip_barrier); +} + +LIR_Opr LIR_Assembler::receiverOpr() { + return FrameMap::receiver_opr; +} + +LIR_Opr LIR_Assembler::osrBufferPointer() { + return FrameMap::as_pointer_opr(receiverOpr()->as_register()); +} + +void LIR_Assembler::breakpoint() { Unimplemented(); } + +void LIR_Assembler::push(LIR_Opr opr) { Unimplemented(); } + +void LIR_Assembler::pop(LIR_Opr opr) { Unimplemented(); } + +static jlong as_long(LIR_Opr data) { + jlong result; + switch (data->type()) { + case T_INT: + result = (data->as_jint()); + break; + case T_LONG: + result = (data->as_jlong()); + break; + default: + ShouldNotReachHere(); + result = 0; // unreachable + } + return result; +} + +Address LIR_Assembler::as_Address(LIR_Address* addr, Register tmp) { + if (addr->base()->is_illegal()) { + assert(addr->index()->is_illegal(), "must be illegal too"); + __ movptr(tmp, addr->disp()); + return Address(tmp, 0); + } + + Register base = addr->base()->as_pointer_register(); + LIR_Opr index_opr = addr->index(); + + if (index_opr->is_illegal()) { + return Address(base, addr->disp()); + } + + int scale = addr->scale(); + if (index_opr->is_cpu_register()) { + Register index; + if (index_opr->is_single_cpu()) { + index = index_opr->as_register(); + } else { + index = index_opr->as_register_lo(); + } + if (scale != 0) { + __ shadd(tmp, index, base, tmp, scale); + } else { + __ add(tmp, base, index); + } + return Address(tmp, addr->disp()); + } else if (index_opr->is_constant()) { + intptr_t addr_offset = (((intptr_t)index_opr->as_constant_ptr()->as_jint()) << scale) + addr->disp(); + return Address(base, addr_offset); + } + + Unimplemented(); + return Address(); +} + +Address LIR_Assembler::as_Address_hi(LIR_Address* addr) { + ShouldNotReachHere(); + return Address(); +} + +Address LIR_Assembler::as_Address(LIR_Address* addr) { + return as_Address(addr, t0); +} + +Address LIR_Assembler::as_Address_lo(LIR_Address* addr) { + return as_Address(addr); +} + +// Ensure a valid Address (base + offset) to a stack-slot. If stack access is +// not encodable as a base + (immediate) offset, generate an explicit address +// calculation to hold the address in t0. +Address LIR_Assembler::stack_slot_address(int index, uint size, int adjust) { + precond(size == 4 || size == 8); + Address addr = frame_map()->address_for_slot(index, adjust); + precond(addr.getMode() == Address::base_plus_offset); + precond(addr.base() == sp); + precond(addr.offset() > 0); + uint mask = size - 1; + assert((addr.offset() & mask) == 0, "scaled offsets only"); + + return addr; +} + +void LIR_Assembler::osr_entry() { + offsets()->set_value(CodeOffsets::OSR_Entry, code_offset()); + BlockBegin* osr_entry = compilation()->hir()->osr_entry(); + guarantee(osr_entry != NULL, "NULL osr_entry!"); + ValueStack* entry_state = osr_entry->state(); + int number_of_locks = entry_state->locks_size(); + + // we jump here if osr happens with the interpreter + // state set up to continue at the beginning of the + // loop that triggered osr - in particular, we have + // the following registers setup: + // + // x12: osr buffer + // + + //build frame + ciMethod* m = compilation()->method(); + __ build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes()); + + // OSR buffer is + // + // locals[nlocals-1..0] + // monitors[0..number_of_locks] + // + // locals is a direct copy of the interpreter frame so in the osr buffer + // so first slot in the local array is the last local from the interpreter + // and last slot is local[0] (receiver) from the interpreter + // + // Similarly with locks. The first lock slot in the osr buffer is the nth lock + // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock + // in the interpreter frame (the method lock if a sync method) + + // Initialize monitors in the compiled activation. + // x12: pointer to osr buffer + // All other registers are dead at this point and the locals will be + // copied into place by code emitted in the IR. + + Register OSR_buf = osrBufferPointer()->as_pointer_register(); + { + assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); + int monitor_offset = BytesPerWord * method()->max_locals() + + (2 * BytesPerWord) * (number_of_locks - 1); + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in + // the OSR buffer using 2 word entries: first the lock and then + // the oop. + for (int i = 0; i < number_of_locks; i++) { + int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); +#ifdef ASSERT + // verify the interpreter's monitor has a non-null object + { + Label L; + __ ld(t0, Address(OSR_buf, slot_offset + 1 * BytesPerWord)); + __ bnez(t0, L); + __ stop("locked object is NULL"); + __ bind(L); + } +#endif // ASSERT + __ ld(x9, Address(OSR_buf, slot_offset + 0)); + __ sd(x9, frame_map()->address_for_monitor_lock(i)); + __ ld(x9, Address(OSR_buf, slot_offset + 1 * BytesPerWord)); + __ sd(x9, frame_map()->address_for_monitor_object(i)); + } + } +} + +// inline cache check; done before the frame is built. +int LIR_Assembler::check_icache() { + Register receiver = FrameMap::receiver_opr->as_register(); + Register ic_klass = IC_Klass; + int start_offset = __ offset(); + Label dont; + __ inline_cache_check(receiver, ic_klass, dont); + + // if icache check fails, then jump to runtime routine + // Note: RECEIVER must still contain the receiver! + __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + + // We align the verified entry point unless the method body + // (including its inline cache check) will fit in a single 64-byte + // icache line. + if (!method()->is_accessor() || __ offset() - start_offset > 4 * 4) { + // force alignment after the cache check. + __ align(CodeEntryAlignment); + } + + __ bind(dont); + return start_offset; +} + +void LIR_Assembler::jobject2reg(jobject o, Register reg) { + if (o == NULL) { + __ mv(reg, zr); + } else { + __ movoop(reg, o, /* immediate */ true); + } +} + +void LIR_Assembler::jobject2reg_with_patching(Register reg, CodeEmitInfo *info) { + deoptimize_trap(info); +} + +// This specifies the rsp decrement needed to build the frame +int LIR_Assembler::initial_frame_size_in_bytes() const { + // if rounding, must let FrameMap know! + + return in_bytes(frame_map()->framesize_in_bytes()); +} + +int LIR_Assembler::emit_exception_handler() { + // if the last instruction is a call (typically to do a throw which + // is coming at the end after block reordering) the return address + // must still point into the code area in order to avoid assertion + // failures when searching for the corresponding bci ==> add a nop + // (was bug 5/14/1999 -gri) + __ nop(); + + // generate code for exception handler + address handler_base = __ start_a_stub(exception_handler_size()); + if (handler_base == NULL) { + // not enough space left for the handler + bailout("exception handler overflow"); + return -1; + } + + int offset = code_offset(); + + // the exception oop and pc are in x10, and x13 + // no other registers need to be preserved, so invalidate them + __ invalidate_registers(false, true, true, false, true, true); + + // check that there is really an exception + __ verify_not_null_oop(x10); + + // search an exception handler (x10: exception oop, x13: throwing pc) + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::handle_exception_from_callee_id))); + __ should_not_reach_here(); + guarantee(code_offset() - offset <= exception_handler_size(), "overflow"); + __ end_a_stub(); + + return offset; +} + +// Emit the code to remove the frame from the stack in the exception +// unwind path. +int LIR_Assembler::emit_unwind_handler() { +#ifndef PRODUCT + if (CommentedAssembly) { + _masm->block_comment("Unwind handler"); + } +#endif // PRODUCT + + int offset = code_offset(); + + // Fetch the exception from TLS and clear out exception related thread state + __ ld(x10, Address(xthread, JavaThread::exception_oop_offset())); + __ sd(zr, Address(xthread, JavaThread::exception_oop_offset())); + __ sd(zr, Address(xthread, JavaThread::exception_pc_offset())); + + __ bind(_unwind_handler_entry); + __ verify_not_null_oop(x10); + if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { + __ mv(x9, x10); // Perserve the exception + } + + // Preform needed unlocking + MonitorExitStub* stub = NULL; + if (method()->is_synchronized()) { + monitor_address(0, FrameMap::r10_opr); + stub = new MonitorExitStub(FrameMap::r10_opr, true, 0); + if (UseHeavyMonitors) { + __ j(*stub->entry()); + } else { + __ unlock_object(x15, x14, x10, *stub->entry()); + } + __ bind(*stub->continuation()); + } + + if (compilation()->env()->dtrace_method_probes()) { + __ mv(c_rarg0, xthread); + __ mov_metadata(c_rarg1, method()->constant_encoding()); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), c_rarg0, c_rarg1); + } + + if (method()->is_synchronized() || compilation()->env()->dtrace_method_probes()) { + __ mv(x10, x9); // Restore the exception + } + + // remove the activation and dispatch to the unwind handler + __ block_comment("remove_frame and dispatch to the unwind handler"); + __ remove_frame(initial_frame_size_in_bytes()); + __ far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::unwind_exception_id))); + + // Emit the slow path assembly + if (stub != NULL) { + stub->emit_code(this); + } + + return offset; +} + +int LIR_Assembler::emit_deopt_handler() { + // if the last instruciton is a call (typically to do a throw which + // is coming at the end after block reordering) the return address + // must still point into the code area in order to avoid assertion + // failures when searching for the corresponding bck => add a nop + // (was bug 5/14/1999 - gri) + __ nop(); + + // generate code for exception handler + address handler_base = __ start_a_stub(deopt_handler_size()); + if (handler_base == NULL) { + // not enough space left for the handler + bailout("deopt handler overflow"); + return -1; + } + + int offset = code_offset(); + + __ auipc(ra, 0); + __ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); + guarantee(code_offset() - offset <= deopt_handler_size(), "overflow"); + __ end_a_stub(); + + return offset; +} + +void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) { + assert(result->is_illegal() || !result->is_single_cpu() || result->as_register() == x10, "word returns are in x10"); + + // Pop the stack before the safepoint code + __ remove_frame(initial_frame_size_in_bytes()); + + if (StackReservedPages > 0 && compilation()->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + + code_stub->set_safepoint_offset(__ offset()); + __ relocate(relocInfo::poll_return_type); + __ safepoint_poll(*code_stub->entry(), true /* at_return */, false /* acquire */, true /* in_nmethod */); + __ ret(); +} + +int LIR_Assembler::safepoint_poll(LIR_Opr tmp, CodeEmitInfo* info) { + guarantee(info != NULL, "Shouldn't be NULL"); + __ get_polling_page(t0, relocInfo::poll_type); + add_debug_info_for_branch(info); // This isn't just debug info: + // it's the oop map + __ read_polling_page(t0, 0, relocInfo::poll_type); + return __ offset(); +} + +void LIR_Assembler::move_regs(Register from_reg, Register to_reg) { + __ mv(to_reg, from_reg); +} + +void LIR_Assembler::swap_reg(Register a, Register b) { Unimplemented(); } + +void LIR_Assembler::const2reg(LIR_Opr src, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { + assert(src->is_constant(), "should not call otherwise"); + assert(dest->is_register(), "should not call otherwise"); + LIR_Const* c = src->as_constant_ptr(); + address const_addr = NULL; + + switch (c->type()) { + case T_INT: + assert(patch_code == lir_patch_none, "no patching handled here"); + __ mvw(dest->as_register(), c->as_jint()); + break; + + case T_ADDRESS: + assert(patch_code == lir_patch_none, "no patching handled here"); + __ mv(dest->as_register(), c->as_jint()); + break; + + case T_LONG: + assert(patch_code == lir_patch_none, "no patching handled here"); + __ mv(dest->as_register_lo(), (intptr_t)c->as_jlong()); + break; + + case T_OBJECT: + case T_ARRAY: + if (patch_code == lir_patch_none) { + jobject2reg(c->as_jobject(), dest->as_register()); + } else { + jobject2reg_with_patching(dest->as_register(), info); + } + break; + + case T_METADATA: + if (patch_code != lir_patch_none) { + klass2reg_with_patching(dest->as_register(), info); + } else { + __ mov_metadata(dest->as_register(), c->as_metadata()); + } + break; + + case T_FLOAT: + const_addr = float_constant(c->as_jfloat()); + assert(const_addr != NULL, "must create float constant in the constant table"); + __ flw(dest->as_float_reg(), InternalAddress(const_addr)); + break; + + case T_DOUBLE: + const_addr = double_constant(c->as_jdouble()); + assert(const_addr != NULL, "must create double constant in the constant table"); + __ fld(dest->as_double_reg(), InternalAddress(const_addr)); + break; + + default: + ShouldNotReachHere(); + } +} + +void LIR_Assembler::const2stack(LIR_Opr src, LIR_Opr dest) { + assert(src->is_constant(), "should not call otherwise"); + assert(dest->is_stack(), "should not call otherwise"); + LIR_Const* c = src->as_constant_ptr(); + switch (c->type()) { + case T_OBJECT: + if (c->as_jobject() == NULL) { + __ sd(zr, frame_map()->address_for_slot(dest->single_stack_ix())); + } else { + const2reg(src, FrameMap::t1_opr, lir_patch_none, NULL); + reg2stack(FrameMap::t1_opr, dest, c->type(), false); + } + break; + case T_ADDRESS: // fall through + const2reg(src, FrameMap::t1_opr, lir_patch_none, NULL); + reg2stack(FrameMap::t1_opr, dest, c->type(), false); + case T_INT: // fall through + case T_FLOAT: + if (c->as_jint_bits() == 0) { + __ sw(zr, frame_map()->address_for_slot(dest->single_stack_ix())); + } else { + __ mvw(t1, c->as_jint_bits()); + __ sw(t1, frame_map()->address_for_slot(dest->single_stack_ix())); + } + break; + case T_LONG: // fall through + case T_DOUBLE: + if (c->as_jlong_bits() == 0) { + __ sd(zr, frame_map()->address_for_slot(dest->double_stack_ix(), + lo_word_offset_in_bytes)); + } else { + __ mv(t1, (intptr_t)c->as_jlong_bits()); + __ sd(t1, frame_map()->address_for_slot(dest->double_stack_ix(), + lo_word_offset_in_bytes)); + } + break; + default: + ShouldNotReachHere(); + } +} + +void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info, bool wide) { + assert(src->is_constant(), "should not call otherwise"); + assert(dest->is_address(), "should not call otherwise"); + LIR_Const* c = src->as_constant_ptr(); + LIR_Address* to_addr = dest->as_address_ptr(); + void (Assembler::* insn)(Register Rt, const Address &adr, Register temp); + switch (type) { + case T_ADDRESS: + assert(c->as_jint() == 0, "should be"); + insn = &Assembler::sd; break; + case T_LONG: + assert(c->as_jlong() == 0, "should be"); + insn = &Assembler::sd; break; + case T_DOUBLE: + assert(c->as_jdouble() == 0.0, "should be"); + insn = &Assembler::sd; break; + case T_INT: + assert(c->as_jint() == 0, "should be"); + insn = &Assembler::sw; break; + case T_FLOAT: + assert(c->as_jfloat() == 0.0f, "should be"); + insn = &Assembler::sw; break; + case T_OBJECT: // fall through + case T_ARRAY: + assert(c->as_jobject() == 0, "should be"); + if (UseCompressedOops && !wide) { + insn = &Assembler::sw; + } else { + insn = &Assembler::sd; + } + break; + case T_CHAR: // fall through + case T_SHORT: + assert(c->as_jint() == 0, "should be"); + insn = &Assembler::sh; + break; + case T_BOOLEAN: // fall through + case T_BYTE: + assert(c->as_jint() == 0, "should be"); + insn = &Assembler::sb; break; + default: + ShouldNotReachHere(); + insn = &Assembler::sd; // unreachable + } + if (info != NULL) { + add_debug_info_for_null_check_here(info); + } + (_masm->*insn)(zr, as_Address(to_addr), t0); +} + +void LIR_Assembler::reg2reg(LIR_Opr src, LIR_Opr dest) { + assert(src->is_register(), "should not call otherwise"); + assert(dest->is_register(), "should not call otherwise"); + + // move between cpu-registers + if (dest->is_single_cpu()) { + if (src->type() == T_LONG) { + // Can do LONG -> OBJECT + move_regs(src->as_register_lo(), dest->as_register()); + return; + } + assert(src->is_single_cpu(), "must match"); + if (src->type() == T_OBJECT) { + __ verify_oop(src->as_register()); + } + move_regs(src->as_register(), dest->as_register()); + } else if (dest->is_double_cpu()) { + if (is_reference_type(src->type())) { + __ verify_oop(src->as_register()); + move_regs(src->as_register(), dest->as_register_lo()); + return; + } + assert(src->is_double_cpu(), "must match"); + Register f_lo = src->as_register_lo(); + Register f_hi = src->as_register_hi(); + Register t_lo = dest->as_register_lo(); + Register t_hi = dest->as_register_hi(); + assert(f_hi == f_lo, "must be same"); + assert(t_hi == t_lo, "must be same"); + move_regs(f_lo, t_lo); + } else if (dest->is_single_fpu()) { + assert(src->is_single_fpu(), "expect single fpu"); + __ fmv_s(dest->as_float_reg(), src->as_float_reg()); + } else if (dest->is_double_fpu()) { + assert(src->is_double_fpu(), "expect double fpu"); + __ fmv_d(dest->as_double_reg(), src->as_double_reg()); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::reg2stack(LIR_Opr src, LIR_Opr dest, BasicType type, bool pop_fpu_stack) { + precond(src->is_register() && dest->is_stack()); + + uint const c_sz32 = sizeof(uint32_t); + uint const c_sz64 = sizeof(uint64_t); + + assert(src->is_register(), "should not call otherwise"); + assert(dest->is_stack(), "should not call otherwise"); + if (src->is_single_cpu()) { + int index = dest->single_stack_ix(); + if (is_reference_type(type)) { + __ sd(src->as_register(), stack_slot_address(index, c_sz64)); + __ verify_oop(src->as_register()); + } else if (type == T_METADATA || type == T_DOUBLE || type == T_ADDRESS) { + __ sd(src->as_register(), stack_slot_address(index, c_sz64)); + } else { + __ sw(src->as_register(), stack_slot_address(index, c_sz32)); + } + } else if (src->is_double_cpu()) { + int index = dest->double_stack_ix(); + Address dest_addr_LO = stack_slot_address(index, c_sz64, lo_word_offset_in_bytes); + __ sd(src->as_register_lo(), dest_addr_LO); + } else if (src->is_single_fpu()) { + int index = dest->single_stack_ix(); + __ fsw(src->as_float_reg(), stack_slot_address(index, c_sz32)); + } else if (src->is_double_fpu()) { + int index = dest->double_stack_ix(); + __ fsd(src->as_double_reg(), stack_slot_address(index, c_sz64)); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::reg2mem(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_PatchCode patch_code, CodeEmitInfo* info, bool pop_fpu_stack, bool wide) { + LIR_Address* to_addr = dest->as_address_ptr(); + // t0 was used as tmp reg in as_Address, so we use t1 as compressed_src + Register compressed_src = t1; + + if (patch_code != lir_patch_none) { + deoptimize_trap(info); + return; + } + + if (is_reference_type(type)) { + __ verify_oop(src->as_register()); + + if (UseCompressedOops && !wide) { + __ encode_heap_oop(compressed_src, src->as_register()); + } else { + compressed_src = src->as_register(); + } + } + + int null_check_here = code_offset(); + + switch (type) { + case T_FLOAT: + __ fsw(src->as_float_reg(), as_Address(to_addr)); + break; + + case T_DOUBLE: + __ fsd(src->as_double_reg(), as_Address(to_addr)); + break; + + case T_ARRAY: // fall through + case T_OBJECT: + if (UseCompressedOops && !wide) { + __ sw(compressed_src, as_Address(to_addr)); + } else { + __ sd(compressed_src, as_Address(to_addr)); + } + break; + case T_METADATA: + // We get here to store a method pointer to the stack to pass to + // a dtrace runtime call. This can't work on 64 bit with + // compressed klass ptrs: T_METADATA can be compressed klass + // ptr or a 64 bit method pointer. + ShouldNotReachHere(); + __ sd(src->as_register(), as_Address(to_addr)); + break; + case T_ADDRESS: + __ sd(src->as_register(), as_Address(to_addr)); + break; + case T_INT: + __ sw(src->as_register(), as_Address(to_addr)); + break; + case T_LONG: + __ sd(src->as_register_lo(), as_Address(to_addr)); + break; + case T_BYTE: // fall through + case T_BOOLEAN: + __ sb(src->as_register(), as_Address(to_addr)); + break; + case T_CHAR: // fall through + case T_SHORT: + __ sh(src->as_register(), as_Address(to_addr)); + break; + default: + ShouldNotReachHere(); + } + + if (info != NULL) { + add_debug_info_for_null_check(null_check_here, info); + } +} + +void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) { + precond(src->is_stack() && dest->is_register()); + + uint const c_sz32 = sizeof(uint32_t); + uint const c_sz64 = sizeof(uint64_t); + + if (dest->is_single_cpu()) { + int index = src->single_stack_ix(); + if (type == T_INT) { + __ lw(dest->as_register(), stack_slot_address(index, c_sz32)); + } else if (is_reference_type(type)) { + __ ld(dest->as_register(), stack_slot_address(index, c_sz64)); + __ verify_oop(dest->as_register()); + } else if (type == T_METADATA || type == T_ADDRESS) { + __ ld(dest->as_register(), stack_slot_address(index, c_sz64)); + } else { + __ lwu(dest->as_register(), stack_slot_address(index, c_sz32)); + } + } else if (dest->is_double_cpu()) { + int index = src->double_stack_ix(); + Address src_addr_LO = stack_slot_address(index, c_sz64, lo_word_offset_in_bytes); + __ ld(dest->as_register_lo(), src_addr_LO); + } else if (dest->is_single_fpu()) { + int index = src->single_stack_ix(); + __ flw(dest->as_float_reg(), stack_slot_address(index, c_sz32)); + } else if (dest->is_double_fpu()) { + int index = src->double_stack_ix(); + __ fld(dest->as_double_reg(), stack_slot_address(index, c_sz64)); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::klass2reg_with_patching(Register reg, CodeEmitInfo* info) { + deoptimize_trap(info); +} + +void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { + LIR_Opr temp; + if (type == T_LONG || type == T_DOUBLE) { + temp = FrameMap::t1_long_opr; + } else { + temp = FrameMap::t1_opr; + } + + stack2reg(src, temp, src->type()); + reg2stack(temp, dest, dest->type(), false); +} + +void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide) { + assert(src->is_address(), "should not call otherwise"); + assert(dest->is_register(), "should not call otherwise"); + + LIR_Address* addr = src->as_address_ptr(); + LIR_Address* from_addr = src->as_address_ptr(); + + if (addr->base()->type() == T_OBJECT) { + __ verify_oop(addr->base()->as_pointer_register()); + } + + if (patch_code != lir_patch_none) { + deoptimize_trap(info); + return; + } + + if (info != NULL) { + add_debug_info_for_null_check_here(info); + } + + int null_check_here = code_offset(); + switch (type) { + case T_FLOAT: + __ flw(dest->as_float_reg(), as_Address(from_addr)); + break; + case T_DOUBLE: + __ fld(dest->as_double_reg(), as_Address(from_addr)); + break; + case T_ARRAY: // fall through + case T_OBJECT: + if (UseCompressedOops && !wide) { + __ lwu(dest->as_register(), as_Address(from_addr)); + } else { + __ ld(dest->as_register(), as_Address(from_addr)); + } + break; + case T_METADATA: + // We get here to store a method pointer to the stack to pass to + // a dtrace runtime call. This can't work on 64 bit with + // compressed klass ptrs: T_METADATA can be a compressed klass + // ptr or a 64 bit method pointer. + ShouldNotReachHere(); + __ ld(dest->as_register(), as_Address(from_addr)); + break; + case T_ADDRESS: + __ ld(dest->as_register(), as_Address(from_addr)); + break; + case T_INT: + __ lw(dest->as_register(), as_Address(from_addr)); + break; + case T_LONG: + __ ld(dest->as_register_lo(), as_Address_lo(from_addr)); + break; + case T_BYTE: + __ lb(dest->as_register(), as_Address(from_addr)); + break; + case T_BOOLEAN: + __ lbu(dest->as_register(), as_Address(from_addr)); + break; + case T_CHAR: + __ lhu(dest->as_register(), as_Address(from_addr)); + break; + case T_SHORT: + __ lh(dest->as_register(), as_Address(from_addr)); + break; + default: + ShouldNotReachHere(); + } + + if (is_reference_type(type)) { + if (UseCompressedOops && !wide) { + __ decode_heap_oop(dest->as_register()); + } + + if (!UseZGC) { + // Load barrier has not yet been applied, so ZGC can't verify the oop here + __ verify_oop(dest->as_register()); + } + } +} + +void LIR_Assembler::emit_op3(LIR_Op3* op) { + switch (op->code()) { + case lir_idiv: // fall through + case lir_irem: + arithmetic_idiv(op->code(), + op->in_opr1(), + op->in_opr2(), + op->in_opr3(), + op->result_opr(), + op->info()); + break; + case lir_fmad: + __ fmadd_d(op->result_opr()->as_double_reg(), + op->in_opr1()->as_double_reg(), + op->in_opr2()->as_double_reg(), + op->in_opr3()->as_double_reg()); + break; + case lir_fmaf: + __ fmadd_s(op->result_opr()->as_float_reg(), + op->in_opr1()->as_float_reg(), + op->in_opr2()->as_float_reg(), + op->in_opr3()->as_float_reg()); + break; + default: + ShouldNotReachHere(); + } +} + +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type, + LIR_Opr cmp_opr1, LIR_Opr cmp_opr2) { + Label label; + + emit_branch(condition, cmp_opr1, cmp_opr2, label, /* is_far */ false, + /* is_unordered */ (condition == lir_cond_greaterEqual || condition == lir_cond_greater) ? false : true); + + Label done; + move_op(opr2, result, type, lir_patch_none, NULL, + false, // pop_fpu_stack + false); // wide + __ j(done); + __ bind(label); + move_op(opr1, result, type, lir_patch_none, NULL, + false, // pop_fpu_stack + false); // wide + __ bind(done); +} + +void LIR_Assembler::emit_opBranch(LIR_OpBranch* op) { + LIR_Condition condition = op->cond(); + if (condition == lir_cond_always) { + if (op->info() != NULL) { + add_debug_info_for_branch(op->info()); + } + } else { + assert(op->in_opr1() != LIR_OprFact::illegalOpr && op->in_opr2() != LIR_OprFact::illegalOpr, "conditional branches must have legal operands"); + } + bool is_unordered = (op->ublock() == op->block()); + emit_branch(condition, op->in_opr1(), op->in_opr2(), *op->label(), /* is_far */ true, is_unordered); +} + +void LIR_Assembler::emit_branch(LIR_Condition cmp_flag, LIR_Opr cmp1, LIR_Opr cmp2, Label& label, + bool is_far, bool is_unordered) { + + if (cmp_flag == lir_cond_always) { + __ j(label); + return; + } + + if (cmp1->is_cpu_register()) { + Register reg1 = as_reg(cmp1); + if (cmp2->is_cpu_register()) { + Register reg2 = as_reg(cmp2); + __ c1_cmp_branch(cmp_flag, reg1, reg2, label, cmp1->type(), is_far); + } else if (cmp2->is_constant()) { + const2reg_helper(cmp2); + __ c1_cmp_branch(cmp_flag, reg1, t0, label, cmp2->type(), is_far); + } else { + ShouldNotReachHere(); + } + } else if (cmp1->is_single_fpu()) { + assert(cmp2->is_single_fpu(), "expect single float register"); + __ c1_float_cmp_branch(cmp_flag, cmp1->as_float_reg(), cmp2->as_float_reg(), label, is_far, is_unordered); + } else if (cmp1->is_double_fpu()) { + assert(cmp2->is_double_fpu(), "expect double float register"); + __ c1_float_cmp_branch(cmp_flag | C1_MacroAssembler::c1_double_branch_mask, + cmp1->as_double_reg(), cmp2->as_double_reg(), label, is_far, is_unordered); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::emit_opConvert(LIR_OpConvert* op) { + LIR_Opr src = op->in_opr(); + LIR_Opr dest = op->result_opr(); + + switch (op->bytecode()) { + case Bytecodes::_i2f: + __ fcvt_s_w(dest->as_float_reg(), src->as_register()); break; + case Bytecodes::_i2d: + __ fcvt_d_w(dest->as_double_reg(), src->as_register()); break; + case Bytecodes::_l2d: + __ fcvt_d_l(dest->as_double_reg(), src->as_register_lo()); break; + case Bytecodes::_l2f: + __ fcvt_s_l(dest->as_float_reg(), src->as_register_lo()); break; + case Bytecodes::_f2d: + __ fcvt_d_s(dest->as_double_reg(), src->as_float_reg()); break; + case Bytecodes::_d2f: + __ fcvt_s_d(dest->as_float_reg(), src->as_double_reg()); break; + case Bytecodes::_i2c: + __ zero_extend(dest->as_register(), src->as_register(), 16); break; + case Bytecodes::_i2l: + __ addw(dest->as_register_lo(), src->as_register(), zr); break; + case Bytecodes::_i2s: + __ sign_extend(dest->as_register(), src->as_register(), 16); break; + case Bytecodes::_i2b: + __ sign_extend(dest->as_register(), src->as_register(), 8); break; + case Bytecodes::_l2i: + _masm->block_comment("FIXME: This coulde be no-op"); + __ addw(dest->as_register(), src->as_register_lo(), zr); break; + case Bytecodes::_d2l: + __ fcvt_l_d_safe(dest->as_register_lo(), src->as_double_reg()); break; + case Bytecodes::_f2i: + __ fcvt_w_s_safe(dest->as_register(), src->as_float_reg()); break; + case Bytecodes::_f2l: + __ fcvt_l_s_safe(dest->as_register_lo(), src->as_float_reg()); break; + case Bytecodes::_d2i: + __ fcvt_w_d_safe(dest->as_register(), src->as_double_reg()); break; + default: + ShouldNotReachHere(); + } +} + +void LIR_Assembler::emit_alloc_obj(LIR_OpAllocObj* op) { + if (op->init_check()) { + __ lbu(t0, Address(op->klass()->as_register(), + InstanceKlass::init_state_offset())); + __ mvw(t1, InstanceKlass::fully_initialized); + add_debug_info_for_null_check_here(op->stub()->info()); + __ bne(t0, t1, *op->stub()->entry(), /* is_far */ true); + } + + __ allocate_object(op->obj()->as_register(), + op->tmp1()->as_register(), + op->tmp2()->as_register(), + op->header_size(), + op->object_size(), + op->klass()->as_register(), + *op->stub()->entry()); + + __ bind(*op->stub()->continuation()); +} + +void LIR_Assembler::emit_alloc_array(LIR_OpAllocArray* op) { + Register len = op->len()->as_register(); + + if (UseSlowPath || + (!UseFastNewObjectArray && is_reference_type(op->type())) || + (!UseFastNewTypeArray && !is_reference_type(op->type()))) { + __ j(*op->stub()->entry()); + } else { + Register tmp1 = op->tmp1()->as_register(); + Register tmp2 = op->tmp2()->as_register(); + Register tmp3 = op->tmp3()->as_register(); + if (len == tmp1) { + tmp1 = tmp3; + } else if (len == tmp2) { + tmp2 = tmp3; + } else if (len == tmp3) { + // everything is ok + } else { + __ mv(tmp3, len); + } + __ allocate_array(op->obj()->as_register(), + len, + tmp1, + tmp2, + arrayOopDesc::header_size(op->type()), + array_element_size(op->type()), + op->klass()->as_register(), + *op->stub()->entry()); + } + __ bind(*op->stub()->continuation()); +} + +void LIR_Assembler::type_profile_helper(Register mdo, ciMethodData *md, ciProfileData *data, + Register recv, Label* update_done) { + for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) { + Label next_test; + // See if the receiver is receiver[n]. + __ ld(t1, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i)))); + __ bne(recv, t1, next_test); + Address data_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i))); + __ add_memory_int64(data_addr, DataLayout::counter_increment); + __ j(*update_done); + __ bind(next_test); + } + + // Didn't find receiver; find next empty slot and fill it in + for (uint i = 0; i < ReceiverTypeData::row_limit(); i++) { + Label next_test; + Address recv_addr(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_offset(i))); + __ ld(t1, recv_addr); + __ bnez(t1, next_test); + __ sd(recv, recv_addr); + __ li(t1, DataLayout::counter_increment); + __ sd(t1, Address(mdo, md->byte_offset_of_slot(data, ReceiverTypeData::receiver_count_offset(i)))); + __ j(*update_done); + __ bind(next_test); + } +} + +void LIR_Assembler::data_check(LIR_OpTypeCheck *op, ciMethodData **md, ciProfileData **data) { + ciMethod* method = op->profiled_method(); + assert(method != NULL, "Should have method"); + int bci = op->profiled_bci(); + *md = method->method_data_or_null(); + guarantee(*md != NULL, "Sanity"); + *data = ((*md)->bci_to_data(bci)); + assert(*data != NULL, "need data for type check"); + assert((*data)->is_ReceiverTypeData(), "need ReceiverTypeData for type check"); +} + +void LIR_Assembler::typecheck_helper_slowcheck(ciKlass *k, Register obj, Register Rtmp1, + Register k_RInfo, Register klass_RInfo, + Label *failure_target, Label *success_target) { + // get object class + // not a safepoint as obj null check happens earlier + __ load_klass(klass_RInfo, obj); + if (k->is_loaded()) { + // See if we get an immediate positive hit + __ ld(t0, Address(klass_RInfo, int64_t(k->super_check_offset()))); + if ((juint)in_bytes(Klass::secondary_super_cache_offset()) != k->super_check_offset()) { + __ bne(k_RInfo, t0, *failure_target, /* is_far */ true); + // successful cast, fall through to profile or jump + } else { + // See if we get an immediate positive hit + __ beq(k_RInfo, t0, *success_target); + // check for self + __ beq(klass_RInfo, k_RInfo, *success_target); + + __ addi(sp, sp, -2 * wordSize); // 2: store k_RInfo and klass_RInfo + __ sd(k_RInfo, Address(sp, 0)); // sub klass + __ sd(klass_RInfo, Address(sp, wordSize)); // super klass + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); + // load result to k_RInfo + __ ld(k_RInfo, Address(sp, 0)); + __ addi(sp, sp, 2 * wordSize); // 2: pop out k_RInfo and klass_RInfo + // result is a boolean + __ beqz(k_RInfo, *failure_target, /* is_far */ true); + // successful cast, fall through to profile or jump + } + } else { + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, NULL); + // call out-of-line instance of __ check_klass_subtytpe_slow_path(...) + __ addi(sp, sp, -2 * wordSize); // 2: store k_RInfo and klass_RInfo + __ sd(klass_RInfo, Address(sp, wordSize)); // sub klass + __ sd(k_RInfo, Address(sp, 0)); // super klass + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); + // load result to k_RInfo + __ ld(k_RInfo, Address(sp, 0)); + __ addi(sp, sp, 2 * wordSize); // 2: pop out k_RInfo and klass_RInfo + // result is a boolean + __ beqz(k_RInfo, *failure_target, /* is_far */ true); + // successful cast, fall thriugh to profile or jump + } +} + +void LIR_Assembler::profile_object(ciMethodData* md, ciProfileData* data, Register obj, + Register klass_RInfo, Label* obj_is_null) { + Label not_null; + __ bnez(obj, not_null); + // Object is null, update MDO and exit + Register mdo = klass_RInfo; + __ mov_metadata(mdo, md->constant_encoding()); + Address data_addr = __ form_address(t1, mdo, md->byte_offset_of_slot(data, DataLayout::flags_offset())); + __ lbu(t0, data_addr); + __ ori(t0, t0, BitData::null_seen_byte_constant()); + __ sb(t0, data_addr); + __ j(*obj_is_null); + __ bind(not_null); +} + +void LIR_Assembler::typecheck_loaded(LIR_OpTypeCheck *op, ciKlass* k, Register k_RInfo) { + if (!k->is_loaded()) { + klass2reg_with_patching(k_RInfo, op->info_for_patch()); + } else { + __ mov_metadata(k_RInfo, k->constant_encoding()); + } +} + +void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, Label* failure, Label* obj_is_null) { + Register obj = op->object()->as_register(); + Register k_RInfo = op->tmp1()->as_register(); + Register klass_RInfo = op->tmp2()->as_register(); + Register dst = op->result_opr()->as_register(); + ciKlass* k = op->klass(); + Register Rtmp1 = noreg; + + // check if it needs to be profiled + ciMethodData* md = NULL; + ciProfileData* data = NULL; + + const bool should_profile = op->should_profile(); + if (should_profile) { + data_check(op, &md, &data); + } + Label profile_cast_success, profile_cast_failure; + Label *success_target = should_profile ? &profile_cast_success : success; + Label *failure_target = should_profile ? &profile_cast_failure : failure; + + if (obj == k_RInfo) { + k_RInfo = dst; + } else if (obj == klass_RInfo) { + klass_RInfo = dst; + } + if (k->is_loaded() && !UseCompressedClassPointers) { + select_different_registers(obj, dst, k_RInfo, klass_RInfo); + } else { + Rtmp1 = op->tmp3()->as_register(); + select_different_registers(obj, dst, k_RInfo, klass_RInfo, Rtmp1); + } + + assert_different_registers(obj, k_RInfo, klass_RInfo); + + if (should_profile) { + profile_object(md, data, obj, klass_RInfo, obj_is_null); + } else { + __ beqz(obj, *obj_is_null); + } + + typecheck_loaded(op, k, k_RInfo); + __ verify_oop(obj); + + if (op->fast_check()) { + // get object class + // not a safepoint as obj null check happens earlier + __ load_klass(t0, obj); + __ bne(t0, k_RInfo, *failure_target, /* is_far */ true); + // successful cast, fall through to profile or jump + } else { + typecheck_helper_slowcheck(k, obj, Rtmp1, k_RInfo, klass_RInfo, failure_target, success_target); + } + if (should_profile) { + type_profile(obj, md, klass_RInfo, k_RInfo, data, success, failure, profile_cast_success, profile_cast_failure); + } + __ j(*success); +} + +void LIR_Assembler::emit_opTypeCheck(LIR_OpTypeCheck* op) { + const bool should_profile = op->should_profile(); + + LIR_Code code = op->code(); + if (code == lir_store_check) { + typecheck_lir_store(op, should_profile); + } else if (code == lir_checkcast) { + Register obj = op->object()->as_register(); + Register dst = op->result_opr()->as_register(); + Label success; + emit_typecheck_helper(op, &success, op->stub()->entry(), &success); + __ bind(success); + if (dst != obj) { + __ mv(dst, obj); + } + } else if (code == lir_instanceof) { + Register obj = op->object()->as_register(); + Register dst = op->result_opr()->as_register(); + Label success, failure, done; + emit_typecheck_helper(op, &success, &failure, &failure); + __ bind(failure); + __ mv(dst, zr); + __ j(done); + __ bind(success); + __ mv(dst, 1); + __ bind(done); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { + assert(VM_Version::supports_cx8(), "wrong machine"); + Register addr; + if (op->addr()->is_register()) { + addr = as_reg(op->addr()); + } else { + assert(op->addr()->is_address(), "what else?"); + LIR_Address* addr_ptr = op->addr()->as_address_ptr(); + assert(addr_ptr->disp() == 0, "need 0 disp"); + assert(addr_ptr->index() == LIR_Opr::illegalOpr(), "need 0 index"); + addr = as_reg(addr_ptr->base()); + } + Register newval = as_reg(op->new_value()); + Register cmpval = as_reg(op->cmp_value()); + + if (op->code() == lir_cas_obj) { + if (UseCompressedOops) { + Register tmp1 = op->tmp1()->as_register(); + assert(op->tmp1()->is_valid(), "must be"); + __ encode_heap_oop(tmp1, cmpval); + cmpval = tmp1; + __ encode_heap_oop(t1, newval); + newval = t1; + caswu(addr, newval, cmpval); + } else { + casl(addr, newval, cmpval); + } + } else if (op->code() == lir_cas_int) { + casw(addr, newval, cmpval); + } else { + casl(addr, newval, cmpval); + } +} + +void LIR_Assembler::intrinsic_op(LIR_Code code, LIR_Opr value, LIR_Opr unused, LIR_Opr dest, LIR_Op* op) { + switch (code) { + case lir_abs: __ fabs_d(dest->as_double_reg(), value->as_double_reg()); break; + case lir_sqrt: __ fsqrt_d(dest->as_double_reg(), value->as_double_reg()); break; + default: ShouldNotReachHere(); + } +} + +void LIR_Assembler::logic_op(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst) { + assert(left->is_single_cpu() || left->is_double_cpu(), "expect single or double register"); + Register Rleft = left->is_single_cpu() ? left->as_register() : left->as_register_lo(); + if (dst->is_single_cpu()) { + Register Rdst = dst->as_register(); + if (right->is_constant()) { + int right_const = right->as_jint(); + if (Assembler::operand_valid_for_add_immediate(right_const)) { + logic_op_imm(Rdst, Rleft, right_const, code); + __ addw(Rdst, Rdst, zr); + } else { + __ mv(t0, right_const); + logic_op_reg32(Rdst, Rleft, t0, code); + } + } else { + Register Rright = right->is_single_cpu() ? right->as_register() : right->as_register_lo(); + logic_op_reg32(Rdst, Rleft, Rright, code); + } + } else { + Register Rdst = dst->as_register_lo(); + if (right->is_constant()) { + long right_const = right->as_jlong(); + if (Assembler::operand_valid_for_add_immediate(right_const)) { + logic_op_imm(Rdst, Rleft, right_const, code); + } else { + __ mv(t0, right_const); + logic_op_reg(Rdst, Rleft, t0, code); + } + } else { + Register Rright = right->is_single_cpu() ? right->as_register() : right->as_register_lo(); + logic_op_reg(Rdst, Rleft, Rright, code); + } + } +} + +void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr src, LIR_Opr result, LIR_Op2* op) { + ShouldNotCallThis(); +} + +void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr dst, LIR_Op2* op) { + if (code == lir_cmp_fd2i || code == lir_ucmp_fd2i) { + bool is_unordered_less = (code == lir_ucmp_fd2i); + if (left->is_single_fpu()) { + __ float_cmp(true, is_unordered_less ? -1 : 1, + left->as_float_reg(), right->as_float_reg(), dst->as_register()); + } else if (left->is_double_fpu()) { + __ float_cmp(false, is_unordered_less ? -1 : 1, + left->as_double_reg(), right->as_double_reg(), dst->as_register()); + } else { + ShouldNotReachHere(); + } + } else if (code == lir_cmp_l2i) { + __ cmp_l2i(dst->as_register(), left->as_register_lo(), right->as_register_lo()); + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::align_call(LIR_Code code) { + // With RVC a call instruction may get 2-byte aligned. + // The address of the call instruction needs to be 4-byte aligned to + // ensure that it does not span a cache line so that it can be patched. + __ align(4); +} + +void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) { + address call = __ trampoline_call(Address(op->addr(), rtype)); + if (call == NULL) { + bailout("trampoline stub overflow"); + return; + } + add_call_info(code_offset(), op->info()); +} + +void LIR_Assembler::ic_call(LIR_OpJavaCall* op) { + address call = __ ic_call(op->addr()); + if (call == NULL) { + bailout("trampoline stub overflow"); + return; + } + add_call_info(code_offset(), op->info()); +} + +void LIR_Assembler::emit_static_call_stub() { + address call_pc = __ pc(); + assert((__ offset() % 4) == 0, "bad alignment"); + address stub = __ start_a_stub(call_stub_size()); + if (stub == NULL) { + bailout("static call stub overflow"); + return; + } + + int start = __ offset(); + + __ relocate(static_stub_Relocation::spec(call_pc)); + __ emit_static_call_stub(); + + assert(__ offset() - start + CompiledStaticCall::to_trampoline_stub_size() + <= call_stub_size(), "stub too big"); + __ end_a_stub(); +} + +void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { + assert(exceptionOop->as_register() == x10, "must match"); + assert(exceptionPC->as_register() == x13, "must match"); + + // exception object is not added to oop map by LinearScan + // (LinearScan assumes that no oops are in fixed registers) + info->add_register_oop(exceptionOop); + Runtime1::StubID unwind_id; + + // get current pc information + // pc is only needed if the method has an exception handler, the unwind code does not need it. + if (compilation()->debug_info_recorder()->last_pc_offset() == __ offset()) { + // As no instructions have been generated yet for this LIR node it's + // possible that an oop map already exists for the current offset. + // In that case insert an dummy NOP here to ensure all oop map PCs + // are unique. See JDK-8237483. + __ nop(); + } + int pc_for_athrow_offset = __ offset(); + InternalAddress pc_for_athrow(__ pc()); + int32_t off = 0; + __ la_patchable(exceptionPC->as_register(), pc_for_athrow, off); + __ addi(exceptionPC->as_register(), exceptionPC->as_register(), off); + add_call_info(pc_for_athrow_offset, info); // for exception handler + + __ verify_not_null_oop(x10); + // search an exception handler (x10: exception oop, x13: throwing pc) + if (compilation()->has_fpu_code()) { + unwind_id = Runtime1::handle_exception_id; + } else { + unwind_id = Runtime1::handle_exception_nofpu_id; + } + __ far_call(RuntimeAddress(Runtime1::entry_for(unwind_id))); + __ nop(); +} + +void LIR_Assembler::unwind_op(LIR_Opr exceptionOop) { + assert(exceptionOop->as_register() == x10, "must match"); + __ j(_unwind_handler_entry); +} + +void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, LIR_Opr count, LIR_Opr dest, LIR_Opr tmp) { + Register left_reg = left->is_single_cpu() ? left->as_register() : left->as_register_lo(); + Register dest_reg = dest->is_single_cpu() ? dest->as_register() : dest->as_register_lo(); + Register count_reg = count->as_register(); + if (dest->is_single_cpu()) { + assert (dest->type() == T_INT, "unexpected result type"); + assert (left->type() == T_INT, "unexpected left type"); + __ andi(t0, count_reg, 31); // should not shift more than 31 bits + switch (code) { + case lir_shl: __ sllw(dest_reg, left_reg, t0); break; + case lir_shr: __ sraw(dest_reg, left_reg, t0); break; + case lir_ushr: __ srlw(dest_reg, left_reg, t0); break; + default: ShouldNotReachHere(); + } + } else if (dest->is_double_cpu()) { + __ andi(t0, count_reg, 63); // should not shift more than 63 bits + switch (code) { + case lir_shl: __ sll(dest_reg, left_reg, t0); break; + case lir_shr: __ sra(dest_reg, left_reg, t0); break; + case lir_ushr: __ srl(dest_reg, left_reg, t0); break; + default: ShouldNotReachHere(); + } + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::shift_op(LIR_Code code, LIR_Opr left, jint count, LIR_Opr dest) { + Register left_reg = left->is_single_cpu() ? left->as_register() : left->as_register_lo(); + Register dest_reg = dest->is_single_cpu() ? dest->as_register() : dest->as_register_lo(); + if (dest->is_single_cpu()) { + assert (dest->type() == T_INT, "unexpected result type"); + assert (left->type() == T_INT, "unexpected left type"); + count &= 0x1f; + if (count != 0) { + switch (code) { + case lir_shl: __ slliw(dest_reg, left_reg, count); break; + case lir_shr: __ sraiw(dest_reg, left_reg, count); break; + case lir_ushr: __ srliw(dest_reg, left_reg, count); break; + default: ShouldNotReachHere(); + } + } else { + move_regs(left_reg, dest_reg); + } + } else if (dest->is_double_cpu()) { + count &= 0x3f; + if (count != 0) { + switch (code) { + case lir_shl: __ slli(dest_reg, left_reg, count); break; + case lir_shr: __ srai(dest_reg, left_reg, count); break; + case lir_ushr: __ srli(dest_reg, left_reg, count); break; + default: ShouldNotReachHere(); + } + } else { + move_regs(left->as_register_lo(), dest->as_register_lo()); + } + } else { + ShouldNotReachHere(); + } +} + +void LIR_Assembler::emit_lock(LIR_OpLock* op) { + Register obj = op->obj_opr()->as_register(); // may not be an oop + Register hdr = op->hdr_opr()->as_register(); + Register lock = op->lock_opr()->as_register(); + if (UseHeavyMonitors) { + __ j(*op->stub()->entry()); + } else if (op->code() == lir_lock) { + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + // add debug info for NullPointerException only if one is possible + int null_check_offset = __ lock_object(hdr, obj, lock, *op->stub()->entry()); + if (op->info() != NULL) { + add_debug_info_for_null_check(null_check_offset, op->info()); + } + } else if (op->code() == lir_unlock) { + assert(BasicLock::displaced_header_offset_in_bytes() == 0, "lock_reg must point to the displaced header"); + __ unlock_object(hdr, obj, lock, *op->stub()->entry()); + } else { + Unimplemented(); + } + __ bind(*op->stub()->continuation()); +} + +void LIR_Assembler::emit_load_klass(LIR_OpLoadKlass* op) { + Register obj = op->obj()->as_pointer_register(); + Register result = op->result_opr()->as_pointer_register(); + + CodeEmitInfo* info = op->info(); + if (info != NULL) { + add_debug_info_for_null_check_here(info); + } + + if (UseCompressedClassPointers) { + __ lwu(result, Address(obj, oopDesc::klass_offset_in_bytes())); + __ decode_klass_not_null(result); + } else { + __ ld(result, Address(obj, oopDesc::klass_offset_in_bytes())); + } +} + +void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) { + ciMethod* method = op->profiled_method(); + int bci = op->profiled_bci(); + + // Update counter for all call types + ciMethodData* md = method->method_data_or_null(); + guarantee(md != NULL, "Sanity"); + ciProfileData* data = md->bci_to_data(bci); + assert(data != NULL && data->is_CounterData(), "need CounterData for calls"); + assert(op->mdo()->is_single_cpu(), "mdo must be allocated"); + Register mdo = op->mdo()->as_register(); + __ mov_metadata(mdo, md->constant_encoding()); + Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); + // Perform additional virtual call profiling for invokevirtual and + // invokeinterface bytecodes + if (op->should_profile_receiver_type()) { + assert(op->recv()->is_single_cpu(), "recv must be allocated"); + Register recv = op->recv()->as_register(); + assert_different_registers(mdo, recv); + assert(data->is_VirtualCallData(), "need VirtualCallData for virtual calls"); + ciKlass* known_klass = op->known_holder(); + if (C1OptimizeVirtualCallProfiling && known_klass != NULL) { + // We know the type that will be seen at this call site; we can + // statically update the MethodData* rather than needing to do + // dynamic tests on the receiver type + // NOTE: we should probably put a lock around this search to + // avoid collisions by concurrent compilations + ciVirtualCallData* vc_data = (ciVirtualCallData*) data; + uint i; + for (i = 0; i < VirtualCallData::row_limit(); i++) { + ciKlass* receiver = vc_data->receiver(i); + if (known_klass->equals(receiver)) { + Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); + __ add_memory_int64(data_addr, DataLayout::counter_increment); + return; + } + } + + // Receiver type not found in profile data; select an empty slot + // Note that this is less efficient than it should be because it + // always does a write to the receiver part of the + // VirtualCallData rather than just the first time + for (i = 0; i < VirtualCallData::row_limit(); i++) { + ciKlass* receiver = vc_data->receiver(i); + if (receiver == NULL) { + Address recv_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_offset(i))); + __ mov_metadata(t1, known_klass->constant_encoding()); + __ sd(t1, recv_addr); + Address data_addr(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))); + __ add_memory_int64(data_addr, DataLayout::counter_increment); + return; + } + } + } else { + __ load_klass(recv, recv); + Label update_done; + type_profile_helper(mdo, md, data, recv, &update_done); + // Receiver did not match any saved receiver and there is no empty row for it. + // Increment total counter to indicate polymorphic case. + __ add_memory_int64(counter_addr, DataLayout::counter_increment); + + __ bind(update_done); + } + } else { + // Static call + __ add_memory_int64(counter_addr, DataLayout::counter_increment); + } +} + +void LIR_Assembler::emit_delay(LIR_OpDelay*) { Unimplemented(); } + +void LIR_Assembler::monitor_address(int monitor_no, LIR_Opr dst) { + __ la(dst->as_register(), frame_map()->address_for_monitor_lock(monitor_no)); +} + +void LIR_Assembler::emit_updatecrc32(LIR_OpUpdateCRC32* op) { Unimplemented(); } + +void LIR_Assembler::check_conflict(ciKlass* exact_klass, intptr_t current_klass, + Register tmp, Label &next, Label &none, + Address mdo_addr) { + if (exact_klass == NULL || TypeEntries::is_type_none(current_klass)) { + if (exact_klass != NULL) { + __ mov_metadata(tmp, exact_klass->constant_encoding()); + } else { + __ load_klass(tmp, tmp); + } + + __ ld(t1, mdo_addr); + __ xorr(tmp, tmp, t1); + __ andi(t0, tmp, TypeEntries::type_klass_mask); + // klass seen before, nothing to do. The unknown bit may have been + // set already but no need to check. + __ beqz(t0, next); + + // already unknown. Nothing to do anymore. + __ andi(t0, tmp, TypeEntries::type_unknown); + __ bnez(t0, next); + + if (TypeEntries::is_type_none(current_klass)) { + __ beqz(t1, none); + __ li(t0, (u1)TypeEntries::null_seen); + __ beq(t0, t1, none); + // There is a chance that the checks above (re-reading profiling + // data from memory) fail if another thread has just set the + // profiling to this obj's klass + __ membar(MacroAssembler::LoadLoad); + __ ld(t1, mdo_addr); + __ xorr(tmp, tmp, t1); + __ andi(t0, tmp, TypeEntries::type_klass_mask); + __ beqz(t0, next); + } + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "conflict only"); + + __ ld(tmp, mdo_addr); + // already unknown. Nothing to do anymore. + __ andi(t0, tmp, TypeEntries::type_unknown); + __ bnez(t0, next); + } + + // different than before. Cannot keep accurate profile. + __ ld(t1, mdo_addr); + __ ori(t1, t1, TypeEntries::type_unknown); + __ sd(t1, mdo_addr); + + if (TypeEntries::is_type_none(current_klass)) { + __ j(next); + + __ bind(none); + // first time here. Set profile type. + __ sd(tmp, mdo_addr); + } +} + +void LIR_Assembler::check_no_conflict(ciKlass* exact_klass, intptr_t current_klass, Register tmp, + Address mdo_addr, Label &next) { + // There's a single possible klass at this profile point + assert(exact_klass != NULL, "should be"); + if (TypeEntries::is_type_none(current_klass)) { + __ mov_metadata(tmp, exact_klass->constant_encoding()); + __ ld(t1, mdo_addr); + __ xorr(tmp, tmp, t1); + __ andi(t0, tmp, TypeEntries::type_klass_mask); + __ beqz(t0, next); +#ifdef ASSERT + { + Label ok; + __ ld(t0, mdo_addr); + __ beqz(t0, ok); + __ li(t1, (u1)TypeEntries::null_seen); + __ beq(t0, t1, ok); + // may have been set by another thread + __ membar(MacroAssembler::LoadLoad); + __ mov_metadata(t0, exact_klass->constant_encoding()); + __ ld(t1, mdo_addr); + __ xorr(t1, t0, t1); + __ andi(t1, t1, TypeEntries::type_mask); + __ beqz(t1, ok); + + __ stop("unexpected profiling mismatch"); + __ bind(ok); + } +#endif + // first time here. Set profile type. + __ sd(tmp, mdo_addr); + } else { + assert(ciTypeEntries::valid_ciklass(current_klass) != NULL && + ciTypeEntries::valid_ciklass(current_klass) != exact_klass, "inconsistent"); + + __ ld(tmp, mdo_addr); + // already unknown. Nothing to do anymore. + __ andi(t0, tmp, TypeEntries::type_unknown); + __ bnez(t0, next); + + __ ori(tmp, tmp, TypeEntries::type_unknown); + __ sd(tmp, mdo_addr); + } +} + +void LIR_Assembler::check_null(Register tmp, Label &update, intptr_t current_klass, + Address mdo_addr, bool do_update, Label &next) { + __ bnez(tmp, update); + if (!TypeEntries::was_null_seen(current_klass)) { + __ ld(t1, mdo_addr); + __ ori(t1, t1, TypeEntries::null_seen); + __ sd(t1, mdo_addr); + } + if (do_update) { + __ j(next); + } +} + +void LIR_Assembler::emit_profile_type(LIR_OpProfileType* op) { + COMMENT("emit_profile_type {"); + Register obj = op->obj()->as_register(); + Register tmp = op->tmp()->as_pointer_register(); + Address mdo_addr = as_Address(op->mdp()->as_address_ptr()); + ciKlass* exact_klass = op->exact_klass(); + intptr_t current_klass = op->current_klass(); + bool not_null = op->not_null(); + bool no_conflict = op->no_conflict(); + + Label update, next, none; + + bool do_null = !not_null; + bool exact_klass_set = exact_klass != NULL && ciTypeEntries::valid_ciklass(current_klass) == exact_klass; + bool do_update = !TypeEntries::is_type_unknown(current_klass) && !exact_klass_set; + + assert(do_null || do_update, "why are we here?"); + assert(!TypeEntries::was_null_seen(current_klass) || do_update, "why are we here?"); + assert_different_registers(tmp, t0, t1, mdo_addr.base()); + + __ verify_oop(obj); + + if (tmp != obj) { + __ mv(tmp, obj); + } + if (do_null) { + check_null(tmp, update, current_klass, mdo_addr, do_update, next); +#ifdef ASSERT + } else { + __ bnez(tmp, update); + __ stop("unexpected null obj"); +#endif + } + + __ bind(update); + + if (do_update) { +#ifdef ASSERT + if (exact_klass != NULL) { + check_exact_klass(tmp, exact_klass); + } +#endif + if (!no_conflict) { + check_conflict(exact_klass, current_klass, tmp, next, none, mdo_addr); + } else { + check_no_conflict(exact_klass, current_klass, tmp, mdo_addr, next); + } + + __ bind(next); + } + COMMENT("} emit_profile_type"); +} + +void LIR_Assembler::align_backward_branch_target() { } + +void LIR_Assembler::negate(LIR_Opr left, LIR_Opr dest, LIR_Opr tmp) { + // tmp must be unused + assert(tmp->is_illegal(), "wasting a register if tmp is allocated"); + + if (left->is_single_cpu()) { + assert(dest->is_single_cpu(), "expect single result reg"); + __ negw(dest->as_register(), left->as_register()); + } else if (left->is_double_cpu()) { + assert(dest->is_double_cpu(), "expect double result reg"); + __ neg(dest->as_register_lo(), left->as_register_lo()); + } else if (left->is_single_fpu()) { + assert(dest->is_single_fpu(), "expect single float result reg"); + __ fneg_s(dest->as_float_reg(), left->as_float_reg()); + } else { + assert(left->is_double_fpu(), "expect double float operand reg"); + assert(dest->is_double_fpu(), "expect double float result reg"); + __ fneg_d(dest->as_double_reg(), left->as_double_reg()); + } +} + + +void LIR_Assembler::leal(LIR_Opr addr, LIR_Opr dest, LIR_PatchCode patch_code, CodeEmitInfo* info) { + if (patch_code != lir_patch_none) { + deoptimize_trap(info); + return; + } + + LIR_Address* adr = addr->as_address_ptr(); + Register dst = dest->as_register_lo(); + + assert_different_registers(dst, t0); + if (adr->base()->is_valid() && dst == adr->base()->as_pointer_register() && (!adr->index()->is_cpu_register())) { + int scale = adr->scale(); + intptr_t offset = adr->disp(); + LIR_Opr index_op = adr->index(); + if (index_op->is_constant()) { + offset += ((intptr_t)index_op->as_constant_ptr()->as_jint()) << scale; + } + + if (!is_imm_in_range(offset, 12, 0)) { + __ la(t0, as_Address(adr)); + __ mv(dst, t0); + return; + } + } + + __ la(dst, as_Address(adr)); +} + + +void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* args, LIR_Opr tmp, CodeEmitInfo* info) { + assert(!tmp->is_valid(), "don't need temporary"); + + CodeBlob *cb = CodeCache::find_blob(dest); + if (cb != NULL) { + __ far_call(RuntimeAddress(dest)); + } else { + int32_t offset = 0; + __ la_patchable(t0, RuntimeAddress(dest), offset); + __ jalr(x1, t0, offset); + } + + if (info != NULL) { + add_call_info_here(info); + } +} + +void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) { + if (dest->is_address() || src->is_address()) { + move_op(src, dest, type, lir_patch_none, info, /* pop_fpu_stack */ false, /* wide */ false); + } else { + ShouldNotReachHere(); + } +} + +#ifdef ASSERT +// emit run-time assertion +void LIR_Assembler::emit_assert(LIR_OpAssert* op) { + assert(op->code() == lir_assert, "must be"); + + Label ok; + if (op->in_opr1()->is_valid()) { + assert(op->in_opr2()->is_valid(), "both operands must be valid"); + bool is_unordered = false; + LIR_Condition cond = op->condition(); + emit_branch(cond, op->in_opr1(), op->in_opr2(), ok, /* is_far */ false, + /* is_unordered */(cond == lir_cond_greaterEqual || cond == lir_cond_greater) ? false : true); + } else { + assert(op->in_opr2()->is_illegal(), "both operands must be illegal"); + assert(op->condition() == lir_cond_always, "no other conditions allowed"); + } + + if (op->halt()) { + const char* str = __ code_string(op->msg()); + __ stop(str); + } else { + breakpoint(); + } + __ bind(ok); +} +#endif + +#ifndef PRODUCT +#define COMMENT(x) do { __ block_comment(x); } while (0) +#else +#define COMMENT(x) +#endif + +void LIR_Assembler::membar() { + COMMENT("membar"); + __ membar(MacroAssembler::AnyAny); +} + +void LIR_Assembler::membar_acquire() { + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); +} + +void LIR_Assembler::membar_release() { + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); +} + +void LIR_Assembler::membar_loadload() { + __ membar(MacroAssembler::LoadLoad); +} + +void LIR_Assembler::membar_storestore() { + __ membar(MacroAssembler::StoreStore); +} + +void LIR_Assembler::membar_loadstore() { __ membar(MacroAssembler::LoadStore); } + +void LIR_Assembler::membar_storeload() { __ membar(MacroAssembler::StoreLoad); } + +void LIR_Assembler::on_spin_wait() { + Unimplemented(); +} + +void LIR_Assembler::get_thread(LIR_Opr result_reg) { + __ mv(result_reg->as_register(), xthread); +} + +void LIR_Assembler::peephole(LIR_List *lir) {} + +void LIR_Assembler::atomic_op(LIR_Code code, LIR_Opr src, LIR_Opr data, LIR_Opr dest, LIR_Opr tmp_op) { + Address addr = as_Address(src->as_address_ptr()); + BasicType type = src->type(); + bool is_oop = is_reference_type(type); + + get_op(type); + + switch (code) { + case lir_xadd: + { + RegisterOrConstant inc; + Register tmp = as_reg(tmp_op); + Register dst = as_reg(dest); + if (data->is_constant()) { + inc = RegisterOrConstant(as_long(data)); + assert_different_registers(dst, addr.base(), tmp); + assert_different_registers(tmp, t0); + } else { + inc = RegisterOrConstant(as_reg(data)); + assert_different_registers(inc.as_register(), dst, addr.base(), tmp); + } + __ la(tmp, addr); + (_masm->*add)(dst, inc, tmp); + break; + } + case lir_xchg: + { + Register tmp = tmp_op->as_register(); + Register obj = as_reg(data); + Register dst = as_reg(dest); + if (is_oop && UseCompressedOops) { + __ encode_heap_oop(t0, obj); + obj = t0; + } + assert_different_registers(obj, addr.base(), tmp, dst); + __ la(tmp, addr); + (_masm->*xchg)(dst, obj, tmp); + if (is_oop && UseCompressedOops) { + __ decode_heap_oop(dst); + } + } + break; + default: + ShouldNotReachHere(); + } + __ membar(MacroAssembler::AnyAny); +} + +int LIR_Assembler::array_element_size(BasicType type) const { + int elem_size = type2aelembytes(type); + return exact_log2(elem_size); +} + +// helper functions which checks for overflow and sets bailout if it +// occurs. Always returns a valid embeddable pointer but in the +// bailout case the pointer won't be to unique storage. +address LIR_Assembler::float_constant(float f) { + address const_addr = __ float_constant(f); + if (const_addr == NULL) { + bailout("const section overflow"); + return __ code()->consts()->start(); + } else { + return const_addr; + } +} + +address LIR_Assembler::double_constant(double d) { + address const_addr = __ double_constant(d); + if (const_addr == NULL) { + bailout("const section overflow"); + return __ code()->consts()->start(); + } else { + return const_addr; + } +} + +address LIR_Assembler::int_constant(jlong n) { + address const_addr = __ long_constant(n); + if (const_addr == NULL) { + bailout("const section overflow"); + return __ code()->consts()->start(); + } else { + return const_addr; + } +} + +void LIR_Assembler::casw(Register addr, Register newval, Register cmpval) { + __ cmpxchg(addr, cmpval, newval, Assembler::int32, Assembler::aq /* acquire */, + Assembler::rl /* release */, t0, true /* result as bool */); + __ seqz(t0, t0); // cmpxchg not equal, set t0 to 1 + __ membar(MacroAssembler::AnyAny); +} + +void LIR_Assembler::caswu(Register addr, Register newval, Register cmpval) { + __ cmpxchg(addr, cmpval, newval, Assembler::uint32, Assembler::aq /* acquire */, + Assembler::rl /* release */, t0, true /* result as bool */); + __ seqz(t0, t0); // cmpxchg not equal, set t0 to 1 + __ membar(MacroAssembler::AnyAny); +} + +void LIR_Assembler::casl(Register addr, Register newval, Register cmpval) { + __ cmpxchg(addr, cmpval, newval, Assembler::int64, Assembler::aq /* acquire */, + Assembler::rl /* release */, t0, true /* result as bool */); + __ seqz(t0, t0); // cmpxchg not equal, set t0 to 1 + __ membar(MacroAssembler::AnyAny); +} + +void LIR_Assembler::deoptimize_trap(CodeEmitInfo *info) { + address target = NULL; + + switch (patching_id(info)) { + case PatchingStub::access_field_id: + target = Runtime1::entry_for(Runtime1::access_field_patching_id); + break; + case PatchingStub::load_klass_id: + target = Runtime1::entry_for(Runtime1::load_klass_patching_id); + break; + case PatchingStub::load_mirror_id: + target = Runtime1::entry_for(Runtime1::load_mirror_patching_id); + break; + case PatchingStub::load_appendix_id: + target = Runtime1::entry_for(Runtime1::load_appendix_patching_id); + break; + default: ShouldNotReachHere(); + } + + __ far_call(RuntimeAddress(target)); + add_call_info_here(info); +} + +void LIR_Assembler::check_exact_klass(Register tmp, ciKlass* exact_klass) { + Label ok; + __ load_klass(tmp, tmp); + __ mov_metadata(t0, exact_klass->constant_encoding()); + __ beq(tmp, t0, ok); + __ stop("exact klass and actual klass differ"); + __ bind(ok); +} + +void LIR_Assembler::get_op(BasicType type) { + switch (type) { + case T_INT: + xchg = &MacroAssembler::atomic_xchgalw; + add = &MacroAssembler::atomic_addalw; + break; + case T_LONG: + xchg = &MacroAssembler::atomic_xchgal; + add = &MacroAssembler::atomic_addal; + break; + case T_OBJECT: + case T_ARRAY: + if (UseCompressedOops) { + xchg = &MacroAssembler::atomic_xchgalwu; + add = &MacroAssembler::atomic_addalw; + } else { + xchg = &MacroAssembler::atomic_xchgal; + add = &MacroAssembler::atomic_addal; + } + break; + default: + ShouldNotReachHere(); + } +} + +// emit_opTypeCheck sub functions +void LIR_Assembler::typecheck_lir_store(LIR_OpTypeCheck* op, bool should_profile) { + Register value = op->object()->as_register(); + Register array = op->array()->as_register(); + Register k_RInfo = op->tmp1()->as_register(); + Register klass_RInfo = op->tmp2()->as_register(); + Register Rtmp1 = op->tmp3()->as_register(); + + CodeStub* stub = op->stub(); + + // check if it needs to be profiled + ciMethodData* md = NULL; + ciProfileData* data = NULL; + + if (should_profile) { + data_check(op, &md, &data); + } + Label profile_cast_success, profile_cast_failure, done; + Label *success_target = should_profile ? &profile_cast_success : &done; + Label *failure_target = should_profile ? &profile_cast_failure : stub->entry(); + + if (should_profile) { + profile_object(md, data, value, klass_RInfo, &done); + } else { + __ beqz(value, done); + } + + add_debug_info_for_null_check_here(op->info_for_exception()); + __ load_klass(k_RInfo, array); + __ load_klass(klass_RInfo, value); + + lir_store_slowcheck(k_RInfo, klass_RInfo, Rtmp1, success_target, failure_target); + + // fall through to the success case + if (should_profile) { + Register mdo = klass_RInfo; + Register recv = k_RInfo; + __ bind(profile_cast_success); + __ mov_metadata(mdo, md->constant_encoding()); + __ load_klass(recv, value); + type_profile_helper(mdo, md, data, recv, &done); + __ j(done); + + __ bind(profile_cast_failure); + __ mov_metadata(mdo, md->constant_encoding()); + Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); + __ ld(t1, counter_addr); + __ addi(t1, t1, -DataLayout::counter_increment); + __ sd(t1, counter_addr); + __ j(*stub->entry()); + } + + __ bind(done); +} + +void LIR_Assembler::add_debug_info_for_branch(address adr, CodeEmitInfo* info) { + _masm->code_section()->relocate(adr, relocInfo::poll_type); + int pc_offset = code_offset(); + flush_debug_info(pc_offset); + info->record_debug_info(compilation()->debug_info_recorder(), pc_offset); + if (info->exception_handlers() != NULL) { + compilation()->add_exception_handlers_for_pco(pc_offset, info->exception_handlers()); + } +} + +void LIR_Assembler::type_profile(Register obj, ciMethodData* md, Register klass_RInfo, Register k_RInfo, + ciProfileData* data, Label* success, Label* failure, + Label& profile_cast_success, Label& profile_cast_failure) { + Register mdo = klass_RInfo; + Register recv = k_RInfo; + __ bind(profile_cast_success); + __ mov_metadata(mdo, md->constant_encoding()); + __ load_klass(recv, obj); + Label update_done; + type_profile_helper(mdo, md, data, recv, success); + __ j(*success); + + __ bind(profile_cast_failure); + __ mov_metadata(mdo, md->constant_encoding()); + Address counter_addr = __ form_address(t1, mdo, md->byte_offset_of_slot(data, CounterData::count_offset())); + __ ld(t0, counter_addr); + __ addi(t0, t0, -DataLayout::counter_increment); + __ sd(t0, counter_addr); + __ j(*failure); +} + +void LIR_Assembler::lir_store_slowcheck(Register k_RInfo, Register klass_RInfo, Register Rtmp1, + Label* success_target, Label* failure_target) { + // get instance klass (it's already uncompressed) + __ ld(k_RInfo, Address(k_RInfo, ObjArrayKlass::element_klass_offset())); + // perform the fast part of the checking logic + __ check_klass_subtype_fast_path(klass_RInfo, k_RInfo, Rtmp1, success_target, failure_target, NULL); + // call out-of-line instance of __ check_klass_subtype_slow_path(...) + __ addi(sp, sp, -2 * wordSize); // 2: store k_RInfo and klass_RInfo + __ sd(klass_RInfo, Address(sp, wordSize)); // sub klass + __ sd(k_RInfo, Address(sp, 0)); // super klass + __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::slow_subtype_check_id))); + // load result to k_RInfo + __ ld(k_RInfo, Address(sp, 0)); + __ addi(sp, sp, 2 * wordSize); // 2: pop out k_RInfo and klass_RInfo + // result is a boolean + __ beqz(k_RInfo, *failure_target, /* is_far */ true); +} + +void LIR_Assembler::const2reg_helper(LIR_Opr src) { + switch (src->as_constant_ptr()->type()) { + case T_INT: + case T_ADDRESS: + case T_OBJECT: + case T_ARRAY: + case T_METADATA: + const2reg(src, FrameMap::t0_opr, lir_patch_none, NULL); + break; + case T_LONG: + const2reg(src, FrameMap::t0_long_opr, lir_patch_none, NULL); + break; + case T_FLOAT: + case T_DOUBLE: + default: + ShouldNotReachHere(); + } +} + +void LIR_Assembler::logic_op_reg32(Register dst, Register left, Register right, LIR_Code code) { + switch (code) { + case lir_logic_and: __ andrw(dst, left, right); break; + case lir_logic_or: __ orrw (dst, left, right); break; + case lir_logic_xor: __ xorrw(dst, left, right); break; + default: ShouldNotReachHere(); + } +} + +void LIR_Assembler::logic_op_reg(Register dst, Register left, Register right, LIR_Code code) { + switch (code) { + case lir_logic_and: __ andr(dst, left, right); break; + case lir_logic_or: __ orr (dst, left, right); break; + case lir_logic_xor: __ xorr(dst, left, right); break; + default: ShouldNotReachHere(); + } +} + +void LIR_Assembler::logic_op_imm(Register dst, Register left, int right, LIR_Code code) { + switch (code) { + case lir_logic_and: __ andi(dst, left, right); break; + case lir_logic_or: __ ori (dst, left, right); break; + case lir_logic_xor: __ xori(dst, left, right); break; + default: ShouldNotReachHere(); + } +} + +void LIR_Assembler::store_parameter(Register r, int offset_from_rsp_in_words) { + assert(offset_from_rsp_in_words >= 0, "invalid offset from rsp"); + int offset_from_rsp_in_bytes = offset_from_rsp_in_words * BytesPerWord; + assert(offset_from_rsp_in_bytes < frame_map()->reserved_argument_area_size(), "invalid offset"); + __ sd(r, Address(sp, offset_from_rsp_in_bytes)); +} + +void LIR_Assembler::store_parameter(jint c, int offset_from_rsp_in_words) { + assert(offset_from_rsp_in_words >= 0, "invalid offset from rsp"); + int offset_from_rsp_in_bytes = offset_from_rsp_in_words * BytesPerWord; + assert(offset_from_rsp_in_bytes < frame_map()->reserved_argument_area_size(), "invalid offset"); + __ li(t0, c); + __ sd(t0, Address(sp, offset_from_rsp_in_bytes)); +} + +#undef __ diff --git a/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp new file mode 100644 index 00000000000..051328c3a8a --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_LIRASSEMBLER_RISCV_HPP +#define CPU_RISCV_C1_LIRASSEMBLER_RISCV_HPP + +// ArrayCopyStub needs access to bailout +friend class ArrayCopyStub; + +private: + +#include "c1_LIRAssembler_arith_riscv.hpp" +#include "c1_LIRAssembler_arraycopy_riscv.hpp" + + int array_element_size(BasicType type) const; + + static Register as_reg(LIR_Opr op) { + return op->is_double_cpu() ? op->as_register_lo() : op->as_register(); + } + + Address as_Address(LIR_Address* addr, Register tmp); + + // helper functions which checks for overflow and sets bailout if it + // occurs. Always returns a valid embeddable pointer but in the + // bailout case the pointer won't be to unique storage. + address float_constant(float f); + address double_constant(double d); + address int_constant(jlong n); + + // Ensure we have a valid Address (base + offset) to a stack-slot. + Address stack_slot_address(int index, uint shift, int adjust = 0); + + // Record the type of the receiver in ReceiverTypeData + void type_profile_helper(Register mdo, + ciMethodData *md, ciProfileData *data, + Register recv, Label* update_done); + + void add_debug_info_for_branch(address adr, CodeEmitInfo* info); + + void casw(Register addr, Register newval, Register cmpval); + void caswu(Register addr, Register newval, Register cmpval); + void casl(Register addr, Register newval, Register cmpval); + + void poll_for_safepoint(relocInfo::relocType rtype, CodeEmitInfo* info = NULL); + + void deoptimize_trap(CodeEmitInfo *info); + + enum { + // See emit_static_call_stub for detail + // CompiledStaticCall::to_interp_stub_size() (14) + CompiledStaticCall::to_trampoline_stub_size() (1 + 3 + address) + _call_stub_size = 14 * NativeInstruction::instruction_size + + (NativeInstruction::instruction_size + NativeCallTrampolineStub::instruction_size), + // See emit_exception_handler for detail + // verify_not_null_oop + far_call + should_not_reach_here + invalidate_registers(DEBUG_ONLY) + _exception_handler_size = DEBUG_ONLY(584) NOT_DEBUG(548), // or smaller + // See emit_deopt_handler for detail + // auipc (1) + far_jump (6 or 2) + _deopt_handler_size = 1 * NativeInstruction::instruction_size + + 6 * NativeInstruction::instruction_size // or smaller + }; + + void check_conflict(ciKlass* exact_klass, intptr_t current_klass, Register tmp, + Label &next, Label &none, Address mdo_addr); + void check_no_conflict(ciKlass* exact_klass, intptr_t current_klass, Register tmp, Address mdo_addr, Label &next); + + void check_exact_klass(Register tmp, ciKlass* exact_klass); + + void check_null(Register tmp, Label &update, intptr_t current_klass, Address mdo_addr, bool do_update, Label &next); + + void (MacroAssembler::*add)(Register prev, RegisterOrConstant incr, Register addr); + void (MacroAssembler::*xchg)(Register prev, Register newv, Register addr); + + void get_op(BasicType type); + + // emit_typecheck_helper sub functions + void data_check(LIR_OpTypeCheck *op, ciMethodData **md, ciProfileData **data); + void typecheck_helper_slowcheck(ciKlass* k, Register obj, Register Rtmp1, + Register k_RInfo, Register klass_RInfo, + Label* failure_target, Label* success_target); + void profile_object(ciMethodData* md, ciProfileData* data, Register obj, + Register klass_RInfo, Label* obj_is_null); + void typecheck_loaded(LIR_OpTypeCheck* op, ciKlass* k, Register k_RInfo); + + // emit_opTypeCheck sub functions + void typecheck_lir_store(LIR_OpTypeCheck* op, bool should_profile); + + void type_profile(Register obj, ciMethodData* md, Register klass_RInfo, Register k_RInfo, + ciProfileData* data, Label* success, Label* failure, + Label& profile_cast_success, Label& profile_cast_failure); + + void lir_store_slowcheck(Register k_RInfo, Register klass_RInfo, Register Rtmp1, + Label* success_target, Label* failure_target); + + void const2reg_helper(LIR_Opr src); + + void emit_branch(LIR_Condition cmp_flag, LIR_Opr cmp1, LIR_Opr cmp2, Label& label, bool is_far, bool is_unordered); + + void logic_op_reg32(Register dst, Register left, Register right, LIR_Code code); + void logic_op_reg(Register dst, Register left, Register right, LIR_Code code); + void logic_op_imm(Register dst, Register left, int right, LIR_Code code); + +public: + + void emit_cmove(LIR_Op4* op); + + void store_parameter(Register r, int offset_from_rsp_in_words); + void store_parameter(jint c, int offset_from_rsp_in_words); + +#endif // CPU_RISCV_C1_LIRASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp new file mode 100644 index 00000000000..e126f148cdf --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -0,0 +1,1075 @@ +/* + * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "c1/c1_Compilation.hpp" +#include "c1/c1_FrameMap.hpp" +#include "c1/c1_Instruction.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_LIRGenerator.hpp" +#include "c1/c1_Runtime1.hpp" +#include "c1/c1_ValueStack.hpp" +#include "ci/ciArray.hpp" +#include "ci/ciObjArrayKlass.hpp" +#include "ci/ciTypeArrayKlass.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "utilities/powerOfTwo.hpp" +#include "vmreg_riscv.inline.hpp" + +#ifdef ASSERT +#define __ gen()->lir(__FILE__, __LINE__)-> +#else +#define __ gen()->lir()-> +#endif + +// Item will be loaded into a byte register; Intel only +void LIRItem::load_byte_item() { + load_item(); +} + + +void LIRItem::load_nonconstant() { + LIR_Opr r = value()->operand(); + if (r->is_constant()) { + _result = r; + } else { + load_item(); + } +} + +//-------------------------------------------------------------- +// LIRGenerator +//-------------------------------------------------------------- + + +LIR_Opr LIRGenerator::exceptionOopOpr() { return FrameMap::r10_oop_opr; } +LIR_Opr LIRGenerator::exceptionPcOpr() { return FrameMap::r13_opr; } +LIR_Opr LIRGenerator::divInOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } +LIR_Opr LIRGenerator::divOutOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } +LIR_Opr LIRGenerator::remOutOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } +LIR_Opr LIRGenerator::shiftCountOpr() { Unimplemented(); return LIR_OprFact::illegalOpr; } +LIR_Opr LIRGenerator::syncLockOpr() { return new_register(T_INT); } +LIR_Opr LIRGenerator::syncTempOpr() { return FrameMap::r10_opr; } +LIR_Opr LIRGenerator::getThreadTemp() { return LIR_OprFact::illegalOpr; } + + +LIR_Opr LIRGenerator::result_register_for(ValueType* type, bool callee) { + LIR_Opr opr; + switch (type->tag()) { + case intTag: opr = FrameMap::r10_opr; break; + case objectTag: opr = FrameMap::r10_oop_opr; break; + case longTag: opr = FrameMap::long10_opr; break; + case floatTag: opr = FrameMap::fpu10_float_opr; break; + case doubleTag: opr = FrameMap::fpu10_double_opr; break; + + case addressTag: // fall through + default: + ShouldNotReachHere(); + return LIR_OprFact::illegalOpr; + } + + assert(opr->type_field() == as_OprType(as_BasicType(type)), "type mismatch"); + return opr; +} + + +LIR_Opr LIRGenerator::rlock_byte(BasicType type) { + LIR_Opr reg = new_register(T_INT); + set_vreg_flag(reg, LIRGenerator::byte_reg); + return reg; +} + +//--------- loading items into registers -------------------------------- + + +bool LIRGenerator::can_store_as_constant(Value v, BasicType type) const { + if (v->type()->as_IntConstant() != NULL) { + return v->type()->as_IntConstant()->value() == 0; + } else if (v->type()->as_LongConstant() != NULL) { + return v->type()->as_LongConstant()->value() == 0; + } else if (v->type()->as_ObjectConstant() != NULL) { + return v->type()->as_ObjectConstant()->value()->is_null_object(); + } else if (v->type()->as_FloatConstant() != NULL) { + return jint_cast(v->type()->as_FloatConstant()->value()) == 0.0f; + } else if (v->type()->as_DoubleConstant() != NULL) { + return jlong_cast(v->type()->as_DoubleConstant()->value()) == 0.0; + } + return false; +} + +bool LIRGenerator::can_inline_as_constant(Value v) const { + if (v->type()->as_IntConstant() != NULL) { + int value = v->type()->as_IntConstant()->value(); + // "-value" must be defined for value may be used for sub + return Assembler::operand_valid_for_add_immediate(value) && + Assembler::operand_valid_for_add_immediate(- value); + } else if (v->type()->as_ObjectConstant() != NULL) { + return v->type()->as_ObjectConstant()->value()->is_null_object(); + } else if (v->type()->as_LongConstant() != NULL) { + long value = v->type()->as_LongConstant()->value(); + // "-value" must be defined for value may be used for sub + return Assembler::operand_valid_for_add_immediate(value) && + Assembler::operand_valid_for_add_immediate(- value); + } else if (v->type()->as_FloatConstant() != NULL) { + return v->type()->as_FloatConstant()->value() == 0.0f; + } else if (v->type()->as_DoubleConstant() != NULL) { + return v->type()->as_DoubleConstant()->value() == 0.0; + } + return false; +} + +bool LIRGenerator::can_inline_as_constant(LIR_Const* c) const { + if (c->as_constant() != NULL) { + long constant = 0; + switch (c->type()) { + case T_INT: constant = c->as_jint(); break; + case T_LONG: constant = c->as_jlong(); break; + default: return false; + } + // "-constant" must be defined for c may be used for sub + return Assembler::operand_valid_for_add_immediate(constant) && + Assembler::operand_valid_for_add_immediate(- constant); + } + return false; +} + +LIR_Opr LIRGenerator::safepoint_poll_register() { + return LIR_OprFact::illegalOpr; +} + +LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, + int shift, int disp, BasicType type) { + assert(base->is_register(), "must be"); + + if (index->is_constant()) { + LIR_Const *constant = index->as_constant_ptr(); + jlong c; + if (constant->type() == T_INT) { + c = (jlong(index->as_jint()) << shift) + disp; + } else { + assert(constant->type() == T_LONG, "should be"); + c = (index->as_jlong() << shift) + disp; + } + if ((jlong)((jint)c) == c) { + return new LIR_Address(base, (jint)c, type); + } else { + LIR_Opr tmp = new_register(T_LONG); + __ move(index, tmp); + return new LIR_Address(base, tmp, type); + } + } + + return new LIR_Address(base, index, (LIR_Address::Scale)shift, disp, type); +} + +LIR_Address* LIRGenerator::emit_array_address(LIR_Opr array_opr, LIR_Opr index_opr, + BasicType type) { + int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(type); + int elem_size = type2aelembytes(type); + int shift = exact_log2(elem_size); + return generate_address(array_opr, index_opr, shift, offset_in_bytes, type); +} + +LIR_Opr LIRGenerator::load_immediate(int x, BasicType type) { + LIR_Opr r; + switch (type) { + case T_LONG: + r = LIR_OprFact::longConst(x); + break; + case T_INT: + r = LIR_OprFact::intConst(x); + break; + default: + ShouldNotReachHere(); + } + return r; +} + +void LIRGenerator::increment_counter(address counter, BasicType type, int step) { + LIR_Opr pointer = new_pointer_register(); + __ move(LIR_OprFact::intptrConst(counter), pointer); + LIR_Address* addr = new LIR_Address(pointer, type); + increment_counter(addr, step); +} + +void LIRGenerator::increment_counter(LIR_Address* addr, int step) { + LIR_Opr reg = new_register(addr->type()); + __ load(addr, reg); + __ add(reg, load_immediate(step, addr->type()), reg); + __ store(reg, addr); +} + +void LIRGenerator::cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info) { + LIR_Opr reg = new_register(T_INT); + __ load(generate_address(base, disp, T_INT), reg, info); + __ cmp(condition, reg, LIR_OprFact::intConst(c)); +} + +void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr base, int disp, BasicType type, CodeEmitInfo* info) { + LIR_Opr reg1 = new_register(T_INT); + __ load(generate_address(base, disp, type), reg1, info); + __ cmp(condition, reg, reg1); +} + +bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, jint c, LIR_Opr result, LIR_Opr tmp) { + if (tmp->is_valid() && c > 0 && c < max_jint) { + if (is_power_of_2(c - 1)) { + __ shift_left(left, exact_log2(c - 1), tmp); + __ add(tmp, left, result); + return true; + } else if (is_power_of_2(c + 1)) { + __ shift_left(left, exact_log2(c + 1), tmp); + __ sub(tmp, left, result); + return true; + } + } + return false; +} + +void LIRGenerator::store_stack_parameter (LIR_Opr item, ByteSize offset_from_sp) { + BasicType type = item->type(); + __ store(item, new LIR_Address(FrameMap::sp_opr, in_bytes(offset_from_sp), type)); +} + +void LIRGenerator::array_store_check(LIR_Opr value, LIR_Opr array, CodeEmitInfo* store_check_info, + ciMethod* profiled_method, int profiled_bci) { + LIR_Opr tmp1 = new_register(objectType); + LIR_Opr tmp2 = new_register(objectType); + LIR_Opr tmp3 = new_register(objectType); + __ store_check(value, array, tmp1, tmp2, tmp3, store_check_info, profiled_method, profiled_bci); +} + +//---------------------------------------------------------------------- +// visitor functions +//---------------------------------------------------------------------- + +void LIRGenerator::do_MonitorEnter(MonitorEnter* x) { + assert(x->is_pinned(), ""); + LIRItem obj(x->obj(), this); + obj.load_item(); + + set_no_result(x); + + // "lock" stores the address of the monitor stack slot, so this is not an oop + LIR_Opr lock = new_register(T_INT); + + CodeEmitInfo* info_for_exception = NULL; + if (x->needs_null_check()) { + info_for_exception = state_for(x); + } + // this CodeEmitInfo must not have the xhandlers because here the + // object is already locked (xhandlers expect object to be unlocked) + CodeEmitInfo* info = state_for(x, x->state(), true); + monitor_enter(obj.result(), lock, syncTempOpr(), LIR_OprFact::illegalOpr, + x->monitor_no(), info_for_exception, info); +} + +void LIRGenerator::do_MonitorExit(MonitorExit* x) { + assert(x->is_pinned(), ""); + + LIRItem obj(x->obj(), this); + obj.dont_load_item(); + + LIR_Opr lock = new_register(T_INT); + LIR_Opr obj_temp = new_register(T_INT); + set_no_result(x); + monitor_exit(obj_temp, lock, syncTempOpr(), LIR_OprFact::illegalOpr, x->monitor_no()); +} + +// neg +void LIRGenerator::do_NegateOp(NegateOp* x) { + LIRItem from(x->x(), this); + from.load_item(); + LIR_Opr result = rlock_result(x); + __ negate(from.result(), result); +} + +// for _fadd, _fmul, _fsub, _fdiv, _frem +// _dadd, _dmul, _dsub, _ddiv, _drem +void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) { + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + + if (x->op() == Bytecodes::_frem || x->op() == Bytecodes::_drem) { + + // float remainder is implemented as a direct call into the runtime + BasicTypeList signature(2); + if (x->op() == Bytecodes::_frem) { + signature.append(T_FLOAT); + signature.append(T_FLOAT); + } else { + signature.append(T_DOUBLE); + signature.append(T_DOUBLE); + } + CallingConvention* cc = frame_map()->c_calling_convention(&signature); + + const LIR_Opr result_reg = result_register_for(x->type()); + + left.load_item(); + __ move(left.result(), cc->at(0)); + right.load_item_force(cc->at(1)); + + address entry; + if (x->op() == Bytecodes::_frem) { + entry = CAST_FROM_FN_PTR(address, SharedRuntime::frem); + } else { + entry = CAST_FROM_FN_PTR(address, SharedRuntime::drem); + } + + LIR_Opr result = rlock_result(x); + __ call_runtime_leaf(entry, getThreadTemp(), result_reg, cc->args()); + __ move(result_reg, result); + + return; + } + + if (!left.is_register()) { + left.load_item(); + } + // Always load right hand side. + right.load_item(); + + LIR_Opr reg = rlock(x); + arithmetic_op_fpu(x->op(), reg, left.result(), right.result()); + + set_result(x, round_item(reg)); +} + +// for _ladd, _lmul, _lsub, _ldiv, _lrem +void LIRGenerator::do_ArithmeticOp_Long(ArithmeticOp* x) { + + // missing test if instr is commutative and if we should swap + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + + if (x->op() == Bytecodes::_ldiv || x->op() == Bytecodes::_lrem) { + + left.load_item(); + + bool need_zero_check = true; + if (right.is_constant()) { + jlong c = right.get_jlong_constant(); + // no need to do div-by-zero check if the divisor is a non-zero constant + if (c != 0) { need_zero_check = false; } + // do not load right if the divisor is a power-of-2 constant + if (c > 0 && is_power_of_2(c)) { + right.dont_load_item(); + } else { + right.load_item(); + } + } else { + right.load_item(); + } + if (need_zero_check) { + CodeEmitInfo* info = state_for(x); + __ cmp(lir_cond_equal, right.result(), LIR_OprFact::longConst(0)); + __ branch(lir_cond_equal, new DivByZeroStub(info)); + } + + rlock_result(x); + switch (x->op()) { + case Bytecodes::_lrem: + __ rem(left.result(), right.result(), x->operand()); + break; + case Bytecodes::_ldiv: + __ div(left.result(), right.result(), x->operand()); + break; + default: + ShouldNotReachHere(); + } + } else { + assert(x->op() == Bytecodes::_lmul || x->op() == Bytecodes::_ladd || x->op() == Bytecodes::_lsub, + "expect lmul, ladd or lsub"); + // add, sub, mul + left.load_item(); + if (!right.is_register()) { + if (x->op() == Bytecodes::_lmul || + !right.is_constant() || + (x->op() == Bytecodes::_ladd && + !Assembler::operand_valid_for_add_immediate(right.get_jlong_constant())) || + (x->op() == Bytecodes::_lsub && + !Assembler::operand_valid_for_add_immediate(-right.get_jlong_constant()))) { + right.load_item(); + } else { // add, sub + assert(x->op() == Bytecodes::_ladd || x->op() == Bytecodes::_lsub, "expected ladd or lsub"); + // don't load constants to save register + right.load_nonconstant(); + } + } + rlock_result(x); + arithmetic_op_long(x->op(), x->operand(), left.result(), right.result(), NULL); + } +} + +// for: _iadd, _imul, _isub, _idiv, _irem +void LIRGenerator::do_ArithmeticOp_Int(ArithmeticOp* x) { + + // Test if instr is commutative and if we should swap + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + LIRItem* left_arg = &left; + LIRItem* right_arg = &right; + if (x->is_commutative() && left.is_stack() && right.is_register()) { + // swap them if left is real stack (or cached) and right is real register(not cached) + left_arg = &right; + right_arg = &left; + } + left_arg->load_item(); + // do not need to load right, as we can handle stack and constants + if (x->op() == Bytecodes::_idiv || x->op() == Bytecodes::_irem) { + + rlock_result(x); + + bool need_zero_check = true; + if (right.is_constant()) { + jint c = right.get_jint_constant(); + // no need to do div-by-zero check if the divisor is a non-zero constant + if (c != 0) { need_zero_check = false; } + // do not load right if the divisor is a power-of-2 constant + if (c > 0 && is_power_of_2(c)) { + right_arg->dont_load_item(); + } else { + right_arg->load_item(); + } + } else { + right_arg->load_item(); + } + if (need_zero_check) { + CodeEmitInfo* info = state_for(x); + __ cmp(lir_cond_equal, right_arg->result(), LIR_OprFact::longConst(0)); + __ branch(lir_cond_equal, new DivByZeroStub(info)); + } + + LIR_Opr ill = LIR_OprFact::illegalOpr; + if (x->op() == Bytecodes::_irem) { + __ irem(left_arg->result(), right_arg->result(), x->operand(), ill, NULL); + } else if (x->op() == Bytecodes::_idiv) { + __ idiv(left_arg->result(), right_arg->result(), x->operand(), ill, NULL); + } + + } else if (x->op() == Bytecodes::_iadd || x->op() == Bytecodes::_isub) { + if (right.is_constant() && + ((x->op() == Bytecodes::_iadd && !Assembler::operand_valid_for_add_immediate(right.get_jint_constant())) || + (x->op() == Bytecodes::_isub && !Assembler::operand_valid_for_add_immediate(-right.get_jint_constant())))) { + right.load_nonconstant(); + } else { + right.load_item(); + } + rlock_result(x); + arithmetic_op_int(x->op(), x->operand(), left_arg->result(), right_arg->result(), LIR_OprFact::illegalOpr); + } else { + assert (x->op() == Bytecodes::_imul, "expect imul"); + if (right.is_constant()) { + jint c = right.get_jint_constant(); + if (c > 0 && c < max_jint && (is_power_of_2(c) || is_power_of_2(c - 1) || is_power_of_2(c + 1))) { + right_arg->dont_load_item(); + } else { + // Cannot use constant op. + right_arg->load_item(); + } + } else { + right.load_item(); + } + rlock_result(x); + arithmetic_op_int(x->op(), x->operand(), left_arg->result(), right_arg->result(), new_register(T_INT)); + } +} + +void LIRGenerator::do_ArithmeticOp(ArithmeticOp* x) { + // when an operand with use count 1 is the left operand, then it is + // likely that no move for 2-operand-LIR-form is necessary + if (x->is_commutative() && x->y()->as_Constant() == NULL && x->x()->use_count() > x->y()->use_count()) { + x->swap_operands(); + } + + ValueTag tag = x->type()->tag(); + assert(x->x()->type()->tag() == tag && x->y()->type()->tag() == tag, "wrong parameters"); + switch (tag) { + case floatTag: + case doubleTag: do_ArithmeticOp_FPU(x); return; + case longTag: do_ArithmeticOp_Long(x); return; + case intTag: do_ArithmeticOp_Int(x); return; + default: ShouldNotReachHere(); return; + } +} + +// _ishl, _lshl, _ishr, _lshr, _iushr, _lushr +void LIRGenerator::do_ShiftOp(ShiftOp* x) { + LIRItem value(x->x(), this); + LIRItem count(x->y(), this); + + value.load_item(); + if (count.is_constant()) { + assert(count.type()->as_IntConstant() != NULL || count.type()->as_LongConstant() != NULL , "should be"); + count.dont_load_item(); + } else { + count.load_item(); + } + + LIR_Opr res = rlock_result(x); + shift_op(x->op(), res, value.result(), count.result(), LIR_OprFact::illegalOpr); +} + + +// _iand, _land, _ior, _lor, _ixor, _lxor +void LIRGenerator::do_LogicOp(LogicOp* x) { + + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + + left.load_item(); + rlock_result(x); + ValueTag tag = right.type()->tag(); + if (right.is_constant() && + ((tag == longTag && Assembler::operand_valid_for_add_immediate(right.get_jlong_constant())) || + (tag == intTag && Assembler::operand_valid_for_add_immediate(right.get_jint_constant())))) { + right.dont_load_item(); + } else { + right.load_item(); + } + + switch (x->op()) { + case Bytecodes::_iand: // fall through + case Bytecodes::_land: + __ logical_and(left.result(), right.result(), x->operand()); break; + case Bytecodes::_ior: // fall through + case Bytecodes::_lor: + __ logical_or(left.result(), right.result(), x->operand()); break; + case Bytecodes::_ixor: // fall through + case Bytecodes::_lxor: + __ logical_xor(left.result(), right.result(), x->operand()); break; + default: Unimplemented(); + } +} + +// _lcmp, _fcmpl, _fcmpg, _dcmpl, _dcmpg +void LIRGenerator::do_CompareOp(CompareOp* x) { + LIRItem left(x->x(), this); + LIRItem right(x->y(), this); + ValueTag tag = x->x()->type()->tag(); + if (tag == longTag) { + left.set_destroys_register(); + } + left.load_item(); + right.load_item(); + LIR_Opr reg = rlock_result(x); + + if (x->x()->type()->is_float_kind()) { + Bytecodes::Code code = x->op(); + __ fcmp2int(left.result(), right.result(), reg, (code == Bytecodes::_fcmpl || code == Bytecodes::_dcmpl)); + } else if (x->x()->type()->tag() == longTag) { + __ lcmp2int(left.result(), right.result(), reg); + } else { + Unimplemented(); + } +} + +LIR_Opr LIRGenerator::atomic_cmpxchg(BasicType type, LIR_Opr addr, LIRItem& cmp_value, LIRItem& new_value) { + LIR_Opr ill = LIR_OprFact::illegalOpr; // for convenience + new_value.load_item(); + cmp_value.load_item(); + LIR_Opr result = new_register(T_INT); + if (is_reference_type(type)) { + __ cas_obj(addr, cmp_value.result(), new_value.result(), new_register(T_INT), new_register(T_INT), result); + } else if (type == T_INT) { + __ cas_int(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); + } else if (type == T_LONG) { + __ cas_long(addr->as_address_ptr()->base(), cmp_value.result(), new_value.result(), ill, ill); + } else { + ShouldNotReachHere(); + } + __ logical_xor(FrameMap::r5_opr, LIR_OprFact::intConst(1), result); + return result; +} + +LIR_Opr LIRGenerator::atomic_xchg(BasicType type, LIR_Opr addr, LIRItem& value) { + bool is_oop = is_reference_type(type); + LIR_Opr result = new_register(type); + value.load_item(); + assert(type == T_INT || is_oop LP64_ONLY( || type == T_LONG ), "unexpected type"); + LIR_Opr tmp = new_register(T_INT); + __ xchg(addr, value.result(), result, tmp); + return result; +} + +LIR_Opr LIRGenerator::atomic_add(BasicType type, LIR_Opr addr, LIRItem& value) { + LIR_Opr result = new_register(type); + value.load_item(); + assert(type == T_INT LP64_ONLY( || type == T_LONG ), "unexpected type"); + LIR_Opr tmp = new_register(T_INT); + __ xadd(addr, value.result(), result, tmp); + return result; +} + +void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { + assert(x->number_of_arguments() == 1 || (x->number_of_arguments() == 2 && x->id() == vmIntrinsics::_dpow), + "wrong type"); + + switch (x->id()) { + case vmIntrinsics::_dexp: // fall through + case vmIntrinsics::_dlog: // fall through + case vmIntrinsics::_dpow: // fall through + case vmIntrinsics::_dcos: // fall through + case vmIntrinsics::_dsin: // fall through + case vmIntrinsics::_dtan: // fall through + case vmIntrinsics::_dlog10: + do_LibmIntrinsic(x); + break; + case vmIntrinsics::_dabs: // fall through + case vmIntrinsics::_dsqrt: // fall through + case vmIntrinsics::_dsqrt_strict: { + assert(x->number_of_arguments() == 1, "wrong type"); + LIRItem value(x->argument_at(0), this); + value.load_item(); + LIR_Opr dst = rlock_result(x); + + switch (x->id()) { + case vmIntrinsics::_dsqrt: // fall through + case vmIntrinsics::_dsqrt_strict: { + __ sqrt(value.result(), dst, LIR_OprFact::illegalOpr); + break; + } + case vmIntrinsics::_dabs: { + __ abs(value.result(), dst, LIR_OprFact::illegalOpr); + break; + } + default: + ShouldNotReachHere(); + } + break; + } + default: + ShouldNotReachHere(); + } +} + +void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { + LIRItem value(x->argument_at(0), this); + value.set_destroys_register(); + LIR_Opr calc_result = rlock_result(x); + LIR_Opr result_reg = result_register_for(x->type()); + CallingConvention* cc = NULL; + BasicTypeList signature(1); + signature.append(T_DOUBLE); + if (x->id() == vmIntrinsics::_dpow) { signature.append(T_DOUBLE); } + cc = frame_map()->c_calling_convention(&signature); + value.load_item_force(cc->at(0)); + if (x->id() == vmIntrinsics::_dpow) { + LIRItem value1(x->argument_at(1), this); + value1.set_destroys_register(); + value1.load_item_force(cc->at(1)); + } + switch (x->id()) { + case vmIntrinsics::_dexp: + if (StubRoutines::dexp() != NULL) { __ call_runtime_leaf(StubRoutines::dexp(), getThreadTemp(), result_reg, cc->args()); } + else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dexp), getThreadTemp(), result_reg, cc->args()); } + break; + case vmIntrinsics::_dlog: + if (StubRoutines::dlog() != NULL) { __ call_runtime_leaf(StubRoutines::dlog(), getThreadTemp(), result_reg, cc->args()); } + else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog), getThreadTemp(), result_reg, cc->args()); } + break; + case vmIntrinsics::_dlog10: + if (StubRoutines::dlog10() != NULL) { __ call_runtime_leaf(StubRoutines::dlog10(), getThreadTemp(), result_reg, cc->args()); } + else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dlog10), getThreadTemp(), result_reg, cc->args()); } + break; + case vmIntrinsics::_dsin: + if (StubRoutines::dsin() != NULL) { __ call_runtime_leaf(StubRoutines::dsin(), getThreadTemp(), result_reg, cc->args()); } + else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dsin), getThreadTemp(), result_reg, cc->args()); } + break; + case vmIntrinsics::_dcos: + if (StubRoutines::dcos() != NULL) { __ call_runtime_leaf(StubRoutines::dcos(), getThreadTemp(), result_reg, cc->args()); } + else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dcos), getThreadTemp(), result_reg, cc->args()); } + break; + case vmIntrinsics::_dtan: + if (StubRoutines::dtan() != NULL) { __ call_runtime_leaf(StubRoutines::dtan(), getThreadTemp(), result_reg, cc->args()); } + else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtan), getThreadTemp(), result_reg, cc->args()); } + break; + case vmIntrinsics::_dpow: + if (StubRoutines::dpow() != NULL) { __ call_runtime_leaf(StubRoutines::dpow(), getThreadTemp(), result_reg, cc->args()); } + else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dpow), getThreadTemp(), result_reg, cc->args()); } + break; + default: ShouldNotReachHere(); + } + __ move(result_reg, calc_result); +} + + +void LIRGenerator::do_ArrayCopy(Intrinsic* x) { + assert(x->number_of_arguments() == 5, "wrong type"); + + // Make all state_for calls early since they can emit code + CodeEmitInfo* info = state_for(x, x->state()); + + LIRItem src(x->argument_at(0), this); + LIRItem src_pos(x->argument_at(1), this); + LIRItem dst(x->argument_at(2), this); + LIRItem dst_pos(x->argument_at(3), this); + LIRItem length(x->argument_at(4), this); + + // operands for arraycopy must use fixed registers, otherwise + // LinearScan will fail allocation (because arraycopy always needs a + // call) + + // The java calling convention will give us enough registers + // so that on the stub side the args will be perfect already. + // On the other slow/special case side we call C and the arg + // positions are not similar enough to pick one as the best. + // Also because the java calling convention is a "shifted" version + // of the C convention we can process the java args trivially into C + // args without worry of overwriting during the xfer + + src.load_item_force (FrameMap::as_oop_opr(j_rarg0)); + src_pos.load_item_force (FrameMap::as_opr(j_rarg1)); + dst.load_item_force (FrameMap::as_oop_opr(j_rarg2)); + dst_pos.load_item_force (FrameMap::as_opr(j_rarg3)); + length.load_item_force (FrameMap::as_opr(j_rarg4)); + + LIR_Opr tmp = FrameMap::as_opr(j_rarg5); + + set_no_result(x); + + int flags; + ciArrayKlass* expected_type = NULL; + arraycopy_helper(x, &flags, &expected_type); + + __ arraycopy(src.result(), src_pos.result(), dst.result(), dst_pos.result(), length.result(), tmp, + expected_type, flags, info); // does add_safepoint +} + +void LIRGenerator::do_update_CRC32(Intrinsic* x) { + ShouldNotReachHere(); +} + +void LIRGenerator::do_update_CRC32C(Intrinsic* x) { + ShouldNotReachHere(); +} + +void LIRGenerator::do_FmaIntrinsic(Intrinsic* x) { + assert(x->number_of_arguments() == 3, "wrong type"); + assert(UseFMA, "Needs FMA instructions support."); + LIRItem value(x->argument_at(0), this); + LIRItem value1(x->argument_at(1), this); + LIRItem value2(x->argument_at(2), this); + + value.load_item(); + value1.load_item(); + value2.load_item(); + + LIR_Opr calc_input = value.result(); + LIR_Opr calc_input1 = value1.result(); + LIR_Opr calc_input2 = value2.result(); + LIR_Opr calc_result = rlock_result(x); + + switch (x->id()) { + case vmIntrinsics::_fmaD: __ fmad(calc_input, calc_input1, calc_input2, calc_result); break; + case vmIntrinsics::_fmaF: __ fmaf(calc_input, calc_input1, calc_input2, calc_result); break; + default: ShouldNotReachHere(); + } +} + +void LIRGenerator::do_vectorizedMismatch(Intrinsic* x) { + fatal("vectorizedMismatch intrinsic is not implemented on this platform"); +} + +// _i2l, _i2f, _i2d, _l2i, _l2f, _l2d, _f2i, _f2l, _f2d, _d2i, _d2l, _d2f +// _i2b, _i2c, _i2s +void LIRGenerator::do_Convert(Convert* x) { + LIRItem value(x->value(), this); + value.load_item(); + LIR_Opr input = value.result(); + LIR_Opr result = rlock(x); + + // arguments of lir_convert + LIR_Opr conv_input = input; + LIR_Opr conv_result = result; + + __ convert(x->op(), conv_input, conv_result); + + assert(result->is_virtual(), "result must be virtual register"); + set_result(x, result); +} + +void LIRGenerator::do_NewInstance(NewInstance* x) { +#ifndef PRODUCT + if (PrintNotLoaded && !x->klass()->is_loaded()) { + tty->print_cr(" ###class not loaded at new bci %d", x->printable_bci()); + } +#endif + CodeEmitInfo* info = state_for(x, x->state()); + LIR_Opr reg = result_register_for(x->type()); + new_instance(reg, x->klass(), x->is_unresolved(), + FrameMap::r12_oop_opr, + FrameMap::r15_oop_opr, + FrameMap::r14_oop_opr, + LIR_OprFact::illegalOpr, + FrameMap::r13_metadata_opr, + info); + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + +void LIRGenerator::do_NewTypeArray(NewTypeArray* x) { + CodeEmitInfo* info = state_for(x, x->state()); + + LIRItem length(x->length(), this); + length.load_item_force(FrameMap::r9_opr); + + LIR_Opr reg = result_register_for(x->type()); + LIR_Opr tmp1 = FrameMap::r12_oop_opr; + LIR_Opr tmp2 = FrameMap::r14_oop_opr; + LIR_Opr tmp3 = FrameMap::r15_oop_opr; + LIR_Opr tmp4 = reg; + LIR_Opr klass_reg = FrameMap::r13_metadata_opr; + LIR_Opr len = length.result(); + BasicType elem_type = x->elt_type(); + + __ metadata2reg(ciTypeArrayKlass::make(elem_type)->constant_encoding(), klass_reg); + + CodeStub* slow_path = new NewTypeArrayStub(klass_reg, len, reg, info); + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, elem_type, klass_reg, slow_path); + + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + +void LIRGenerator::do_NewObjectArray(NewObjectArray* x) { + LIRItem length(x->length(), this); + // in case of patching (i.e., object class is not yet loaded), we need to reexecute the instruction + // and therefore provide the state before the parameters have been consumed + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || PatchALot) { + patching_info = state_for(x, x->state_before()); + } + + CodeEmitInfo* info = state_for(x, x->state()); + + LIR_Opr reg = result_register_for(x->type()); + LIR_Opr tmp1 = FrameMap::r12_oop_opr; + LIR_Opr tmp2 = FrameMap::r14_oop_opr; + LIR_Opr tmp3 = FrameMap::r15_oop_opr; + LIR_Opr tmp4 = reg; + LIR_Opr klass_reg = FrameMap::r13_metadata_opr; + + length.load_item_force(FrameMap::r9_opr); + LIR_Opr len = length.result(); + + CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info); + ciKlass* obj = (ciKlass*) ciObjArrayKlass::make(x->klass()); + if (obj == ciEnv::unloaded_ciobjarrayklass()) { + BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error"); + } + klass2reg_with_patching(klass_reg, obj, patching_info); + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path); + + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + + +void LIRGenerator::do_NewMultiArray(NewMultiArray* x) { + Values* dims = x->dims(); + int i = dims->length(); + LIRItemList* items = new LIRItemList(i, i, NULL); + while (i-- > 0) { + LIRItem* size = new LIRItem(dims->at(i), this); + items->at_put(i, size); + } + + // Evaluate state_for early since it may emit code. + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || PatchALot) { + patching_info = state_for(x, x->state_before()); + + // Cannot re-use same xhandlers for multiple CodeEmitInfos, so + // clone all handlers (NOTE: Usually this is handled transparently + // by the CodeEmitInfo cloning logic in CodeStub constructors but + // is done explicitly here because a stub isn't being used). + x->set_exception_handlers(new XHandlers(x->exception_handlers())); + } + CodeEmitInfo* info = state_for(x, x->state()); + + i = dims->length(); + while (i-- > 0) { + LIRItem* size = items->at(i); + size->load_item(); + + store_stack_parameter(size->result(), in_ByteSize(i * BytesPerInt)); + } + + LIR_Opr klass_reg = FrameMap::r10_metadata_opr; + klass2reg_with_patching(klass_reg, x->klass(), patching_info); + + LIR_Opr rank = FrameMap::r9_opr; + __ move(LIR_OprFact::intConst(x->rank()), rank); + LIR_Opr varargs = FrameMap::r12_opr; + __ move(FrameMap::sp_opr, varargs); + LIR_OprList* args = new LIR_OprList(3); + args->append(klass_reg); + args->append(rank); + args->append(varargs); + LIR_Opr reg = result_register_for(x->type()); + __ call_runtime(Runtime1::entry_for(Runtime1::new_multi_array_id), + LIR_OprFact::illegalOpr, + reg, args, info); + + LIR_Opr result = rlock_result(x); + __ move(reg, result); +} + +void LIRGenerator::do_BlockBegin(BlockBegin* x) { + // nothing to do for now +} + +void LIRGenerator::do_CheckCast(CheckCast* x) { + LIRItem obj(x->obj(), this); + + CodeEmitInfo* patching_info = NULL; + if (!x->klass()->is_loaded() || + (PatchALot && !x->is_incompatible_class_change_check() && !x->is_invokespecial_receiver_check())) { + // must do this before locking the destination register as an oop register, + // and before the obj is loaded (the latter is for deoptimization) + patching_info = state_for(x, x->state_before()); + } + obj.load_item(); + + // info for exceptions + CodeEmitInfo* info_for_exception = + (x->needs_exception_state() ? state_for(x) : + state_for(x, x->state_before(), true /*ignore_xhandler*/ )); + + CodeStub* stub = NULL; + if (x->is_incompatible_class_change_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new SimpleExceptionStub(Runtime1::throw_incompatible_class_change_error_id, LIR_OprFact::illegalOpr, + info_for_exception); + } else if (x->is_invokespecial_receiver_check()) { + assert(patching_info == NULL, "can't patch this"); + stub = new DeoptimizeStub(info_for_exception, + Deoptimization::Reason_class_check, + Deoptimization::Action_none); + } else { + stub = new SimpleExceptionStub(Runtime1::throw_class_cast_exception_id, obj.result(), info_for_exception); + } + LIR_Opr reg = rlock_result(x); + LIR_Opr tmp3 = LIR_OprFact::illegalOpr; + if (!x->klass()->is_loaded() || UseCompressedClassPointers) { + tmp3 = new_register(objectType); + } + __ checkcast(reg, obj.result(), x->klass(), + new_register(objectType), new_register(objectType), tmp3, + x->direct_compare(), info_for_exception, patching_info, stub, + x->profiled_method(), x->profiled_bci()); +} + +void LIRGenerator::do_InstanceOf(InstanceOf* x) { + LIRItem obj(x->obj(), this); + + // result and test object may not be in same register + LIR_Opr reg = rlock_result(x); + CodeEmitInfo* patching_info = NULL; + if ((!x->klass()->is_loaded() || PatchALot)) { + // must do this before locking the destination register as an oop register + patching_info = state_for(x, x->state_before()); + } + obj.load_item(); + LIR_Opr tmp3 = LIR_OprFact::illegalOpr; + if (!x->klass()->is_loaded() || UseCompressedClassPointers) { + tmp3 = new_register(objectType); + } + __ instanceof(reg, obj.result(), x->klass(), + new_register(objectType), new_register(objectType), tmp3, + x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci()); +} + +void LIRGenerator::do_If(If* x) { + // If should have two successors + assert(x->number_of_sux() == 2, "inconsistency"); + ValueTag tag = x->x()->type()->tag(); + bool is_safepoint = x->is_safepoint(); + + If::Condition cond = x->cond(); + + LIRItem xitem(x->x(), this); + LIRItem yitem(x->y(), this); + LIRItem* xin = &xitem; + LIRItem* yin = &yitem; + + if (tag == longTag) { + // for longs, only conditions "eql", "neq", "lss", "geq" are valid; + // mirror for other conditions + if (cond == If::gtr || cond == If::leq) { + cond = Instruction::mirror(cond); + xin = &yitem; + yin = &xitem; + } + xin->set_destroys_register(); + } + xin->load_item(); + yin->load_item(); + + set_no_result(x); + + LIR_Opr left = xin->result(); + LIR_Opr right = yin->result(); + + // add safepoint before generating condition code so it can be recomputed + if (x->is_safepoint()) { + // increment backedge counter if needed + increment_backedge_counter_conditionally(lir_cond(cond), left, right, state_for(x, x->state_before()), + x->tsux()->bci(), x->fsux()->bci(), x->profiled_bci()); + __ safepoint(LIR_OprFact::illegalOpr, state_for(x, x->state_before())); + } + + // Generate branch profiling. Profiling code doesn't kill flags. + __ cmp(lir_cond(cond), left, right); + profile_branch(x, cond); + move_to_phi(x->state()); + if (x->x()->type()->is_float_kind()) { + __ branch(lir_cond(cond), x->tsux(), x->usux()); + } else { + __ branch(lir_cond(cond), x->tsux()); + } + assert(x->default_sux() == x->fsux(), "wrong destination above"); + __ jump(x->default_sux()); +} + +LIR_Opr LIRGenerator::getThreadPointer() { + return FrameMap::as_pointer_opr(xthread); +} + +void LIRGenerator::trace_block_entry(BlockBegin* block) { Unimplemented(); } + +void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, + CodeEmitInfo* info) { + __ volatile_store_mem_reg(value, address, info); +} + +void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, + CodeEmitInfo* info) { + __ volatile_load_mem_reg(address, result, info); +} diff --git a/src/hotspot/cpu/riscv/c1_LIR_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIR_riscv.cpp new file mode 100644 index 00000000000..5f1c394ab3d --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LIR_riscv.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/register.hpp" +#include "c1/c1_LIR.hpp" + +FloatRegister LIR_Opr::as_float_reg() const { + return as_FloatRegister(fpu_regnr()); +} + +FloatRegister LIR_Opr::as_double_reg() const { + return as_FloatRegister(fpu_regnrLo()); +} + +// Reg2 unused. +LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) { + assert(as_FloatRegister(reg2) == fnoreg, "Not used on this platform"); + return (LIR_Opr)(intptr_t)((reg1 << LIR_Opr::reg1_shift) | + (reg1 << LIR_Opr::reg2_shift) | + LIR_Opr::double_type | + LIR_Opr::fpu_register | + LIR_Opr::double_size); +} + +#ifndef PRODUCT +void LIR_Address::verify() const { + assert(base()->is_cpu_register(), "wrong base operand"); + assert(index()->is_illegal() || index()->is_double_cpu() || index()->is_single_cpu(), "wrong index operand"); + assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || + base()->type() == T_METADATA, "wrong type for addresses"); +} +#endif // PRODUCT diff --git a/src/hotspot/cpu/riscv/c1_LinearScan_riscv.cpp b/src/hotspot/cpu/riscv/c1_LinearScan_riscv.cpp new file mode 100644 index 00000000000..78a61128bdd --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LinearScan_riscv.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_Instruction.hpp" +#include "c1/c1_LinearScan.hpp" +#include "utilities/bitMap.inline.hpp" + +void LinearScan::allocate_fpu_stack() { + // No FPU stack on RISCV +} diff --git a/src/hotspot/cpu/riscv/c1_LinearScan_riscv.hpp b/src/hotspot/cpu/riscv/c1_LinearScan_riscv.hpp new file mode 100644 index 00000000000..d7ca7b0fd05 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_LinearScan_riscv.hpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_LINEARSCAN_RISCV_HPP +#define CPU_RISCV_C1_LINEARSCAN_RISCV_HPP + +inline bool LinearScan::is_processed_reg_num(int reg_num) +{ + return reg_num <= FrameMap::last_cpu_reg() || reg_num >= pd_nof_cpu_regs_frame_map; +} + +inline int LinearScan::num_physical_regs(BasicType type) { + return 1; +} + +inline bool LinearScan::requires_adjacent_regs(BasicType type) { + return false; +} + +inline bool LinearScan::is_caller_save(int assigned_reg) { + assert(assigned_reg >= 0 && assigned_reg < nof_regs, "should call this only for registers"); + if (assigned_reg < pd_first_callee_saved_reg) { + return true; + } + if (assigned_reg > pd_last_callee_saved_reg && assigned_reg < pd_first_callee_saved_fpu_reg_1) { + return true; + } + if (assigned_reg > pd_last_callee_saved_fpu_reg_1 && assigned_reg < pd_first_callee_saved_fpu_reg_2) { + return true; + } + if (assigned_reg > pd_last_callee_saved_fpu_reg_2 && assigned_reg < pd_last_fpu_reg) { + return true; + } + return false; +} + +inline void LinearScan::pd_add_temps(LIR_Op* op) { + // No special case behaviours yet +} + + +// Implementation of LinearScanWalker + +inline bool LinearScanWalker::pd_init_regs_for_alloc(Interval* cur) +{ + if (allocator()->gen()->is_vreg_flag_set(cur->reg_num(), LIRGenerator::callee_saved)) { + assert(cur->type() != T_FLOAT && cur->type() != T_DOUBLE, "cpu regs only"); + _first_reg = pd_first_callee_saved_reg; + _last_reg = pd_last_callee_saved_reg; + return true; + } else if (cur->type() == T_INT || cur->type() == T_LONG || cur->type() == T_OBJECT || + cur->type() == T_ADDRESS || cur->type() == T_METADATA) { + _first_reg = pd_first_cpu_reg; + _last_reg = pd_last_allocatable_cpu_reg; + return true; + } + return false; +} + +#endif // CPU_RISCV_C1_LINEARSCAN_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp new file mode 100644 index 00000000000..6f656c8c533 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.cpp @@ -0,0 +1,432 @@ +/* + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_LIR.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "classfile/systemDictionary.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "interpreter/interpreter.hpp" +#include "oops/arrayOop.hpp" +#include "oops/markWord.hpp" +#include "runtime/basicLock.hpp" +#include "runtime/os.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" + +void C1_MacroAssembler::float_cmp(bool is_float, int unordered_result, + FloatRegister freg0, FloatRegister freg1, + Register result) +{ + if (is_float) { + float_compare(result, freg0, freg1, unordered_result); + } else { + double_compare(result, freg0, freg1, unordered_result); + } +} + +int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { + const int aligned_mask = BytesPerWord - 1; + const int hdr_offset = oopDesc::mark_offset_in_bytes(); + assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); + Label done; + int null_check_offset = -1; + + verify_oop(obj); + + // save object being locked into the BasicObjectLock + sd(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes())); + + null_check_offset = offset(); + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(hdr, obj); + lwu(hdr, Address(hdr, Klass::access_flags_offset())); + andi(t0, hdr, JVM_ACC_IS_VALUE_BASED_CLASS); + bnez(t0, slow_case, true /* is_far */); + } + + // Load object header + ld(hdr, Address(obj, hdr_offset)); + // and mark it as unlocked + ori(hdr, hdr, markWord::unlocked_value); + // save unlocked object header into the displaced header location on the stack + sd(hdr, Address(disp_hdr, 0)); + // test if object header is still the same (i.e. unlocked), and if so, store the + // displaced header address in the object header - if it is not the same, get the + // object header instead + la(t1, Address(obj, hdr_offset)); + cmpxchgptr(hdr, disp_hdr, t1, t0, done, /*fallthough*/NULL); + // if the object header was the same, we're done + // if the object header was not the same, it is now in the hdr register + // => test if it is a stack pointer into the same stack (recursive locking), i.e.: + // + // 1) (hdr & aligned_mask) == 0 + // 2) sp <= hdr + // 3) hdr <= sp + page_size + // + // these 3 tests can be done by evaluating the following expression: + // + // (hdr -sp) & (aligned_mask - page_size) + // + // assuming both the stack pointer and page_size have their least + // significant 2 bits cleared and page_size is a power of 2 + sub(hdr, hdr, sp); + li(t0, aligned_mask - os::vm_page_size()); + andr(hdr, hdr, t0); + // for recursive locking, the result is zero => save it in the displaced header + // location (NULL in the displaced hdr location indicates recursive locking) + sd(hdr, Address(disp_hdr, 0)); + // otherwise we don't care about the result and handle locking via runtime call + bnez(hdr, slow_case, /* is_far */ true); + bind(done); + return null_check_offset; +} + +void C1_MacroAssembler::unlock_object(Register hdr, Register obj, Register disp_hdr, Label& slow_case) { + const int aligned_mask = BytesPerWord - 1; + const int hdr_offset = oopDesc::mark_offset_in_bytes(); + assert(hdr != obj && hdr != disp_hdr && obj != disp_hdr, "registers must be different"); + Label done; + + // load displaced header + ld(hdr, Address(disp_hdr, 0)); + // if the loaded hdr is NULL we had recursive locking + // if we had recursive locking, we are done + beqz(hdr, done); + // load object + ld(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes())); + verify_oop(obj); + // test if object header is pointing to the displaced header, and if so, restore + // the displaced header in the object - if the object header is not pointing to + // the displaced header, get the object header instead + // if the object header was not pointing to the displaced header, + // we do unlocking via runtime call + if (hdr_offset) { + la(t0, Address(obj, hdr_offset)); + cmpxchgptr(disp_hdr, hdr, t0, t1, done, &slow_case); + } else { + cmpxchgptr(disp_hdr, hdr, obj, t1, done, &slow_case); + } + bind(done); +} + +// Defines obj, preserves var_size_in_bytes +void C1_MacroAssembler::try_allocate(Register obj, Register var_size_in_bytes, int con_size_in_bytes, Register tmp1, Register tmp2, Label& slow_case) { + if (UseTLAB) { + tlab_allocate(obj, var_size_in_bytes, con_size_in_bytes, tmp1, tmp2, slow_case, /* is_far */ true); + } else { + eden_allocate(obj, var_size_in_bytes, con_size_in_bytes, tmp1, slow_case, /* is_far */ true); + } +} + +void C1_MacroAssembler::initialize_header(Register obj, Register klass, Register len, Register tmp1, Register tmp2) { + assert_different_registers(obj, klass, len); + // This assumes that all prototype bits fitr in an int32_t + mv(tmp1, (int32_t)(intptr_t)markWord::prototype().value()); + sd(tmp1, Address(obj, oopDesc::mark_offset_in_bytes())); + + if (UseCompressedClassPointers) { // Take care not to kill klass + encode_klass_not_null(tmp1, klass); + sw(tmp1, Address(obj, oopDesc::klass_offset_in_bytes())); + } else { + sd(klass, Address(obj, oopDesc::klass_offset_in_bytes())); + } + + if (len->is_valid()) { + sw(len, Address(obj, arrayOopDesc::length_offset_in_bytes())); + } else if (UseCompressedClassPointers) { + store_klass_gap(obj, zr); + } +} + +// preserves obj, destroys len_in_bytes +void C1_MacroAssembler::initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register tmp) { + assert(hdr_size_in_bytes >= 0, "header size must be positive or 0"); + Label done; + + // len_in_bytes is positive and ptr sized + sub(len_in_bytes, len_in_bytes, hdr_size_in_bytes); + beqz(len_in_bytes, done); + + // Preserve obj + if (hdr_size_in_bytes) { + add(obj, obj, hdr_size_in_bytes); + } + zero_memory(obj, len_in_bytes, tmp); + if (hdr_size_in_bytes) { + sub(obj, obj, hdr_size_in_bytes); + } + + bind(done); +} + +void C1_MacroAssembler::allocate_object(Register obj, Register tmp1, Register tmp2, int header_size, int object_size, Register klass, Label& slow_case) { + assert_different_registers(obj, tmp1, tmp2); + assert(header_size >= 0 && object_size >= header_size, "illegal sizes"); + + try_allocate(obj, noreg, object_size * BytesPerWord, tmp1, tmp2, slow_case); + + initialize_object(obj, klass, noreg, object_size * HeapWordSize, tmp1, tmp2, UseTLAB); +} + +void C1_MacroAssembler::initialize_object(Register obj, Register klass, Register var_size_in_bytes, int con_size_in_bytes, Register tmp1, Register tmp2, bool is_tlab_allocated) { + assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, + "con_size_in_bytes is not multiple of alignment"); + const int hdr_size_in_bytes = instanceOopDesc::header_size() * HeapWordSize; + + initialize_header(obj, klass, noreg, tmp1, tmp2); + + if (!(UseTLAB && ZeroTLAB && is_tlab_allocated)) { + // clear rest of allocated space + const Register index = tmp2; + // 16: multipler for threshold + const int threshold = 16 * BytesPerWord; // approximate break even point for code size (see comments below) + if (var_size_in_bytes != noreg) { + mv(index, var_size_in_bytes); + initialize_body(obj, index, hdr_size_in_bytes, tmp1); + } else if (con_size_in_bytes <= threshold) { + // use explicit null stores + int i = hdr_size_in_bytes; + if (i < con_size_in_bytes && (con_size_in_bytes % (2 * BytesPerWord))) { // 2: multipler for BytesPerWord + sd(zr, Address(obj, i)); + i += BytesPerWord; + } + for (; i < con_size_in_bytes; i += BytesPerWord) { + sd(zr, Address(obj, i)); + } + } else if (con_size_in_bytes > hdr_size_in_bytes) { + block_comment("zero memory"); + // use loop to null out the fields + int words = (con_size_in_bytes - hdr_size_in_bytes) / BytesPerWord; + mv(index, words / 8); // 8: byte size + + const int unroll = 8; // Number of sd(zr) instructions we'll unroll + int remainder = words % unroll; + la(t0, Address(obj, hdr_size_in_bytes + remainder * BytesPerWord)); + + Label entry_point, loop; + j(entry_point); + + bind(loop); + sub(index, index, 1); + for (int i = -unroll; i < 0; i++) { + if (-i == remainder) { + bind(entry_point); + } + sd(zr, Address(t0, i * wordSize)); + } + if (remainder == 0) { + bind(entry_point); + } + add(t0, t0, unroll * wordSize); + bnez(index, loop); + } + } + + membar(MacroAssembler::StoreStore); + + if (CURRENT_ENV->dtrace_alloc_probes()) { + assert(obj == x10, "must be"); + far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id))); + } + + verify_oop(obj); +} + +void C1_MacroAssembler::allocate_array(Register obj, Register len, Register tmp1, Register tmp2, int header_size, int f, Register klass, Label& slow_case) { + assert_different_registers(obj, len, tmp1, tmp2, klass); + + // determine alignment mask + assert(!(BytesPerWord & 1), "must be multiple of 2 for masking code to work"); + + // check for negative or excessive length + mv(t0, (int32_t)max_array_allocation_length); + bgeu(len, t0, slow_case, /* is_far */ true); + + const Register arr_size = tmp2; // okay to be the same + // align object end + mv(arr_size, (int32_t)header_size * BytesPerWord + MinObjAlignmentInBytesMask); + shadd(arr_size, len, arr_size, t0, f); + andi(arr_size, arr_size, ~(uint)MinObjAlignmentInBytesMask); + + try_allocate(obj, arr_size, 0, tmp1, tmp2, slow_case); + + initialize_header(obj, klass, len, tmp1, tmp2); + + // clear rest of allocated space + const Register len_zero = len; + initialize_body(obj, arr_size, header_size * BytesPerWord, len_zero); + + membar(MacroAssembler::StoreStore); + + if (CURRENT_ENV->dtrace_alloc_probes()) { + assert(obj == x10, "must be"); + far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::dtrace_object_alloc_id))); + } + + verify_oop(obj); +} + +void C1_MacroAssembler::inline_cache_check(Register receiver, Register iCache, Label &L) { + verify_oop(receiver); + // explicit NULL check not needed since load from [klass_offset] causes a trap + // check against inline cache + assert(!MacroAssembler::needs_explicit_null_check(oopDesc::klass_offset_in_bytes()), "must add explicit null check"); + cmp_klass(receiver, iCache, t0, L); +} + +void C1_MacroAssembler::build_frame(int framesize, int bang_size_in_bytes) { + assert(bang_size_in_bytes >= framesize, "stack bang size incorrect"); + // Make sure there is enough stack space for this method's activation. + // Note that we do this before creating a frame. + generate_stack_overflow_check(bang_size_in_bytes); + MacroAssembler::build_frame(framesize); + + // Insert nmethod entry barrier into frame. + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->nmethod_entry_barrier(this); +} + +void C1_MacroAssembler::remove_frame(int framesize) { + MacroAssembler::remove_frame(framesize); +} + + +void C1_MacroAssembler::verified_entry(bool breakAtEntry) { + // If we have to make this method not-entrant we'll overwrite its + // first instruction with a jump. For this action to be legal we + // must ensure that this first instruction is a J, JAL or NOP. + // Make it a NOP. + + nop(); +} + +void C1_MacroAssembler::load_parameter(int offset_in_words, Register reg) { + // fp + -2: link + // + -1: return address + // + 0: argument with offset 0 + // + 1: argument with offset 1 + // + 2: ... + ld(reg, Address(fp, offset_in_words * BytesPerWord)); +} + +#ifndef PRODUCT + +void C1_MacroAssembler::verify_stack_oop(int stack_offset) { + if (!VerifyOops) { + return; + } + verify_oop_addr(Address(sp, stack_offset), "oop"); +} + +void C1_MacroAssembler::verify_not_null_oop(Register r) { + if (!VerifyOops) return; + Label not_null; + bnez(r, not_null); + stop("non-null oop required"); + bind(not_null); + verify_oop(r); +} + +void C1_MacroAssembler::invalidate_registers(bool inv_x10, bool inv_x9, bool inv_x12, bool inv_x13, bool inv_x14, bool inv_x15) { +#ifdef ASSERT + static int nn; + if (inv_x10) { mv(x10, 0xDEAD); } + if (inv_x9) { mv(x9, 0xDEAD); } + if (inv_x12) { mv(x12, nn++); } + if (inv_x13) { mv(x13, 0xDEAD); } + if (inv_x14) { mv(x14, 0xDEAD); } + if (inv_x15) { mv(x15, 0xDEAD); } +#endif // ASSERT +} +#endif // ifndef PRODUCT + +typedef void (C1_MacroAssembler::*c1_cond_branch_insn)(Register op1, Register op2, Label& label, bool is_far); +typedef void (C1_MacroAssembler::*c1_float_cond_branch_insn)(FloatRegister op1, FloatRegister op2, + Label& label, bool is_far, bool is_unordered); + +static c1_cond_branch_insn c1_cond_branch[] = +{ + /* SHORT branches */ + (c1_cond_branch_insn)&Assembler::beq, + (c1_cond_branch_insn)&Assembler::bne, + (c1_cond_branch_insn)&Assembler::blt, + (c1_cond_branch_insn)&Assembler::ble, + (c1_cond_branch_insn)&Assembler::bge, + (c1_cond_branch_insn)&Assembler::bgt, + (c1_cond_branch_insn)&Assembler::bleu, // lir_cond_belowEqual + (c1_cond_branch_insn)&Assembler::bgeu // lir_cond_aboveEqual +}; + +static c1_float_cond_branch_insn c1_float_cond_branch[] = +{ + /* FLOAT branches */ + (c1_float_cond_branch_insn)&MacroAssembler::float_beq, + (c1_float_cond_branch_insn)&MacroAssembler::float_bne, + (c1_float_cond_branch_insn)&MacroAssembler::float_blt, + (c1_float_cond_branch_insn)&MacroAssembler::float_ble, + (c1_float_cond_branch_insn)&MacroAssembler::float_bge, + (c1_float_cond_branch_insn)&MacroAssembler::float_bgt, + NULL, // lir_cond_belowEqual + NULL, // lir_cond_aboveEqual + + /* DOUBLE branches */ + (c1_float_cond_branch_insn)&MacroAssembler::double_beq, + (c1_float_cond_branch_insn)&MacroAssembler::double_bne, + (c1_float_cond_branch_insn)&MacroAssembler::double_blt, + (c1_float_cond_branch_insn)&MacroAssembler::double_ble, + (c1_float_cond_branch_insn)&MacroAssembler::double_bge, + (c1_float_cond_branch_insn)&MacroAssembler::double_bgt, + NULL, // lir_cond_belowEqual + NULL // lir_cond_aboveEqual +}; + +void C1_MacroAssembler::c1_cmp_branch(int cmpFlag, Register op1, Register op2, Label& label, + BasicType type, bool is_far) { + if (type == T_OBJECT || type == T_ARRAY) { + assert(cmpFlag == lir_cond_equal || cmpFlag == lir_cond_notEqual, "Should be equal or notEqual"); + if (cmpFlag == lir_cond_equal) { + beq(op1, op2, label, is_far); + } else { + bne(op1, op2, label, is_far); + } + } else { + assert(cmpFlag >= 0 && cmpFlag < (int)(sizeof(c1_cond_branch) / sizeof(c1_cond_branch[0])), + "invalid c1 conditional branch index"); + (this->*c1_cond_branch[cmpFlag])(op1, op2, label, is_far); + } +} + +void C1_MacroAssembler::c1_float_cmp_branch(int cmpFlag, FloatRegister op1, FloatRegister op2, Label& label, + bool is_far, bool is_unordered) { + assert(cmpFlag >= 0 && + cmpFlag < (int)(sizeof(c1_float_cond_branch) / sizeof(c1_float_cond_branch[0])), + "invalid c1 float conditional branch index"); + (this->*c1_float_cond_branch[cmpFlag])(op1, op2, label, is_far, is_unordered); +} diff --git a/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp new file mode 100644 index 00000000000..dfd3c17d7c7 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_MacroAssembler_riscv.hpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_MACROASSEMBLER_RISCV_HPP +#define CPU_RISCV_C1_MACROASSEMBLER_RISCV_HPP + +using MacroAssembler::build_frame; +using MacroAssembler::null_check; + +// C1_MacroAssembler contains high-level macros for C1 + + private: + int _rsp_offset; // track rsp changes + // initialization + void pd_init() { _rsp_offset = 0; } + + + public: + void try_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register tmp1, // temp register + Register tmp2, // temp register + Label& slow_case // continuation point if fast allocation fails + ); + + void initialize_header(Register obj, Register klass, Register len, Register tmp1, Register tmp2); + void initialize_body(Register obj, Register len_in_bytes, int hdr_size_in_bytes, Register tmp); + + void float_cmp(bool is_float, int unordered_result, + FloatRegister f0, FloatRegister f1, + Register result); + + // locking + // hdr : must be x10, contents destroyed + // obj : must point to the object to lock, contents preserved + // disp_hdr: must point to the displaced header location, contents preserved + // returns code offset at which to add null check debug information + int lock_object (Register swap, Register obj, Register disp_hdr, Label& slow_case); + + // unlocking + // hdr : contents destroyed + // obj : must point to the object to lock, contents preserved + // disp_hdr: must be x10 & must point to the displaced header location, contents destroyed + void unlock_object(Register swap, Register obj, Register lock, Label& slow_case); + + void initialize_object( + Register obj, // result: pointer to object after successful allocation + Register klass, // object klass + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register tmp1, // temp register + Register tmp2, // temp register + bool is_tlab_allocated // the object was allocated in a TLAB; relevant for the implementation of ZeroTLAB + ); + + // allocation of fixed-size objects + // (can also be used to allocate fixed-size arrays, by setting + // hdr_size correctly and storing the array length afterwards) + // obj : will contain pointer to allocated object + // t1, t2 : temp registers - contents destroyed + // header_size: size of object header in words + // object_size: total size of object in words + // slow_case : exit to slow case implementation if fast allocation fails + void allocate_object(Register obj, Register tmp1, Register tmp2, int header_size, int object_size, Register klass, Label& slow_case); + + enum { + max_array_allocation_length = 0x00FFFFFF + }; + + // allocation of arrays + // obj : will contain pointer to allocated object + // len : array length in number of elements + // t : temp register - contents destroyed + // header_size: size of object header in words + // f : element scale factor + // slow_case : exit to slow case implementation if fast allocation fails + void allocate_array(Register obj, Register len, Register tmp1, Register tmp2, int header_size, int f, Register klass, Label& slow_case); + + int rsp_offset() const { return _rsp_offset; } + + void invalidate_registers(bool inv_r0, bool inv_r19, bool inv_r2, bool inv_r3, bool inv_r4, bool inv_r5) PRODUCT_RETURN; + + // This platform only uses signal-based null checks. The Label is not needed. + void null_check(Register r, Label *Lnull = NULL) { MacroAssembler::null_check(r); } + + void load_parameter(int offset_in_words, Register reg); + + void inline_cache_check(Register receiver, Register iCache, Label &L); + + static const int c1_double_branch_mask = 1 << 3; // depend on c1_float_cond_branch + void c1_cmp_branch(int cmpFlag, Register op1, Register op2, Label& label, BasicType type, bool is_far); + void c1_float_cmp_branch(int cmpFlag, FloatRegister op1, FloatRegister op2, Label& label, + bool is_far, bool is_unordered = false); + +#endif // CPU_RISCV_C1_MACROASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp new file mode 100644 index 00000000000..f523c9ed50a --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_Runtime1_riscv.cpp @@ -0,0 +1,1172 @@ +/* + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "c1/c1_CodeStubs.hpp" +#include "c1/c1_Defs.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "c1/c1_Runtime1.hpp" +#include "compiler/disassembler.hpp" +#include "compiler/oopMap.hpp" +#include "gc/shared/cardTable.hpp" +#include "gc/shared/cardTableBarrierSet.hpp" +#include "interpreter/interpreter.hpp" +#include "memory/universe.hpp" +#include "nativeInst_riscv.hpp" +#include "oops/compiledICHolder.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "register_riscv.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/signature.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/vframe.hpp" +#include "runtime/vframeArray.hpp" +#include "utilities/powerOfTwo.hpp" +#include "vmreg_riscv.inline.hpp" + + +// Implementation of StubAssembler + +int StubAssembler::call_RT(Register oop_result, Register metadata_result, address entry, int args_size) { + // setup registers + assert(!(oop_result->is_valid() || metadata_result->is_valid()) || oop_result != metadata_result, + "registers must be different"); + assert(oop_result != xthread && metadata_result != xthread, "registers must be different"); + assert(args_size >= 0, "illegal args_size"); + bool align_stack = false; + + mv(c_rarg0, xthread); + set_num_rt_args(0); // Nothing on stack + + Label retaddr; + set_last_Java_frame(sp, fp, retaddr, t0); + + // do the call + int32_t off = 0; + la_patchable(t0, RuntimeAddress(entry), off); + jalr(x1, t0, off); + bind(retaddr); + int call_offset = offset(); + // verify callee-saved register +#ifdef ASSERT + push_reg(x10, sp); + { Label L; + get_thread(x10); + beq(xthread, x10, L); + stop("StubAssembler::call_RT: xthread not callee saved?"); + bind(L); + } + pop_reg(x10, sp); +#endif + reset_last_Java_frame(true); + + // check for pending exceptions + { Label L; + // check for pending exceptions (java_thread is set upon return) + ld(t0, Address(xthread, in_bytes(Thread::pending_exception_offset()))); + beqz(t0, L); + // exception pending => remove activation and forward to exception handler + // make sure that the vm_results are cleared + if (oop_result->is_valid()) { + sd(zr, Address(xthread, JavaThread::vm_result_offset())); + } + if (metadata_result->is_valid()) { + sd(zr, Address(xthread, JavaThread::vm_result_2_offset())); + } + if (frame_size() == no_frame_size) { + leave(); + far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + } else if (_stub_id == Runtime1::forward_exception_id) { + should_not_reach_here(); + } else { + far_jump(RuntimeAddress(Runtime1::entry_for(Runtime1::forward_exception_id))); + } + bind(L); + } + // get oop results if there are any and reset the values in the thread + if (oop_result->is_valid()) { + get_vm_result(oop_result, xthread); + } + if (metadata_result->is_valid()) { + get_vm_result_2(metadata_result, xthread); + } + return call_offset; +} + +int StubAssembler::call_RT(Register oop_result, Register metadata_result, address entry, Register arg1) { + mv(c_rarg1, arg1); + return call_RT(oop_result, metadata_result, entry, 1); +} + +int StubAssembler::call_RT(Register oop_result, Register metadata_result, address entry, Register arg1, Register arg2) { + const int arg_num = 2; + if (c_rarg1 == arg2) { + if (c_rarg2 == arg1) { + xorr(arg1, arg1, arg2); + xorr(arg2, arg1, arg2); + xorr(arg1, arg1, arg2); + } else { + mv(c_rarg2, arg2); + mv(c_rarg1, arg1); + } + } else { + mv(c_rarg1, arg1); + mv(c_rarg2, arg2); + } + return call_RT(oop_result, metadata_result, entry, arg_num); +} + +int StubAssembler::call_RT(Register oop_result, Register metadata_result, address entry, Register arg1, Register arg2, Register arg3) { + const int arg_num = 3; + // if there is any conflict use the stack + if (arg1 == c_rarg2 || arg1 == c_rarg3 || + arg2 == c_rarg1 || arg2 == c_rarg3 || + arg3 == c_rarg1 || arg3 == c_rarg2) { + const int arg1_sp_offset = 0; + const int arg2_sp_offset = 1; + const int arg3_sp_offset = 2; + addi(sp, sp, -(arg_num + 1) * wordSize); + sd(arg1, Address(sp, arg1_sp_offset * wordSize)); + sd(arg2, Address(sp, arg2_sp_offset * wordSize)); + sd(arg3, Address(sp, arg3_sp_offset * wordSize)); + + ld(c_rarg1, Address(sp, arg1_sp_offset * wordSize)); + ld(c_rarg2, Address(sp, arg2_sp_offset * wordSize)); + ld(c_rarg3, Address(sp, arg3_sp_offset * wordSize)); + addi(sp, sp, (arg_num + 1) * wordSize); + } else { + mv(c_rarg1, arg1); + mv(c_rarg2, arg2); + mv(c_rarg3, arg3); + } + return call_RT(oop_result, metadata_result, entry, arg_num); +} + +enum return_state_t { + does_not_return, requires_return +}; + +// Implementation of StubFrame + +class StubFrame: public StackObj { + private: + StubAssembler* _sasm; + bool _return_state; + + public: + StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments, return_state_t return_state=requires_return); + void load_argument(int offset_in_words, Register reg); + + ~StubFrame(); +};; + +void StubAssembler::prologue(const char* name, bool must_gc_arguments) { + set_info(name, must_gc_arguments); + enter(); +} + +void StubAssembler::epilogue() { + leave(); + ret(); +} + +#define __ _sasm-> + +StubFrame::StubFrame(StubAssembler* sasm, const char* name, bool must_gc_arguments, return_state_t return_state) { + _sasm = sasm; + _return_state = return_state; + __ prologue(name, must_gc_arguments); +} + +// load parameters that were stored with LIR_Assembler::store_parameter +// Note: offsets for store_parameter and load_argument must match +void StubFrame::load_argument(int offset_in_words, Register reg) { + __ load_parameter(offset_in_words, reg); +} + + +StubFrame::~StubFrame() { + if (_return_state == requires_return) { + __ epilogue(); + } else { + __ should_not_reach_here(); + } + _sasm = NULL; +} + +#undef __ + + +// Implementation of Runtime1 + +#define __ sasm-> + +const int float_regs_as_doubles_size_in_slots = pd_nof_fpu_regs_frame_map * 2; + +// Stack layout for saving/restoring all the registers needed during a runtime +// call (this includes deoptimization) +// Note: note that users of this frame may well have arguments to some runtime +// while these values are on the stack. These positions neglect those arguments +// but the code in save_live_registers will take the argument count into +// account. +// + +enum reg_save_layout { + reg_save_frame_size = 32 /* float */ + 30 /* integer excluding x3, x4 */ +}; + +// Save off registers which might be killed by calls into the runtime. +// Tries to smart of about FPU registers. In particular we separate +// saving and describing the FPU registers for deoptimization since we +// have to save the FPU registers twice if we describe them. The +// deopt blob is the only thing which needs to describe FPU registers. +// In all other cases it should be sufficient to simply save their +// current value. + +static int cpu_reg_save_offsets[FrameMap::nof_cpu_regs]; +static int fpu_reg_save_offsets[FrameMap::nof_fpu_regs]; + +static OopMap* generate_oop_map(StubAssembler* sasm, bool save_fpu_registers) { + int frame_size_in_bytes = reg_save_frame_size * BytesPerWord; + sasm->set_frame_size(frame_size_in_bytes / BytesPerWord); + int frame_size_in_slots = frame_size_in_bytes / sizeof(jint); + OopMap* oop_map = new OopMap(frame_size_in_slots, 0); + assert_cond(oop_map != NULL); + + // caller save registers only, see FrameMap::initialize + // in c1_FrameMap_riscv.cpp for detail. + const static Register caller_save_cpu_regs[FrameMap::max_nof_caller_save_cpu_regs] = { + x7, x10, x11, x12, x13, x14, x15, x16, x17, x28, x29, x30, x31 + }; + + for (int i = 0; i < FrameMap::max_nof_caller_save_cpu_regs; i++) { + Register r = caller_save_cpu_regs[i]; + int sp_offset = cpu_reg_save_offsets[r->encoding()]; + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), + r->as_VMReg()); + } + + // fpu_regs + if (save_fpu_registers) { + for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { + FloatRegister r = as_FloatRegister(i); + int sp_offset = fpu_reg_save_offsets[i]; + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset), + r->as_VMReg()); + } + } + return oop_map; +} + +static OopMap* save_live_registers(StubAssembler* sasm, + bool save_fpu_registers = true) { + __ block_comment("save_live_registers"); + + // if the number of pushed regs is odd, one slot will be reserved for alignment + __ push_reg(RegSet::range(x5, x31), sp); // integer registers except ra(x1) & sp(x2) & gp(x3) & tp(x4) + + if (save_fpu_registers) { + // float registers + __ addi(sp, sp, -(FrameMap::nof_fpu_regs * wordSize)); + for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { + __ fsd(as_FloatRegister(i), Address(sp, i * wordSize)); + } + } else { + // we define reg_save_layout = 62 as the fixed frame size, + // we should also sub 32 * wordSize to sp when save_fpu_registers == false + __ addi(sp, sp, -32 * wordSize); + } + + return generate_oop_map(sasm, save_fpu_registers); +} + +static void restore_live_registers(StubAssembler* sasm, bool restore_fpu_registers = true) { + if (restore_fpu_registers) { + for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { + __ fld(as_FloatRegister(i), Address(sp, i * wordSize)); + } + __ addi(sp, sp, FrameMap::nof_fpu_regs * wordSize); + } else { + // we define reg_save_layout = 64 as the fixed frame size, + // we should also add 32 * wordSize to sp when save_fpu_registers == false + __ addi(sp, sp, 32 * wordSize); + } + + // if the number of popped regs is odd, the reserved slot for alignment will be removed + __ pop_reg(RegSet::range(x5, x31), sp); // integer registers except ra(x1) & sp(x2) & gp(x3) & tp(x4) +} + +static void restore_live_registers_except_r10(StubAssembler* sasm, bool restore_fpu_registers = true) { + if (restore_fpu_registers) { + for (int i = 0; i < FrameMap::nof_fpu_regs; i++) { + __ fld(as_FloatRegister(i), Address(sp, i * wordSize)); + } + __ addi(sp, sp, FrameMap::nof_fpu_regs * wordSize); + } else { + // we define reg_save_layout = 64 as the fixed frame size, + // we should also add 32 * wordSize to sp when save_fpu_registers == false + __ addi(sp, sp, 32 * wordSize); + } + + // pop integer registers except ra(x1) & sp(x2) & gp(x3) & tp(x4) & x10 + // there is one reserved slot for alignment on the stack in save_live_registers(). + __ pop_reg(RegSet::range(x5, x9), sp); // pop x5 ~ x9 with the reserved slot for alignment + __ pop_reg(RegSet::range(x11, x31), sp); // pop x11 ~ x31; x10 will be automatically skipped here +} + +void Runtime1::initialize_pd() { + int i = 0; + int sp_offset = 0; + const int step = 2; // SP offsets are in halfwords + + // all float registers are saved explicitly + for (i = 0; i < FrameMap::nof_fpu_regs; i++) { + fpu_reg_save_offsets[i] = sp_offset; + sp_offset += step; + } + + // a slot reserved for stack 16-byte alignment, see MacroAssembler::push_reg + sp_offset += step; + // we save x5 ~ x31, except x0 ~ x4: loop starts from x5 + for (i = 5; i < FrameMap::nof_cpu_regs; i++) { + cpu_reg_save_offsets[i] = sp_offset; + sp_offset += step; + } +} + +// target: the entry point of the method that creates and posts the exception oop +// has_argument: true if the exception needs arguments (passed in t0 and t1) + +OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) { + // make a frame and preserve the caller's caller-save registers + OopMap* oop_map = save_live_registers(sasm); + assert_cond(oop_map != NULL); + int call_offset = 0; + if (!has_argument) { + call_offset = __ call_RT(noreg, noreg, target); + } else { + __ mv(c_rarg1, t0); + __ mv(c_rarg2, t1); + call_offset = __ call_RT(noreg, noreg, target); + } + OopMapSet* oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, oop_map); + + return oop_maps; +} + +OopMapSet* Runtime1::generate_handle_exception(StubID id, StubAssembler *sasm) { + __ block_comment("generate_handle_exception"); + + // incoming parameters + const Register exception_oop = x10; + const Register exception_pc = x13; + + OopMapSet* oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + OopMap* oop_map = NULL; + + switch (id) { + case forward_exception_id: + // We're handling an exception in the context of a compiled frame. + // The registers have been saved in the standard places. Perform + // an exception lookup in the caller and dispatch to the handler + // if found. Otherwise unwind and dispatch to the callers + // exception handler. + oop_map = generate_oop_map(sasm, 1 /* thread */); + + // load and clear pending exception oop into x10 + __ ld(exception_oop, Address(xthread, Thread::pending_exception_offset())); + __ sd(zr, Address(xthread, Thread::pending_exception_offset())); + + // load issuing PC (the return address for this stub) into x13 + __ ld(exception_pc, Address(fp, frame::return_addr_offset * BytesPerWord)); + + // make sure that the vm_results are cleared (may be unnecessary) + __ sd(zr, Address(xthread, JavaThread::vm_result_offset())); + __ sd(zr, Address(xthread, JavaThread::vm_result_2_offset())); + break; + case handle_exception_nofpu_id: + case handle_exception_id: + // At this point all registers MAY be live. + oop_map = save_live_registers(sasm, id != handle_exception_nofpu_id); + break; + case handle_exception_from_callee_id: { + // At this point all registers except exception oop (x10) and + // exception pc (ra) are dead. + const int frame_size = 2 /* fp, return address */; + oop_map = new OopMap(frame_size * VMRegImpl::slots_per_word, 0); + sasm->set_frame_size(frame_size); + break; + } + default: ShouldNotReachHere(); + } + + // verify that only x10 and x13 are valid at this time + __ invalidate_registers(false, true, true, false, true, true); + // verify that x10 contains a valid exception + __ verify_not_null_oop(exception_oop); + +#ifdef ASSERT + // check that fields in JavaThread for exception oop and issuing pc are + // empty before writing to them + Label oop_empty; + __ ld(t0, Address(xthread, JavaThread::exception_oop_offset())); + __ beqz(t0, oop_empty); + __ stop("exception oop already set"); + __ bind(oop_empty); + + Label pc_empty; + __ ld(t0, Address(xthread, JavaThread::exception_pc_offset())); + __ beqz(t0, pc_empty); + __ stop("exception pc already set"); + __ bind(pc_empty); +#endif + + // save exception oop and issuing pc into JavaThread + // (exception handler will load it from here) + __ sd(exception_oop, Address(xthread, JavaThread::exception_oop_offset())); + __ sd(exception_pc, Address(xthread, JavaThread::exception_pc_offset())); + + // patch throwing pc into return address (has bci & oop map) + __ sd(exception_pc, Address(fp, frame::return_addr_offset * BytesPerWord)); + + // compute the exception handler. + // the exception oop and the throwing pc are read from the fields in JavaThread + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, exception_handler_for_pc)); + guarantee(oop_map != NULL, "NULL oop_map!"); + oop_maps->add_gc_map(call_offset, oop_map); + + // x10: handler address + // will be the deopt blob if nmethod was deoptimized while we looked up + // handler regardless of whether handler existed in the nmethod. + + // only x10 is valid at this time, all other registers have been destroyed by the runtime call + __ invalidate_registers(false, true, true, true, true, true); + + // patch the return address, this stub will directly return to the exception handler + __ sd(x10, Address(fp, frame::return_addr_offset * BytesPerWord)); + + switch (id) { + case forward_exception_id: + case handle_exception_nofpu_id: + case handle_exception_id: + // Restore the registers that were saved at the beginning. + restore_live_registers(sasm, id != handle_exception_nofpu_id); + break; + case handle_exception_from_callee_id: + break; + default: ShouldNotReachHere(); + } + + return oop_maps; +} + + +void Runtime1::generate_unwind_exception(StubAssembler *sasm) { + // incoming parameters + const Register exception_oop = x10; + // other registers used in this stub + const Register handler_addr = x11; + + // verify that only x10, is valid at this time + __ invalidate_registers(false, true, true, true, true, true); + +#ifdef ASSERT + // check that fields in JavaThread for exception oop and issuing pc are empty + Label oop_empty; + __ ld(t0, Address(xthread, JavaThread::exception_oop_offset())); + __ beqz(t0, oop_empty); + __ stop("exception oop must be empty"); + __ bind(oop_empty); + + Label pc_empty; + __ ld(t0, Address(xthread, JavaThread::exception_pc_offset())); + __ beqz(t0, pc_empty); + __ stop("exception pc must be empty"); + __ bind(pc_empty); +#endif + + // Save our return address because + // exception_handler_for_return_address will destroy it. We also + // save exception_oop + __ addi(sp, sp, -2 * wordSize); + __ sd(exception_oop, Address(sp, wordSize)); + __ sd(ra, Address(sp)); + + // search the exception handler address of the caller (using the return address) + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address), xthread, ra); + // x10: exception handler address of the caller + + // Only x10 is valid at this time; all other registers have been + // destroyed by the call. + __ invalidate_registers(false, true, true, true, false, true); + + // move result of call into correct register + __ mv(handler_addr, x10); + + // get throwing pc (= return address). + // ra has been destroyed by the call + __ ld(ra, Address(sp)); + __ ld(exception_oop, Address(sp, wordSize)); + __ addi(sp, sp, 2 * wordSize); + __ mv(x13, ra); + + __ verify_not_null_oop(exception_oop); + + // continue at exception handler (return address removed) + // note: do *not* remove arguments when unwinding the + // activation since the caller assumes having + // all arguments on the stack when entering the + // runtime to determine the exception handler + // (GC happens at call site with arguments!) + // x10: exception oop + // x13: throwing pc + // x11: exception handler + __ jr(handler_addr); +} + +OopMapSet* Runtime1::generate_patching(StubAssembler* sasm, address target) { + // use the maximum number of runtime-arguments here because it is difficult to + // distinguish each RT-Call. + // Note: This number affects also the RT-Call in generate_handle_exception because + // the oop-map is shared for all calls. + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + + OopMap* oop_map = save_live_registers(sasm); + assert_cond(oop_map != NULL); + + __ mv(c_rarg0, xthread); + Label retaddr; + __ set_last_Java_frame(sp, fp, retaddr, t0); + // do the call + int32_t off = 0; + __ la_patchable(t0, RuntimeAddress(target), off); + __ jalr(x1, t0, off); + __ bind(retaddr); + OopMapSet* oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(__ offset(), oop_map); + // verify callee-saved register +#ifdef ASSERT + { Label L; + __ get_thread(t0); + __ beq(xthread, t0, L); + __ stop("StubAssembler::call_RT: xthread not callee saved?"); + __ bind(L); + } +#endif + __ reset_last_Java_frame(true); + +#ifdef ASSERT + // Check that fields in JavaThread for exception oop and issuing pc are empty + Label oop_empty; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ beqz(t0, oop_empty); + __ stop("exception oop must be empty"); + __ bind(oop_empty); + + Label pc_empty; + __ ld(t0, Address(xthread, JavaThread::exception_pc_offset())); + __ beqz(t0, pc_empty); + __ stop("exception pc must be empty"); + __ bind(pc_empty); +#endif + + // Runtime will return true if the nmethod has been deoptimized, this is the + // expected scenario and anything else is an error. Note that we maintain a + // check on the result purely as a defensive measure. + Label no_deopt; + __ beqz(x10, no_deopt); // Have we deoptimized? + + // Perform a re-execute. The proper return address is already on the stack, + // we just need to restore registers, pop all of our frames but the return + // address and jump to the deopt blob. + + restore_live_registers(sasm); + __ leave(); + __ far_jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); + + __ bind(no_deopt); + __ stop("deopt not performed"); + + return oop_maps; +} + +OopMapSet* Runtime1::generate_code_for(StubID id, StubAssembler* sasm) { + // for better readability + const bool dont_gc_arguments = false; + + // default value; overwritten for some optimized stubs that are called from methods that do not use the fpu + bool save_fpu_registers = true; + + // stub code & info for the different stubs + OopMapSet* oop_maps = NULL; + switch (id) { + { + case forward_exception_id: + { + oop_maps = generate_handle_exception(id, sasm); + __ leave(); + __ ret(); + } + break; + + case throw_div0_exception_id: + { + StubFrame f(sasm, "throw_div0_exception", dont_gc_arguments, does_not_return); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_div0_exception), false); + } + break; + + case throw_null_pointer_exception_id: + { StubFrame f(sasm, "throw_null_pointer_exception", dont_gc_arguments, does_not_return); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_null_pointer_exception), false); + } + break; + + case new_instance_id: + case fast_new_instance_id: + case fast_new_instance_init_check_id: + { + Register klass = x13; // Incoming + Register obj = x10; // Result + + if (id == new_instance_id) { + __ set_info("new_instance", dont_gc_arguments); + } else if (id == fast_new_instance_id) { + __ set_info("fast new_instance", dont_gc_arguments); + } else { + assert(id == fast_new_instance_init_check_id, "bad StubID"); + __ set_info("fast new_instance init check", dont_gc_arguments); + } + + // If TLAB is disabled, see if there is support for inlining contiguous + // allocations. + // Otherwise, just go to the slow path. + if ((id == fast_new_instance_id || id == fast_new_instance_init_check_id) && + !UseTLAB && Universe::heap()->supports_inline_contig_alloc()) { + Label slow_path; + Register obj_size = x12; + Register tmp1 = x9; + Register tmp2 = x14; + assert_different_registers(klass, obj, obj_size, tmp1, tmp2); + + const int sp_offset = 2; + const int x9_offset = 1; + const int zr_offset = 0; + __ addi(sp, sp, -(sp_offset * wordSize)); + __ sd(x9, Address(sp, x9_offset * wordSize)); + __ sd(zr, Address(sp, zr_offset * wordSize)); + + if (id == fast_new_instance_init_check_id) { + // make sure the klass is initialized + __ lbu(t0, Address(klass, InstanceKlass::init_state_offset())); + __ mv(t1, InstanceKlass::fully_initialized); + __ bne(t0, t1, slow_path); + } + +#ifdef ASSERT + // assert object can be fast path allocated + { + Label ok, not_ok; + __ lw(obj_size, Address(klass, Klass::layout_helper_offset())); + // make sure it's an instance. For instances, layout helper is a positive number. + // For arrays, layout helper is a negative number + __ blez(obj_size, not_ok); + __ andi(t0, obj_size, Klass::_lh_instance_slow_path_bit); + __ beqz(t0, ok); + __ bind(not_ok); + __ stop("assert(can be fast path allocated)"); + __ should_not_reach_here(); + __ bind(ok); + } +#endif // ASSERT + + // get the instance size + __ lwu(obj_size, Address(klass, Klass::layout_helper_offset())); + + __ eden_allocate(obj, obj_size, 0, tmp1, slow_path); + + __ initialize_object(obj, klass, obj_size, 0, tmp1, tmp2, /* is_tlab_allocated */ false); + __ verify_oop(obj); + __ ld(x9, Address(sp, x9_offset * wordSize)); + __ ld(zr, Address(sp, zr_offset * wordSize)); + __ addi(sp, sp, sp_offset * wordSize); + __ ret(); + + __ bind(slow_path); + __ ld(x9, Address(sp, x9_offset * wordSize)); + __ ld(zr, Address(sp, zr_offset * wordSize)); + __ addi(sp, sp, sp_offset * wordSize); + } + + __ enter(); + OopMap* map = save_live_registers(sasm); + assert_cond(map != NULL); + int call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_instance), klass); + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, map); + restore_live_registers_except_r10(sasm); + __ verify_oop(obj); + __ leave(); + __ ret(); + + // x10: new instance + } + + break; + + case counter_overflow_id: + { + Register bci = x10; + Register method = x11; + __ enter(); + OopMap* map = save_live_registers(sasm); + assert_cond(map != NULL); + + const int bci_off = 0; + const int method_off = 1; + // Retrieve bci + __ lw(bci, Address(fp, bci_off * BytesPerWord)); + // And a pointer to the Method* + __ ld(method, Address(fp, method_off * BytesPerWord)); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, counter_overflow), bci, method); + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, map); + restore_live_registers(sasm); + __ leave(); + __ ret(); + } + break; + + case new_type_array_id: + case new_object_array_id: + { + Register length = x9; // Incoming + Register klass = x13; // Incoming + Register obj = x10; // Result + + if (id == new_type_array_id) { + __ set_info("new_type_array", dont_gc_arguments); + } else { + __ set_info("new_object_array", dont_gc_arguments); + } + +#ifdef ASSERT + // assert object type is really an array of the proper kind + { + Label ok; + Register tmp = obj; + __ lwu(tmp, Address(klass, Klass::layout_helper_offset())); + __ sraiw(tmp, tmp, Klass::_lh_array_tag_shift); + int tag = ((id == new_type_array_id) ? Klass::_lh_array_tag_type_value : Klass::_lh_array_tag_obj_value); + __ mv(t0, tag); + __ beq(t0, tmp, ok); + __ stop("assert(is an array klass)"); + __ should_not_reach_here(); + __ bind(ok); + } +#endif // ASSERT + + // If TLAB is disabled, see if there is support for inlining contiguous + // allocations. + // Otherwise, just go to the slow path. + if (!UseTLAB && Universe::heap()->supports_inline_contig_alloc()) { + Register arr_size = x14; + Register tmp1 = x12; + Register tmp2 = x15; + Label slow_path; + assert_different_registers(length, klass, obj, arr_size, tmp1, tmp2); + + // check that array length is small enough for fast path. + __ mv(t0, C1_MacroAssembler::max_array_allocation_length); + __ bgtu(length, t0, slow_path); + + // get the allocation size: round_up(hdr + length << (layout_helper & 0x1F)) + __ lwu(tmp1, Address(klass, Klass::layout_helper_offset())); + __ andi(t0, tmp1, 0x1f); + __ sll(arr_size, length, t0); + int lh_header_size_width = exact_log2(Klass::_lh_header_size_mask + 1); + int lh_header_size_msb = Klass::_lh_header_size_shift + lh_header_size_width; + __ slli(tmp1, tmp1, XLEN - lh_header_size_msb); + __ srli(tmp1, tmp1, XLEN - lh_header_size_width); + __ add(arr_size, arr_size, tmp1); + __ addi(arr_size, arr_size, MinObjAlignmentInBytesMask); // align up + __ andi(arr_size, arr_size, ~(uint)MinObjAlignmentInBytesMask); + + __ eden_allocate(obj, arr_size, 0, tmp1, slow_path); // preserves arr_size + + __ initialize_header(obj, klass, length, tmp1, tmp2); + __ lbu(tmp1, Address(klass, + in_bytes(Klass::layout_helper_offset()) + + (Klass::_lh_header_size_shift / BitsPerByte))); + assert(Klass::_lh_header_size_shift % BitsPerByte == 0, "bytewise"); + assert(Klass::_lh_header_size_mask <= 0xFF, "bytewise"); + __ andi(tmp1, tmp1, Klass::_lh_header_size_mask); + __ sub(arr_size, arr_size, tmp1); // body length + __ add(tmp1, tmp1, obj); // body start + __ initialize_body(tmp1, arr_size, 0, tmp2); + __ membar(MacroAssembler::StoreStore); + __ verify_oop(obj); + + __ ret(); + + __ bind(slow_path); + } + + __ enter(); + OopMap* map = save_live_registers(sasm); + assert_cond(map != NULL); + int call_offset = 0; + if (id == new_type_array_id) { + call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length); + } else { + call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length); + } + + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, map); + restore_live_registers_except_r10(sasm); + + __ verify_oop(obj); + __ leave(); + __ ret(); + + // x10: new array + } + break; + + case new_multi_array_id: + { + StubFrame f(sasm, "new_multi_array", dont_gc_arguments); + // x10: klass + // x9: rank + // x12: address of 1st dimension + OopMap* map = save_live_registers(sasm); + assert_cond(map != NULL); + __ mv(c_rarg1, x10); + __ mv(c_rarg3, x12); + __ mv(c_rarg2, x9); + int call_offset = __ call_RT(x10, noreg, CAST_FROM_FN_PTR(address, new_multi_array), x11, x12, x13); + + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, map); + restore_live_registers_except_r10(sasm); + + // x10: new multi array + __ verify_oop(x10); + } + break; + + case register_finalizer_id: + { + __ set_info("register_finalizer", dont_gc_arguments); + + // This is called via call_runtime so the arguments + // will be place in C abi locations + __ verify_oop(c_rarg0); + + // load the klass and check the has finalizer flag + Label register_finalizer; + Register t = x15; + __ load_klass(t, x10); + __ lwu(t, Address(t, Klass::access_flags_offset())); + __ andi(t0, t, JVM_ACC_HAS_FINALIZER); + __ bnez(t0, register_finalizer); + __ ret(); + + __ bind(register_finalizer); + __ enter(); + OopMap* oop_map = save_live_registers(sasm); + assert_cond(oop_map != NULL); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, SharedRuntime::register_finalizer), x10); + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, oop_map); + + // Now restore all the live registers + restore_live_registers(sasm); + + __ leave(); + __ ret(); + } + break; + + case throw_class_cast_exception_id: + { + StubFrame f(sasm, "throw_class_cast_exception", dont_gc_arguments, does_not_return); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_class_cast_exception), true); + } + break; + + case throw_incompatible_class_change_error_id: + { + StubFrame f(sasm, "throw_incompatible_class_cast_exception", dont_gc_arguments, does_not_return); + oop_maps = generate_exception_throw(sasm, + CAST_FROM_FN_PTR(address, throw_incompatible_class_change_error), false); + } + break; + + case slow_subtype_check_id: + { + // Typical calling sequence: + // push klass_RInfo (object klass or other subclass) + // push sup_k_RInfo (array element klass or other superclass) + // jump to slow_subtype_check + // Note that the subclass is pushed first, and is therefore deepest. + enum layout { + x10_off, x10_off_hi, + x12_off, x12_off_hi, + x14_off, x14_off_hi, + x15_off, x15_off_hi, + sup_k_off, sup_k_off_hi, + klass_off, klass_off_hi, + framesize, + result_off = sup_k_off + }; + + __ set_info("slow_subtype_check", dont_gc_arguments); + __ push_reg(RegSet::of(x10, x12, x14, x15), sp); + + __ ld(x14, Address(sp, (klass_off) * VMRegImpl::stack_slot_size)); // sub klass + __ ld(x10, Address(sp, (sup_k_off) * VMRegImpl::stack_slot_size)); // super klass + + Label miss; + __ check_klass_subtype_slow_path(x14, x10, x12, x15, NULL, &miss); + + // fallthrough on success: + __ li(t0, 1); + __ sd(t0, Address(sp, (result_off) * VMRegImpl::stack_slot_size)); // result + __ pop_reg(RegSet::of(x10, x12, x14, x15), sp); + __ ret(); + + __ bind(miss); + __ sd(zr, Address(sp, (result_off) * VMRegImpl::stack_slot_size)); // result + __ pop_reg(RegSet::of(x10, x12, x14, x15), sp); + __ ret(); + } + break; + + case monitorenter_nofpu_id: + save_fpu_registers = false; + // fall through + case monitorenter_id: + { + StubFrame f(sasm, "monitorenter", dont_gc_arguments); + OopMap* map = save_live_registers(sasm, save_fpu_registers); + assert_cond(map != NULL); + + // Called with store_parameter and not C abi + f.load_argument(1, x10); // x10: object + f.load_argument(0, x11); // x11: lock address + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorenter), x10, x11); + + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, map); + restore_live_registers(sasm, save_fpu_registers); + } + break; + + case monitorexit_nofpu_id: + save_fpu_registers = false; + // fall through + case monitorexit_id: + { + StubFrame f(sasm, "monitorexit", dont_gc_arguments); + OopMap* map = save_live_registers(sasm, save_fpu_registers); + assert_cond(map != NULL); + + // Called with store_parameter and not C abi + f.load_argument(0, x10); // x10: lock address + + // note: really a leaf routine but must setup last java sp + // => use call_RT for now (speed can be improved by + // doing last java sp setup manually) + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, monitorexit), x10); + + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, map); + restore_live_registers(sasm, save_fpu_registers); + } + break; + + case deoptimize_id: + { + StubFrame f(sasm, "deoptimize", dont_gc_arguments, does_not_return); + OopMap* oop_map = save_live_registers(sasm); + assert_cond(oop_map != NULL); + f.load_argument(0, c_rarg1); + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, deoptimize), c_rarg1); + + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, oop_map); + restore_live_registers(sasm); + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + __ leave(); + __ far_jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); + } + break; + + case throw_range_check_failed_id: + { + StubFrame f(sasm, "range_check_failed", dont_gc_arguments, does_not_return); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_range_check_exception), true); + } + break; + + case unwind_exception_id: + { + __ set_info("unwind_exception", dont_gc_arguments); + // note: no stubframe since we are about to leave the current + // activation and we are calling a leaf VM function only. + generate_unwind_exception(sasm); + } + break; + + case access_field_patching_id: + { + StubFrame f(sasm, "access_field_patching", dont_gc_arguments, does_not_return); + // we should set up register map + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, access_field_patching)); + } + break; + + case load_klass_patching_id: + { + StubFrame f(sasm, "load_klass_patching", dont_gc_arguments, does_not_return); + // we should set up register map + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_klass_patching)); + } + break; + + case load_mirror_patching_id: + { + StubFrame f(sasm, "load_mirror_patching", dont_gc_arguments, does_not_return); + // we should set up register map + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_mirror_patching)); + } + break; + + case load_appendix_patching_id: + { + StubFrame f(sasm, "load_appendix_patching", dont_gc_arguments, does_not_return); + // we should set up register map + oop_maps = generate_patching(sasm, CAST_FROM_FN_PTR(address, move_appendix_patching)); + } + break; + + case handle_exception_nofpu_id: + case handle_exception_id: + { + StubFrame f(sasm, "handle_exception", dont_gc_arguments); + oop_maps = generate_handle_exception(id, sasm); + } + break; + + case handle_exception_from_callee_id: + { + StubFrame f(sasm, "handle_exception_from_callee", dont_gc_arguments); + oop_maps = generate_handle_exception(id, sasm); + } + break; + + case throw_index_exception_id: + { + StubFrame f(sasm, "index_range_check_failed", dont_gc_arguments, does_not_return); + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_index_exception), true); + } + break; + + case throw_array_store_exception_id: + { + StubFrame f(sasm, "throw_array_store_exception", dont_gc_arguments, does_not_return); + // tos + 0: link + // + 1: return address + oop_maps = generate_exception_throw(sasm, CAST_FROM_FN_PTR(address, throw_array_store_exception), true); + } + break; + + case predicate_failed_trap_id: + { + StubFrame f(sasm, "predicate_failed_trap", dont_gc_arguments, does_not_return); + + OopMap* map = save_live_registers(sasm); + assert_cond(map != NULL); + + int call_offset = __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, predicate_failed_trap)); + oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + oop_maps->add_gc_map(call_offset, map); + restore_live_registers(sasm); + __ leave(); + DeoptimizationBlob* deopt_blob = SharedRuntime::deopt_blob(); + assert(deopt_blob != NULL, "deoptimization blob must have been created"); + + __ far_jump(RuntimeAddress(deopt_blob->unpack_with_reexecution())); + } + break; + + case dtrace_object_alloc_id: + { // c_rarg0: object + StubFrame f(sasm, "dtrace_object_alloc", dont_gc_arguments); + save_live_registers(sasm); + + __ call_VM_leaf(CAST_FROM_FN_PTR(address, static_cast(SharedRuntime::dtrace_object_alloc)), c_rarg0); + + restore_live_registers(sasm); + } + break; + + default: + { + StubFrame f(sasm, "unimplemented entry", dont_gc_arguments, does_not_return); + __ li(x10, (int) id); + __ call_RT(noreg, noreg, CAST_FROM_FN_PTR(address, unimplemented_entry), x10); + __ should_not_reach_here(); + } + break; + } + } + return oop_maps; +} + +#undef __ + +const char *Runtime1::pd_name_for_address(address entry) { Unimplemented(); return 0; } diff --git a/src/hotspot/cpu/riscv/c1_globals_riscv.hpp b/src/hotspot/cpu/riscv/c1_globals_riscv.hpp new file mode 100644 index 00000000000..fe46f7b21c8 --- /dev/null +++ b/src/hotspot/cpu/riscv/c1_globals_riscv.hpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C1_GLOBALS_RISCV_HPP +#define CPU_RISCV_C1_GLOBALS_RISCV_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// Sets the default values for platform dependent flags used by the client compiler. +// (see c1_globals.hpp) + +#ifndef COMPILER2 +define_pd_global(bool, BackgroundCompilation, true ); +define_pd_global(bool, InlineIntrinsics, true ); +define_pd_global(bool, PreferInterpreterNativeStubs, false); +define_pd_global(bool, ProfileTraps, false); +define_pd_global(bool, UseOnStackReplacement, true ); +define_pd_global(bool, TieredCompilation, false); +define_pd_global(intx, CompileThreshold, 1500 ); + +define_pd_global(intx, OnStackReplacePercentage, 933 ); +define_pd_global(intx, NewSizeThreadIncrease, 4*K ); +define_pd_global(intx, InitialCodeCacheSize, 160*K); +define_pd_global(intx, ReservedCodeCacheSize, 32*M ); +define_pd_global(intx, NonProfiledCodeHeapSize, 13*M ); +define_pd_global(intx, ProfiledCodeHeapSize, 14*M ); +define_pd_global(intx, NonNMethodCodeHeapSize, 5*M ); +define_pd_global(bool, ProfileInterpreter, false); +define_pd_global(intx, CodeCacheExpansionSize, 32*K ); +define_pd_global(uintx, CodeCacheMinBlockLength, 1); +define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); +define_pd_global(bool, NeverActAsServerClassMachine, true ); +define_pd_global(uint64_t, MaxRAM, 1ULL*G); +define_pd_global(bool, CICompileOSR, true ); +#endif // !COMPILER2 +define_pd_global(bool, UseTypeProfile, false); + +define_pd_global(bool, OptimizeSinglePrecision, true ); +define_pd_global(bool, CSEArrayLength, false); +define_pd_global(bool, TwoOperandLIRForm, false); + +#endif // CPU_RISCV_C1_GLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp new file mode 100644 index 00000000000..27770dc17aa --- /dev/null +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -0,0 +1,1646 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "opto/c2_MacroAssembler.hpp" +#include "opto/intrinsicnode.hpp" +#include "opto/subnode.hpp" +#include "runtime/stubRoutines.hpp" + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#define STOP(error) stop(error) +#else +#define BLOCK_COMMENT(str) block_comment(str) +#define STOP(error) block_comment(error); stop(error) +#endif + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +// short string +// StringUTF16.indexOfChar +// StringLatin1.indexOfChar +void C2_MacroAssembler::string_indexof_char_short(Register str1, Register cnt1, + Register ch, Register result, + bool isL) +{ + Register ch1 = t0; + Register index = t1; + + BLOCK_COMMENT("string_indexof_char_short {"); + + Label LOOP, LOOP1, LOOP4, LOOP8; + Label MATCH, MATCH1, MATCH2, MATCH3, + MATCH4, MATCH5, MATCH6, MATCH7, NOMATCH; + + mv(result, -1); + mv(index, zr); + + bind(LOOP); + addi(t0, index, 8); + ble(t0, cnt1, LOOP8); + addi(t0, index, 4); + ble(t0, cnt1, LOOP4); + j(LOOP1); + + bind(LOOP8); + isL ? lbu(ch1, Address(str1, 0)) : lhu(ch1, Address(str1, 0)); + beq(ch, ch1, MATCH); + isL ? lbu(ch1, Address(str1, 1)) : lhu(ch1, Address(str1, 2)); + beq(ch, ch1, MATCH1); + isL ? lbu(ch1, Address(str1, 2)) : lhu(ch1, Address(str1, 4)); + beq(ch, ch1, MATCH2); + isL ? lbu(ch1, Address(str1, 3)) : lhu(ch1, Address(str1, 6)); + beq(ch, ch1, MATCH3); + isL ? lbu(ch1, Address(str1, 4)) : lhu(ch1, Address(str1, 8)); + beq(ch, ch1, MATCH4); + isL ? lbu(ch1, Address(str1, 5)) : lhu(ch1, Address(str1, 10)); + beq(ch, ch1, MATCH5); + isL ? lbu(ch1, Address(str1, 6)) : lhu(ch1, Address(str1, 12)); + beq(ch, ch1, MATCH6); + isL ? lbu(ch1, Address(str1, 7)) : lhu(ch1, Address(str1, 14)); + beq(ch, ch1, MATCH7); + addi(index, index, 8); + addi(str1, str1, isL ? 8 : 16); + blt(index, cnt1, LOOP); + j(NOMATCH); + + bind(LOOP4); + isL ? lbu(ch1, Address(str1, 0)) : lhu(ch1, Address(str1, 0)); + beq(ch, ch1, MATCH); + isL ? lbu(ch1, Address(str1, 1)) : lhu(ch1, Address(str1, 2)); + beq(ch, ch1, MATCH1); + isL ? lbu(ch1, Address(str1, 2)) : lhu(ch1, Address(str1, 4)); + beq(ch, ch1, MATCH2); + isL ? lbu(ch1, Address(str1, 3)) : lhu(ch1, Address(str1, 6)); + beq(ch, ch1, MATCH3); + addi(index, index, 4); + addi(str1, str1, isL ? 4 : 8); + bge(index, cnt1, NOMATCH); + + bind(LOOP1); + isL ? lbu(ch1, Address(str1)) : lhu(ch1, Address(str1)); + beq(ch, ch1, MATCH); + addi(index, index, 1); + addi(str1, str1, isL ? 1 : 2); + blt(index, cnt1, LOOP1); + j(NOMATCH); + + bind(MATCH1); + addi(index, index, 1); + j(MATCH); + + bind(MATCH2); + addi(index, index, 2); + j(MATCH); + + bind(MATCH3); + addi(index, index, 3); + j(MATCH); + + bind(MATCH4); + addi(index, index, 4); + j(MATCH); + + bind(MATCH5); + addi(index, index, 5); + j(MATCH); + + bind(MATCH6); + addi(index, index, 6); + j(MATCH); + + bind(MATCH7); + addi(index, index, 7); + + bind(MATCH); + mv(result, index); + bind(NOMATCH); + BLOCK_COMMENT("} string_indexof_char_short"); +} + +// StringUTF16.indexOfChar +// StringLatin1.indexOfChar +void C2_MacroAssembler::string_indexof_char(Register str1, Register cnt1, + Register ch, Register result, + Register tmp1, Register tmp2, + Register tmp3, Register tmp4, + bool isL) +{ + Label CH1_LOOP, HIT, NOMATCH, DONE, DO_LONG; + Register ch1 = t0; + Register orig_cnt = t1; + Register mask1 = tmp3; + Register mask2 = tmp2; + Register match_mask = tmp1; + Register trailing_char = tmp4; + Register unaligned_elems = tmp4; + + BLOCK_COMMENT("string_indexof_char {"); + beqz(cnt1, NOMATCH); + + addi(t0, cnt1, isL ? -32 : -16); + bgtz(t0, DO_LONG); + string_indexof_char_short(str1, cnt1, ch, result, isL); + j(DONE); + + bind(DO_LONG); + mv(orig_cnt, cnt1); + if (AvoidUnalignedAccesses) { + Label ALIGNED; + andi(unaligned_elems, str1, 0x7); + beqz(unaligned_elems, ALIGNED); + sub(unaligned_elems, unaligned_elems, 8); + neg(unaligned_elems, unaligned_elems); + if (!isL) { + srli(unaligned_elems, unaligned_elems, 1); + } + // do unaligned part per element + string_indexof_char_short(str1, unaligned_elems, ch, result, isL); + bgez(result, DONE); + mv(orig_cnt, cnt1); + sub(cnt1, cnt1, unaligned_elems); + bind(ALIGNED); + } + + // duplicate ch + if (isL) { + slli(ch1, ch, 8); + orr(ch, ch1, ch); + } + slli(ch1, ch, 16); + orr(ch, ch1, ch); + slli(ch1, ch, 32); + orr(ch, ch1, ch); + + if (!isL) { + slli(cnt1, cnt1, 1); + } + + uint64_t mask0101 = UCONST64(0x0101010101010101); + uint64_t mask0001 = UCONST64(0x0001000100010001); + mv(mask1, isL ? mask0101 : mask0001); + uint64_t mask7f7f = UCONST64(0x7f7f7f7f7f7f7f7f); + uint64_t mask7fff = UCONST64(0x7fff7fff7fff7fff); + mv(mask2, isL ? mask7f7f : mask7fff); + + bind(CH1_LOOP); + ld(ch1, Address(str1)); + addi(str1, str1, 8); + addi(cnt1, cnt1, -8); + compute_match_mask(ch1, ch, match_mask, mask1, mask2); + bnez(match_mask, HIT); + bgtz(cnt1, CH1_LOOP); + j(NOMATCH); + + bind(HIT); + ctzc_bit(trailing_char, match_mask, isL, ch1, result); + srli(trailing_char, trailing_char, 3); + addi(cnt1, cnt1, 8); + ble(cnt1, trailing_char, NOMATCH); + // match case + if (!isL) { + srli(cnt1, cnt1, 1); + srli(trailing_char, trailing_char, 1); + } + + sub(result, orig_cnt, cnt1); + add(result, result, trailing_char); + j(DONE); + + bind(NOMATCH); + mv(result, -1); + + bind(DONE); + BLOCK_COMMENT("} string_indexof_char"); +} + +typedef void (MacroAssembler::* load_chr_insn)(Register rd, const Address &adr, Register temp); + +// Search for needle in haystack and return index or -1 +// x10: result +// x11: haystack +// x12: haystack_len +// x13: needle +// x14: needle_len +void C2_MacroAssembler::string_indexof(Register haystack, Register needle, + Register haystack_len, Register needle_len, + Register tmp1, Register tmp2, + Register tmp3, Register tmp4, + Register tmp5, Register tmp6, + Register result, int ae) +{ + assert(ae != StrIntrinsicNode::LU, "Invalid encoding"); + + Label LINEARSEARCH, LINEARSTUB, DONE, NOMATCH; + + Register ch1 = t0; + Register ch2 = t1; + Register nlen_tmp = tmp1; // needle len tmp + Register hlen_tmp = tmp2; // haystack len tmp + Register result_tmp = tmp4; + + bool isLL = ae == StrIntrinsicNode::LL; + + bool needle_isL = ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UL; + bool haystack_isL = ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::LU; + int needle_chr_shift = needle_isL ? 0 : 1; + int haystack_chr_shift = haystack_isL ? 0 : 1; + int needle_chr_size = needle_isL ? 1 : 2; + int haystack_chr_size = haystack_isL ? 1 : 2; + load_chr_insn needle_load_1chr = needle_isL ? (load_chr_insn)&MacroAssembler::lbu : + (load_chr_insn)&MacroAssembler::lhu; + load_chr_insn haystack_load_1chr = haystack_isL ? (load_chr_insn)&MacroAssembler::lbu : + (load_chr_insn)&MacroAssembler::lhu; + + BLOCK_COMMENT("string_indexof {"); + + // Note, inline_string_indexOf() generates checks: + // if (pattern.count > src.count) return -1; + // if (pattern.count == 0) return 0; + + // We have two strings, a source string in haystack, haystack_len and a pattern string + // in needle, needle_len. Find the first occurence of pattern in source or return -1. + + // For larger pattern and source we use a simplified Boyer Moore algorithm. + // With a small pattern and source we use linear scan. + + // needle_len >=8 && needle_len < 256 && needle_len < haystack_len/4, use bmh algorithm. + sub(result_tmp, haystack_len, needle_len); + // needle_len < 8, use linear scan + sub(t0, needle_len, 8); + bltz(t0, LINEARSEARCH); + // needle_len >= 256, use linear scan + sub(t0, needle_len, 256); + bgez(t0, LINEARSTUB); + // needle_len >= haystack_len/4, use linear scan + srli(t0, haystack_len, 2); + bge(needle_len, t0, LINEARSTUB); + + // Boyer-Moore-Horspool introduction: + // The Boyer Moore alogorithm is based on the description here:- + // + // http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm + // + // This describes and algorithm with 2 shift rules. The 'Bad Character' rule + // and the 'Good Suffix' rule. + // + // These rules are essentially heuristics for how far we can shift the + // pattern along the search string. + // + // The implementation here uses the 'Bad Character' rule only because of the + // complexity of initialisation for the 'Good Suffix' rule. + // + // This is also known as the Boyer-Moore-Horspool algorithm: + // + // http://en.wikipedia.org/wiki/Boyer-Moore-Horspool_algorithm + // + // #define ASIZE 256 + // + // int bm(unsigned char *pattern, int m, unsigned char *src, int n) { + // int i, j; + // unsigned c; + // unsigned char bc[ASIZE]; + // + // /* Preprocessing */ + // for (i = 0; i < ASIZE; ++i) + // bc[i] = m; + // for (i = 0; i < m - 1; ) { + // c = pattern[i]; + // ++i; + // // c < 256 for Latin1 string, so, no need for branch + // #ifdef PATTERN_STRING_IS_LATIN1 + // bc[c] = m - i; + // #else + // if (c < ASIZE) bc[c] = m - i; + // #endif + // } + // + // /* Searching */ + // j = 0; + // while (j <= n - m) { + // c = src[i+j]; + // if (pattern[m-1] == c) + // int k; + // for (k = m - 2; k >= 0 && pattern[k] == src[k + j]; --k); + // if (k < 0) return j; + // // c < 256 for Latin1 string, so, no need for branch + // #ifdef SOURCE_STRING_IS_LATIN1_AND_PATTERN_STRING_IS_LATIN1 + // // LL case: (c< 256) always true. Remove branch + // j += bc[pattern[j+m-1]]; + // #endif + // #ifdef SOURCE_STRING_IS_UTF_AND_PATTERN_STRING_IS_UTF + // // UU case: need if (c if not. + // if (c < ASIZE) + // j += bc[pattern[j+m-1]]; + // else + // j += m + // #endif + // } + // return -1; + // } + + // temp register:t0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, result + Label BCLOOP, BCSKIP, BMLOOPSTR2, BMLOOPSTR1, BMSKIP, BMADV, BMMATCH, + BMLOOPSTR1_LASTCMP, BMLOOPSTR1_CMP, BMLOOPSTR1_AFTER_LOAD, BM_INIT_LOOP; + + Register haystack_end = haystack_len; + Register skipch = tmp2; + + // pattern length is >=8, so, we can read at least 1 register for cases when + // UTF->Latin1 conversion is not needed(8 LL or 4UU) and half register for + // UL case. We'll re-read last character in inner pre-loop code to have + // single outer pre-loop load + const int firstStep = isLL ? 7 : 3; + + const int ASIZE = 256; + const int STORE_BYTES = 8; // 8 bytes stored per instruction(sd) + + sub(sp, sp, ASIZE); + + // init BC offset table with default value: needle_len + slli(t0, needle_len, 8); + orr(t0, t0, needle_len); // [63...16][needle_len][needle_len] + slli(tmp1, t0, 16); + orr(t0, tmp1, t0); // [63...32][needle_len][needle_len][needle_len][needle_len] + slli(tmp1, t0, 32); + orr(tmp5, tmp1, t0); // tmp5: 8 elements [needle_len] + + mv(ch1, sp); // ch1 is t0 + mv(tmp6, ASIZE / STORE_BYTES); // loop iterations + + bind(BM_INIT_LOOP); + // for (i = 0; i < ASIZE; ++i) + // bc[i] = m; + for (int i = 0; i < 4; i++) { + sd(tmp5, Address(ch1, i * wordSize)); + } + add(ch1, ch1, 32); + sub(tmp6, tmp6, 4); + bgtz(tmp6, BM_INIT_LOOP); + + sub(nlen_tmp, needle_len, 1); // m - 1, index of the last element in pattern + Register orig_haystack = tmp5; + mv(orig_haystack, haystack); + // result_tmp = tmp4 + shadd(haystack_end, result_tmp, haystack, haystack_end, haystack_chr_shift); + sub(ch2, needle_len, 1); // bc offset init value, ch2 is t1 + mv(tmp3, needle); + + // for (i = 0; i < m - 1; ) { + // c = pattern[i]; + // ++i; + // // c < 256 for Latin1 string, so, no need for branch + // #ifdef PATTERN_STRING_IS_LATIN1 + // bc[c] = m - i; + // #else + // if (c < ASIZE) bc[c] = m - i; + // #endif + // } + bind(BCLOOP); + (this->*needle_load_1chr)(ch1, Address(tmp3), noreg); + add(tmp3, tmp3, needle_chr_size); + if (!needle_isL) { + // ae == StrIntrinsicNode::UU + mv(tmp6, ASIZE); + bgeu(ch1, tmp6, BCSKIP); + } + add(tmp4, sp, ch1); + sb(ch2, Address(tmp4)); // store skip offset to BC offset table + + bind(BCSKIP); + sub(ch2, ch2, 1); // for next pattern element, skip distance -1 + bgtz(ch2, BCLOOP); + + // tmp6: pattern end, address after needle + shadd(tmp6, needle_len, needle, tmp6, needle_chr_shift); + if (needle_isL == haystack_isL) { + // load last 8 bytes (8LL/4UU symbols) + ld(tmp6, Address(tmp6, -wordSize)); + } else { + // UL: from UTF-16(source) search Latin1(pattern) + lwu(tmp6, Address(tmp6, -wordSize / 2)); // load last 4 bytes(4 symbols) + // convert Latin1 to UTF. eg: 0x0000abcd -> 0x0a0b0c0d + // We'll have to wait until load completed, but it's still faster than per-character loads+checks + srli(tmp3, tmp6, BitsPerByte * (wordSize / 2 - needle_chr_size)); // pattern[m-1], eg:0x0000000a + slli(ch2, tmp6, XLEN - 24); + srli(ch2, ch2, XLEN - 8); // pattern[m-2], 0x0000000b + slli(ch1, tmp6, XLEN - 16); + srli(ch1, ch1, XLEN - 8); // pattern[m-3], 0x0000000c + andi(tmp6, tmp6, 0xff); // pattern[m-4], 0x0000000d + slli(ch2, ch2, 16); + orr(ch2, ch2, ch1); // 0x00000b0c + slli(result, tmp3, 48); // use result as temp register + orr(tmp6, tmp6, result); // 0x0a00000d + slli(result, ch2, 16); + orr(tmp6, tmp6, result); // UTF-16:0x0a0b0c0d + } + + // i = m - 1; + // skipch = j + i; + // if (skipch == pattern[m - 1] + // for (k = m - 2; k >= 0 && pattern[k] == src[k + j]; --k); + // else + // move j with bad char offset table + bind(BMLOOPSTR2); + // compare pattern to source string backward + shadd(result, nlen_tmp, haystack, result, haystack_chr_shift); + (this->*haystack_load_1chr)(skipch, Address(result), noreg); + sub(nlen_tmp, nlen_tmp, firstStep); // nlen_tmp is positive here, because needle_len >= 8 + if (needle_isL == haystack_isL) { + // re-init tmp3. It's for free because it's executed in parallel with + // load above. Alternative is to initialize it before loop, but it'll + // affect performance on in-order systems with 2 or more ld/st pipelines + srli(tmp3, tmp6, BitsPerByte * (wordSize - needle_chr_size)); // UU/LL: pattern[m-1] + } + if (!isLL) { // UU/UL case + slli(ch2, nlen_tmp, 1); // offsets in bytes + } + bne(tmp3, skipch, BMSKIP); // if not equal, skipch is bad char + add(result, haystack, isLL ? nlen_tmp : ch2); + ld(ch2, Address(result)); // load 8 bytes from source string + mv(ch1, tmp6); + if (isLL) { + j(BMLOOPSTR1_AFTER_LOAD); + } else { + sub(nlen_tmp, nlen_tmp, 1); // no need to branch for UU/UL case. cnt1 >= 8 + j(BMLOOPSTR1_CMP); + } + + bind(BMLOOPSTR1); + shadd(ch1, nlen_tmp, needle, ch1, needle_chr_shift); + (this->*needle_load_1chr)(ch1, Address(ch1), noreg); + shadd(ch2, nlen_tmp, haystack, ch2, haystack_chr_shift); + (this->*haystack_load_1chr)(ch2, Address(ch2), noreg); + + bind(BMLOOPSTR1_AFTER_LOAD); + sub(nlen_tmp, nlen_tmp, 1); + bltz(nlen_tmp, BMLOOPSTR1_LASTCMP); + + bind(BMLOOPSTR1_CMP); + beq(ch1, ch2, BMLOOPSTR1); + + bind(BMSKIP); + if (!isLL) { + // if we've met UTF symbol while searching Latin1 pattern, then we can + // skip needle_len symbols + if (needle_isL != haystack_isL) { + mv(result_tmp, needle_len); + } else { + mv(result_tmp, 1); + } + mv(t0, ASIZE); + bgeu(skipch, t0, BMADV); + } + add(result_tmp, sp, skipch); + lbu(result_tmp, Address(result_tmp)); // load skip offset + + bind(BMADV); + sub(nlen_tmp, needle_len, 1); + // move haystack after bad char skip offset + shadd(haystack, result_tmp, haystack, result, haystack_chr_shift); + ble(haystack, haystack_end, BMLOOPSTR2); + add(sp, sp, ASIZE); + j(NOMATCH); + + bind(BMLOOPSTR1_LASTCMP); + bne(ch1, ch2, BMSKIP); + + bind(BMMATCH); + sub(result, haystack, orig_haystack); + if (!haystack_isL) { + srli(result, result, 1); + } + add(sp, sp, ASIZE); + j(DONE); + + bind(LINEARSTUB); + sub(t0, needle_len, 16); // small patterns still should be handled by simple algorithm + bltz(t0, LINEARSEARCH); + mv(result, zr); + RuntimeAddress stub = NULL; + if (isLL) { + stub = RuntimeAddress(StubRoutines::riscv::string_indexof_linear_ll()); + assert(stub.target() != NULL, "string_indexof_linear_ll stub has not been generated"); + } else if (needle_isL) { + stub = RuntimeAddress(StubRoutines::riscv::string_indexof_linear_ul()); + assert(stub.target() != NULL, "string_indexof_linear_ul stub has not been generated"); + } else { + stub = RuntimeAddress(StubRoutines::riscv::string_indexof_linear_uu()); + assert(stub.target() != NULL, "string_indexof_linear_uu stub has not been generated"); + } + trampoline_call(stub); + j(DONE); + + bind(NOMATCH); + mv(result, -1); + j(DONE); + + bind(LINEARSEARCH); + string_indexof_linearscan(haystack, needle, haystack_len, needle_len, tmp1, tmp2, tmp3, tmp4, -1, result, ae); + + bind(DONE); + BLOCK_COMMENT("} string_indexof"); +} + +// string_indexof +// result: x10 +// src: x11 +// src_count: x12 +// pattern: x13 +// pattern_count: x14 or 1/2/3/4 +void C2_MacroAssembler::string_indexof_linearscan(Register haystack, Register needle, + Register haystack_len, Register needle_len, + Register tmp1, Register tmp2, + Register tmp3, Register tmp4, + int needle_con_cnt, Register result, int ae) +{ + // Note: + // needle_con_cnt > 0 means needle_len register is invalid, needle length is constant + // for UU/LL: needle_con_cnt[1, 4], UL: needle_con_cnt = 1 + assert(needle_con_cnt <= 4, "Invalid needle constant count"); + assert(ae != StrIntrinsicNode::LU, "Invalid encoding"); + + Register ch1 = t0; + Register ch2 = t1; + Register hlen_neg = haystack_len, nlen_neg = needle_len; + Register nlen_tmp = tmp1, hlen_tmp = tmp2, result_tmp = tmp4; + + bool isLL = ae == StrIntrinsicNode::LL; + + bool needle_isL = ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UL; + bool haystack_isL = ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::LU; + int needle_chr_shift = needle_isL ? 0 : 1; + int haystack_chr_shift = haystack_isL ? 0 : 1; + int needle_chr_size = needle_isL ? 1 : 2; + int haystack_chr_size = haystack_isL ? 1 : 2; + + load_chr_insn needle_load_1chr = needle_isL ? (load_chr_insn)&MacroAssembler::lbu : + (load_chr_insn)&MacroAssembler::lhu; + load_chr_insn haystack_load_1chr = haystack_isL ? (load_chr_insn)&MacroAssembler::lbu : + (load_chr_insn)&MacroAssembler::lhu; + load_chr_insn load_2chr = isLL ? (load_chr_insn)&MacroAssembler::lhu : (load_chr_insn)&MacroAssembler::lwu; + load_chr_insn load_4chr = isLL ? (load_chr_insn)&MacroAssembler::lwu : (load_chr_insn)&MacroAssembler::ld; + + Label DO1, DO2, DO3, MATCH, NOMATCH, DONE; + + Register first = tmp3; + + if (needle_con_cnt == -1) { + Label DOSHORT, FIRST_LOOP, STR2_NEXT, STR1_LOOP, STR1_NEXT; + + sub(t0, needle_len, needle_isL == haystack_isL ? 4 : 2); + bltz(t0, DOSHORT); + + (this->*needle_load_1chr)(first, Address(needle), noreg); + slli(t0, needle_len, needle_chr_shift); + add(needle, needle, t0); + neg(nlen_neg, t0); + slli(t0, result_tmp, haystack_chr_shift); + add(haystack, haystack, t0); + neg(hlen_neg, t0); + + bind(FIRST_LOOP); + add(t0, haystack, hlen_neg); + (this->*haystack_load_1chr)(ch2, Address(t0), noreg); + beq(first, ch2, STR1_LOOP); + + bind(STR2_NEXT); + add(hlen_neg, hlen_neg, haystack_chr_size); + blez(hlen_neg, FIRST_LOOP); + j(NOMATCH); + + bind(STR1_LOOP); + add(nlen_tmp, nlen_neg, needle_chr_size); + add(hlen_tmp, hlen_neg, haystack_chr_size); + bgez(nlen_tmp, MATCH); + + bind(STR1_NEXT); + add(ch1, needle, nlen_tmp); + (this->*needle_load_1chr)(ch1, Address(ch1), noreg); + add(ch2, haystack, hlen_tmp); + (this->*haystack_load_1chr)(ch2, Address(ch2), noreg); + bne(ch1, ch2, STR2_NEXT); + add(nlen_tmp, nlen_tmp, needle_chr_size); + add(hlen_tmp, hlen_tmp, haystack_chr_size); + bltz(nlen_tmp, STR1_NEXT); + j(MATCH); + + bind(DOSHORT); + if (needle_isL == haystack_isL) { + sub(t0, needle_len, 2); + bltz(t0, DO1); + bgtz(t0, DO3); + } + } + + if (needle_con_cnt == 4) { + Label CH1_LOOP; + (this->*load_4chr)(ch1, Address(needle), noreg); + sub(result_tmp, haystack_len, 4); + slli(tmp3, result_tmp, haystack_chr_shift); // result as tmp + add(haystack, haystack, tmp3); + neg(hlen_neg, tmp3); + + bind(CH1_LOOP); + add(ch2, haystack, hlen_neg); + (this->*load_4chr)(ch2, Address(ch2), noreg); + beq(ch1, ch2, MATCH); + add(hlen_neg, hlen_neg, haystack_chr_size); + blez(hlen_neg, CH1_LOOP); + j(NOMATCH); + } + + if ((needle_con_cnt == -1 && needle_isL == haystack_isL) || needle_con_cnt == 2) { + Label CH1_LOOP; + BLOCK_COMMENT("string_indexof DO2 {"); + bind(DO2); + (this->*load_2chr)(ch1, Address(needle), noreg); + if (needle_con_cnt == 2) { + sub(result_tmp, haystack_len, 2); + } + slli(tmp3, result_tmp, haystack_chr_shift); + add(haystack, haystack, tmp3); + neg(hlen_neg, tmp3); + + bind(CH1_LOOP); + add(tmp3, haystack, hlen_neg); + (this->*load_2chr)(ch2, Address(tmp3), noreg); + beq(ch1, ch2, MATCH); + add(hlen_neg, hlen_neg, haystack_chr_size); + blez(hlen_neg, CH1_LOOP); + j(NOMATCH); + BLOCK_COMMENT("} string_indexof DO2"); + } + + if ((needle_con_cnt == -1 && needle_isL == haystack_isL) || needle_con_cnt == 3) { + Label FIRST_LOOP, STR2_NEXT, STR1_LOOP; + BLOCK_COMMENT("string_indexof DO3 {"); + + bind(DO3); + (this->*load_2chr)(first, Address(needle), noreg); + (this->*needle_load_1chr)(ch1, Address(needle, 2 * needle_chr_size), noreg); + if (needle_con_cnt == 3) { + sub(result_tmp, haystack_len, 3); + } + slli(hlen_tmp, result_tmp, haystack_chr_shift); + add(haystack, haystack, hlen_tmp); + neg(hlen_neg, hlen_tmp); + + bind(FIRST_LOOP); + add(ch2, haystack, hlen_neg); + (this->*load_2chr)(ch2, Address(ch2), noreg); + beq(first, ch2, STR1_LOOP); + + bind(STR2_NEXT); + add(hlen_neg, hlen_neg, haystack_chr_size); + blez(hlen_neg, FIRST_LOOP); + j(NOMATCH); + + bind(STR1_LOOP); + add(hlen_tmp, hlen_neg, 2 * haystack_chr_size); + add(ch2, haystack, hlen_tmp); + (this->*haystack_load_1chr)(ch2, Address(ch2), noreg); + bne(ch1, ch2, STR2_NEXT); + j(MATCH); + BLOCK_COMMENT("} string_indexof DO3"); + } + + if (needle_con_cnt == -1 || needle_con_cnt == 1) { + Label DO1_LOOP; + + BLOCK_COMMENT("string_indexof DO1 {"); + bind(DO1); + (this->*needle_load_1chr)(ch1, Address(needle), noreg); + sub(result_tmp, haystack_len, 1); + mv(tmp3, result_tmp); + if (haystack_chr_shift) { + slli(tmp3, result_tmp, haystack_chr_shift); + } + add(haystack, haystack, tmp3); + neg(hlen_neg, tmp3); + + bind(DO1_LOOP); + add(tmp3, haystack, hlen_neg); + (this->*haystack_load_1chr)(ch2, Address(tmp3), noreg); + beq(ch1, ch2, MATCH); + add(hlen_neg, hlen_neg, haystack_chr_size); + blez(hlen_neg, DO1_LOOP); + BLOCK_COMMENT("} string_indexof DO1"); + } + + bind(NOMATCH); + mv(result, -1); + j(DONE); + + bind(MATCH); + srai(t0, hlen_neg, haystack_chr_shift); + add(result, result_tmp, t0); + + bind(DONE); +} + +// Compare strings. +void C2_MacroAssembler::string_compare(Register str1, Register str2, + Register cnt1, Register cnt2, Register result, Register tmp1, Register tmp2, + Register tmp3, int ae) +{ + Label DONE, SHORT_LOOP, SHORT_STRING, SHORT_LAST, TAIL, STUB, + DIFFERENCE, NEXT_WORD, SHORT_LOOP_TAIL, SHORT_LAST2, SHORT_LAST_INIT, + SHORT_LOOP_START, TAIL_CHECK, L; + + const int STUB_THRESHOLD = 64 + 8; + bool isLL = ae == StrIntrinsicNode::LL; + bool isLU = ae == StrIntrinsicNode::LU; + bool isUL = ae == StrIntrinsicNode::UL; + + bool str1_isL = isLL || isLU; + bool str2_isL = isLL || isUL; + + // for L strings, 1 byte for 1 character + // for U strings, 2 bytes for 1 character + int str1_chr_size = str1_isL ? 1 : 2; + int str2_chr_size = str2_isL ? 1 : 2; + int minCharsInWord = isLL ? wordSize : wordSize / 2; + + load_chr_insn str1_load_chr = str1_isL ? (load_chr_insn)&MacroAssembler::lbu : (load_chr_insn)&MacroAssembler::lhu; + load_chr_insn str2_load_chr = str2_isL ? (load_chr_insn)&MacroAssembler::lbu : (load_chr_insn)&MacroAssembler::lhu; + + BLOCK_COMMENT("string_compare {"); + + // Bizzarely, the counts are passed in bytes, regardless of whether they + // are L or U strings, however the result is always in characters. + if (!str1_isL) { + sraiw(cnt1, cnt1, 1); + } + if (!str2_isL) { + sraiw(cnt2, cnt2, 1); + } + + // Compute the minimum of the string lengths and save the difference in result. + sub(result, cnt1, cnt2); + bgt(cnt1, cnt2, L); + mv(cnt2, cnt1); + bind(L); + + // A very short string + li(t0, minCharsInWord); + ble(cnt2, t0, SHORT_STRING); + + // Compare longwords + // load first parts of strings and finish initialization while loading + { + if (str1_isL == str2_isL) { // LL or UU + // load 8 bytes once to compare + ld(tmp1, Address(str1)); + beq(str1, str2, DONE); + ld(tmp2, Address(str2)); + li(t0, STUB_THRESHOLD); + bge(cnt2, t0, STUB); + sub(cnt2, cnt2, minCharsInWord); + beqz(cnt2, TAIL_CHECK); + // convert cnt2 from characters to bytes + if (!str1_isL) { + slli(cnt2, cnt2, 1); + } + add(str2, str2, cnt2); + add(str1, str1, cnt2); + sub(cnt2, zr, cnt2); + } else if (isLU) { // LU case + lwu(tmp1, Address(str1)); + ld(tmp2, Address(str2)); + li(t0, STUB_THRESHOLD); + bge(cnt2, t0, STUB); + addi(cnt2, cnt2, -4); + add(str1, str1, cnt2); + sub(cnt1, zr, cnt2); + slli(cnt2, cnt2, 1); + add(str2, str2, cnt2); + inflate_lo32(tmp3, tmp1); + mv(tmp1, tmp3); + sub(cnt2, zr, cnt2); + addi(cnt1, cnt1, 4); + } else { // UL case + ld(tmp1, Address(str1)); + lwu(tmp2, Address(str2)); + li(t0, STUB_THRESHOLD); + bge(cnt2, t0, STUB); + addi(cnt2, cnt2, -4); + slli(t0, cnt2, 1); + sub(cnt1, zr, t0); + add(str1, str1, t0); + add(str2, str2, cnt2); + inflate_lo32(tmp3, tmp2); + mv(tmp2, tmp3); + sub(cnt2, zr, cnt2); + addi(cnt1, cnt1, 8); + } + addi(cnt2, cnt2, isUL ? 4 : 8); + bgez(cnt2, TAIL); + xorr(tmp3, tmp1, tmp2); + bnez(tmp3, DIFFERENCE); + + // main loop + bind(NEXT_WORD); + if (str1_isL == str2_isL) { // LL or UU + add(t0, str1, cnt2); + ld(tmp1, Address(t0)); + add(t0, str2, cnt2); + ld(tmp2, Address(t0)); + addi(cnt2, cnt2, 8); + } else if (isLU) { // LU case + add(t0, str1, cnt1); + lwu(tmp1, Address(t0)); + add(t0, str2, cnt2); + ld(tmp2, Address(t0)); + addi(cnt1, cnt1, 4); + inflate_lo32(tmp3, tmp1); + mv(tmp1, tmp3); + addi(cnt2, cnt2, 8); + } else { // UL case + add(t0, str2, cnt2); + lwu(tmp2, Address(t0)); + add(t0, str1, cnt1); + ld(tmp1, Address(t0)); + inflate_lo32(tmp3, tmp2); + mv(tmp2, tmp3); + addi(cnt1, cnt1, 8); + addi(cnt2, cnt2, 4); + } + bgez(cnt2, TAIL); + + xorr(tmp3, tmp1, tmp2); + beqz(tmp3, NEXT_WORD); + j(DIFFERENCE); + bind(TAIL); + xorr(tmp3, tmp1, tmp2); + bnez(tmp3, DIFFERENCE); + // Last longword. In the case where length == 4 we compare the + // same longword twice, but that's still faster than another + // conditional branch. + if (str1_isL == str2_isL) { // LL or UU + ld(tmp1, Address(str1)); + ld(tmp2, Address(str2)); + } else if (isLU) { // LU case + lwu(tmp1, Address(str1)); + ld(tmp2, Address(str2)); + inflate_lo32(tmp3, tmp1); + mv(tmp1, tmp3); + } else { // UL case + lwu(tmp2, Address(str2)); + ld(tmp1, Address(str1)); + inflate_lo32(tmp3, tmp2); + mv(tmp2, tmp3); + } + bind(TAIL_CHECK); + xorr(tmp3, tmp1, tmp2); + beqz(tmp3, DONE); + + // Find the first different characters in the longwords and + // compute their difference. + bind(DIFFERENCE); + ctzc_bit(result, tmp3, isLL); // count zero from lsb to msb + srl(tmp1, tmp1, result); + srl(tmp2, tmp2, result); + if (isLL) { + andi(tmp1, tmp1, 0xFF); + andi(tmp2, tmp2, 0xFF); + } else { + andi(tmp1, tmp1, 0xFFFF); + andi(tmp2, tmp2, 0xFFFF); + } + sub(result, tmp1, tmp2); + j(DONE); + } + + bind(STUB); + RuntimeAddress stub = NULL; + switch (ae) { + case StrIntrinsicNode::LL: + stub = RuntimeAddress(StubRoutines::riscv::compare_long_string_LL()); + break; + case StrIntrinsicNode::UU: + stub = RuntimeAddress(StubRoutines::riscv::compare_long_string_UU()); + break; + case StrIntrinsicNode::LU: + stub = RuntimeAddress(StubRoutines::riscv::compare_long_string_LU()); + break; + case StrIntrinsicNode::UL: + stub = RuntimeAddress(StubRoutines::riscv::compare_long_string_UL()); + break; + default: + ShouldNotReachHere(); + } + assert(stub.target() != NULL, "compare_long_string stub has not been generated"); + trampoline_call(stub); + j(DONE); + + bind(SHORT_STRING); + // Is the minimum length zero? + beqz(cnt2, DONE); + // arrange code to do most branches while loading and loading next characters + // while comparing previous + (this->*str1_load_chr)(tmp1, Address(str1), t0); + addi(str1, str1, str1_chr_size); + addi(cnt2, cnt2, -1); + beqz(cnt2, SHORT_LAST_INIT); + (this->*str2_load_chr)(cnt1, Address(str2), t0); + addi(str2, str2, str2_chr_size); + j(SHORT_LOOP_START); + bind(SHORT_LOOP); + addi(cnt2, cnt2, -1); + beqz(cnt2, SHORT_LAST); + bind(SHORT_LOOP_START); + (this->*str1_load_chr)(tmp2, Address(str1), t0); + addi(str1, str1, str1_chr_size); + (this->*str2_load_chr)(t0, Address(str2), t0); + addi(str2, str2, str2_chr_size); + bne(tmp1, cnt1, SHORT_LOOP_TAIL); + addi(cnt2, cnt2, -1); + beqz(cnt2, SHORT_LAST2); + (this->*str1_load_chr)(tmp1, Address(str1), t0); + addi(str1, str1, str1_chr_size); + (this->*str2_load_chr)(cnt1, Address(str2), t0); + addi(str2, str2, str2_chr_size); + beq(tmp2, t0, SHORT_LOOP); + sub(result, tmp2, t0); + j(DONE); + bind(SHORT_LOOP_TAIL); + sub(result, tmp1, cnt1); + j(DONE); + bind(SHORT_LAST2); + beq(tmp2, t0, DONE); + sub(result, tmp2, t0); + + j(DONE); + bind(SHORT_LAST_INIT); + (this->*str2_load_chr)(cnt1, Address(str2), t0); + addi(str2, str2, str2_chr_size); + bind(SHORT_LAST); + beq(tmp1, cnt1, DONE); + sub(result, tmp1, cnt1); + + bind(DONE); + + BLOCK_COMMENT("} string_compare"); +} + +void C2_MacroAssembler::arrays_equals(Register a1, Register a2, Register tmp3, + Register tmp4, Register tmp5, Register tmp6, Register result, + Register cnt1, int elem_size) { + Label DONE, SAME, NEXT_DWORD, SHORT, TAIL, TAIL2, IS_TMP5_ZR; + Register tmp1 = t0; + Register tmp2 = t1; + Register cnt2 = tmp2; // cnt2 only used in array length compare + Register elem_per_word = tmp6; + int log_elem_size = exact_log2(elem_size); + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE); + + assert(elem_size == 1 || elem_size == 2, "must be char or byte"); + assert_different_registers(a1, a2, result, cnt1, t0, t1, tmp3, tmp4, tmp5, tmp6); + li(elem_per_word, wordSize / elem_size); + + BLOCK_COMMENT("arrays_equals {"); + + // if (a1 == a2), return true + beq(a1, a2, SAME); + + mv(result, false); + beqz(a1, DONE); + beqz(a2, DONE); + lwu(cnt1, Address(a1, length_offset)); + lwu(cnt2, Address(a2, length_offset)); + bne(cnt2, cnt1, DONE); + beqz(cnt1, SAME); + + slli(tmp5, cnt1, 3 + log_elem_size); + sub(tmp5, zr, tmp5); + add(a1, a1, base_offset); + add(a2, a2, base_offset); + ld(tmp3, Address(a1, 0)); + ld(tmp4, Address(a2, 0)); + ble(cnt1, elem_per_word, SHORT); // short or same + + // Main 16 byte comparison loop with 2 exits + bind(NEXT_DWORD); { + ld(tmp1, Address(a1, wordSize)); + ld(tmp2, Address(a2, wordSize)); + sub(cnt1, cnt1, 2 * wordSize / elem_size); + blez(cnt1, TAIL); + bne(tmp3, tmp4, DONE); + ld(tmp3, Address(a1, 2 * wordSize)); + ld(tmp4, Address(a2, 2 * wordSize)); + add(a1, a1, 2 * wordSize); + add(a2, a2, 2 * wordSize); + ble(cnt1, elem_per_word, TAIL2); + } beq(tmp1, tmp2, NEXT_DWORD); + j(DONE); + + bind(TAIL); + xorr(tmp4, tmp3, tmp4); + xorr(tmp2, tmp1, tmp2); + sll(tmp2, tmp2, tmp5); + orr(tmp5, tmp4, tmp2); + j(IS_TMP5_ZR); + + bind(TAIL2); + bne(tmp1, tmp2, DONE); + + bind(SHORT); + xorr(tmp4, tmp3, tmp4); + sll(tmp5, tmp4, tmp5); + + bind(IS_TMP5_ZR); + bnez(tmp5, DONE); + + bind(SAME); + mv(result, true); + // That's it. + bind(DONE); + + BLOCK_COMMENT("} array_equals"); +} + +// Compare Strings + +// For Strings we're passed the address of the first characters in a1 +// and a2 and the length in cnt1. +// elem_size is the element size in bytes: either 1 or 2. +// There are two implementations. For arrays >= 8 bytes, all +// comparisons (including the final one, which may overlap) are +// performed 8 bytes at a time. For strings < 8 bytes, we compare a +// halfword, then a short, and then a byte. + +void C2_MacroAssembler::string_equals(Register a1, Register a2, + Register result, Register cnt1, int elem_size) +{ + Label SAME, DONE, SHORT, NEXT_WORD; + Register tmp1 = t0; + Register tmp2 = t1; + + assert(elem_size == 1 || elem_size == 2, "must be 2 or 1 byte"); + assert_different_registers(a1, a2, result, cnt1, t0, t1); + + BLOCK_COMMENT("string_equals {"); + + mv(result, false); + + // Check for short strings, i.e. smaller than wordSize. + sub(cnt1, cnt1, wordSize); + bltz(cnt1, SHORT); + + // Main 8 byte comparison loop. + bind(NEXT_WORD); { + ld(tmp1, Address(a1, 0)); + add(a1, a1, wordSize); + ld(tmp2, Address(a2, 0)); + add(a2, a2, wordSize); + sub(cnt1, cnt1, wordSize); + bne(tmp1, tmp2, DONE); + } bgtz(cnt1, NEXT_WORD); + + // Last longword. In the case where length == 4 we compare the + // same longword twice, but that's still faster than another + // conditional branch. + // cnt1 could be 0, -1, -2, -3, -4 for chars; -4 only happens when + // length == 4. + add(tmp1, a1, cnt1); + ld(tmp1, Address(tmp1, 0)); + add(tmp2, a2, cnt1); + ld(tmp2, Address(tmp2, 0)); + bne(tmp1, tmp2, DONE); + j(SAME); + + bind(SHORT); + Label TAIL03, TAIL01; + + // 0-7 bytes left. + andi(t0, cnt1, 4); + beqz(t0, TAIL03); + { + lwu(tmp1, Address(a1, 0)); + add(a1, a1, 4); + lwu(tmp2, Address(a2, 0)); + add(a2, a2, 4); + bne(tmp1, tmp2, DONE); + } + + bind(TAIL03); + // 0-3 bytes left. + andi(t0, cnt1, 2); + beqz(t0, TAIL01); + { + lhu(tmp1, Address(a1, 0)); + add(a1, a1, 2); + lhu(tmp2, Address(a2, 0)); + add(a2, a2, 2); + bne(tmp1, tmp2, DONE); + } + + bind(TAIL01); + if (elem_size == 1) { // Only needed when comparing 1-byte elements + // 0-1 bytes left. + andi(t0, cnt1, 1); + beqz(t0, SAME); + { + lbu(tmp1, a1, 0); + lbu(tmp2, a2, 0); + bne(tmp1, tmp2, DONE); + } + } + + // Arrays are equal. + bind(SAME); + mv(result, true); + + // That's it. + bind(DONE); + BLOCK_COMMENT("} string_equals"); +} + +typedef void (Assembler::*conditional_branch_insn)(Register op1, Register op2, Label& label, bool is_far); +typedef void (MacroAssembler::*float_conditional_branch_insn)(FloatRegister op1, FloatRegister op2, Label& label, + bool is_far, bool is_unordered); + +static conditional_branch_insn conditional_branches[] = +{ + /* SHORT branches */ + (conditional_branch_insn)&Assembler::beq, + (conditional_branch_insn)&Assembler::bgt, + NULL, // BoolTest::overflow + (conditional_branch_insn)&Assembler::blt, + (conditional_branch_insn)&Assembler::bne, + (conditional_branch_insn)&Assembler::ble, + NULL, // BoolTest::no_overflow + (conditional_branch_insn)&Assembler::bge, + + /* UNSIGNED branches */ + (conditional_branch_insn)&Assembler::beq, + (conditional_branch_insn)&Assembler::bgtu, + NULL, + (conditional_branch_insn)&Assembler::bltu, + (conditional_branch_insn)&Assembler::bne, + (conditional_branch_insn)&Assembler::bleu, + NULL, + (conditional_branch_insn)&Assembler::bgeu +}; + +static float_conditional_branch_insn float_conditional_branches[] = +{ + /* FLOAT SHORT branches */ + (float_conditional_branch_insn)&MacroAssembler::float_beq, + (float_conditional_branch_insn)&MacroAssembler::float_bgt, + NULL, // BoolTest::overflow + (float_conditional_branch_insn)&MacroAssembler::float_blt, + (float_conditional_branch_insn)&MacroAssembler::float_bne, + (float_conditional_branch_insn)&MacroAssembler::float_ble, + NULL, // BoolTest::no_overflow + (float_conditional_branch_insn)&MacroAssembler::float_bge, + + /* DOUBLE SHORT branches */ + (float_conditional_branch_insn)&MacroAssembler::double_beq, + (float_conditional_branch_insn)&MacroAssembler::double_bgt, + NULL, + (float_conditional_branch_insn)&MacroAssembler::double_blt, + (float_conditional_branch_insn)&MacroAssembler::double_bne, + (float_conditional_branch_insn)&MacroAssembler::double_ble, + NULL, + (float_conditional_branch_insn)&MacroAssembler::double_bge +}; + +void C2_MacroAssembler::cmp_branch(int cmpFlag, Register op1, Register op2, Label& label, bool is_far) { + assert(cmpFlag >= 0 && cmpFlag < (int)(sizeof(conditional_branches) / sizeof(conditional_branches[0])), + "invalid conditional branch index"); + (this->*conditional_branches[cmpFlag])(op1, op2, label, is_far); +} + +// This is a function should only be used by C2. Flip the unordered when unordered-greater, C2 would use +// unordered-lesser instead of unordered-greater. Finally, commute the result bits at function do_one_bytecode(). +void C2_MacroAssembler::float_cmp_branch(int cmpFlag, FloatRegister op1, FloatRegister op2, Label& label, bool is_far) { + assert(cmpFlag >= 0 && cmpFlag < (int)(sizeof(float_conditional_branches) / sizeof(float_conditional_branches[0])), + "invalid float conditional branch index"); + int booltest_flag = cmpFlag & ~(C2_MacroAssembler::double_branch_mask); + (this->*float_conditional_branches[cmpFlag])(op1, op2, label, is_far, + (booltest_flag == (BoolTest::ge) || booltest_flag == (BoolTest::gt)) ? false : true); +} + +void C2_MacroAssembler::enc_cmpUEqNeLeGt_imm0_branch(int cmpFlag, Register op1, Label& L, bool is_far) { + switch (cmpFlag) { + case BoolTest::eq: + case BoolTest::le: + beqz(op1, L, is_far); + break; + case BoolTest::ne: + case BoolTest::gt: + bnez(op1, L, is_far); + break; + default: + ShouldNotReachHere(); + } +} + +void C2_MacroAssembler::enc_cmpEqNe_imm0_branch(int cmpFlag, Register op1, Label& L, bool is_far) { + switch (cmpFlag) { + case BoolTest::eq: + beqz(op1, L, is_far); + break; + case BoolTest::ne: + bnez(op1, L, is_far); + break; + default: + ShouldNotReachHere(); + } +} + +void C2_MacroAssembler::enc_cmove(int cmpFlag, Register op1, Register op2, Register dst, Register src) { + Label L; + cmp_branch(cmpFlag ^ (1 << neg_cond_bits), op1, op2, L); + mv(dst, src); + bind(L); +} + +// Set dst to NaN if any NaN input. +void C2_MacroAssembler::minmax_FD(FloatRegister dst, FloatRegister src1, FloatRegister src2, + bool is_double, bool is_min) { + assert_different_registers(dst, src1, src2); + + Label Done; + fsflags(zr); + if (is_double) { + is_min ? fmin_d(dst, src1, src2) + : fmax_d(dst, src1, src2); + // Checking NaNs + flt_d(zr, src1, src2); + } else { + is_min ? fmin_s(dst, src1, src2) + : fmax_s(dst, src1, src2); + // Checking NaNs + flt_s(zr, src1, src2); + } + + frflags(t0); + beqz(t0, Done); + + // In case of NaNs + is_double ? fadd_d(dst, src1, src2) + : fadd_s(dst, src1, src2); + + bind(Done); +} + +void C2_MacroAssembler::element_compare(Register a1, Register a2, Register result, Register cnt, Register tmp1, Register tmp2, + VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, bool islatin, Label &DONE) { + Label loop; + Assembler::SEW sew = islatin ? Assembler::e8 : Assembler::e16; + + bind(loop); + vsetvli(tmp1, cnt, sew, Assembler::m2); + vlex_v(vr1, a1, sew); + vlex_v(vr2, a2, sew); + vmsne_vv(vrs, vr1, vr2); + vfirst_m(tmp2, vrs); + bgez(tmp2, DONE); + sub(cnt, cnt, tmp1); + if (!islatin) { + slli(tmp1, tmp1, 1); // get byte counts + } + add(a1, a1, tmp1); + add(a2, a2, tmp1); + bnez(cnt, loop); + + mv(result, true); +} + +void C2_MacroAssembler::string_equals_v(Register a1, Register a2, Register result, Register cnt, int elem_size) { + Label DONE; + Register tmp1 = t0; + Register tmp2 = t1; + + BLOCK_COMMENT("string_equals_v {"); + + mv(result, false); + + if (elem_size == 2) { + srli(cnt, cnt, 1); + } + + element_compare(a1, a2, result, cnt, tmp1, tmp2, v0, v2, v0, elem_size == 1, DONE); + + bind(DONE); + BLOCK_COMMENT("} string_equals_v"); +} + +// used by C2 ClearArray patterns. +// base: Address of a buffer to be zeroed +// cnt: Count in HeapWords +// +// base, cnt, v0, v1 and t0 are clobbered. +void C2_MacroAssembler::clear_array_v(Register base, Register cnt) { + Label loop; + + // making zero words + vsetvli(t0, cnt, Assembler::e64, Assembler::m4); + vxor_vv(v0, v0, v0); + + bind(loop); + vsetvli(t0, cnt, Assembler::e64, Assembler::m4); + vse64_v(v0, base); + sub(cnt, cnt, t0); + shadd(base, t0, base, t0, 3); + bnez(cnt, loop); +} + +void C2_MacroAssembler::arrays_equals_v(Register a1, Register a2, Register result, + Register cnt1, int elem_size) { + Label DONE; + Register tmp1 = t0; + Register tmp2 = t1; + Register cnt2 = tmp2; + int length_offset = arrayOopDesc::length_offset_in_bytes(); + int base_offset = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE); + + BLOCK_COMMENT("arrays_equals_v {"); + + // if (a1 == a2), return true + mv(result, true); + beq(a1, a2, DONE); + + mv(result, false); + // if a1 == null or a2 == null, return false + beqz(a1, DONE); + beqz(a2, DONE); + // if (a1.length != a2.length), return false + lwu(cnt1, Address(a1, length_offset)); + lwu(cnt2, Address(a2, length_offset)); + bne(cnt1, cnt2, DONE); + + la(a1, Address(a1, base_offset)); + la(a2, Address(a2, base_offset)); + + element_compare(a1, a2, result, cnt1, tmp1, tmp2, v0, v2, v0, elem_size == 1, DONE); + + bind(DONE); + + BLOCK_COMMENT("} arrays_equals_v"); +} + +void C2_MacroAssembler::string_compare_v(Register str1, Register str2, Register cnt1, Register cnt2, + Register result, Register tmp1, Register tmp2, int encForm) { + Label DIFFERENCE, DONE, L, loop; + bool encLL = encForm == StrIntrinsicNode::LL; + bool encLU = encForm == StrIntrinsicNode::LU; + bool encUL = encForm == StrIntrinsicNode::UL; + + bool str1_isL = encLL || encLU; + bool str2_isL = encLL || encUL; + + int minCharsInWord = encLL ? wordSize : wordSize / 2; + + BLOCK_COMMENT("string_compare {"); + + // for Lating strings, 1 byte for 1 character + // for UTF16 strings, 2 bytes for 1 character + if (!str1_isL) + sraiw(cnt1, cnt1, 1); + if (!str2_isL) + sraiw(cnt2, cnt2, 1); + + // if str1 == str2, return the difference + // save the minimum of the string lengths in cnt2. + sub(result, cnt1, cnt2); + bgt(cnt1, cnt2, L); + mv(cnt2, cnt1); + bind(L); + + if (str1_isL == str2_isL) { // LL or UU + element_compare(str1, str2, zr, cnt2, tmp1, tmp2, v2, v4, v1, encLL, DIFFERENCE); + j(DONE); + } else { // LU or UL + Register strL = encLU ? str1 : str2; + Register strU = encLU ? str2 : str1; + VectorRegister vstr1 = encLU ? v4 : v0; + VectorRegister vstr2 = encLU ? v0 : v4; + + bind(loop); + vsetvli(tmp1, cnt2, Assembler::e8, Assembler::m2); + vle8_v(vstr1, strL); + vsetvli(tmp1, cnt2, Assembler::e16, Assembler::m4); + vzext_vf2(vstr2, vstr1); + vle16_v(vstr1, strU); + vmsne_vv(v0, vstr2, vstr1); + vfirst_m(tmp2, v0); + bgez(tmp2, DIFFERENCE); + sub(cnt2, cnt2, tmp1); + add(strL, strL, tmp1); + shadd(strU, tmp1, strU, tmp1, 1); + bnez(cnt2, loop); + j(DONE); + } + bind(DIFFERENCE); + slli(tmp1, tmp2, 1); + add(str1, str1, str1_isL ? tmp2 : tmp1); + add(str2, str2, str2_isL ? tmp2 : tmp1); + str1_isL ? lbu(tmp1, Address(str1, 0)) : lhu(tmp1, Address(str1, 0)); + str2_isL ? lbu(tmp2, Address(str2, 0)) : lhu(tmp2, Address(str2, 0)); + sub(result, tmp1, tmp2); + + bind(DONE); +} + +void C2_MacroAssembler::byte_array_inflate_v(Register src, Register dst, Register len, Register tmp) { + Label loop; + assert_different_registers(src, dst, len, tmp, t0); + + BLOCK_COMMENT("byte_array_inflate_v {"); + bind(loop); + vsetvli(tmp, len, Assembler::e8, Assembler::m2); + vle8_v(v2, src); + vsetvli(t0, len, Assembler::e16, Assembler::m4); + vzext_vf2(v0, v2); + vse16_v(v0, dst); + sub(len, len, tmp); + add(src, src, tmp); + shadd(dst, tmp, dst, tmp, 1); + bnez(len, loop); + BLOCK_COMMENT("} byte_array_inflate_v"); +} + +// Compress char[] array to byte[]. +// result: the array length if every element in array can be encoded; 0, otherwise. +void C2_MacroAssembler::char_array_compress_v(Register src, Register dst, Register len, Register result, Register tmp) { + Label done; + encode_iso_array_v(src, dst, len, result, tmp); + beqz(len, done); + mv(result, zr); + bind(done); +} + +// result: the number of elements had been encoded. +void C2_MacroAssembler::encode_iso_array_v(Register src, Register dst, Register len, Register result, Register tmp) { + Label loop, DIFFERENCE, DONE; + + BLOCK_COMMENT("encode_iso_array_v {"); + mv(result, 0); + + bind(loop); + mv(tmp, 0xff); + vsetvli(t0, len, Assembler::e16, Assembler::m2); + vle16_v(v2, src); + // if element > 0xff, stop + vmsgtu_vx(v1, v2, tmp); + vfirst_m(tmp, v1); + vmsbf_m(v0, v1); + // compress char to byte + vsetvli(t0, len, Assembler::e8); + vncvt_x_x_w(v1, v2, Assembler::v0_t); + vse8_v(v1, dst, Assembler::v0_t); + + bgez(tmp, DIFFERENCE); + add(result, result, t0); + add(dst, dst, t0); + sub(len, len, t0); + shadd(src, t0, src, t0, 1); + bnez(len, loop); + j(DONE); + + bind(DIFFERENCE); + add(result, result, tmp); + + bind(DONE); + BLOCK_COMMENT("} encode_iso_array_v"); +} + +void C2_MacroAssembler::count_positives_v(Register ary, Register len, Register result, Register tmp) { + Label LOOP, SET_RESULT, DONE; + + BLOCK_COMMENT("count_positives_v {"); + mv(result, zr); + + bind(LOOP); + vsetvli(t0, len, Assembler::e8, Assembler::m4); + vle8_v(v0, ary); + vmslt_vx(v0, v0, zr); + vfirst_m(tmp, v0); + bgez(tmp, SET_RESULT); + // if tmp == -1, all bytes are positive + add(result, result, t0); + + sub(len, len, t0); + add(ary, ary, t0); + bnez(len, LOOP); + j(DONE); + + // add remaining positive bytes count + bind(SET_RESULT); + add(result, result, tmp); + + bind(DONE); + BLOCK_COMMENT("} count_positives_v"); +} + +void C2_MacroAssembler::string_indexof_char_v(Register str1, Register cnt1, + Register ch, Register result, + Register tmp1, Register tmp2, + bool isL) { + mv(result, zr); + + Label loop, MATCH, DONE; + Assembler::SEW sew = isL ? Assembler::e8 : Assembler::e16; + bind(loop); + vsetvli(tmp1, cnt1, sew, Assembler::m4); + vlex_v(v0, str1, sew); + vmseq_vx(v0, v0, ch); + vfirst_m(tmp2, v0); + bgez(tmp2, MATCH); // if equal, return index + + add(result, result, tmp1); + sub(cnt1, cnt1, tmp1); + if (!isL) slli(tmp1, tmp1, 1); + add(str1, str1, tmp1); + bnez(cnt1, loop); + + mv(result, -1); + j(DONE); + + bind(MATCH); + add(result, result, tmp2); + + bind(DONE); +} + +// Set dst to NaN if any NaN input. +void C2_MacroAssembler::minmax_FD_v(VectorRegister dst, VectorRegister src1, VectorRegister src2, + bool is_double, bool is_min) { + assert_different_registers(dst, src1, src2); + + vsetvli(t0, x0, is_double ? Assembler::e64 : Assembler::e32); + + is_min ? vfmin_vv(dst, src1, src2) + : vfmax_vv(dst, src1, src2); + + vmfne_vv(v0, src1, src1); + vfadd_vv(dst, src1, src1, Assembler::v0_t); + vmfne_vv(v0, src2, src2); + vfadd_vv(dst, src2, src2, Assembler::v0_t); +} + +// Set dst to NaN if any NaN input. +void C2_MacroAssembler::reduce_minmax_FD_v(FloatRegister dst, + FloatRegister src1, VectorRegister src2, + VectorRegister tmp1, VectorRegister tmp2, + bool is_double, bool is_min) { + assert_different_registers(src2, tmp1, tmp2); + + Label L_done, L_NaN; + vsetvli(t0, x0, is_double ? Assembler::e64 : Assembler::e32); + vfmv_s_f(tmp2, src1); + + is_min ? vfredmin_vs(tmp1, src2, tmp2) + : vfredmax_vs(tmp1, src2, tmp2); + + fsflags(zr); + // Checking NaNs + vmflt_vf(tmp2, src2, src1); + frflags(t0); + bnez(t0, L_NaN); + j(L_done); + + bind(L_NaN); + vfmv_s_f(tmp2, src1); + vfredsum_vs(tmp1, src2, tmp2); + + bind(L_done); + vfmv_f_s(dst, tmp1); +} diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp new file mode 100644 index 00000000000..c71df4c101b --- /dev/null +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C2_MACROASSEMBLER_RISCV_HPP +#define CPU_RISCV_C2_MACROASSEMBLER_RISCV_HPP + +// C2_MacroAssembler contains high-level macros for C2 + + private: + void element_compare(Register r1, Register r2, + Register result, Register cnt, + Register tmp1, Register tmp2, + VectorRegister vr1, VectorRegister vr2, + VectorRegister vrs, + bool is_latin, Label& DONE); + public: + + void string_compare(Register str1, Register str2, + Register cnt1, Register cnt2, Register result, + Register tmp1, Register tmp2, Register tmp3, + int ae); + + void string_indexof_char_short(Register str1, Register cnt1, + Register ch, Register result, + bool isL); + + void string_indexof_char(Register str1, Register cnt1, + Register ch, Register result, + Register tmp1, Register tmp2, + Register tmp3, Register tmp4, + bool isL); + + void string_indexof(Register str1, Register str2, + Register cnt1, Register cnt2, + Register tmp1, Register tmp2, + Register tmp3, Register tmp4, + Register tmp5, Register tmp6, + Register result, int ae); + + void string_indexof_linearscan(Register haystack, Register needle, + Register haystack_len, Register needle_len, + Register tmp1, Register tmp2, + Register tmp3, Register tmp4, + int needle_con_cnt, Register result, int ae); + + void arrays_equals(Register r1, Register r2, + Register tmp3, Register tmp4, + Register tmp5, Register tmp6, + Register result, Register cnt1, + int elem_size); + + void string_equals(Register r1, Register r2, + Register result, Register cnt1, + int elem_size); + + // refer to conditional_branches and float_conditional_branches + static const int bool_test_bits = 3; + static const int neg_cond_bits = 2; + static const int unsigned_branch_mask = 1 << bool_test_bits; + static const int double_branch_mask = 1 << bool_test_bits; + + // cmp + void cmp_branch(int cmpFlag, + Register op1, Register op2, + Label& label, bool is_far = false); + + void float_cmp_branch(int cmpFlag, + FloatRegister op1, FloatRegister op2, + Label& label, bool is_far = false); + + void enc_cmpUEqNeLeGt_imm0_branch(int cmpFlag, Register op, + Label& L, bool is_far = false); + + void enc_cmpEqNe_imm0_branch(int cmpFlag, Register op, + Label& L, bool is_far = false); + + void enc_cmove(int cmpFlag, + Register op1, Register op2, + Register dst, Register src); + + void spill(Register r, bool is64, int offset) { + is64 ? sd(r, Address(sp, offset)) + : sw(r, Address(sp, offset)); + } + + void spill(FloatRegister f, bool is64, int offset) { + is64 ? fsd(f, Address(sp, offset)) + : fsw(f, Address(sp, offset)); + } + + void spill(VectorRegister v, int offset) { + add(t0, sp, offset); + vs1r_v(v, t0); + } + + void unspill(Register r, bool is64, int offset) { + is64 ? ld(r, Address(sp, offset)) + : lw(r, Address(sp, offset)); + } + + void unspillu(Register r, bool is64, int offset) { + is64 ? ld(r, Address(sp, offset)) + : lwu(r, Address(sp, offset)); + } + + void unspill(FloatRegister f, bool is64, int offset) { + is64 ? fld(f, Address(sp, offset)) + : flw(f, Address(sp, offset)); + } + + void unspill(VectorRegister v, int offset) { + add(t0, sp, offset); + vl1r_v(v, t0); + } + + void spill_copy_vector_stack_to_stack(int src_offset, int dst_offset, int vec_reg_size_in_bytes) { + assert(vec_reg_size_in_bytes % 16 == 0, "unexpected vector reg size"); + unspill(v0, src_offset); + spill(v0, dst_offset); + } + + void minmax_FD(FloatRegister dst, + FloatRegister src1, FloatRegister src2, + bool is_double, bool is_min); + + // intrinsic methods implemented by rvv instructions + void string_equals_v(Register r1, Register r2, + Register result, Register cnt1, + int elem_size); + + void arrays_equals_v(Register r1, Register r2, + Register result, Register cnt1, + int elem_size); + + void string_compare_v(Register str1, Register str2, + Register cnt1, Register cnt2, + Register result, + Register tmp1, Register tmp2, + int encForm); + + void clear_array_v(Register base, Register cnt); + + void byte_array_inflate_v(Register src, Register dst, + Register len, Register tmp); + + void char_array_compress_v(Register src, Register dst, + Register len, Register result, + Register tmp); + + void encode_iso_array_v(Register src, Register dst, + Register len, Register result, + Register tmp); + + void count_positives_v(Register ary, Register len, + Register result, Register tmp); + + void string_indexof_char_v(Register str1, Register cnt1, + Register ch, Register result, + Register tmp1, Register tmp2, + bool isL); + + void minmax_FD_v(VectorRegister dst, + VectorRegister src1, VectorRegister src2, + bool is_double, bool is_min); + + void reduce_minmax_FD_v(FloatRegister dst, + FloatRegister src1, VectorRegister src2, + VectorRegister tmp1, VectorRegister tmp2, + bool is_double, bool is_min); + +#endif // CPU_RISCV_C2_MACROASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c2_globals_riscv.hpp b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp new file mode 100644 index 00000000000..53a41665f4b --- /dev/null +++ b/src/hotspot/cpu/riscv/c2_globals_riscv.hpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_C2_GLOBALS_RISCV_HPP +#define CPU_RISCV_C2_GLOBALS_RISCV_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// Sets the default values for platform dependent flags used by the server compiler. +// (see c2_globals.hpp). Alpha-sorted. + +define_pd_global(bool, BackgroundCompilation, true); +define_pd_global(bool, CICompileOSR, true); +define_pd_global(bool, InlineIntrinsics, true); +define_pd_global(bool, PreferInterpreterNativeStubs, false); +define_pd_global(bool, ProfileTraps, true); +define_pd_global(bool, UseOnStackReplacement, true); +define_pd_global(bool, ProfileInterpreter, true); +define_pd_global(bool, TieredCompilation, COMPILER1_PRESENT(true) NOT_COMPILER1(false)); +define_pd_global(intx, CompileThreshold, 10000); + +define_pd_global(intx, OnStackReplacePercentage, 140); +define_pd_global(intx, ConditionalMoveLimit, 0); +define_pd_global(intx, FreqInlineSize, 325); +define_pd_global(intx, MinJumpTableSize, 10); +define_pd_global(intx, InteriorEntryAlignment, 16); +define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); +define_pd_global(intx, LoopUnrollLimit, 60); +define_pd_global(intx, LoopPercentProfileLimit, 10); +// InitialCodeCacheSize derived from specjbb2000 run. +define_pd_global(intx, InitialCodeCacheSize, 2496*K); // Integral multiple of CodeCacheExpansionSize +define_pd_global(intx, CodeCacheExpansionSize, 64*K); + +// Ergonomics related flags +define_pd_global(uint64_t,MaxRAM, 128ULL*G); +define_pd_global(intx, RegisterCostAreaRatio, 16000); + +// Peephole and CISC spilling both break the graph, and so makes the +// scheduler sick. +define_pd_global(bool, OptoPeephole, false); +define_pd_global(bool, UseCISCSpill, false); +define_pd_global(bool, OptoScheduling, true); +define_pd_global(bool, OptoBundling, false); +define_pd_global(bool, OptoRegScheduling, false); +define_pd_global(bool, SuperWordLoopUnrollAnalysis, true); +define_pd_global(bool, IdealizeClearArrayNode, true); + +define_pd_global(intx, ReservedCodeCacheSize, 48*M); +define_pd_global(intx, NonProfiledCodeHeapSize, 21*M); +define_pd_global(intx, ProfiledCodeHeapSize, 22*M); +define_pd_global(intx, NonNMethodCodeHeapSize, 5*M ); +define_pd_global(uintx, CodeCacheMinBlockLength, 6); +define_pd_global(uintx, CodeCacheMinimumUseSpace, 400*K); + +// Ergonomics related flags +define_pd_global(bool, NeverActAsServerClassMachine, false); + +define_pd_global(bool, TrapBasedRangeChecks, false); // Not needed. + +#endif // CPU_RISCV_C2_GLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/c2_init_riscv.cpp b/src/hotspot/cpu/riscv/c2_init_riscv.cpp new file mode 100644 index 00000000000..cdbd69807be --- /dev/null +++ b/src/hotspot/cpu/riscv/c2_init_riscv.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2019, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "opto/compile.hpp" +#include "opto/node.hpp" + +// processor dependent initialization for riscv + +extern void reg_mask_init(); + +void Compile::pd_compiler2_init() { + guarantee(CodeEntryAlignment >= InteriorEntryAlignment, "" ); + reg_mask_init(); +} diff --git a/src/hotspot/cpu/riscv/c2_safepointPollStubTable_riscv.cpp b/src/hotspot/cpu/riscv/c2_safepointPollStubTable_riscv.cpp new file mode 100644 index 00000000000..a90d9fdc160 --- /dev/null +++ b/src/hotspot/cpu/riscv/c2_safepointPollStubTable_riscv.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "opto/compile.hpp" +#include "opto/node.hpp" +#include "opto/output.hpp" +#include "runtime/sharedRuntime.hpp" + +#define __ masm. +void C2SafepointPollStubTable::emit_stub_impl(MacroAssembler& masm, C2SafepointPollStub* entry) const { + assert(SharedRuntime::polling_page_return_handler_blob() != NULL, + "polling page return stub not created yet"); + address stub = SharedRuntime::polling_page_return_handler_blob()->entry_point(); + RuntimeAddress callback_addr(stub); + + __ bind(entry->_stub_label); + InternalAddress safepoint_pc(masm.pc() - masm.offset() + entry->_safepoint_offset); + masm.code_section()->relocate(masm.pc(), safepoint_pc.rspec()); + __ la(t0, safepoint_pc.target()); + __ sd(t0, Address(xthread, JavaThread::saved_exception_pc_offset())); + __ far_jump(callback_addr); +} +#undef __ diff --git a/src/hotspot/cpu/riscv/codeBuffer_riscv.hpp b/src/hotspot/cpu/riscv/codeBuffer_riscv.hpp new file mode 100644 index 00000000000..14a68b45026 --- /dev/null +++ b/src/hotspot/cpu/riscv/codeBuffer_riscv.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_CODEBUFFER_RISCV_HPP +#define CPU_RISCV_CODEBUFFER_RISCV_HPP + +private: + void pd_initialize() {} + +public: + void flush_bundle(bool start_new_bundle) {} + +#endif // CPU_RISCV_CODEBUFFER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/compiledIC_riscv.cpp b/src/hotspot/cpu/riscv/compiledIC_riscv.cpp new file mode 100644 index 00000000000..75bc4be7840 --- /dev/null +++ b/src/hotspot/cpu/riscv/compiledIC_riscv.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/compiledIC.hpp" +#include "code/icBuffer.hpp" +#include "code/nmethod.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/safepoint.hpp" + +// ---------------------------------------------------------------------------- + +#define __ _masm. +address CompiledStaticCall::emit_to_interp_stub(CodeBuffer &cbuf, address mark) { + precond(cbuf.stubs()->start() != badAddress); + precond(cbuf.stubs()->end() != badAddress); + // Stub is fixed up when the corresponding call is converted from + // calling compiled code to calling interpreted code. + // mv xmethod, 0 + // jalr -4 # to self + + if (mark == NULL) { + mark = cbuf.insts_mark(); // Get mark within main instrs section. + } + + // Note that the code buffer's insts_mark is always relative to insts. + // That's why we must use the macroassembler to generate a stub. + MacroAssembler _masm(&cbuf); + + address base = __ start_a_stub(to_interp_stub_size()); + int offset = __ offset(); + if (base == NULL) { + return NULL; // CodeBuffer::expand failed + } + // static stub relocation stores the instruction address of the call + __ relocate(static_stub_Relocation::spec(mark)); + + __ emit_static_call_stub(); + + assert((__ offset() - offset) <= (int)to_interp_stub_size(), "stub too big"); + __ end_a_stub(); + return base; +} +#undef __ + +int CompiledStaticCall::to_interp_stub_size() { + // fence_i + fence* + (lui, addi, slli, addi, slli, addi) + (lui, addi, slli, addi, slli) + jalr + return NativeFenceI::instruction_size() + 12 * NativeInstruction::instruction_size; +} + +int CompiledStaticCall::to_trampoline_stub_size() { + // Somewhat pessimistically, we count 4 instructions here (although + // there are only 3) because we sometimes emit an alignment nop. + // Trampoline stubs are always word aligned. + return NativeInstruction::instruction_size + NativeCallTrampolineStub::instruction_size; +} + +// Relocation entries for call stub, compiled java to interpreter. +int CompiledStaticCall::reloc_to_interp_stub() { + return 4; // 3 in emit_to_interp_stub + 1 in emit_call +} + +void CompiledDirectStaticCall::set_to_interpreted(const methodHandle& callee, address entry) { + address stub = find_stub(); + guarantee(stub != NULL, "stub not found"); + + if (TraceICs) { + ResourceMark rm; + tty->print_cr("CompiledDirectStaticCall@" INTPTR_FORMAT ": set_to_interpreted %s", + p2i(instruction_address()), + callee->name_and_sig_as_C_string()); + } + + // Creation also verifies the object. + NativeMovConstReg* method_holder + = nativeMovConstReg_at(stub + NativeFenceI::instruction_size()); +#ifdef ASSERT + NativeGeneralJump* jump = nativeGeneralJump_at(method_holder->next_instruction_address()); + + verify_mt_safe(callee, entry, method_holder, jump); +#endif + // Update stub. + method_holder->set_data((intptr_t)callee()); + NativeGeneralJump::insert_unconditional(method_holder->next_instruction_address(), entry); + ICache::invalidate_range(stub, to_interp_stub_size()); + // Update jump to call. + set_destination_mt_safe(stub); +} + +void CompiledDirectStaticCall::set_stub_to_clean(static_stub_Relocation* static_stub) { + // Reset stub. + address stub = static_stub->addr(); + assert(stub != NULL, "stub not found"); + assert(CompiledICLocker::is_safe(stub), "mt unsafe call"); + // Creation also verifies the object. + NativeMovConstReg* method_holder + = nativeMovConstReg_at(stub + NativeFenceI::instruction_size()); + method_holder->set_data(0); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + jump->set_jump_destination((address)-1); +} + +//----------------------------------------------------------------------------- +// Non-product mode code +#ifndef PRODUCT + +void CompiledDirectStaticCall::verify() { + // Verify call. + _call->verify(); + _call->verify_alignment(); + + // Verify stub. + address stub = find_stub(); + assert(stub != NULL, "no stub found for static call"); + // Creation also verifies the object. + NativeMovConstReg* method_holder + = nativeMovConstReg_at(stub + NativeFenceI::instruction_size()); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + + // Verify state. + assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); +} + +#endif // !PRODUCT diff --git a/src/hotspot/cpu/riscv/copy_riscv.hpp b/src/hotspot/cpu/riscv/copy_riscv.hpp new file mode 100644 index 00000000000..bceadcc5dcc --- /dev/null +++ b/src/hotspot/cpu/riscv/copy_riscv.hpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_COPY_RISCV_HPP +#define CPU_RISCV_COPY_RISCV_HPP + +#include OS_CPU_HEADER(copy) + +static void pd_fill_to_words(HeapWord* tohw, size_t count, juint value) { + julong* to = (julong*) tohw; + julong v = ((julong) value << 32) | value; + while (count-- > 0) { + *to++ = v; + } +} + +static void pd_fill_to_aligned_words(HeapWord* tohw, size_t count, juint value) { + pd_fill_to_words(tohw, count, value); +} + +static void pd_fill_to_bytes(void* to, size_t count, jubyte value) { + (void)memset(to, value, count); +} + +static void pd_zero_to_words(HeapWord* tohw, size_t count) { + pd_fill_to_words(tohw, count, 0); +} + +static void pd_zero_to_bytes(void* to, size_t count) { + (void)memset(to, 0, count); +} + +static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + (void)memmove(to, from, count * HeapWordSize); +} + +static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + switch (count) { + case 8: to[7] = from[7]; // fall through + case 7: to[6] = from[6]; // fall through + case 6: to[5] = from[5]; // fall through + case 5: to[4] = from[4]; // fall through + case 4: to[3] = from[3]; // fall through + case 3: to[2] = from[2]; // fall through + case 2: to[1] = from[1]; // fall through + case 1: to[0] = from[0]; // fall through + case 0: break; + default: + memcpy(to, from, count * HeapWordSize); + break; + } +} + +static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) { + shared_disjoint_words_atomic(from, to, count); +} + +static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + pd_conjoint_words(from, to, count); +} + +static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) { + pd_disjoint_words(from, to, count); +} + +static void pd_conjoint_bytes(const void* from, void* to, size_t count) { + (void)memmove(to, from, count); +} + +static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) { + pd_conjoint_bytes(from, to, count); +} + +static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { + _Copy_conjoint_jshorts_atomic(from, to, count); +} + +static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { + _Copy_conjoint_jints_atomic(from, to, count); +} + +static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { + _Copy_conjoint_jlongs_atomic(from, to, count); +} + +static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) { + assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size."); + _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count); +} + +static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_bytes(from, to, count); +} + +static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_jshorts(from, to, count); +} + +static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_jints(from, to, count); +} + +static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) { + _Copy_arrayof_conjoint_jlongs(from, to, count); +} + +static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) { + assert(!UseCompressedOops, "foo!"); + assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size"); + _Copy_arrayof_conjoint_jlongs(from, to, count); +} + +#endif // CPU_RISCV_COPY_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/disassembler_riscv.hpp b/src/hotspot/cpu/riscv/disassembler_riscv.hpp new file mode 100644 index 00000000000..b0e5560c906 --- /dev/null +++ b/src/hotspot/cpu/riscv/disassembler_riscv.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_DISASSEMBLER_RISCV_HPP +#define CPU_RISCV_DISASSEMBLER_RISCV_HPP + +static int pd_instruction_alignment() { + return 1; +} + +static const char* pd_cpu_opts() { + return ""; +} + +// Returns address of n-th instruction preceding addr, +// NULL if no preceding instruction can be found. +// On riscv, we assume a constant instruction length. +// It might be beneficial to check "is_readable" as we do on ppc and s390. +static address find_prev_instr(address addr, int n_instr) { + return addr - Assembler::instruction_size * n_instr; +} + +// special-case instruction decoding. +// There may be cases where the binutils disassembler doesn't do +// the perfect job. In those cases, decode_instruction0 may kick in +// and do it right. +// If nothing had to be done, just return "here", otherwise return "here + instr_len(here)" +static address decode_instruction0(address here, outputStream* st, address virtual_begin = NULL) { + return here; +} + +// platform-specific instruction annotations (like value of loaded constants) +static void annotate(address pc, outputStream* st) {} + +#endif // CPU_RISCV_DISASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/foreign_globals_riscv.cpp b/src/hotspot/cpu/riscv/foreign_globals_riscv.cpp new file mode 100644 index 00000000000..5c700be9c91 --- /dev/null +++ b/src/hotspot/cpu/riscv/foreign_globals_riscv.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "prims/foreign_globals.hpp" +#include "utilities/debug.hpp" + +// Stubbed out, implement later +const ABIDescriptor ForeignGlobals::parse_abi_descriptor_impl(jobject jabi) const { + Unimplemented(); + return {}; +} + +const BufferLayout ForeignGlobals::parse_buffer_layout_impl(jobject jlayout) const { + Unimplemented(); + return {}; +} + +const CallRegs ForeignGlobals::parse_call_regs_impl(jobject jconv) const { + ShouldNotCallThis(); + return {}; +} diff --git a/src/hotspot/cpu/riscv/foreign_globals_riscv.hpp b/src/hotspot/cpu/riscv/foreign_globals_riscv.hpp new file mode 100644 index 00000000000..3ac89752c27 --- /dev/null +++ b/src/hotspot/cpu/riscv/foreign_globals_riscv.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_FOREIGN_GLOBALS_RISCV_HPP +#define CPU_RISCV_FOREIGN_GLOBALS_RISCV_HPP + +class ABIDescriptor {}; +class BufferLayout {}; + +#endif // CPU_RISCV_FOREIGN_GLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp new file mode 100644 index 00000000000..6e38960598a --- /dev/null +++ b/src/hotspot/cpu/riscv/frame_riscv.cpp @@ -0,0 +1,697 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "compiler/oopMap.hpp" +#include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" +#include "memory/universe.hpp" +#include "oops/markWord.hpp" +#include "oops/method.hpp" +#include "oops/oop.inline.hpp" +#include "prims/methodHandles.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/monitorChunk.hpp" +#include "runtime/os.inline.hpp" +#include "runtime/signature.hpp" +#include "runtime/stackWatermarkSet.hpp" +#include "runtime/stubCodeGenerator.hpp" +#include "runtime/stubRoutines.hpp" +#include "vmreg_riscv.inline.hpp" +#ifdef COMPILER1 +#include "c1/c1_Runtime1.hpp" +#include "runtime/vframeArray.hpp" +#endif + +#ifdef ASSERT +void RegisterMap::check_location_valid() { +} +#endif + + +// Profiling/safepoint support + +bool frame::safe_for_sender(JavaThread *thread) { + address addr_sp = (address)_sp; + address addr_fp = (address)_fp; + address unextended_sp = (address)_unextended_sp; + + // consider stack guards when trying to determine "safe" stack pointers + // sp must be within the usable part of the stack (not in guards) + if (!thread->is_in_usable_stack(addr_sp)) { + return false; + } + + // When we are running interpreted code the machine stack pointer, SP, is + // set low enough so that the Java expression stack can grow and shrink + // without ever exceeding the machine stack bounds. So, ESP >= SP. + + // When we call out of an interpreted method, SP is incremented so that + // the space between SP and ESP is removed. The SP saved in the callee's + // frame is the SP *before* this increment. So, when we walk a stack of + // interpreter frames the sender's SP saved in a frame might be less than + // the SP at the point of call. + + // So unextended sp must be within the stack but we need not to check + // that unextended sp >= sp + + if (!thread->is_in_full_stack_checked(unextended_sp)) { + return false; + } + + // an fp must be within the stack and above (but not equal) sp + // second evaluation on fp+ is added to handle situation where fp is -1 + bool fp_safe = thread->is_in_stack_range_excl(addr_fp, addr_sp) && + thread->is_in_full_stack_checked(addr_fp + (return_addr_offset * sizeof(void*))); + + // We know sp/unextended_sp are safe only fp is questionable here + + // If the current frame is known to the code cache then we can attempt to + // to construct the sender and do some validation of it. This goes a long way + // toward eliminating issues when we get in frame construction code + + if (_cb != NULL) { + + // First check if frame is complete and tester is reliable + // Unfortunately we can only check frame complete for runtime stubs and nmethod + // other generic buffer blobs are more problematic so we just assume they are + // ok. adapter blobs never have a frame complete and are never ok. + + if (!_cb->is_frame_complete_at(_pc)) { + if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { + return false; + } + } + + // Could just be some random pointer within the codeBlob + if (!_cb->code_contains(_pc)) { + return false; + } + + // Entry frame checks + if (is_entry_frame()) { + // an entry frame must have a valid fp. + return fp_safe && is_entry_frame_valid(thread); + } + + intptr_t* sender_sp = NULL; + intptr_t* sender_unextended_sp = NULL; + address sender_pc = NULL; + intptr_t* saved_fp = NULL; + + if (is_interpreted_frame()) { + // fp must be safe + if (!fp_safe) { + return false; + } + + sender_pc = (address)this->fp()[return_addr_offset]; + // for interpreted frames, the value below is the sender "raw" sp, + // which can be different from the sender unextended sp (the sp seen + // by the sender) because of current frame local variables + sender_sp = (intptr_t*) addr_at(sender_sp_offset); + sender_unextended_sp = (intptr_t*) this->fp()[interpreter_frame_sender_sp_offset]; + saved_fp = (intptr_t*) this->fp()[link_offset]; + } else { + // must be some sort of compiled/runtime frame + // fp does not have to be safe (although it could be check for c1?) + + // check for a valid frame_size, otherwise we are unlikely to get a valid sender_pc + if (_cb->frame_size() <= 0) { + return false; + } + + sender_sp = _unextended_sp + _cb->frame_size(); + // Is sender_sp safe? + if (!thread->is_in_full_stack_checked((address)sender_sp)) { + return false; + } + + sender_unextended_sp = sender_sp; + sender_pc = (address) *(sender_sp - 1); + saved_fp = (intptr_t*) *(sender_sp - 2); + } + + + // If the potential sender is the interpreter then we can do some more checking + if (Interpreter::contains(sender_pc)) { + + // fp is always saved in a recognizable place in any code we generate. However + // only if the sender is interpreted/call_stub (c1 too?) are we certain that the saved fp + // is really a frame pointer. + if (!thread->is_in_stack_range_excl((address)saved_fp, (address)sender_sp)) { + return false; + } + + // construct the potential sender + frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); + + return sender.is_interpreted_frame_valid(thread); + } + + // We must always be able to find a recognizable pc + CodeBlob* sender_blob = CodeCache::find_blob_unsafe(sender_pc); + if (sender_pc == NULL || sender_blob == NULL) { + return false; + } + + // Could be a zombie method + if (sender_blob->is_zombie() || sender_blob->is_unloaded()) { + return false; + } + + // Could just be some random pointer within the codeBlob + if (!sender_blob->code_contains(sender_pc)) { + return false; + } + + // We should never be able to see an adapter if the current frame is something from code cache + if (sender_blob->is_adapter_blob()) { + return false; + } + + // Could be the call_stub + if (StubRoutines::returns_to_call_stub(sender_pc)) { + if (!thread->is_in_stack_range_excl((address)saved_fp, (address)sender_sp)) { + return false; + } + + // construct the potential sender + frame sender(sender_sp, sender_unextended_sp, saved_fp, sender_pc); + + // Validate the JavaCallWrapper an entry frame must have + address jcw = (address)sender.entry_frame_call_wrapper(); + + bool jcw_safe = (jcw < thread->stack_base()) && (jcw > (address)sender.fp()); + + return jcw_safe; + } + + CompiledMethod* nm = sender_blob->as_compiled_method_or_null(); + if (nm != NULL) { + if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || + nm->method()->is_method_handle_intrinsic()) { + return false; + } + } + + // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size + // because the return address counts against the callee's frame. + if (sender_blob->frame_size() <= 0) { + assert(!sender_blob->is_compiled(), "should count return address at least"); + return false; + } + + // We should never be able to see anything here except an nmethod. If something in the + // code cache (current frame) is called by an entity within the code cache that entity + // should not be anything but the call stub (already covered), the interpreter (already covered) + // or an nmethod. + if (!sender_blob->is_compiled()) { + return false; + } + + // Could put some more validation for the potential non-interpreted sender + // frame we'd create by calling sender if I could think of any. Wait for next crash in forte... + + // One idea is seeing if the sender_pc we have is one that we'd expect to call to current cb + + // We've validated the potential sender that would be created + return true; + } + + // Must be native-compiled frame. Since sender will try and use fp to find + // linkages it must be safe + if (!fp_safe) { + return false; + } + + // Will the pc we fetch be non-zero (which we'll find at the oldest frame) + if ((address)this->fp()[return_addr_offset] == NULL) { return false; } + + return true; +} + +void frame::patch_pc(Thread* thread, address pc) { + assert(_cb == CodeCache::find_blob(pc), "unexpected pc"); + address* pc_addr = &(((address*) sp())[-1]); + if (TracePcPatching) { + tty->print_cr("patch_pc at address " INTPTR_FORMAT " [" INTPTR_FORMAT " -> " INTPTR_FORMAT "]", + p2i(pc_addr), p2i(*pc_addr), p2i(pc)); + } + // Either the return address is the original one or we are going to + // patch in the same address that's already there. + assert(_pc == *pc_addr || pc == *pc_addr, "must be"); + *pc_addr = pc; + address original_pc = CompiledMethod::get_deopt_original_pc(this); + if (original_pc != NULL) { + assert(original_pc == _pc, "expected original PC to be stored before patching"); + _deopt_state = is_deoptimized; + // leave _pc as is + } else { + _deopt_state = not_deoptimized; + _pc = pc; + } +} + +bool frame::is_interpreted_frame() const { + return Interpreter::contains(pc()); +} + +int frame::frame_size(RegisterMap* map) const { + frame sender = this->sender(map); + return sender.sp() - sp(); +} + +intptr_t* frame::entry_frame_argument_at(int offset) const { + // convert offset to index to deal with tsi + int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize); + // Entry frame's arguments are always in relation to unextended_sp() + return &unextended_sp()[index]; +} + +// sender_sp +intptr_t* frame::interpreter_frame_sender_sp() const { + assert(is_interpreted_frame(), "interpreted frame expected"); + return (intptr_t*) at(interpreter_frame_sender_sp_offset); +} + +void frame::set_interpreter_frame_sender_sp(intptr_t* sender_sp) { + assert(is_interpreted_frame(), "interpreted frame expected"); + ptr_at_put(interpreter_frame_sender_sp_offset, (intptr_t) sender_sp); +} + + +// monitor elements + +BasicObjectLock* frame::interpreter_frame_monitor_begin() const { + return (BasicObjectLock*) addr_at(interpreter_frame_monitor_block_bottom_offset); +} + +BasicObjectLock* frame::interpreter_frame_monitor_end() const { + BasicObjectLock* result = (BasicObjectLock*) *addr_at(interpreter_frame_monitor_block_top_offset); + // make sure the pointer points inside the frame + assert(sp() <= (intptr_t*) result, "monitor end should be above the stack pointer"); + assert((intptr_t*) result < fp(), "monitor end should be strictly below the frame pointer"); + return result; +} + +void frame::interpreter_frame_set_monitor_end(BasicObjectLock* value) { + *((BasicObjectLock**)addr_at(interpreter_frame_monitor_block_top_offset)) = value; +} + +// Used by template based interpreter deoptimization +void frame::interpreter_frame_set_last_sp(intptr_t* last_sp) { + *((intptr_t**)addr_at(interpreter_frame_last_sp_offset)) = last_sp; +} + +frame frame::sender_for_entry_frame(RegisterMap* map) const { + assert(map != NULL, "map must be set"); + // Java frame called from C; skip all C frames and return top C + // frame of that chunk as the sender + JavaFrameAnchor* jfa = entry_frame_call_wrapper()->anchor(); + assert(!entry_frame_is_first(), "next Java fp must be non zero"); + assert(jfa->last_Java_sp() > sp(), "must be above this frame on stack"); + // Since we are walking the stack now this nested anchor is obviously walkable + // even if it wasn't when it was stacked. + if (!jfa->walkable()) { + // Capture _last_Java_pc (if needed) and mark anchor walkable. + jfa->capture_last_Java_pc(); + } + map->clear(); + assert(map->include_argument_oops(), "should be set by clear"); + vmassert(jfa->last_Java_pc() != NULL, "not walkable"); + frame fr(jfa->last_Java_sp(), jfa->last_Java_fp(), jfa->last_Java_pc()); + return fr; +} + +OptimizedEntryBlob::FrameData* OptimizedEntryBlob::frame_data_for_frame(const frame& frame) const { + ShouldNotCallThis(); + return nullptr; +} + +bool frame::optimized_entry_frame_is_first() const { + ShouldNotCallThis(); + return false; +} + +frame frame::sender_for_optimized_entry_frame(RegisterMap* map) const { + ShouldNotCallThis(); + return {}; +} + +//------------------------------------------------------------------------------ +// frame::verify_deopt_original_pc +// +// Verifies the calculated original PC of a deoptimization PC for the +// given unextended SP. +#ifdef ASSERT +void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) { + frame fr; + + // This is ugly but it's better than to change {get,set}_original_pc + // to take an SP value as argument. And it's only a debugging + // method anyway. + fr._unextended_sp = unextended_sp; + + assert_cond(nm != NULL); + address original_pc = nm->get_original_pc(&fr); + assert(nm->insts_contains_inclusive(original_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); +} +#endif + +//------------------------------------------------------------------------------ +// frame::adjust_unextended_sp +void frame::adjust_unextended_sp() { + // On riscv, sites calling method handle intrinsics and lambda forms are treated + // as any other call site. Therefore, no special action is needed when we are + // returning to any of these call sites. + + if (_cb != NULL) { + CompiledMethod* sender_cm = _cb->as_compiled_method_or_null(); + if (sender_cm != NULL) { + // If the sender PC is a deoptimization point, get the original PC. + if (sender_cm->is_deopt_entry(_pc) || + sender_cm->is_deopt_mh_entry(_pc)) { + DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp)); + } + } + } +} + +//------------------------------------------------------------------------------ +// frame::update_map_with_saved_link +void frame::update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr) { + // The interpreter and compiler(s) always save fp in a known + // location on entry. We must record where that location is + // so that if fp was live on callout from c2 we can find + // the saved copy no matter what it called. + + // Since the interpreter always saves fp if we record where it is then + // we don't have to always save fp on entry and exit to c2 compiled + // code, on entry will be enough. + assert(map != NULL, "map must be set"); + map->set_location(::fp->as_VMReg(), (address) link_addr); + // this is weird "H" ought to be at a higher address however the + // oopMaps seems to have the "H" regs at the same address and the + // vanilla register. + map->set_location(::fp->as_VMReg()->next(), (address) link_addr); +} + + +//------------------------------------------------------------------------------ +// frame::sender_for_interpreter_frame +frame frame::sender_for_interpreter_frame(RegisterMap* map) const { + // SP is the raw SP from the sender after adapter or interpreter + // extension. + intptr_t* sender_sp = this->sender_sp(); + + // This is the sp before any possible extension (adapter/locals). + intptr_t* unextended_sp = interpreter_frame_sender_sp(); + +#ifdef COMPILER2 + assert(map != NULL, "map must be set"); + if (map->update_map()) { + update_map_with_saved_link(map, (intptr_t**) addr_at(link_offset)); + } +#endif // COMPILER2 + + return frame(sender_sp, unextended_sp, link(), sender_pc()); +} + + +//------------------------------------------------------------------------------ +// frame::sender_for_compiled_frame +frame frame::sender_for_compiled_frame(RegisterMap* map) const { + // we cannot rely upon the last fp having been saved to the thread + // in C2 code but it will have been pushed onto the stack. so we + // have to find it relative to the unextended sp + + assert(_cb->frame_size() >= 0, "must have non-zero frame size"); + intptr_t* l_sender_sp = unextended_sp() + _cb->frame_size(); + intptr_t* unextended_sp = l_sender_sp; + + // the return_address is always the word on the stack + address sender_pc = (address) *(l_sender_sp + frame::return_addr_offset); + + intptr_t** saved_fp_addr = (intptr_t**) (l_sender_sp + frame::link_offset); + + assert(map != NULL, "map must be set"); + if (map->update_map()) { + // Tell GC to use argument oopmaps for some runtime stubs that need it. + // For C1, the runtime stub might not have oop maps, so set this flag + // outside of update_register_map. + map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread())); + if (_cb->oop_maps() != NULL) { + OopMapSet::update_register_map(this, map); + } + + // Since the prolog does the save and restore of FP there is no + // oopmap for it so we must fill in its location as if there was + // an oopmap entry since if our caller was compiled code there + // could be live jvm state in it. + update_map_with_saved_link(map, saved_fp_addr); + } + + return frame(l_sender_sp, unextended_sp, *saved_fp_addr, sender_pc); +} + +//------------------------------------------------------------------------------ +// frame::sender_raw +frame frame::sender_raw(RegisterMap* map) const { + // Default is we done have to follow them. The sender_for_xxx will + // update it accordingly + assert(map != NULL, "map must be set"); + map->set_include_argument_oops(false); + + if (is_entry_frame()) { + return sender_for_entry_frame(map); + } + if (is_interpreted_frame()) { + return sender_for_interpreter_frame(map); + } + assert(_cb == CodeCache::find_blob(pc()),"Must be the same"); + + // This test looks odd: why is it not is_compiled_frame() ? That's + // because stubs also have OOP maps. + if (_cb != NULL) { + return sender_for_compiled_frame(map); + } + + // Must be native-compiled frame, i.e. the marshaling code for native + // methods that exists in the core system. + return frame(sender_sp(), link(), sender_pc()); +} + +frame frame::sender(RegisterMap* map) const { + frame result = sender_raw(map); + + if (map->process_frames()) { + StackWatermarkSet::on_iteration(map->thread(), result); + } + + return result; +} + +bool frame::is_interpreted_frame_valid(JavaThread* thread) const { + assert(is_interpreted_frame(), "Not an interpreted frame"); + // These are reasonable sanity checks + if (fp() == NULL || (intptr_t(fp()) & (wordSize-1)) != 0) { + return false; + } + if (sp() == NULL || (intptr_t(sp()) & (wordSize-1)) != 0) { + return false; + } + if (fp() + interpreter_frame_initial_sp_offset < sp()) { + return false; + } + // These are hacks to keep us out of trouble. + // The problem with these is that they mask other problems + if (fp() <= sp()) { // this attempts to deal with unsigned comparison above + return false; + } + + // do some validation of frame elements + + // first the method + Method* m = *interpreter_frame_method_addr(); + // validate the method we'd find in this potential sender + if (!Method::is_valid_method(m)) { + return false; + } + + // stack frames shouldn't be much larger than max_stack elements + // this test requires the use of unextended_sp which is the sp as seen by + // the current frame, and not sp which is the "raw" pc which could point + // further because of local variables of the callee method inserted after + // method arguments + if (fp() - unextended_sp() > 1024 + m->max_stack()*Interpreter::stackElementSize) { + return false; + } + + // validate bci/bcx + address bcp = interpreter_frame_bcp(); + if (m->validate_bci_from_bcp(bcp) < 0) { + return false; + } + + // validate constantPoolCache* + ConstantPoolCache* cp = *interpreter_frame_cache_addr(); + if (MetaspaceObj::is_valid(cp) == false) { + return false; + } + + // validate locals + address locals = (address) *interpreter_frame_locals_addr(); + if (locals > thread->stack_base() || locals < (address) fp()) { + return false; + } + + // We'd have to be pretty unlucky to be mislead at this point + return true; +} + +BasicType frame::interpreter_frame_result(oop* oop_result, jvalue* value_result) { + assert(is_interpreted_frame(), "interpreted frame expected"); + Method* method = interpreter_frame_method(); + BasicType type = method->result_type(); + + intptr_t* tos_addr = NULL; + if (method->is_native()) { + tos_addr = (intptr_t*)sp(); + if (type == T_FLOAT || type == T_DOUBLE) { + // This is because we do a push(ltos) after push(dtos) in generate_native_entry. + tos_addr += 2 * Interpreter::stackElementWords; + } + } else { + tos_addr = (intptr_t*)interpreter_frame_tos_address(); + } + + switch (type) { + case T_OBJECT : + case T_ARRAY : { + oop obj; + if (method->is_native()) { + obj = cast_to_oop(at(interpreter_frame_oop_temp_offset)); + } else { + oop* obj_p = (oop*)tos_addr; + obj = (obj_p == NULL) ? (oop)NULL : *obj_p; + } + assert(Universe::is_in_heap_or_null(obj), "sanity check"); + *oop_result = obj; + break; + } + case T_BOOLEAN : value_result->z = *(jboolean*)tos_addr; break; + case T_BYTE : value_result->b = *(jbyte*)tos_addr; break; + case T_CHAR : value_result->c = *(jchar*)tos_addr; break; + case T_SHORT : value_result->s = *(jshort*)tos_addr; break; + case T_INT : value_result->i = *(jint*)tos_addr; break; + case T_LONG : value_result->j = *(jlong*)tos_addr; break; + case T_FLOAT : { + value_result->f = *(jfloat*)tos_addr; + break; + } + case T_DOUBLE : value_result->d = *(jdouble*)tos_addr; break; + case T_VOID : /* Nothing to do */ break; + default : ShouldNotReachHere(); + } + + return type; +} + + +intptr_t* frame::interpreter_frame_tos_at(jint offset) const { + int index = (Interpreter::expr_offset_in_bytes(offset)/wordSize); + return &interpreter_frame_tos_address()[index]; +} + +#ifndef PRODUCT + +#define DESCRIBE_FP_OFFSET(name) \ + values.describe(frame_no, fp() + frame::name##_offset, #name) + +void frame::describe_pd(FrameValues& values, int frame_no) { + if (is_interpreted_frame()) { + DESCRIBE_FP_OFFSET(interpreter_frame_sender_sp); + DESCRIBE_FP_OFFSET(interpreter_frame_last_sp); + DESCRIBE_FP_OFFSET(interpreter_frame_method); + DESCRIBE_FP_OFFSET(interpreter_frame_mdp); + DESCRIBE_FP_OFFSET(interpreter_frame_mirror); + DESCRIBE_FP_OFFSET(interpreter_frame_cache); + DESCRIBE_FP_OFFSET(interpreter_frame_locals); + DESCRIBE_FP_OFFSET(interpreter_frame_bcp); + DESCRIBE_FP_OFFSET(interpreter_frame_initial_sp); + } +} +#endif + +intptr_t *frame::initial_deoptimization_info() { + // Not used on riscv, but we must return something. + return NULL; +} + +intptr_t* frame::real_fp() const { + if (_cb != NULL) { + // use the frame size if valid + int size = _cb->frame_size(); + if (size > 0) { + return unextended_sp() + size; + } + } + // else rely on fp() + assert(!is_compiled_frame(), "unknown compiled frame size"); + return fp(); +} + +#undef DESCRIBE_FP_OFFSET + +#ifndef PRODUCT +// This is a generic constructor which is only used by pns() in debug.cpp. +frame::frame(void* ptr_sp, void* ptr_fp, void* pc) { + init((intptr_t*)ptr_sp, (intptr_t*)ptr_fp, (address)pc); +} + +#endif + +void JavaFrameAnchor::make_walkable(JavaThread* thread) { + // last frame set? + if (last_Java_sp() == NULL) { return; } + // already walkable? + if (walkable()) { return; } + vmassert(Thread::current() == (Thread*)thread, "not current thread"); + vmassert(last_Java_sp() != NULL, "not called from Java code?"); + vmassert(last_Java_pc() == NULL, "already walkable"); + capture_last_Java_pc(); + vmassert(walkable(), "something went wrong"); +} + +void JavaFrameAnchor::capture_last_Java_pc() { + vmassert(_last_Java_sp != NULL, "no last frame set"); + vmassert(_last_Java_pc == NULL, "already walkable"); + _last_Java_pc = (address)_last_Java_sp[-1]; +} diff --git a/src/hotspot/cpu/riscv/frame_riscv.hpp b/src/hotspot/cpu/riscv/frame_riscv.hpp new file mode 100644 index 00000000000..c06aaa9e391 --- /dev/null +++ b/src/hotspot/cpu/riscv/frame_riscv.hpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_FRAME_RISCV_HPP +#define CPU_RISCV_FRAME_RISCV_HPP + +#include "runtime/synchronizer.hpp" + +// A frame represents a physical stack frame (an activation). Frames can be +// C or Java frames, and the Java frames can be interpreted or compiled. +// In contrast, vframes represent source-level activations, so that one physical frame +// can correspond to multiple source level frames because of inlining. +// A frame is comprised of {pc, fp, sp} +// ------------------------------ Asm interpreter ---------------------------------------- +// Layout of asm interpreter frame: +// [expression stack ] * <- sp + +// [monitors[0] ] \ +// ... | monitor block size = k +// [monitors[k-1] ] / +// [frame initial esp ] ( == &monitors[0], initially here) initial_sp_offset +// [byte code index/pointr] = bcx() bcx_offset + +// [pointer to locals ] = locals() locals_offset +// [constant pool cache ] = cache() cache_offset + +// [klass of method ] = mirror() mirror_offset +// [padding ] + +// [methodData ] = mdp() mdx_offset +// [Method ] = method() method_offset + +// [last esp ] = last_sp() last_sp_offset +// [old stack pointer ] (sender_sp) sender_sp_offset + +// [old frame pointer ] +// [return pc ] + +// [last sp ] <- fp = link() +// [oop temp ] (only for native calls) + +// [padding ] (to preserve machine SP alignment) +// [locals and parameters ] +// <- sender sp +// ------------------------------ Asm interpreter ---------------------------------------- + +// ------------------------------ C Frame ------------------------------------------------ +// Stack: gcc with -fno-omit-frame-pointer +// . +// . +// +-> . +// | +-----------------+ | +// | | return address | | +// | | previous fp ------+ +// | | saved registers | +// | | local variables | +// | | ... | <-+ +// | +-----------------+ | +// | | return address | | +// +------ previous fp | | +// | saved registers | | +// | local variables | | +// +-> | ... | | +// | +-----------------+ | +// | | return address | | +// | | previous fp ------+ +// | | saved registers | +// | | local variables | +// | | ... | <-+ +// | +-----------------+ | +// | | return address | | +// +------ previous fp | | +// | saved registers | | +// | local variables | | +// $fp --> | ... | | +// +-----------------+ | +// | return address | | +// | previous fp ------+ +// | saved registers | +// $sp --> | local variables | +// +-----------------+ +// ------------------------------ C Frame ------------------------------------------------ + + public: + enum { + pc_return_offset = 0, + // All frames + link_offset = -2, + return_addr_offset = -1, + sender_sp_offset = 0, + // Interpreter frames + interpreter_frame_oop_temp_offset = 1, // for native calls only + + interpreter_frame_sender_sp_offset = -3, + // outgoing sp before a call to an invoked method + interpreter_frame_last_sp_offset = interpreter_frame_sender_sp_offset - 1, + interpreter_frame_method_offset = interpreter_frame_last_sp_offset - 1, + interpreter_frame_mdp_offset = interpreter_frame_method_offset - 1, + interpreter_frame_padding_offset = interpreter_frame_mdp_offset - 1, + interpreter_frame_mirror_offset = interpreter_frame_padding_offset - 1, + interpreter_frame_cache_offset = interpreter_frame_mirror_offset - 1, + interpreter_frame_locals_offset = interpreter_frame_cache_offset - 1, + interpreter_frame_bcp_offset = interpreter_frame_locals_offset - 1, + interpreter_frame_initial_sp_offset = interpreter_frame_bcp_offset - 1, + + interpreter_frame_monitor_block_top_offset = interpreter_frame_initial_sp_offset, + interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset, + + // Entry frames + // n.b. these values are determined by the layout defined in + // stubGenerator for the Java call stub + entry_frame_after_call_words = 22, + entry_frame_call_wrapper_offset = -10, + + // we don't need a save area + arg_reg_save_area_bytes = 0 + }; + + intptr_t ptr_at(int offset) const { + return *ptr_at_addr(offset); + } + + void ptr_at_put(int offset, intptr_t value) { + *ptr_at_addr(offset) = value; + } + + private: + // an additional field beyond _sp and _pc: + intptr_t* _fp; // frame pointer + // The interpreter and adapters will extend the frame of the caller. + // Since oopMaps are based on the sp of the caller before extension + // we need to know that value. However in order to compute the address + // of the return address we need the real "raw" sp. Since sparc already + // uses sp() to mean "raw" sp and unextended_sp() to mean the caller's + // original sp we use that convention. + + intptr_t* _unextended_sp; + void adjust_unextended_sp(); + + intptr_t* ptr_at_addr(int offset) const { + return (intptr_t*) addr_at(offset); + } + +#ifdef ASSERT + // Used in frame::sender_for_{interpreter,compiled}_frame + static void verify_deopt_original_pc( CompiledMethod* nm, intptr_t* unextended_sp); +#endif + + public: + // Constructors + + frame(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc); + + frame(intptr_t* ptr_sp, intptr_t* unextended_sp, intptr_t* ptr_fp, address pc); + + frame(intptr_t* ptr_sp, intptr_t* ptr_fp); + + void init(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc); + + // accessors for the instance variables + // Note: not necessarily the real 'frame pointer' (see real_fp) + intptr_t* fp() const { return _fp; } + + inline address* sender_pc_addr() const; + + // expression stack tos if we are nested in a java call + intptr_t* interpreter_frame_last_sp() const; + + // helper to update a map with callee-saved RBP + static void update_map_with_saved_link(RegisterMap* map, intptr_t** link_addr); + + // deoptimization support + void interpreter_frame_set_last_sp(intptr_t* last_sp); + + static jint interpreter_frame_expression_stack_direction() { return -1; } + + // returns the sending frame, without applying any barriers + frame sender_raw(RegisterMap* map) const; + +#endif // CPU_RISCV_FRAME_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp new file mode 100644 index 00000000000..5ac1bf57f57 --- /dev/null +++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_FRAME_RISCV_INLINE_HPP +#define CPU_RISCV_FRAME_RISCV_INLINE_HPP + +#include "code/codeCache.hpp" +#include "code/vmreg.inline.hpp" + +// Inline functions for RISCV frames: + +// Constructors: + +inline frame::frame() { + _pc = NULL; + _sp = NULL; + _unextended_sp = NULL; + _fp = NULL; + _cb = NULL; + _deopt_state = unknown; +} + +static int spin; + +inline void frame::init(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc) { + intptr_t a = intptr_t(ptr_sp); + intptr_t b = intptr_t(ptr_fp); + _sp = ptr_sp; + _unextended_sp = ptr_sp; + _fp = ptr_fp; + _pc = pc; + assert(pc != NULL, "no pc?"); + _cb = CodeCache::find_blob(pc); + adjust_unextended_sp(); + + address original_pc = CompiledMethod::get_deopt_original_pc(this); + if (original_pc != NULL) { + _pc = original_pc; + _deopt_state = is_deoptimized; + } else { + _deopt_state = not_deoptimized; + } +} + +inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc) { + init(ptr_sp, ptr_fp, pc); +} + +inline frame::frame(intptr_t* ptr_sp, intptr_t* unextended_sp, intptr_t* ptr_fp, address pc) { + intptr_t a = intptr_t(ptr_sp); + intptr_t b = intptr_t(ptr_fp); + _sp = ptr_sp; + _unextended_sp = unextended_sp; + _fp = ptr_fp; + _pc = pc; + assert(pc != NULL, "no pc?"); + _cb = CodeCache::find_blob(pc); + adjust_unextended_sp(); + + address original_pc = CompiledMethod::get_deopt_original_pc(this); + if (original_pc != NULL) { + _pc = original_pc; + assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc), + "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); + _deopt_state = is_deoptimized; + } else { + _deopt_state = not_deoptimized; + } +} + +inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp) { + intptr_t a = intptr_t(ptr_sp); + intptr_t b = intptr_t(ptr_fp); + _sp = ptr_sp; + _unextended_sp = ptr_sp; + _fp = ptr_fp; + _pc = (address)(ptr_sp[-1]); + + // Here's a sticky one. This constructor can be called via AsyncGetCallTrace + // when last_Java_sp is non-null but the pc fetched is junk. If we are truly + // unlucky the junk value could be to a zombied method and we'll die on the + // find_blob call. This is also why we can have no asserts on the validity + // of the pc we find here. AsyncGetCallTrace -> pd_get_top_frame_for_signal_handler + // -> pd_last_frame should use a specialized version of pd_last_frame which could + // call a specilaized frame constructor instead of this one. + // Then we could use the assert below. However this assert is of somewhat dubious + // value. + + _cb = CodeCache::find_blob(_pc); + adjust_unextended_sp(); + + address original_pc = CompiledMethod::get_deopt_original_pc(this); + if (original_pc != NULL) { + _pc = original_pc; + _deopt_state = is_deoptimized; + } else { + _deopt_state = not_deoptimized; + } +} + +// Accessors + +inline bool frame::equal(frame other) const { + bool ret = sp() == other.sp() && + unextended_sp() == other.unextended_sp() && + fp() == other.fp() && + pc() == other.pc(); + assert(!ret || ret && cb() == other.cb() && _deopt_state == other._deopt_state, "inconsistent construction"); + return ret; +} + +// Return unique id for this frame. The id must have a value where we can distinguish +// identity and younger/older relationship. NULL represents an invalid (incomparable) +// frame. +inline intptr_t* frame::id(void) const { return unextended_sp(); } + +// Return true if the frame is older (less recent activation) than the frame represented by id +inline bool frame::is_older(intptr_t* id) const { assert(this->id() != NULL && id != NULL, "NULL frame id"); + return this->id() > id ; } + +inline intptr_t* frame::link() const { return (intptr_t*) *(intptr_t **)addr_at(link_offset); } + +inline intptr_t* frame::link_or_null() const { + intptr_t** ptr = (intptr_t **)addr_at(link_offset); + return os::is_readable_pointer(ptr) ? *ptr : NULL; +} + +inline intptr_t* frame::unextended_sp() const { return _unextended_sp; } + +// Return address +inline address* frame::sender_pc_addr() const { return (address*) addr_at(return_addr_offset); } +inline address frame::sender_pc() const { return *sender_pc_addr(); } +inline intptr_t* frame::sender_sp() const { return addr_at(sender_sp_offset); } + +inline intptr_t** frame::interpreter_frame_locals_addr() const { + return (intptr_t**)addr_at(interpreter_frame_locals_offset); +} + +inline intptr_t* frame::interpreter_frame_last_sp() const { + return *(intptr_t**)addr_at(interpreter_frame_last_sp_offset); +} + +inline intptr_t* frame::interpreter_frame_bcp_addr() const { + return (intptr_t*)addr_at(interpreter_frame_bcp_offset); +} + +inline intptr_t* frame::interpreter_frame_mdp_addr() const { + return (intptr_t*)addr_at(interpreter_frame_mdp_offset); +} + + +// Constant pool cache + +inline ConstantPoolCache** frame::interpreter_frame_cache_addr() const { + return (ConstantPoolCache**)addr_at(interpreter_frame_cache_offset); +} + +// Method + +inline Method** frame::interpreter_frame_method_addr() const { + return (Method**)addr_at(interpreter_frame_method_offset); +} + +// Mirror + +inline oop* frame::interpreter_frame_mirror_addr() const { + return (oop*)addr_at(interpreter_frame_mirror_offset); +} + +// top of expression stack +inline intptr_t* frame::interpreter_frame_tos_address() const { + intptr_t* last_sp = interpreter_frame_last_sp(); + if (last_sp == NULL) { + return sp(); + } else { + // sp() may have been extended or shrunk by an adapter. At least + // check that we don't fall behind the legal region. + // For top deoptimized frame last_sp == interpreter_frame_monitor_end. + assert(last_sp <= (intptr_t*) interpreter_frame_monitor_end(), "bad tos"); + return last_sp; + } +} + +inline oop* frame::interpreter_frame_temp_oop_addr() const { + return (oop *)(fp() + interpreter_frame_oop_temp_offset); +} + +inline int frame::interpreter_frame_monitor_size() { + return BasicObjectLock::size(); +} + + +// expression stack +// (the max_stack arguments are used by the GC; see class FrameClosure) + +inline intptr_t* frame::interpreter_frame_expression_stack() const { + intptr_t* monitor_end = (intptr_t*) interpreter_frame_monitor_end(); + return monitor_end-1; +} + + +// Entry frames + +inline JavaCallWrapper** frame::entry_frame_call_wrapper_addr() const { + return (JavaCallWrapper**)addr_at(entry_frame_call_wrapper_offset); +} + + +// Compiled frames +PRAGMA_DIAG_PUSH +PRAGMA_NONNULL_IGNORED +inline oop frame::saved_oop_result(RegisterMap* map) const { + oop* result_adr = (oop *)map->location(x10->as_VMReg()); + guarantee(result_adr != NULL, "bad register save location"); + return (*result_adr); +} + +inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) { + oop* result_adr = (oop *)map->location(x10->as_VMReg()); + guarantee(result_adr != NULL, "bad register save location"); + *result_adr = obj; +} +PRAGMA_DIAG_POP + +#endif // CPU_RISCV_FRAME_RISCV_INLINE_HPP diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp new file mode 100644 index 00000000000..1c46b3947d3 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.cpp @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "gc/g1/g1BarrierSet.hpp" +#include "gc/g1/g1BarrierSetAssembler.hpp" +#include "gc/g1/g1BarrierSetRuntime.hpp" +#include "gc/g1/g1CardTable.hpp" +#include "gc/g1/g1ThreadLocalData.hpp" +#include "gc/g1/heapRegion.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "interpreter/interp_masm.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/thread.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/g1/c1/g1BarrierSetC1.hpp" +#endif + +#define __ masm-> + +void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register addr, Register count, RegSet saved_regs) { + assert_cond(masm != NULL); + bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; + if (!dest_uninitialized) { + Label done; + Address in_progress(xthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwu(t0, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbu(t0, in_progress); + } + __ beqz(t0, done); + + __ push_reg(saved_regs, sp); + if (count == c_rarg0) { + if (addr == c_rarg1) { + // exactly backwards!! + __ mv(t0, c_rarg0); + __ mv(c_rarg0, c_rarg1); + __ mv(c_rarg1, t0); + } else { + __ mv(c_rarg1, count); + __ mv(c_rarg0, addr); + } + } else { + __ mv(c_rarg0, addr); + __ mv(c_rarg1, count); + } + if (UseCompressedOops) { + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_narrow_oop_entry), 2); + } else { + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_pre_oop_entry), 2); + } + __ pop_reg(saved_regs, sp); + + __ bind(done); + } +} + +void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register start, Register count, Register tmp, RegSet saved_regs) { + assert_cond(masm != NULL); + __ push_reg(saved_regs, sp); + assert_different_registers(start, count, tmp); + assert_different_registers(c_rarg0, count); + __ mv(c_rarg0, start); + __ mv(c_rarg1, count); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2); + __ pop_reg(saved_regs, sp); +} + +void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + bool tosca_live, + bool expand_call) { + // If expand_call is true then we expand the call_VM_leaf macro + // directly to skip generating the check by + // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. + + assert_cond(masm != NULL); + assert(thread == xthread, "must be"); + + Label done; + Label runtime; + + assert_different_registers(obj, pre_val, tmp, t0); + assert(pre_val != noreg && tmp != noreg, "expecting a register"); + + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + Address index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); + Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); + + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { // 4-byte width + __ lwu(tmp, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbu(tmp, in_progress); + } + __ beqz(tmp, done); + + // Do we need to load the previous value? + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + } + + // Is the previous value null? + __ beqz(pre_val, done); + + // Can we store original value in the thread's buffer? + // Is index == 0? + // (The index field is typed as size_t.) + + __ ld(tmp, index); // tmp := *index_adr + __ beqz(tmp, runtime); // tmp == 0? + // If yes, goto runtime + + __ sub(tmp, tmp, wordSize); // tmp := tmp - wordSize + __ sd(tmp, index); // *index_adr := tmp + __ ld(t0, buffer); + __ add(tmp, tmp, t0); // tmp := tmp + *buffer_adr + + // Record the previous value + __ sd(pre_val, Address(tmp, 0)); + __ j(done); + + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(pre_val); + if (tosca_live) { saved += RegSet::of(x10); } + if (obj != noreg) { saved += RegSet::of(obj); } + + __ push_reg(saved, sp); + + if (expand_call) { + assert(pre_val != c_rarg1, "smashed arg"); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); + } else { + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); + } + + __ pop_reg(saved, sp); + + __ bind(done); + +} + +void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp, + Register tmp2) { + assert_cond(masm != NULL); + assert(thread == xthread, "must be"); + assert_different_registers(store_addr, new_val, thread, tmp, tmp2, + t0); + assert(store_addr != noreg && new_val != noreg && tmp != noreg && + tmp2 != noreg, "expecting a register"); + + Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); + Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); + + BarrierSet* bs = BarrierSet::barrier_set(); + CardTableBarrierSet* ctbs = barrier_set_cast(bs); + CardTable* ct = ctbs->card_table(); + + Label done; + Label runtime; + + // Does store cross heap regions? + + __ xorr(tmp, store_addr, new_val); + __ srli(tmp, tmp, HeapRegion::LogOfHRGrainBytes); + __ beqz(tmp, done); + + // crosses regions, storing NULL? + + __ beqz(new_val, done); + + // storing region crossing non-NULL, is card already dirty? + + ExternalAddress cardtable((address) ct->byte_map_base()); + const Register card_addr = tmp; + + __ srli(card_addr, store_addr, CardTable::card_shift()); + + // get the address of the card + __ load_byte_map_base(tmp2); + __ add(card_addr, card_addr, tmp2); + __ lbu(tmp2, Address(card_addr)); + __ mv(t0, (int)G1CardTable::g1_young_card_val()); + __ beq(tmp2, t0, done); + + assert((int)CardTable::dirty_card_val() == 0, "must be 0"); + + __ membar(MacroAssembler::StoreLoad); + + __ lbu(tmp2, Address(card_addr)); + __ beqz(tmp2, done); + + // storing a region crossing, non-NULL oop, card is clean. + // dirty card and log. + + __ sb(zr, Address(card_addr)); + + __ ld(t0, queue_index); + __ beqz(t0, runtime); + __ sub(t0, t0, wordSize); + __ sd(t0, queue_index); + + __ ld(tmp2, buffer); + __ add(t0, tmp2, t0); + __ sd(card_addr, Address(t0, 0)); + __ j(done); + + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(store_addr); + __ push_reg(saved, sp); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); + __ pop_reg(saved, sp); + + __ bind(done); +} + +void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register dst, Address src, Register tmp1, Register tmp_thread) { + assert_cond(masm != NULL); + bool on_oop = is_reference_type(type); + bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0; + bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0; + bool on_reference = on_weak || on_phantom; + ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + if (on_oop && on_reference) { + // RA is live. It must be saved around calls. + __ enter(); // barrier may call runtime + // Generate the G1 pre-barrier code to log the value of + // the referent field in an SATB buffer. + g1_write_barrier_pre(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + xthread /* thread */, + tmp1 /* tmp */, + true /* tosca_live */, + true /* expand_call */); + __ leave(); + } +} + +void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2) { + assert_cond(masm != NULL); + // flatten object address if needed + if (dst.offset() == 0) { + if (dst.base() != x13) { + __ mv(x13, dst.base()); + } + } else { + __ la(x13, dst); + } + + g1_write_barrier_pre(masm, + x13 /* obj */, + tmp2 /* pre_val */, + xthread /* thread */, + tmp1 /* tmp */, + val != noreg /* tosca_live */, + false /* expand_call */); + + if (val == noreg) { + BarrierSetAssembler::store_at(masm, decorators, type, Address(x13, 0), noreg, noreg, noreg); + } else { + // G1 barrier needs uncompressed oop for region cross check. + Register new_val = val; + if (UseCompressedOops) { + new_val = t1; + __ mv(new_val, val); + } + BarrierSetAssembler::store_at(masm, decorators, type, Address(x13, 0), val, noreg, noreg); + g1_write_barrier_post(masm, + x13 /* store_adr */, + new_val /* new_val */, + xthread /* thread */, + tmp1 /* tmp */, + tmp2 /* tmp2 */); + } +} + +#ifdef COMPILER1 + +#undef __ +#define __ ce->masm()-> + +void G1BarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + __ bind(*stub->entry()); + + assert(stub->pre_val()->is_register(), "Precondition."); + + Register pre_val_reg = stub->pre_val()->as_register(); + + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /* wide */); + } + __ beqz(pre_val_reg, *stub->continuation(), /* is_far */ true); + ce->store_parameter(stub->pre_val()->as_register(), 0); + __ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); + __ j(*stub->continuation()); +} + +void G1BarrierSetAssembler::gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub) { + G1BarrierSetC1* bs = (G1BarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + assert(stub->addr()->is_register(), "Precondition"); + assert(stub->new_val()->is_register(), "Precondition"); + Register new_val_reg = stub->new_val()->as_register(); + __ beqz(new_val_reg, *stub->continuation(), /* is_far */ true); + ce->store_parameter(stub->addr()->as_pointer_register(), 0); + __ far_call(RuntimeAddress(bs->post_barrier_c1_runtime_code_blob()->code_begin())); + __ j(*stub->continuation()); +} + +#undef __ + +#define __ sasm-> + +void G1BarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("g1_pre_barrier", false); + + BarrierSet* bs = BarrierSet::barrier_set(); + + // arg0 : previous value of memory + const Register pre_val = x10; + const Register thread = xthread; + const Register tmp = t0; + + Address in_progress(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset())); + Address queue_index(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset())); + Address buffer(thread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset())); + + Label done; + Label runtime; + + // Is marking still active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { // 4-byte width + __ lwu(tmp, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbu(tmp, in_progress); + } + __ beqz(tmp, done); + + // Can we store original value in the thread's buffer? + __ ld(tmp, queue_index); + __ beqz(tmp, runtime); + + __ sub(tmp, tmp, wordSize); + __ sd(tmp, queue_index); + __ ld(t1, buffer); + __ add(tmp, tmp, t1); + __ load_parameter(0, t1); + __ sd(t1, Address(tmp, 0)); + __ j(done); + + __ bind(runtime); + __ push_call_clobbered_registers(); + __ load_parameter(0, pre_val); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_pre_entry), pre_val, thread); + __ pop_call_clobbered_registers(); + __ bind(done); + + __ epilogue(); +} + +void G1BarrierSetAssembler::generate_c1_post_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("g1_post_barrier", false); + + // arg0 : store_address + Address store_addr(fp, 2 * BytesPerWord); // 2 BytesPerWord from fp + + BarrierSet* bs = BarrierSet::barrier_set(); + CardTableBarrierSet* ctbs = barrier_set_cast(bs); + CardTable* ct = ctbs->card_table(); + + Label done; + Label runtime; + + // At this point we know new_value is non-NULL and the new_value crosses regions. + // Must check to see if card is already dirty + const Register thread = xthread; + + Address queue_index(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset())); + Address buffer(thread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset())); + + const Register card_offset = t1; + // RA is free here, so we can use it to hold the byte_map_base. + const Register byte_map_base = ra; + + assert_different_registers(card_offset, byte_map_base, t0); + + __ load_parameter(0, card_offset); + __ srli(card_offset, card_offset, CardTable::card_shift()); + __ load_byte_map_base(byte_map_base); + + // Convert card offset into an address in card_addr + Register card_addr = card_offset; + __ add(card_addr, byte_map_base, card_addr); + + __ lbu(t0, Address(card_addr, 0)); + __ sub(t0, t0, (int)G1CardTable::g1_young_card_val()); + __ beqz(t0, done); + + assert((int)CardTable::dirty_card_val() == 0, "must be 0"); + + __ membar(MacroAssembler::StoreLoad); + __ lbu(t0, Address(card_addr, 0)); + __ beqz(t0, done); + + // storing region crossing non-NULL, card is clean. + // dirty card and log. + __ sb(zr, Address(card_addr, 0)); + + __ ld(t0, queue_index); + __ beqz(t0, runtime); + __ sub(t0, t0, wordSize); + __ sd(t0, queue_index); + + // Reuse RA to hold buffer_addr + const Register buffer_addr = ra; + + __ ld(buffer_addr, buffer); + __ add(t0, buffer_addr, t0); + __ sd(card_addr, Address(t0, 0)); + __ j(done); + + __ bind(runtime); + __ push_call_clobbered_registers(); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_field_post_entry), card_addr, thread); + __ pop_call_clobbered_registers(); + __ bind(done); + __ epilogue(); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp new file mode 100644 index 00000000000..37bc183f39c --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/g1/g1BarrierSetAssembler_riscv.hpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GC_G1_G1BARRIERSETASSEMBLER_RISCV_HPP +#define CPU_RISCV_GC_G1_G1BARRIERSETASSEMBLER_RISCV_HPP + +#include "asm/macroAssembler.hpp" +#include "gc/shared/modRefBarrierSetAssembler.hpp" +#include "utilities/macros.hpp" + +#ifdef COMPILER1 +class LIR_Assembler; +#endif +class StubAssembler; +class G1PreBarrierStub; +class G1PostBarrierStub; + +class G1BarrierSetAssembler: public ModRefBarrierSetAssembler { +protected: + void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register addr, Register count, RegSet saved_regs); + void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register start, Register count, Register tmp, RegSet saved_regs); + + void g1_write_barrier_pre(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + bool tosca_live, + bool expand_call); + + void g1_write_barrier_post(MacroAssembler* masm, + Register store_addr, + Register new_val, + Register thread, + Register tmp, + Register tmp2); + + virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2); + +public: +#ifdef COMPILER1 + void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub); + void gen_post_barrier_stub(LIR_Assembler* ce, G1PostBarrierStub* stub); + + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + void generate_c1_post_barrier_runtime_stub(StubAssembler* sasm); +#endif + + void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register dst, Address src, Register tmp1, Register tmp_thread); +}; + +#endif // CPU_RISCV_GC_G1_G1BARRIERSETASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/g1/g1Globals_riscv.hpp b/src/hotspot/cpu/riscv/gc/g1/g1Globals_riscv.hpp new file mode 100644 index 00000000000..8735fd014ff --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/g1/g1Globals_riscv.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GC_G1_G1GLOBALS_RISCV_HPP +#define CPU_RISCV_GC_G1_G1GLOBALS_RISCV_HPP + +const size_t G1MergeHeapRootsPrefetchCacheSize = 16; + +#endif // CPU_RISCV_GC_G1_G1GLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp new file mode 100644 index 00000000000..3c115a2ea02 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "classfile/classLoaderData.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "gc/shared/barrierSetNMethod.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "interpreter/interp_masm.hpp" +#include "memory/universe.hpp" +#include "runtime/jniHandles.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/thread.hpp" + +#define __ masm-> + +void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register dst, Address src, Register tmp1, Register tmp_thread) { + assert_cond(masm != NULL); + + // RA is live. It must be saved around calls. + + bool in_heap = (decorators & IN_HEAP) != 0; + bool in_native = (decorators & IN_NATIVE) != 0; + bool is_not_null = (decorators & IS_NOT_NULL) != 0; + switch (type) { + case T_OBJECT: // fall through + case T_ARRAY: { + if (in_heap) { + if (UseCompressedOops) { + __ lwu(dst, src); + if (is_not_null) { + __ decode_heap_oop_not_null(dst); + } else { + __ decode_heap_oop(dst); + } + } else { + __ ld(dst, src); + } + } else { + assert(in_native, "why else?"); + __ ld(dst, src); + } + break; + } + case T_BOOLEAN: __ load_unsigned_byte (dst, src); break; + case T_BYTE: __ load_signed_byte (dst, src); break; + case T_CHAR: __ load_unsigned_short(dst, src); break; + case T_SHORT: __ load_signed_short (dst, src); break; + case T_INT: __ lw (dst, src); break; + case T_LONG: __ ld (dst, src); break; + case T_ADDRESS: __ ld (dst, src); break; + case T_FLOAT: __ flw (f10, src); break; + case T_DOUBLE: __ fld (f10, src); break; + default: Unimplemented(); + } +} + +void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2) { + assert_cond(masm != NULL); + bool in_heap = (decorators & IN_HEAP) != 0; + bool in_native = (decorators & IN_NATIVE) != 0; + switch (type) { + case T_OBJECT: // fall through + case T_ARRAY: { + val = val == noreg ? zr : val; + if (in_heap) { + if (UseCompressedOops) { + assert(!dst.uses(val), "not enough registers"); + if (val != zr) { + __ encode_heap_oop(val); + } + __ sw(val, dst); + } else { + __ sd(val, dst); + } + } else { + assert(in_native, "why else?"); + __ sd(val, dst); + } + break; + } + case T_BOOLEAN: + __ andi(val, val, 0x1); // boolean is true if LSB is 1 + __ sb(val, dst); + break; + case T_BYTE: __ sb(val, dst); break; + case T_CHAR: __ sh(val, dst); break; + case T_SHORT: __ sh(val, dst); break; + case T_INT: __ sw(val, dst); break; + case T_LONG: __ sd(val, dst); break; + case T_ADDRESS: __ sd(val, dst); break; + case T_FLOAT: __ fsw(f10, dst); break; + case T_DOUBLE: __ fsd(f10, dst); break; + default: Unimplemented(); + } + +} + +void BarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath) { + assert_cond(masm != NULL); + // If mask changes we need to ensure that the inverse is still encodable as an immediate + STATIC_ASSERT(JNIHandles::weak_tag_mask == 1); + __ andi(obj, obj, ~JNIHandles::weak_tag_mask); + __ ld(obj, Address(obj, 0)); // *obj +} + +// Defines obj, preserves var_size_in_bytes, okay for tmp2 == var_size_in_bytes. +void BarrierSetAssembler::tlab_allocate(MacroAssembler* masm, Register obj, + Register var_size_in_bytes, + int con_size_in_bytes, + Register tmp1, + Register tmp2, + Label& slow_case, + bool is_far) { + assert_cond(masm != NULL); + assert_different_registers(obj, tmp2); + assert_different_registers(obj, var_size_in_bytes); + Register end = tmp2; + + __ ld(obj, Address(xthread, JavaThread::tlab_top_offset())); + if (var_size_in_bytes == noreg) { + __ la(end, Address(obj, con_size_in_bytes)); + } else { + __ add(end, obj, var_size_in_bytes); + } + __ ld(t0, Address(xthread, JavaThread::tlab_end_offset())); + __ bgtu(end, t0, slow_case, is_far); + + // update the tlab top pointer + __ sd(end, Address(xthread, JavaThread::tlab_top_offset())); + + // recover var_size_in_bytes if necessary + if (var_size_in_bytes == end) { + __ sub(var_size_in_bytes, var_size_in_bytes, obj); + } +} + +// Defines obj, preserves var_size_in_bytes +void BarrierSetAssembler::eden_allocate(MacroAssembler* masm, Register obj, + Register var_size_in_bytes, + int con_size_in_bytes, + Register tmp1, + Label& slow_case, + bool is_far) { + assert_cond(masm != NULL); + assert_different_registers(obj, var_size_in_bytes, tmp1); + if (!Universe::heap()->supports_inline_contig_alloc()) { + __ j(slow_case); + } else { + Register end = tmp1; + Label retry; + __ bind(retry); + + // Get the current end of the heap + ExternalAddress address_end((address) Universe::heap()->end_addr()); + { + int32_t offset; + __ la_patchable(t1, address_end, offset); + __ ld(t1, Address(t1, offset)); + } + + // Get the current top of the heap + ExternalAddress address_top((address) Universe::heap()->top_addr()); + { + int32_t offset; + __ la_patchable(t0, address_top, offset); + __ addi(t0, t0, offset); + __ lr_d(obj, t0, Assembler::aqrl); + } + + // Adjust it my the size of our new object + if (var_size_in_bytes == noreg) { + __ la(end, Address(obj, con_size_in_bytes)); + } else { + __ add(end, obj, var_size_in_bytes); + } + + // if end < obj then we wrapped around high memory + __ bltu(end, obj, slow_case, is_far); + + __ bgtu(end, t1, slow_case, is_far); + + // If heap_top hasn't been changed by some other thread, update it. + __ sc_d(t1, end, t0, Assembler::rl); + __ bnez(t1, retry); + + incr_allocated_bytes(masm, var_size_in_bytes, con_size_in_bytes, tmp1); + } +} + +void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, + Register var_size_in_bytes, + int con_size_in_bytes, + Register tmp1) { + assert_cond(masm != NULL); + assert(tmp1->is_valid(), "need temp reg"); + + __ ld(tmp1, Address(xthread, in_bytes(JavaThread::allocated_bytes_offset()))); + if (var_size_in_bytes->is_valid()) { + __ add(tmp1, tmp1, var_size_in_bytes); + } else { + __ add(tmp1, tmp1, con_size_in_bytes); + } + __ sd(tmp1, Address(xthread, in_bytes(JavaThread::allocated_bytes_offset()))); +} + +void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) { + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + + if (bs_nm == NULL) { + return; + } + + // RISCV atomic operations require that the memory address be naturally aligned. + __ align(4); + + Label skip, guard; + Address thread_disarmed_addr(xthread, in_bytes(bs_nm->thread_disarmed_offset())); + + __ lwu(t0, guard); + + // Subsequent loads of oops must occur after load of guard value. + // BarrierSetNMethod::disarm sets guard with release semantics. + __ membar(MacroAssembler::LoadLoad); + __ lwu(t1, thread_disarmed_addr); + __ beq(t0, t1, skip); + + int32_t offset = 0; + __ movptr_with_offset(t0, StubRoutines::riscv::method_entry_barrier(), offset); + __ jalr(ra, t0, offset); + __ j(skip); + + __ bind(guard); + + assert(__ offset() % 4 == 0, "bad alignment"); + __ emit_int32(0); // nmethod guard value. Skipped over in common case. + + __ bind(skip); +} + +void BarrierSetAssembler::c2i_entry_barrier(MacroAssembler* masm) { + BarrierSetNMethod* bs = BarrierSet::barrier_set()->barrier_set_nmethod(); + if (bs == NULL) { + return; + } + + Label bad_call; + __ beqz(xmethod, bad_call); + + // Pointer chase to the method holder to find out if the method is concurrently unloading. + Label method_live; + __ load_method_holder_cld(t0, xmethod); + + // Is it a strong CLD? + __ lwu(t1, Address(t0, ClassLoaderData::keep_alive_offset())); + __ bnez(t1, method_live); + + // Is it a weak but alive CLD? + __ push_reg(RegSet::of(x28, x29), sp); + + __ ld(x28, Address(t0, ClassLoaderData::holder_offset())); + + // Uses x28 & x29, so we must pass new temporaries. + __ resolve_weak_handle(x28, x29); + __ mv(t0, x28); + + __ pop_reg(RegSet::of(x28, x29), sp); + + __ bnez(t0, method_live); + + __ bind(bad_call); + + __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + __ bind(method_live); +} diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp new file mode 100644 index 00000000000..b85f7f5582b --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.hpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GC_SHARED_BARRIERSETASSEMBLER_RISCV_HPP +#define CPU_RISCV_GC_SHARED_BARRIERSETASSEMBLER_RISCV_HPP + +#include "asm/macroAssembler.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetNMethod.hpp" +#include "memory/allocation.hpp" +#include "oops/access.hpp" + +class BarrierSetAssembler: public CHeapObj { +private: + void incr_allocated_bytes(MacroAssembler* masm, + Register var_size_in_bytes, int con_size_in_bytes, + Register t1 = noreg); + +public: + virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, + Register src, Register dst, Register count, RegSet saved_regs) {} + virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, + Register start, Register end, Register tmp, RegSet saved_regs) {} + virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register dst, Address src, Register tmp1, Register tmp_thread); + virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2); + + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath); + + virtual void tlab_allocate(MacroAssembler* masm, + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register tmp1, // temp register + Register tmp2, // temp register + Label& slow_case, // continuation point if fast allocation fails + bool is_far = false + ); + + void eden_allocate(MacroAssembler* masm, + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register tmp1, // temp register + Label& slow_case, // continuation point if fast allocation fails + bool is_far = false + ); + virtual void barrier_stubs_init() {} + + virtual void nmethod_entry_barrier(MacroAssembler* masm); + virtual void c2i_entry_barrier(MacroAssembler* masm); + virtual ~BarrierSetAssembler() {} +}; + +#endif // CPU_RISCV_GC_SHARED_BARRIERSETASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp new file mode 100644 index 00000000000..ae7ee4c5a44 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetNMethod_riscv.cpp @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "code/codeCache.hpp" +#include "code/nativeInst.hpp" +#include "gc/shared/barrierSetNMethod.hpp" +#include "logging/log.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/registerMap.hpp" +#include "runtime/thread.hpp" +#include "utilities/align.hpp" +#include "utilities/debug.hpp" + +class NativeNMethodBarrier: public NativeInstruction { + address instruction_address() const { return addr_at(0); } + + int *guard_addr() { + /* auipc + lwu + fence + lwu + beq + lui + addi + slli + addi + slli + jalr + j */ + return reinterpret_cast(instruction_address() + 12 * 4); + } + +public: + int get_value() { + return Atomic::load_acquire(guard_addr()); + } + + void set_value(int value) { + Atomic::release_store(guard_addr(), value); + } + + void verify() const; +}; + +// Store the instruction bitmask, bits and name for checking the barrier. +struct CheckInsn { + uint32_t mask; + uint32_t bits; + const char *name; +}; + +static const struct CheckInsn barrierInsn[] = { + { 0x00000fff, 0x00000297, "auipc t0, 0 "}, + { 0x000fffff, 0x0002e283, "lwu t0, 48(t0) "}, + { 0xffffffff, 0x0aa0000f, "fence ir, ir "}, + { 0x000fffff, 0x000be303, "lwu t1, 112(xthread)"}, + { 0x01fff07f, 0x00628063, "beq t0, t1, skip "}, + { 0x00000fff, 0x000002b7, "lui t0, imm0 "}, + { 0x000fffff, 0x00028293, "addi t0, t0, imm1 "}, + { 0xffffffff, 0x00b29293, "slli t0, t0, 11 "}, + { 0x000fffff, 0x00028293, "addi t0, t0, imm2 "}, + { 0xffffffff, 0x00529293, "slli t0, t0, 5 "}, + { 0x000fffff, 0x000280e7, "jalr ra, imm3(t0) "}, + { 0x00000fff, 0x0000006f, "j skip "} + /* guard: */ + /* 32bit nmethod guard value */ + /* skip: */ +}; + +// The encodings must match the instructions emitted by +// BarrierSetAssembler::nmethod_entry_barrier. The matching ignores the specific +// register numbers and immediate values in the encoding. +void NativeNMethodBarrier::verify() const { + intptr_t addr = (intptr_t) instruction_address(); + for(unsigned int i = 0; i < sizeof(barrierInsn)/sizeof(struct CheckInsn); i++ ) { + uint32_t inst = *((uint32_t*) addr); + if ((inst & barrierInsn[i].mask) != barrierInsn[i].bits) { + tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", addr, inst); + fatal("not an %s instruction.", barrierInsn[i].name); + } + addr += 4; + } +} + + +/* We're called from an nmethod when we need to deoptimize it. We do + this by throwing away the nmethod's frame and jumping to the + ic_miss stub. This looks like there has been an IC miss at the + entry of the nmethod, so we resolve the call, which will fall back + to the interpreter if the nmethod has been unloaded. */ +void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) { + + typedef struct { + intptr_t *sp; intptr_t *fp; address ra; address pc; + } frame_pointers_t; + + frame_pointers_t *new_frame = (frame_pointers_t *)(return_address_ptr - 5); + + JavaThread *thread = JavaThread::current(); + RegisterMap reg_map(thread, false); + frame frame = thread->last_frame(); + + assert(frame.is_compiled_frame() || frame.is_native_frame(), "must be"); + assert(frame.cb() == nm, "must be"); + frame = frame.sender(®_map); + + LogTarget(Trace, nmethod, barrier) out; + if (out.is_enabled()) { + ResourceMark mark; + log_trace(nmethod, barrier)("deoptimize(nmethod: %s(%p), return_addr: %p, osr: %d, thread: %p(%s), making rsp: %p) -> %p", + nm->method()->name_and_sig_as_C_string(), + nm, *(address *) return_address_ptr, nm->is_osr_method(), thread, + thread->name(), frame.sp(), nm->verified_entry_point()); + } + + new_frame->sp = frame.sp(); + new_frame->fp = frame.fp(); + new_frame->ra = frame.pc(); + new_frame->pc = SharedRuntime::get_handle_wrong_method_stub(); +} + +// This is the offset of the entry barrier from where the frame is completed. +// If any code changes between the end of the verified entry where the entry +// barrier resides, and the completion of the frame, then +// NativeNMethodCmpBarrier::verify() will immediately complain when it does +// not find the expected native instruction at this offset, which needs updating. +// Note that this offset is invariant of PreserveFramePointer. + +// see BarrierSetAssembler::nmethod_entry_barrier +// auipc + lwu + fence + lwu + beq + movptr_with_offset(5 instructions) + jalr + j + int32 +static const int entry_barrier_offset = -4 * 13; + +static NativeNMethodBarrier* native_nmethod_barrier(nmethod* nm) { + address barrier_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset; + NativeNMethodBarrier* barrier = reinterpret_cast(barrier_address); + debug_only(barrier->verify()); + return barrier; +} + +void BarrierSetNMethod::disarm(nmethod* nm) { + if (!supports_entry_barrier(nm)) { + return; + } + + // Disarms the nmethod guard emitted by BarrierSetAssembler::nmethod_entry_barrier. + NativeNMethodBarrier* barrier = native_nmethod_barrier(nm); + + barrier->set_value(disarmed_value()); +} + +bool BarrierSetNMethod::is_armed(nmethod* nm) { + if (!supports_entry_barrier(nm)) { + return false; + } + + NativeNMethodBarrier* barrier = native_nmethod_barrier(nm); + return barrier->get_value() != disarmed_value(); +} diff --git a/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.cpp new file mode 100644 index 00000000000..a419f92b5f6 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/cardTable.hpp" +#include "gc/shared/cardTableBarrierSet.hpp" +#include "gc/shared/cardTableBarrierSetAssembler.hpp" +#include "gc/shared/gc_globals.hpp" +#include "interpreter/interp_masm.hpp" + +#define __ masm-> + + +void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register obj, Register tmp) { + assert_cond(masm != NULL); + assert_different_registers(obj, tmp); + BarrierSet* bs = BarrierSet::barrier_set(); + assert(bs->kind() == BarrierSet::CardTableBarrierSet, "Wrong barrier set kind"); + + __ srli(obj, obj, CardTable::card_shift()); + + assert(CardTable::dirty_card_val() == 0, "must be"); + + __ load_byte_map_base(tmp); + __ add(tmp, obj, tmp); + + if (UseCondCardMark) { + Label L_already_dirty; + __ membar(MacroAssembler::StoreLoad); + __ lbu(t1, Address(tmp)); + __ beqz(t1, L_already_dirty); + __ sb(zr, Address(tmp)); + __ bind(L_already_dirty); + } else { + __ sb(zr, Address(tmp)); + } +} + +void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register start, Register count, Register tmp, RegSet saved_regs) { + assert_cond(masm != NULL); + assert_different_registers(start, tmp); + assert_different_registers(count, tmp); + + Label L_loop, L_done; + const Register end = count; + + __ beqz(count, L_done); // zero count - nothing to do + // end = start + count << LogBytesPerHeapOop + __ shadd(end, count, start, count, LogBytesPerHeapOop); + __ sub(end, end, BytesPerHeapOop); // last element address to make inclusive + + __ srli(start, start, CardTable::card_shift()); + __ srli(end, end, CardTable::card_shift()); + __ sub(count, end, start); // number of bytes to copy + + __ load_byte_map_base(tmp); + __ add(start, start, tmp); + + __ bind(L_loop); + __ add(tmp, start, count); + __ sb(zr, Address(tmp)); + __ sub(count, count, 1); + __ bgez(count, L_loop); + __ bind(L_done); +} + +void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2) { + bool in_heap = (decorators & IN_HEAP) != 0; + bool is_array = (decorators & IS_ARRAY) != 0; + bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0; + bool precise = is_array || on_anonymous; + + bool needs_post_barrier = val != noreg && in_heap; + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, noreg, noreg); + if (needs_post_barrier) { + // flatten object address if needed + if (!precise || dst.offset() == 0) { + store_check(masm, dst.base(), x13); + } else { + assert_cond(masm != NULL); + __ la(x13, dst); + store_check(masm, x13, t0); + } + } +} diff --git a/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.hpp new file mode 100644 index 00000000000..686fe8fa478 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shared/cardTableBarrierSetAssembler_riscv.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_RISCV_HPP +#define CPU_RISCV_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_RISCV_HPP + +#include "asm/macroAssembler.hpp" +#include "gc/shared/modRefBarrierSetAssembler.hpp" + +class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler { +protected: + void store_check(MacroAssembler* masm, Register obj, Register tmp); + + virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register start, Register count, Register tmp, RegSet saved_regs); + virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2); +}; + +#endif // #ifndef CPU_RISCV_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/shared/modRefBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/modRefBarrierSetAssembler_riscv.cpp new file mode 100644 index 00000000000..7aa2015f9ec --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shared/modRefBarrierSetAssembler_riscv.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "gc/shared/modRefBarrierSetAssembler.hpp" + +#define __ masm-> + +void ModRefBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, + Register src, Register dst, Register count, RegSet saved_regs) { + + if (is_oop) { + gen_write_ref_array_pre_barrier(masm, decorators, dst, count, saved_regs); + } +} + +void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, + Register start, Register count, Register tmp, + RegSet saved_regs) { + if (is_oop) { + gen_write_ref_array_post_barrier(masm, decorators, start, count, tmp, saved_regs); + } +} + +void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2) { + if (is_reference_type(type)) { + oop_store_at(masm, decorators, type, dst, val, tmp1, tmp2); + } else { + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); + } +} diff --git a/src/hotspot/cpu/riscv/gc/shared/modRefBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shared/modRefBarrierSetAssembler_riscv.hpp new file mode 100644 index 00000000000..00419c3163c --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shared/modRefBarrierSetAssembler_riscv.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GC_SHARED_MODREFBARRIERSETASSEMBLER_RISCV_HPP +#define CPU_RISCV_GC_SHARED_MODREFBARRIERSETASSEMBLER_RISCV_HPP + +#include "asm/macroAssembler.hpp" +#include "gc/shared/barrierSetAssembler.hpp" + +// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other +// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected +// accesses, which are overridden in the concrete BarrierSetAssembler. + +class ModRefBarrierSetAssembler: public BarrierSetAssembler { +protected: + virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register addr, Register count, RegSet saved_regs) {} + virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, + Register start, Register count, Register tmp, RegSet saved_regs) {} + + virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2) = 0; + +public: + virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, + Register src, Register dst, Register count, RegSet saved_regs); + virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, + Register start, Register count, Register tmp, RegSet saved_regs); + virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2); +}; + +#endif // CPU_RISCV_GC_SHARED_MODREFBARRIERSETASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp new file mode 100644 index 00000000000..cd568cc723f --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shenandoah/c1/shenandoahBarrierSetC1_riscv.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/shared/gc_globals.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" + +#define __ masm->masm()-> + +void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) { + Register addr = _addr->as_register_lo(); + Register newval = _new_value->as_register(); + Register cmpval = _cmp_value->as_register(); + Register tmp1 = _tmp1->as_register(); + Register tmp2 = _tmp2->as_register(); + Register result = result_opr()->as_register(); + + ShenandoahBarrierSet::assembler()->iu_barrier(masm->masm(), newval, t1); + + if (UseCompressedOops) { + __ encode_heap_oop(tmp1, cmpval); + cmpval = tmp1; + __ encode_heap_oop(tmp2, newval); + newval = tmp2; + } + + ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), addr, cmpval, newval, /* acquire */ Assembler::aq, + /* release */ Assembler::rl, /* is_cae */ false, result); +} + +#undef __ + +#ifdef ASSERT +#define __ gen->lir(__FILE__, __LINE__)-> +#else +#define __ gen->lir()-> +#endif + +LIR_Opr ShenandoahBarrierSetC1::atomic_cmpxchg_at_resolved(LIRAccess& access, LIRItem& cmp_value, LIRItem& new_value) { + BasicType bt = access.type(); + if (access.is_oop()) { + LIRGenerator *gen = access.gen(); + if (ShenandoahSATBBarrier) { + pre_barrier(gen, access.access_emit_info(), access.decorators(), access.resolved_addr(), + LIR_OprFact::illegalOpr /* pre_val */); + } + if (ShenandoahCASBarrier) { + cmp_value.load_item(); + new_value.load_item(); + + LIR_Opr tmp1 = gen->new_register(T_OBJECT); + LIR_Opr tmp2 = gen->new_register(T_OBJECT); + LIR_Opr addr = access.resolved_addr()->as_address_ptr()->base(); + LIR_Opr result = gen->new_register(T_INT); + + __ append(new LIR_OpShenandoahCompareAndSwap(addr, cmp_value.result(), new_value.result(), tmp1, tmp2, result)); + return result; + } + } + return BarrierSetC1::atomic_cmpxchg_at_resolved(access, cmp_value, new_value); +} + +LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRItem& value) { + LIRGenerator* gen = access.gen(); + BasicType type = access.type(); + + LIR_Opr result = gen->new_register(type); + value.load_item(); + LIR_Opr value_opr = value.result(); + + if (access.is_oop()) { + value_opr = iu_barrier(access.gen(), value_opr, access.access_emit_info(), access.decorators()); + } + + assert(type == T_INT || is_reference_type(type) LP64_ONLY( || type == T_LONG ), "unexpected type"); + LIR_Opr tmp = gen->new_register(T_INT); + __ xchg(access.resolved_addr(), value_opr, result, tmp); + + if (access.is_oop()) { + result = load_reference_barrier(access.gen(), result, LIR_OprFact::addressConst(0), access.decorators()); + LIR_Opr tmp_opr = gen->new_register(type); + __ move(result, tmp_opr); + result = tmp_opr; + if (ShenandoahSATBBarrier) { + pre_barrier(access.gen(), access.access_emit_info(), access.decorators(), LIR_OprFact::illegalOpr, + result /* pre_val */); + } + } + + return result; +} diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp new file mode 100644 index 00000000000..d0ac6e52436 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2018, 2020, Red Hat, Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" +#include "gc/shenandoah/shenandoahForwarding.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.hpp" +#include "gc/shenandoah/shenandoahRuntime.hpp" +#include "gc/shenandoah/shenandoahThreadLocalData.hpp" +#include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interp_masm.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/thread.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/shenandoah/c1/shenandoahBarrierSetC1.hpp" +#endif + +#define __ masm-> + +void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, + Register src, Register dst, Register count, RegSet saved_regs) { + if (is_oop) { + bool dest_uninitialized = (decorators & IS_DEST_UNINITIALIZED) != 0; + if ((ShenandoahSATBBarrier && !dest_uninitialized) || ShenandoahIUBarrier || ShenandoahLoadRefBarrier) { + + Label done; + + // Avoid calling runtime if count == 0 + __ beqz(count, done); + + // Is GC active? + Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + assert_different_registers(src, dst, count, t0); + + __ lbu(t0, gc_state); + if (ShenandoahSATBBarrier && dest_uninitialized) { + __ andi(t0, t0, ShenandoahHeap::HAS_FORWARDED); + __ beqz(t0, done); + } else { + __ andi(t0, t0, ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::MARKING); + __ beqz(t0, done); + } + + __ push_reg(saved_regs, sp); + if (UseCompressedOops) { + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_narrow_oop_entry), + src, dst, count); + } else { + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::arraycopy_barrier_oop_entry), src, dst, count); + } + __ pop_reg(saved_regs, sp); + __ bind(done); + } + } +} + +void ShenandoahBarrierSetAssembler::shenandoah_write_barrier_pre(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + bool tosca_live, + bool expand_call) { + if (ShenandoahSATBBarrier) { + satb_write_barrier_pre(masm, obj, pre_val, thread, tmp, tosca_live, expand_call); + } +} + +void ShenandoahBarrierSetAssembler::satb_write_barrier_pre(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + bool tosca_live, + bool expand_call) { + // If expand_call is true then we expand the call_VM_leaf macro + // directly to skip generating the check by + // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp. + assert(thread == xthread, "must be"); + + Label done; + Label runtime; + + assert_different_registers(obj, pre_val, tmp, t0); + assert(pre_val != noreg && tmp != noreg, "expecting a register"); + + Address in_progress(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_active_offset())); + Address index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); + Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); + + // Is marking active? + if (in_bytes(SATBMarkQueue::byte_width_of_active()) == 4) { + __ lwu(tmp, in_progress); + } else { + assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "Assumption"); + __ lbu(tmp, in_progress); + } + __ beqz(tmp, done); + + // Do we need to load the previous value? + if (obj != noreg) { + __ load_heap_oop(pre_val, Address(obj, 0), noreg, noreg, AS_RAW); + } + + // Is the previous value null? + __ beqz(pre_val, done); + + // Can we store original value in the thread's buffer? + // Is index == 0? + // (The index field is typed as size_t.) + __ ld(tmp, index); // tmp := *index_adr + __ beqz(tmp, runtime); // tmp == 0? If yes, goto runtime + + __ sub(tmp, tmp, wordSize); // tmp := tmp - wordSize + __ sd(tmp, index); // *index_adr := tmp + __ ld(t0, buffer); + __ add(tmp, tmp, t0); // tmp := tmp + *buffer_adr + + // Record the previous value + __ sd(pre_val, Address(tmp, 0)); + __ j(done); + + __ bind(runtime); + // save the live input values + RegSet saved = RegSet::of(pre_val); + if (tosca_live) saved += RegSet::of(x10); + if (obj != noreg) saved += RegSet::of(obj); + + __ push_reg(saved, sp); + + // Calling the runtime using the regular call_VM_leaf mechanism generates + // code (generated by InterpreterMacroAssember::call_VM_leaf_base) + // that checks that the *(rfp+frame::interpreter_frame_last_sp) == NULL. + // + // If we care generating the pre-barrier without a frame (e.g. in the + // intrinsified Reference.get() routine) then ebp might be pointing to + // the caller frame and so this check will most likely fail at runtime. + // + // Expanding the call directly bypasses the generation of the check. + // So when we do not have have a full interpreter frame on the stack + // expand_call should be passed true. + if (expand_call) { + assert(pre_val != c_rarg1, "smashed arg"); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + } else { + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + } + + __ pop_reg(saved, sp); + + __ bind(done); +} + +void ShenandoahBarrierSetAssembler::resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp) { + assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled"); + + Label is_null; + __ beqz(dst, is_null); + resolve_forward_pointer_not_null(masm, dst, tmp); + __ bind(is_null); +} + +// IMPORTANT: This must preserve all registers, even t0 and t1, except those explicitely +// passed in. +void ShenandoahBarrierSetAssembler::resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp) { + assert(ShenandoahLoadRefBarrier || ShenandoahCASBarrier, "Should be enabled"); + // The below loads the mark word, checks if the lowest two bits are + // set, and if so, clear the lowest two bits and copy the result + // to dst. Otherwise it leaves dst alone. + // Implementing this is surprisingly awkward. I do it here by: + // - Inverting the mark word + // - Test lowest two bits == 0 + // - If so, set the lowest two bits + // - Invert the result back, and copy to dst + RegSet saved_regs = RegSet::of(t2); + bool borrow_reg = (tmp == noreg); + if (borrow_reg) { + // No free registers available. Make one useful. + tmp = t0; + if (tmp == dst) { + tmp = t1; + } + saved_regs += RegSet::of(tmp); + } + + assert_different_registers(tmp, dst, t2); + __ push_reg(saved_regs, sp); + + Label done; + __ ld(tmp, Address(dst, oopDesc::mark_offset_in_bytes())); + __ xori(tmp, tmp, -1); // eon with 0 is equivalent to XOR with -1 + __ andi(t2, tmp, markWord::lock_mask_in_place); + __ bnez(t2, done); + __ ori(tmp, tmp, markWord::marked_value); + __ xori(dst, tmp, -1); // eon with 0 is equivalent to XOR with -1 + __ bind(done); + + __ pop_reg(saved_regs, sp); +} + +void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm, + Register dst, + Address load_addr, + DecoratorSet decorators) { + assert(ShenandoahLoadRefBarrier, "Should be enabled"); + assert(dst != t1 && load_addr.base() != t1, "need t1"); + assert_different_registers(load_addr.base(), t0, t1); + + bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); + bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); + bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); + bool is_native = ShenandoahBarrierSet::is_native_access(decorators); + bool is_narrow = UseCompressedOops && !is_native; + + Label heap_stable, not_cset; + __ enter(); + Address gc_state(xthread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + __ lbu(t1, gc_state); + + // Check for heap stability + if (is_strong) { + __ andi(t1, t1, ShenandoahHeap::HAS_FORWARDED); + __ beqz(t1, heap_stable); + } else { + Label lrb; + __ andi(t0, t1, ShenandoahHeap::WEAK_ROOTS); + __ bnez(t0, lrb); + __ andi(t0, t1, ShenandoahHeap::HAS_FORWARDED); + __ beqz(t0, heap_stable); + __ bind(lrb); + } + + // use x11 for load address + Register result_dst = dst; + if (dst == x11) { + __ mv(t1, dst); + dst = t1; + } + + // Save x10 and x11, unless it is an output register + RegSet saved_regs = RegSet::of(x10, x11) - result_dst; + __ push_reg(saved_regs, sp); + __ la(x11, load_addr); + __ mv(x10, dst); + + // Test for in-cset + if (is_strong) { + __ li(t1, (uint64_t)ShenandoahHeap::in_cset_fast_test_addr()); + __ srli(t0, x10, ShenandoahHeapRegion::region_size_bytes_shift_jint()); + __ add(t1, t1, t0); + __ lbu(t1, Address(t1)); + __ andi(t0, t1, 1); + __ beqz(t0, not_cset); + } + + __ push_call_clobbered_registers(); + if (is_strong) { + if (is_narrow) { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_strong_narrow); + } else { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_strong); + } + } else if (is_weak) { + if (is_narrow) { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_weak_narrow); + } else { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_weak); + } + } else { + assert(is_phantom, "only remaining strength"); + assert(!is_narrow, "phantom access cannot be narrow"); + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_weak); + } + __ jalr(ra); + __ mv(t0, x10); + __ pop_call_clobbered_registers(); + __ mv(x10, t0); + __ bind(not_cset); + __ mv(result_dst, x10); + __ pop_reg(saved_regs, sp); + + __ bind(heap_stable); + __ leave(); +} + +void ShenandoahBarrierSetAssembler::iu_barrier(MacroAssembler* masm, Register dst, Register tmp) { + if (ShenandoahIUBarrier) { + __ push_call_clobbered_registers(); + + satb_write_barrier_pre(masm, noreg, dst, xthread, tmp, true, false); + + __ pop_call_clobbered_registers(); + } +} + +// +// Arguments: +// +// Inputs: +// src: oop location to load from, might be clobbered +// +// Output: +// dst: oop loaded from src location +// +// Kill: +// x30 (tmp reg) +// +// Alias: +// dst: x30 (might use x30 as temporary output register to avoid clobbering src) +// +void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, + DecoratorSet decorators, + BasicType type, + Register dst, + Address src, + Register tmp1, + Register tmp_thread) { + // 1: non-reference load, no additional barrier is needed + if (!is_reference_type(type)) { + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + return; + } + + // 2: load a reference from src location and apply LRB if needed + if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) { + Register result_dst = dst; + + // Preserve src location for LRB + RegSet saved_regs; + if (dst == src.base()) { + dst = (src.base() == x28) ? x29 : x28; + saved_regs = RegSet::of(dst); + __ push_reg(saved_regs, sp); + } + assert_different_registers(dst, src.base()); + + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + + load_reference_barrier(masm, dst, src, decorators); + + if (dst != result_dst) { + __ mv(result_dst, dst); + dst = result_dst; + } + + if (saved_regs.bits() != 0) { + __ pop_reg(saved_regs, sp); + } + } else { + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + } + + // 3: apply keep-alive barrier if needed + if (ShenandoahBarrierSet::need_keep_alive_barrier(decorators, type)) { + __ enter(); + __ push_call_clobbered_registers(); + satb_write_barrier_pre(masm /* masm */, + noreg /* obj */, + dst /* pre_val */, + xthread /* thread */, + tmp1 /* tmp */, + true /* tosca_live */, + true /* expand_call */); + __ pop_call_clobbered_registers(); + __ leave(); + } +} + +void ShenandoahBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2) { + bool on_oop = is_reference_type(type); + if (!on_oop) { + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); + return; + } + + // flatten object address if needed + if (dst.offset() == 0) { + if (dst.base() != x13) { + __ mv(x13, dst.base()); + } + } else { + __ la(x13, dst); + } + + shenandoah_write_barrier_pre(masm, + x13 /* obj */, + tmp2 /* pre_val */, + xthread /* thread */, + tmp1 /* tmp */, + val != noreg /* tosca_live */, + false /* expand_call */); + + if (val == noreg) { + BarrierSetAssembler::store_at(masm, decorators, type, Address(x13, 0), noreg, noreg, noreg); + } else { + iu_barrier(masm, val, tmp1); + // G1 barrier needs uncompressed oop for region cross check. + Register new_val = val; + if (UseCompressedOops) { + new_val = t1; + __ mv(new_val, val); + } + BarrierSetAssembler::store_at(masm, decorators, type, Address(x13, 0), val, noreg, noreg); + } +} + +void ShenandoahBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath) { + Label done; + // Resolve jobject + BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, obj, tmp, slowpath); + + // Check for null. + __ beqz(obj, done); + + assert(obj != t1, "need t1"); + Address gc_state(jni_env, ShenandoahThreadLocalData::gc_state_offset() - JavaThread::jni_environment_offset()); + __ lbu(t1, gc_state); + + // Check for heap in evacuation phase + __ andi(t0, t1, ShenandoahHeap::EVACUATION); + __ bnez(t0, slowpath); + + __ bind(done); +} + +// Special Shenandoah CAS implementation that handles false negatives due +// to concurrent evacuation. The service is more complex than a +// traditional CAS operation because the CAS operation is intended to +// succeed if the reference at addr exactly matches expected or if the +// reference at addr holds a pointer to a from-space object that has +// been relocated to the location named by expected. There are two +// races that must be addressed: +// a) A parallel thread may mutate the contents of addr so that it points +// to a different object. In this case, the CAS operation should fail. +// b) A parallel thread may heal the contents of addr, replacing a +// from-space pointer held in addr with the to-space pointer +// representing the new location of the object. +// Upon entry to cmpxchg_oop, it is assured that new_val equals NULL +// or it refers to an object that is not being evacuated out of +// from-space, or it refers to the to-space version of an object that +// is being evacuated out of from-space. +// +// By default the value held in the result register following execution +// of the generated code sequence is 0 to indicate failure of CAS, +// non-zero to indicate success. If is_cae, the result is the value most +// recently fetched from addr rather than a boolean success indicator. +// +// Clobbers t0, t1 +void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, + Register addr, + Register expected, + Register new_val, + Assembler::Aqrl acquire, + Assembler::Aqrl release, + bool is_cae, + Register result) { + bool is_narrow = UseCompressedOops; + Assembler::operand_size size = is_narrow ? Assembler::uint32 : Assembler::int64; + + assert_different_registers(addr, expected, t0, t1); + assert_different_registers(addr, new_val, t0, t1); + + Label retry, success, fail, done; + + __ bind(retry); + + // Step1: Try to CAS. + __ cmpxchg(addr, expected, new_val, size, acquire, release, /* result */ t1); + + // If success, then we are done. + __ beq(expected, t1, success); + + // Step2: CAS failed, check the forwared pointer. + __ mv(t0, t1); + + if (is_narrow) { + __ decode_heap_oop(t0, t0); + } + resolve_forward_pointer(masm, t0); + + __ encode_heap_oop(t0, t0); + + // Report failure when the forwarded oop was not expected. + __ bne(t0, expected, fail); + + // Step 3: CAS again using the forwarded oop. + __ cmpxchg(addr, t1, new_val, size, acquire, release, /* result */ t0); + + // Retry when failed. + __ bne(t0, t1, retry); + + __ bind(success); + if (is_cae) { + __ mv(result, expected); + } else { + __ addi(result, zr, 1); + } + __ j(done); + + __ bind(fail); + if (is_cae) { + __ mv(result, t0); + } else { + __ mv(result, zr); + } + + __ bind(done); +} + +#undef __ + +#ifdef COMPILER1 + +#define __ ce->masm()-> + +void ShenandoahBarrierSetAssembler::gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub) { + ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + // At this point we know that marking is in progress. + // If do_load() is true then we have to emit the + // load of the previous value; otherwise it has already + // been loaded into _pre_val. + __ bind(*stub->entry()); + + assert(stub->pre_val()->is_register(), "Precondition."); + + Register pre_val_reg = stub->pre_val()->as_register(); + + if (stub->do_load()) { + ce->mem2reg(stub->addr(), stub->pre_val(), T_OBJECT, stub->patch_code(), stub->info(), false /* wide */); + } + __ beqz(pre_val_reg, *stub->continuation(), /* is_far */ true); + ce->store_parameter(stub->pre_val()->as_register(), 0); + __ far_call(RuntimeAddress(bs->pre_barrier_c1_runtime_code_blob()->code_begin())); + __ j(*stub->continuation()); +} + +void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assembler* ce, + ShenandoahLoadReferenceBarrierStub* stub) { + ShenandoahBarrierSetC1* bs = (ShenandoahBarrierSetC1*)BarrierSet::barrier_set()->barrier_set_c1(); + __ bind(*stub->entry()); + + DecoratorSet decorators = stub->decorators(); + bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); + bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); + bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); + bool is_native = ShenandoahBarrierSet::is_native_access(decorators); + + Register obj = stub->obj()->as_register(); + Register res = stub->result()->as_register(); + Register addr = stub->addr()->as_pointer_register(); + Register tmp1 = stub->tmp1()->as_register(); + Register tmp2 = stub->tmp2()->as_register(); + + assert(res == x10, "result must arrive in x10"); + assert_different_registers(tmp1, tmp2, t0); + + if (res != obj) { + __ mv(res, obj); + } + + if (is_strong) { + // Check for object in cset. + __ mv(tmp2, ShenandoahHeap::in_cset_fast_test_addr()); + __ srli(tmp1, res, ShenandoahHeapRegion::region_size_bytes_shift_jint()); + __ add(tmp2, tmp2, tmp1); + __ lbu(tmp2, Address(tmp2)); + __ beqz(tmp2, *stub->continuation(), true /* is_far */); + } + + ce->store_parameter(res, 0); + ce->store_parameter(addr, 1); + + if (is_strong) { + if (is_native) { + __ far_call(RuntimeAddress(bs->load_reference_barrier_strong_native_rt_code_blob()->code_begin())); + } else { + __ far_call(RuntimeAddress(bs->load_reference_barrier_strong_rt_code_blob()->code_begin())); + } + } else if (is_weak) { + __ far_call(RuntimeAddress(bs->load_reference_barrier_weak_rt_code_blob()->code_begin())); + } else { + assert(is_phantom, "only remaining strength"); + __ far_call(RuntimeAddress(bs->load_reference_barrier_phantom_rt_code_blob()->code_begin())); + } + + __ j(*stub->continuation()); +} + +#undef __ + +#define __ sasm-> + +void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm) { + __ prologue("shenandoah_pre_barrier", false); + + // arg0 : previous value of memory + + BarrierSet* bs = BarrierSet::barrier_set(); + + const Register pre_val = x10; + const Register thread = xthread; + const Register tmp = t0; + + Address queue_index(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_index_offset())); + Address buffer(thread, in_bytes(ShenandoahThreadLocalData::satb_mark_queue_buffer_offset())); + + Label done; + Label runtime; + + // Is marking still active? + Address gc_state(thread, in_bytes(ShenandoahThreadLocalData::gc_state_offset())); + __ lb(tmp, gc_state); + __ andi(tmp, tmp, ShenandoahHeap::MARKING); + __ beqz(tmp, done); + + // Can we store original value in the thread's buffer? + __ ld(tmp, queue_index); + __ beqz(tmp, runtime); + + __ sub(tmp, tmp, wordSize); + __ sd(tmp, queue_index); + __ ld(t1, buffer); + __ add(tmp, tmp, t1); + __ load_parameter(0, t1); + __ sd(t1, Address(tmp, 0)); + __ j(done); + + __ bind(runtime); + __ push_call_clobbered_registers(); + __ load_parameter(0, pre_val); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry), pre_val, thread); + __ pop_call_clobbered_registers(); + __ bind(done); + + __ epilogue(); +} + +void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, + DecoratorSet decorators) { + __ prologue("shenandoah_load_reference_barrier", false); + // arg0 : object to be resolved + + __ push_call_clobbered_registers(); + __ load_parameter(0, x10); + __ load_parameter(1, x11); + + bool is_strong = ShenandoahBarrierSet::is_strong_access(decorators); + bool is_weak = ShenandoahBarrierSet::is_weak_access(decorators); + bool is_phantom = ShenandoahBarrierSet::is_phantom_access(decorators); + bool is_native = ShenandoahBarrierSet::is_native_access(decorators); + if (is_strong) { + if (is_native) { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_strong); + } else { + if (UseCompressedOops) { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_strong_narrow); + } else { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_strong); + } + } + } else if (is_weak) { + assert(!is_native, "weak must not be called off-heap"); + if (UseCompressedOops) { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_weak_narrow); + } else { + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_weak); + } + } else { + assert(is_phantom, "only remaining strength"); + assert(is_native, "phantom must only be called off-heap"); + __ li(ra, (int64_t)(uintptr_t)ShenandoahRuntime::load_reference_barrier_phantom); + } + __ jalr(ra); + __ mv(t0, x10); + __ pop_call_clobbered_registers(); + __ mv(x10, t0); + + __ epilogue(); +} + +#undef __ + +#endif // COMPILER1 diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp new file mode 100644 index 00000000000..a705f497667 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.hpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018, 2019, Red Hat, Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GC_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_RISCV_HPP +#define CPU_RISCV_GC_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_RISCV_HPP + +#include "asm/macroAssembler.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.hpp" +#ifdef COMPILER1 +class LIR_Assembler; +class ShenandoahPreBarrierStub; +class ShenandoahLoadReferenceBarrierStub; +class StubAssembler; +#endif +class StubCodeGenerator; + +class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { +private: + + void satb_write_barrier_pre(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + bool tosca_live, + bool expand_call); + void shenandoah_write_barrier_pre(MacroAssembler* masm, + Register obj, + Register pre_val, + Register thread, + Register tmp, + bool tosca_live, + bool expand_call); + + void resolve_forward_pointer(MacroAssembler* masm, Register dst, Register tmp = noreg); + void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); + void load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr, DecoratorSet decorators); + +public: + + void iu_barrier(MacroAssembler* masm, Register dst, Register tmp); + +#ifdef COMPILER1 + void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); + void gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub); + void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); + void generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, DecoratorSet decorators); +#endif + + virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, + Register src, Register dst, Register count, RegSet saved_regs); + + virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Register dst, Address src, Register tmp1, Register tmp_thread); + virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type, + Address dst, Register val, Register tmp1, Register tmp2); + + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, Register jni_env, + Register obj, Register tmp, Label& slowpath); + + void cmpxchg_oop(MacroAssembler* masm, Register addr, Register expected, Register new_val, + Assembler::Aqrl acquire, Assembler::Aqrl release, bool is_cae, Register result); +}; + +#endif // CPU_RISCV_GC_SHENANDOAH_SHENANDOAHBARRIERSETASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoah_riscv64.ad b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoah_riscv64.ad new file mode 100644 index 00000000000..6c855f23c2a --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoah_riscv64.ad @@ -0,0 +1,285 @@ +// +// Copyright (c) 2018, Red Hat, Inc. All rights reserved. +// Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. +// +// + +source_hpp %{ +#include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp" +%} + +instruct compareAndSwapP_shenandoah(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ + match(Set res (ShenandoahCompareAndSwapP mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP tmp, KILL cr); + + format %{ + "cmpxchg_shenandoah $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval with temp $tmp, #@compareAndSwapP_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, + false /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapN_shenandoah(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, iRegNNoSp tmp, rFlagsReg cr) %{ + match(Set res (ShenandoahCompareAndSwapN mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP tmp, KILL cr); + + format %{ + "cmpxchgw_shenandoah $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval with temp $tmp, #@compareAndSwapN_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, + false /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapPAcq_shenandoah(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ + predicate(needs_acquiring_load_reserved(n)); + match(Set res (ShenandoahCompareAndSwapP mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP tmp, KILL cr); + + format %{ + "cmpxchg_acq_shenandoah_oop $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval with temp $tmp, #@compareAndSwapPAcq_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::aq /* acquire */, Assembler::rl /* release */, + false /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapNAcq_shenandoah(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, iRegNNoSp tmp, rFlagsReg cr) %{ + predicate(needs_acquiring_load_reserved(n)); + match(Set res (ShenandoahCompareAndSwapN mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP tmp, KILL cr); + + format %{ + "cmpxchgw_acq_shenandoah_narrow_oop $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval with temp $tmp, #@compareAndSwapNAcq_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::aq /* acquire */, Assembler::rl /* release */, + false /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeN_shenandoah(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegNNoSp tmp, rFlagsReg cr) %{ + match(Set res (ShenandoahCompareAndExchangeN mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + effect(TEMP_DEF res, TEMP tmp, KILL cr); + + format %{ + "cmpxchgw_shenandoah $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeN_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, + true /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeP_shenandoah(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ + match(Set res (ShenandoahCompareAndExchangeP mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP_DEF res, TEMP tmp, KILL cr); + format %{ + "cmpxchg_shenandoah $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval with temp $tmp, #@compareAndExchangeP_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, + true /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapN_shenandoah(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, iRegNNoSp tmp, rFlagsReg cr) %{ + match(Set res (ShenandoahWeakCompareAndSwapN mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP tmp, KILL cr); + format %{ + "cmpxchgw_shenandoah $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval, #@weakCompareAndSwapN_shenandoah" + "mv $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + // Weak is not current supported by ShenandoahBarrierSet::cmpxchg_oop + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, + false /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeNAcq_shenandoah(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval, iRegNNoSp tmp, rFlagsReg cr) %{ + predicate(needs_acquiring_load_reserved(n)); + match(Set res (ShenandoahCompareAndExchangeN mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP_DEF res, TEMP tmp, KILL cr); + format %{ + "cmpxchgw_acq_shenandoah $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeNAcq_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::aq /* acquire */, Assembler::rl /* release */, + true /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangePAcq_shenandoah(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ + predicate(needs_acquiring_load_reserved(n)); + match(Set res (ShenandoahCompareAndExchangeP mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP_DEF res, TEMP tmp, KILL cr); + format %{ + "cmpxchg_acq_shenandoah $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangePAcq_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::aq /* acquire */, Assembler::rl /* release */, + true /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapP_shenandoah(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ + match(Set res (ShenandoahWeakCompareAndSwapP mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP tmp, KILL cr); + format %{ + "cmpxchg_shenandoah $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval, #@weakCompareAndSwapP_shenandoah" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, + false /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapNAcq_shenandoah(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval, iRegNNoSp tmp, rFlagsReg cr) %{ + predicate(needs_acquiring_load_reserved(n)); + match(Set res (ShenandoahWeakCompareAndSwapN mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP tmp, KILL cr); + format %{ + "cmpxchgw_acq_shenandoah $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval, #@weakCompareAndSwapNAcq_shenandoah" + "mv $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + // Weak is not current supported by ShenandoahBarrierSet::cmpxchg_oop + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::aq /* acquire */, Assembler::rl /* release */, + false /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapPAcq_shenandoah(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, iRegPNoSp tmp, rFlagsReg cr) %{ + predicate(needs_acquiring_load_reserved(n)); + match(Set res (ShenandoahWeakCompareAndSwapP mem (Binary oldval newval))); + ins_cost(10 * DEFAULT_COST); + + effect(TEMP tmp, KILL cr); + format %{ + "cmpxchg_acq_shenandoah $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval, #@weakCompareAndSwapPAcq_shenandoah" + "mv $res, EQ\t# $res <-- (EQ ? 1 : 0)" + %} + + ins_encode %{ + Register tmp = $tmp$$Register; + __ mv(tmp, $oldval$$Register); // Must not clobber oldval. + // Weak is not current supported by ShenandoahBarrierSet::cmpxchg_oop + ShenandoahBarrierSet::assembler()->cmpxchg_oop(&_masm, $mem$$Register, tmp, $newval$$Register, + Assembler::aq /* acquire */, Assembler::rl /* release */, + false /* is_cae */, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp new file mode 100644 index 00000000000..3d3f4d4d774 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp @@ -0,0 +1,441 @@ +/* + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/codeBlob.hpp" +#include "code/vmreg.inline.hpp" +#include "gc/z/zBarrier.inline.hpp" +#include "gc/z/zBarrierSet.hpp" +#include "gc/z/zBarrierSetAssembler.hpp" +#include "gc/z/zBarrierSetRuntime.hpp" +#include "gc/z/zThreadLocalData.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/sharedRuntime.hpp" +#include "utilities/macros.hpp" +#ifdef COMPILER1 +#include "c1/c1_LIRAssembler.hpp" +#include "c1/c1_MacroAssembler.hpp" +#include "gc/z/c1/zBarrierSetC1.hpp" +#endif // COMPILER1 +#ifdef COMPILER2 +#include "gc/z/c2/zBarrierSetC2.hpp" +#endif // COMPILER2 + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + +#undef __ +#define __ masm-> + +void ZBarrierSetAssembler::load_at(MacroAssembler* masm, + DecoratorSet decorators, + BasicType type, + Register dst, + Address src, + Register tmp1, + Register tmp_thread) { + if (!ZBarrierSet::barrier_needed(decorators, type)) { + // Barrier not needed + BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); + return; + } + + assert_different_registers(t1, src.base()); + assert_different_registers(t0, t1, dst); + + Label done; + + // Load bad mask into temp register. + __ la(t0, src); + __ ld(t1, address_bad_mask_from_thread(xthread)); + __ ld(dst, Address(t0)); + + // Test reference against bad mask. If mask bad, then we need to fix it up. + __ andr(t1, dst, t1); + __ beqz(t1, done); + + __ enter(); + + __ push_call_clobbered_registers_except(RegSet::of(dst)); + + if (c_rarg0 != dst) { + __ mv(c_rarg0, dst); + } + + __ mv(c_rarg1, t0); + + __ call_VM_leaf(ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), 2); + + // Make sure dst has the return value. + if (dst != x10) { + __ mv(dst, x10); + } + + __ pop_call_clobbered_registers_except(RegSet::of(dst)); + __ leave(); + + __ bind(done); +} + +#ifdef ASSERT + +void ZBarrierSetAssembler::store_at(MacroAssembler* masm, + DecoratorSet decorators, + BasicType type, + Address dst, + Register val, + Register tmp1, + Register tmp2) { + // Verify value + if (is_reference_type(type)) { + // Note that src could be noreg, which means we + // are storing null and can skip verification. + if (val != noreg) { + Label done; + + // tmp1 and tmp2 are often set to noreg. + RegSet savedRegs = RegSet::of(t0); + __ push_reg(savedRegs, sp); + + __ ld(t0, address_bad_mask_from_thread(xthread)); + __ andr(t0, val, t0); + __ beqz(t0, done); + __ stop("Verify oop store failed"); + __ should_not_reach_here(); + __ bind(done); + __ pop_reg(savedRegs, sp); + } + } + + // Store value + BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2); +} + +#endif // ASSERT + +void ZBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, + DecoratorSet decorators, + bool is_oop, + Register src, + Register dst, + Register count, + RegSet saved_regs) { + if (!is_oop) { + // Barrier not needed + return; + } + + BLOCK_COMMENT("ZBarrierSetAssembler::arraycopy_prologue {"); + + assert_different_registers(src, count, t0); + + __ push_reg(saved_regs, sp); + + if (count == c_rarg0 && src == c_rarg1) { + // exactly backwards!! + __ xorr(c_rarg0, c_rarg0, c_rarg1); + __ xorr(c_rarg1, c_rarg0, c_rarg1); + __ xorr(c_rarg0, c_rarg0, c_rarg1); + } else { + __ mv(c_rarg0, src); + __ mv(c_rarg1, count); + } + + __ call_VM_leaf(ZBarrierSetRuntime::load_barrier_on_oop_array_addr(), 2); + + __ pop_reg(saved_regs, sp); + + BLOCK_COMMENT("} ZBarrierSetAssembler::arraycopy_prologue"); +} + +void ZBarrierSetAssembler::try_resolve_jobject_in_native(MacroAssembler* masm, + Register jni_env, + Register robj, + Register tmp, + Label& slowpath) { + BLOCK_COMMENT("ZBarrierSetAssembler::try_resolve_jobject_in_native {"); + + assert_different_registers(jni_env, robj, tmp); + + // Resolve jobject + BarrierSetAssembler::try_resolve_jobject_in_native(masm, jni_env, robj, tmp, slowpath); + + // Compute the offset of address bad mask from the field of jni_environment + long int bad_mask_relative_offset = (long int) (in_bytes(ZThreadLocalData::address_bad_mask_offset()) - + in_bytes(JavaThread::jni_environment_offset())); + + // Load the address bad mask + __ ld(tmp, Address(jni_env, bad_mask_relative_offset)); + + // Check address bad mask + __ andr(tmp, robj, tmp); + __ bnez(tmp, slowpath); + + BLOCK_COMMENT("} ZBarrierSetAssembler::try_resolve_jobject_in_native"); +} + +#ifdef COMPILER2 + +OptoReg::Name ZBarrierSetAssembler::refine_register(const Node* node, OptoReg::Name opto_reg) { + if (!OptoReg::is_reg(opto_reg)) { + return OptoReg::Bad; + } + + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (vm_reg->is_FloatRegister()) { + return opto_reg & ~1; + } + + return opto_reg; +} + +#undef __ +#define __ _masm-> + +class ZSaveLiveRegisters { +private: + MacroAssembler* const _masm; + RegSet _gp_regs; + FloatRegSet _fp_regs; + VectorRegSet _vp_regs; + +public: + void initialize(ZLoadBarrierStubC2* stub) { + // Record registers that needs to be saved/restored + RegMaskIterator rmi(stub->live()); + while (rmi.has_next()) { + const OptoReg::Name opto_reg = rmi.next(); + if (OptoReg::is_reg(opto_reg)) { + const VMReg vm_reg = OptoReg::as_VMReg(opto_reg); + if (vm_reg->is_Register()) { + _gp_regs += RegSet::of(vm_reg->as_Register()); + } else if (vm_reg->is_FloatRegister()) { + _fp_regs += FloatRegSet::of(vm_reg->as_FloatRegister()); + } else if (vm_reg->is_VectorRegister()) { + const VMReg vm_reg_base = OptoReg::as_VMReg(opto_reg & ~(VectorRegisterImpl::max_slots_per_register - 1)); + _vp_regs += VectorRegSet::of(vm_reg_base->as_VectorRegister()); + } else { + fatal("Unknown register type"); + } + } + } + + // Remove C-ABI SOE registers, tmp regs and _ref register that will be updated + _gp_regs -= RegSet::range(x18, x27) + RegSet::of(x2) + RegSet::of(x8, x9) + RegSet::of(x5, stub->ref()); + } + + ZSaveLiveRegisters(MacroAssembler* masm, ZLoadBarrierStubC2* stub) : + _masm(masm), + _gp_regs(), + _fp_regs(), + _vp_regs() { + // Figure out what registers to save/restore + initialize(stub); + + // Save registers + __ push_reg(_gp_regs, sp); + __ push_fp(_fp_regs, sp); + __ push_vp(_vp_regs, sp); + } + + ~ZSaveLiveRegisters() { + // Restore registers + __ pop_vp(_vp_regs, sp); + __ pop_fp(_fp_regs, sp); + __ pop_reg(_gp_regs, sp); + } +}; + +class ZSetupArguments { +private: + MacroAssembler* const _masm; + const Register _ref; + const Address _ref_addr; + +public: + ZSetupArguments(MacroAssembler* masm, ZLoadBarrierStubC2* stub) : + _masm(masm), + _ref(stub->ref()), + _ref_addr(stub->ref_addr()) { + + // Setup arguments + if (_ref_addr.base() == noreg) { + // No self healing + if (_ref != c_rarg0) { + __ mv(c_rarg0, _ref); + } + __ mv(c_rarg1, zr); + } else { + // Self healing + if (_ref == c_rarg0) { + // _ref is already at correct place + __ la(c_rarg1, _ref_addr); + } else if (_ref != c_rarg1) { + // _ref is in wrong place, but not in c_rarg1, so fix it first + __ la(c_rarg1, _ref_addr); + __ mv(c_rarg0, _ref); + } else if (_ref_addr.base() != c_rarg0) { + assert(_ref == c_rarg1, "Mov ref first, vacating c_rarg0"); + __ mv(c_rarg0, _ref); + __ la(c_rarg1, _ref_addr); + } else { + assert(_ref == c_rarg1, "Need to vacate c_rarg1 and _ref_addr is using c_rarg0"); + if (_ref_addr.base() == c_rarg0) { + __ mv(t1, c_rarg1); + __ la(c_rarg1, _ref_addr); + __ mv(c_rarg0, t1); + } else { + ShouldNotReachHere(); + } + } + } + } + + ~ZSetupArguments() { + // Transfer result + if (_ref != x10) { + __ mv(_ref, x10); + } + } +}; + +#undef __ +#define __ masm-> + +void ZBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, ZLoadBarrierStubC2* stub) const { + BLOCK_COMMENT("ZLoadBarrierStubC2"); + + // Stub entry + __ bind(*stub->entry()); + + { + ZSaveLiveRegisters save_live_registers(masm, stub); + ZSetupArguments setup_arguments(masm, stub); + int32_t offset = 0; + __ la_patchable(t0, stub->slow_path(), offset); + __ jalr(x1, t0, offset); + } + + // Stub exit + __ j(*stub->continuation()); +} + +#undef __ + +#endif // COMPILER2 + +#ifdef COMPILER1 +#undef __ +#define __ ce->masm()-> + +void ZBarrierSetAssembler::generate_c1_load_barrier_test(LIR_Assembler* ce, + LIR_Opr ref) const { + assert_different_registers(xthread, ref->as_register(), t1); + __ ld(t1, address_bad_mask_from_thread(xthread)); + __ andr(t1, t1, ref->as_register()); +} + +void ZBarrierSetAssembler::generate_c1_load_barrier_stub(LIR_Assembler* ce, + ZLoadBarrierStubC1* stub) const { + // Stub entry + __ bind(*stub->entry()); + + Register ref = stub->ref()->as_register(); + Register ref_addr = noreg; + Register tmp = noreg; + + if (stub->tmp()->is_valid()) { + // Load address into tmp register + ce->leal(stub->ref_addr(), stub->tmp()); + ref_addr = tmp = stub->tmp()->as_pointer_register(); + } else { + // Address already in register + ref_addr = stub->ref_addr()->as_address_ptr()->base()->as_pointer_register(); + } + + assert_different_registers(ref, ref_addr, noreg); + + // Save x10 unless it is the result or tmp register + // Set up SP to accomodate parameters and maybe x10. + if (ref != x10 && tmp != x10) { + __ sub(sp, sp, 32); + __ sd(x10, Address(sp, 16)); + } else { + __ sub(sp, sp, 16); + } + + // Setup arguments and call runtime stub + ce->store_parameter(ref_addr, 1); + ce->store_parameter(ref, 0); + + __ far_call(stub->runtime_stub()); + + // Verify result + __ verify_oop(x10, "Bad oop"); + + + // Move result into place + if (ref != x10) { + __ mv(ref, x10); + } + + // Restore x10 unless it is the result or tmp register + if (ref != x10 && tmp != x10) { + __ ld(x10, Address(sp, 16)); + __ add(sp, sp, 32); + } else { + __ add(sp, sp, 16); + } + + // Stub exit + __ j(*stub->continuation()); +} + +#undef __ +#define __ sasm-> + +void ZBarrierSetAssembler::generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, + DecoratorSet decorators) const { + __ prologue("zgc_load_barrier stub", false); + + __ push_call_clobbered_registers_except(RegSet::of(x10)); + + // Setup arguments + __ load_parameter(0, c_rarg0); + __ load_parameter(1, c_rarg1); + + __ call_VM_leaf(ZBarrierSetRuntime::load_barrier_on_oop_field_preloaded_addr(decorators), 2); + + __ pop_call_clobbered_registers_except(RegSet::of(x10)); + + __ epilogue(); +} + +#undef __ +#endif // COMPILER1 diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.hpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.hpp new file mode 100644 index 00000000000..dc07ab635fe --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.hpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GC_Z_ZBARRIERSETASSEMBLER_RISCV_HPP +#define CPU_RISCV_GC_Z_ZBARRIERSETASSEMBLER_RISCV_HPP + +#include "code/vmreg.hpp" +#include "oops/accessDecorators.hpp" +#ifdef COMPILER2 +#include "opto/optoreg.hpp" +#endif // COMPILER2 + +#ifdef COMPILER1 +class LIR_Assembler; +class LIR_Opr; +class StubAssembler; +class ZLoadBarrierStubC1; +#endif // COMPILER1 + +#ifdef COMPILER2 +class Node; +class ZLoadBarrierStubC2; +#endif // COMPILER2 + +class ZBarrierSetAssembler : public ZBarrierSetAssemblerBase { +public: + virtual void load_at(MacroAssembler* masm, + DecoratorSet decorators, + BasicType type, + Register dst, + Address src, + Register tmp1, + Register tmp_thread); + +#ifdef ASSERT + virtual void store_at(MacroAssembler* masm, + DecoratorSet decorators, + BasicType type, + Address dst, + Register val, + Register tmp1, + Register tmp2); +#endif // ASSERT + + virtual void arraycopy_prologue(MacroAssembler* masm, + DecoratorSet decorators, + bool is_oop, + Register src, + Register dst, + Register count, + RegSet saved_regs); + + virtual void try_resolve_jobject_in_native(MacroAssembler* masm, + Register jni_env, + Register robj, + Register tmp, + Label& slowpath); + +#ifdef COMPILER1 + void generate_c1_load_barrier_test(LIR_Assembler* ce, + LIR_Opr ref) const; + + void generate_c1_load_barrier_stub(LIR_Assembler* ce, + ZLoadBarrierStubC1* stub) const; + + void generate_c1_load_barrier_runtime_stub(StubAssembler* sasm, + DecoratorSet decorators) const; +#endif // COMPILER1 + +#ifdef COMPILER2 + OptoReg::Name refine_register(const Node* node, + OptoReg::Name opto_reg); + + void generate_c2_load_barrier_stub(MacroAssembler* masm, + ZLoadBarrierStubC2* stub) const; +#endif // COMPILER2 +}; + +#endif // CPU_RISCV_GC_Z_ZBARRIERSETASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.cpp new file mode 100644 index 00000000000..d14997790af --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "gc/shared/gcLogPrecious.hpp" +#include "gc/shared/gc_globals.hpp" +#include "gc/z/zGlobals.hpp" +#include "runtime/globals.hpp" +#include "runtime/os.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/powerOfTwo.hpp" + +#ifdef LINUX +#include +#endif // LINUX + +// +// The heap can have three different layouts, depending on the max heap size. +// +// Address Space & Pointer Layout 1 +// -------------------------------- +// +// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) +// . . +// . . +// . . +// +--------------------------------+ 0x0000014000000000 (20TB) +// | Remapped View | +// +--------------------------------+ 0x0000010000000000 (16TB) +// . . +// +--------------------------------+ 0x00000c0000000000 (12TB) +// | Marked1 View | +// +--------------------------------+ 0x0000080000000000 (8TB) +// | Marked0 View | +// +--------------------------------+ 0x0000040000000000 (4TB) +// . . +// +--------------------------------+ 0x0000000000000000 +// +// 6 4 4 4 4 +// 3 6 5 2 1 0 +// +--------------------+----+-----------------------------------------------+ +// |00000000 00000000 00|1111|11 11111111 11111111 11111111 11111111 11111111| +// +--------------------+----+-----------------------------------------------+ +// | | | +// | | * 41-0 Object Offset (42-bits, 4TB address space) +// | | +// | * 45-42 Metadata Bits (4-bits) 0001 = Marked0 (Address view 4-8TB) +// | 0010 = Marked1 (Address view 8-12TB) +// | 0100 = Remapped (Address view 16-20TB) +// | 1000 = Finalizable (Address view N/A) +// | +// * 63-46 Fixed (18-bits, always zero) +// +// +// Address Space & Pointer Layout 2 +// -------------------------------- +// +// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) +// . . +// . . +// . . +// +--------------------------------+ 0x0000280000000000 (40TB) +// | Remapped View | +// +--------------------------------+ 0x0000200000000000 (32TB) +// . . +// +--------------------------------+ 0x0000180000000000 (24TB) +// | Marked1 View | +// +--------------------------------+ 0x0000100000000000 (16TB) +// | Marked0 View | +// +--------------------------------+ 0x0000080000000000 (8TB) +// . . +// +--------------------------------+ 0x0000000000000000 +// +// 6 4 4 4 4 +// 3 7 6 3 2 0 +// +------------------+-----+------------------------------------------------+ +// |00000000 00000000 0|1111|111 11111111 11111111 11111111 11111111 11111111| +// +-------------------+----+------------------------------------------------+ +// | | | +// | | * 42-0 Object Offset (43-bits, 8TB address space) +// | | +// | * 46-43 Metadata Bits (4-bits) 0001 = Marked0 (Address view 8-16TB) +// | 0010 = Marked1 (Address view 16-24TB) +// | 0100 = Remapped (Address view 32-40TB) +// | 1000 = Finalizable (Address view N/A) +// | +// * 63-47 Fixed (17-bits, always zero) +// +// +// Address Space & Pointer Layout 3 +// -------------------------------- +// +// +--------------------------------+ 0x00007FFFFFFFFFFF (127TB) +// . . +// . . +// . . +// +--------------------------------+ 0x0000500000000000 (80TB) +// | Remapped View | +// +--------------------------------+ 0x0000400000000000 (64TB) +// . . +// +--------------------------------+ 0x0000300000000000 (48TB) +// | Marked1 View | +// +--------------------------------+ 0x0000200000000000 (32TB) +// | Marked0 View | +// +--------------------------------+ 0x0000100000000000 (16TB) +// . . +// +--------------------------------+ 0x0000000000000000 +// +// 6 4 4 4 4 +// 3 8 7 4 3 0 +// +------------------+----+-------------------------------------------------+ +// |00000000 00000000 |1111|1111 11111111 11111111 11111111 11111111 11111111| +// +------------------+----+-------------------------------------------------+ +// | | | +// | | * 43-0 Object Offset (44-bits, 16TB address space) +// | | +// | * 47-44 Metadata Bits (4-bits) 0001 = Marked0 (Address view 16-32TB) +// | 0010 = Marked1 (Address view 32-48TB) +// | 0100 = Remapped (Address view 64-80TB) +// | 1000 = Finalizable (Address view N/A) +// | +// * 63-48 Fixed (16-bits, always zero) +// + +// Default value if probing is not implemented for a certain platform: 128TB +static const size_t DEFAULT_MAX_ADDRESS_BIT = 47; +// Minimum value returned, if probing fails: 64GB +static const size_t MINIMUM_MAX_ADDRESS_BIT = 36; + +static size_t probe_valid_max_address_bit() { +#ifdef LINUX + size_t max_address_bit = 0; + const size_t page_size = os::vm_page_size(); + for (size_t i = DEFAULT_MAX_ADDRESS_BIT; i > MINIMUM_MAX_ADDRESS_BIT; --i) { + const uintptr_t base_addr = ((uintptr_t) 1U) << i; + if (msync((void*)base_addr, page_size, MS_ASYNC) == 0) { + // msync suceeded, the address is valid, and maybe even already mapped. + max_address_bit = i; + break; + } + if (errno != ENOMEM) { + // Some error occured. This should never happen, but msync + // has some undefined behavior, hence ignore this bit. +#ifdef ASSERT + fatal("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); +#else // ASSERT + log_warning_p(gc)("Received '%s' while probing the address space for the highest valid bit", os::errno_name(errno)); +#endif // ASSERT + continue; + } + // Since msync failed with ENOMEM, the page might not be mapped. + // Try to map it, to see if the address is valid. + void* const result_addr = mmap((void*) base_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); + if (result_addr != MAP_FAILED) { + munmap(result_addr, page_size); + } + if ((uintptr_t) result_addr == base_addr) { + // address is valid + max_address_bit = i; + break; + } + } + if (max_address_bit == 0) { + // probing failed, allocate a very high page and take that bit as the maximum + const uintptr_t high_addr = ((uintptr_t) 1U) << DEFAULT_MAX_ADDRESS_BIT; + void* const result_addr = mmap((void*) high_addr, page_size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0); + if (result_addr != MAP_FAILED) { + max_address_bit = BitsPerSize_t - count_leading_zeros((size_t) result_addr) - 1; + munmap(result_addr, page_size); + } + } + log_info_p(gc, init)("Probing address space for the highest valid bit: " SIZE_FORMAT, max_address_bit); + return MAX2(max_address_bit, MINIMUM_MAX_ADDRESS_BIT); +#else // LINUX + return DEFAULT_MAX_ADDRESS_BIT; +#endif // LINUX +} + +size_t ZPlatformAddressOffsetBits() { + const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; + const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; + const size_t min_address_offset_bits = max_address_offset_bits - 2; + const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); + const size_t address_offset_bits = log2i_exact(address_offset); + return clamp(address_offset_bits, min_address_offset_bits, max_address_offset_bits); +} + +size_t ZPlatformAddressMetadataShift() { + return ZPlatformAddressOffsetBits(); +} diff --git a/src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.hpp b/src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.hpp new file mode 100644 index 00000000000..f20ecd9b073 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/z/zGlobals_riscv.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GC_Z_ZGLOBALS_RISCV_HPP +#define CPU_RISCV_GC_Z_ZGLOBALS_RISCV_HPP + +const size_t ZPlatformGranuleSizeShift = 21; // 2MB +const size_t ZPlatformHeapViews = 3; +const size_t ZPlatformCacheLineSize = 64; + +size_t ZPlatformAddressOffsetBits(); +size_t ZPlatformAddressMetadataShift(); + +#endif // CPU_RISCV_GC_Z_ZGLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv64.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv64.ad new file mode 100644 index 00000000000..6b6f87814a5 --- /dev/null +++ b/src/hotspot/cpu/riscv/gc/z/z_riscv64.ad @@ -0,0 +1,233 @@ +// +// Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. +// + +source_hpp %{ + +#include "gc/shared/gc_globals.hpp" +#include "gc/z/c2/zBarrierSetC2.hpp" +#include "gc/z/zThreadLocalData.hpp" + +%} + +source %{ + +static void z_load_barrier(MacroAssembler& _masm, const MachNode* node, Address ref_addr, Register ref, Register tmp, int barrier_data) { + if (barrier_data == ZLoadBarrierElided) { + return; + } + ZLoadBarrierStubC2* const stub = ZLoadBarrierStubC2::create(node, ref_addr, ref, tmp, barrier_data); + __ ld(tmp, Address(xthread, ZThreadLocalData::address_bad_mask_offset())); + __ andr(tmp, tmp, ref); + __ bnez(tmp, *stub->entry(), true /* far */); + __ bind(*stub->continuation()); +} + +static void z_load_barrier_slow_path(MacroAssembler& _masm, const MachNode* node, Address ref_addr, Register ref, Register tmp) { + ZLoadBarrierStubC2* const stub = ZLoadBarrierStubC2::create(node, ref_addr, ref, tmp, ZLoadBarrierStrong); + __ j(*stub->entry()); + __ bind(*stub->continuation()); +} + +%} + +// Load Pointer +instruct zLoadP(iRegPNoSp dst, memory mem) +%{ + match(Set dst (LoadP mem)); + predicate(UseZGC && (n->as_Load()->barrier_data() != 0)); + effect(TEMP dst); + + ins_cost(4 * DEFAULT_COST); + + format %{ "ld $dst, $mem, #@zLoadP" %} + + ins_encode %{ + const Address ref_addr (as_Register($mem$$base), $mem$$disp); + __ ld($dst$$Register, ref_addr); + z_load_barrier(_masm, this, ref_addr, $dst$$Register, t0 /* tmp */, barrier_data()); + %} + + ins_pipe(iload_reg_mem); +%} + +instruct zCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + predicate(UseZGC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong); + effect(KILL cr, TEMP_DEF res); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ "cmpxchg $mem, $oldval, $newval, #@zCompareAndSwapP\n\t" + "mv $res, $res == $oldval" %} + + ins_encode %{ + Label failed; + guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result_as_bool */); + __ beqz($res$$Register, failed); + __ mv(t0, $oldval$$Register); + __ bind(failed); + if (barrier_data() != ZLoadBarrierElided) { + Label good; + __ ld(t1, Address(xthread, ZThreadLocalData::address_bad_mask_offset()), t1 /* tmp */); + __ andr(t1, t1, t0); + __ beqz(t1, good); + z_load_barrier_slow_path(_masm, this, Address($mem$$Register), t0 /* ref */, t1 /* tmp */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result_as_bool */); + __ bind(good); + } + %} + + ins_pipe(pipe_slow); +%} + +instruct zCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval, rFlagsReg cr) %{ + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + predicate(UseZGC && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong)); + effect(KILL cr, TEMP_DEF res); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ "cmpxchg $mem, $oldval, $newval, #@zCompareAndSwapPAcq\n\t" + "mv $res, $res == $oldval" %} + + ins_encode %{ + Label failed; + guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result_as_bool */); + __ beqz($res$$Register, failed); + __ mv(t0, $oldval$$Register); + __ bind(failed); + if (barrier_data() != ZLoadBarrierElided) { + Label good; + __ ld(t1, Address(xthread, ZThreadLocalData::address_bad_mask_offset()), t1 /* tmp */); + __ andr(t1, t1, t0); + __ beqz(t1, good); + z_load_barrier_slow_path(_masm, this, Address($mem$$Register), t0 /* ref */, t1 /* tmp */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result_as_bool */); + __ bind(good); + } + %} + + ins_pipe(pipe_slow); +%} + +instruct zCompareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval) %{ + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + predicate(UseZGC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong); + effect(TEMP_DEF res); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ "cmpxchg $res = $mem, $oldval, $newval, #@zCompareAndExchangeP" %} + + ins_encode %{ + guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register); + if (barrier_data() != ZLoadBarrierElided) { + Label good; + __ ld(t0, Address(xthread, ZThreadLocalData::address_bad_mask_offset())); + __ andr(t0, t0, $res$$Register); + __ beqz(t0, good); + z_load_barrier_slow_path(_masm, this, Address($mem$$Register), $res$$Register /* ref */, t0 /* tmp */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register); + __ bind(good); + } + %} + + ins_pipe(pipe_slow); +%} + +instruct zCompareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval) %{ + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + predicate(UseZGC && needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() == ZLoadBarrierStrong); + effect(TEMP_DEF res); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ "cmpxchg $res = $mem, $oldval, $newval, #@zCompareAndExchangePAcq" %} + + ins_encode %{ + guarantee($mem$$index == -1 && $mem$$disp == 0, "impossible encoding"); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register); + if (barrier_data() != ZLoadBarrierElided) { + Label good; + __ ld(t0, Address(xthread, ZThreadLocalData::address_bad_mask_offset())); + __ andr(t0, t0, $res$$Register); + __ beqz(t0, good); + z_load_barrier_slow_path(_masm, this, Address($mem$$Register), $res$$Register /* ref */, t0 /* tmp */); + __ cmpxchg($mem$$Register, $oldval$$Register, $newval$$Register, Assembler::int64, + Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register); + __ bind(good); + } + %} + + ins_pipe(pipe_slow); +%} + +instruct zGetAndSetP(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{ + match(Set prev (GetAndSetP mem newv)); + predicate(UseZGC && !needs_acquiring_load_reserved(n) && n->as_LoadStore()->barrier_data() != 0); + effect(TEMP_DEF prev, KILL cr); + + ins_cost(2 * VOLATILE_REF_COST); + + format %{ "atomic_xchg $prev, $newv, [$mem], #@zGetAndSetP" %} + + ins_encode %{ + __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); + z_load_barrier(_masm, this, Address(noreg, 0), $prev$$Register, t0 /* tmp */, barrier_data()); + %} + + ins_pipe(pipe_serial); +%} + +instruct zGetAndSetPAcq(indirect mem, iRegP newv, iRegPNoSp prev, rFlagsReg cr) %{ + match(Set prev (GetAndSetP mem newv)); + predicate(UseZGC && needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() != 0)); + effect(TEMP_DEF prev, KILL cr); + + ins_cost(VOLATILE_REF_COST); + + format %{ "atomic_xchg_acq $prev, $newv, [$mem], #@zGetAndSetPAcq" %} + + ins_encode %{ + __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base)); + z_load_barrier(_masm, this, Address(noreg, 0), $prev$$Register, t0 /* tmp */, barrier_data()); + %} + ins_pipe(pipe_serial); +%} diff --git a/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp new file mode 100644 index 00000000000..2936837d951 --- /dev/null +++ b/src/hotspot/cpu/riscv/globalDefinitions_riscv.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GLOBALDEFINITIONS_RISCV_HPP +#define CPU_RISCV_GLOBALDEFINITIONS_RISCV_HPP + +const int StackAlignmentInBytes = 16; + +// Indicates whether the C calling conventions require that +// 32-bit integer argument values are extended to 64 bits. +const bool CCallingConventionRequiresIntsAsLongs = false; + +// RISCV has adopted a multicopy atomic model closely following +// that of ARMv8. +#define CPU_MULTI_COPY_ATOMIC + +// To be safe, we deoptimize when we come across an access that needs +// patching. This is similar to what is done on aarch64. +#define DEOPTIMIZE_WHEN_PATCHING + +#define SUPPORTS_NATIVE_CX8 + +#define SUPPORT_RESERVED_STACK_AREA + +#define COMPRESSED_CLASS_POINTERS_DEPENDS_ON_COMPRESSED_OOPS false + +#define USE_POINTERS_TO_REGISTER_IMPL_ARRAY + +#endif // CPU_RISCV_GLOBALDEFINITIONS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp new file mode 100644 index 00000000000..cbfc0583883 --- /dev/null +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_GLOBALS_RISCV_HPP +#define CPU_RISCV_GLOBALS_RISCV_HPP + +#include "utilities/globalDefinitions.hpp" +#include "utilities/macros.hpp" + +// Sets the default values for platform dependent flags used by the runtime system. +// (see globals.hpp) + +define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks +define_pd_global(bool, TrapBasedNullChecks, false); +define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast + +define_pd_global(uintx, CodeCacheSegmentSize, 64 COMPILER1_AND_COMPILER2_PRESENT(+64)); // Tiered compilation has large code-entry alignment. +define_pd_global(intx, CodeEntryAlignment, 64); +define_pd_global(intx, OptoLoopAlignment, 16); + +#define DEFAULT_STACK_YELLOW_PAGES (2) +#define DEFAULT_STACK_RED_PAGES (1) +// Java_java_net_SocketOutputStream_socketWrite0() uses a 64k buffer on the +// stack if compiled for unix and LP64. To pass stack overflow tests we need +// 20 shadow pages. +#define DEFAULT_STACK_SHADOW_PAGES (20 DEBUG_ONLY(+5)) +#define DEFAULT_STACK_RESERVED_PAGES (1) + +#define MIN_STACK_YELLOW_PAGES DEFAULT_STACK_YELLOW_PAGES +#define MIN_STACK_RED_PAGES DEFAULT_STACK_RED_PAGES +#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES +#define MIN_STACK_RESERVED_PAGES (0) + +define_pd_global(intx, StackYellowPages, DEFAULT_STACK_YELLOW_PAGES); +define_pd_global(intx, StackRedPages, DEFAULT_STACK_RED_PAGES); +define_pd_global(intx, StackShadowPages, DEFAULT_STACK_SHADOW_PAGES); +define_pd_global(intx, StackReservedPages, DEFAULT_STACK_RESERVED_PAGES); + +define_pd_global(bool, RewriteBytecodes, true); +define_pd_global(bool, RewriteFrequentPairs, true); + +define_pd_global(bool, PreserveFramePointer, false); + +define_pd_global(uintx, TypeProfileLevel, 111); + +define_pd_global(bool, CompactStrings, true); + +// Clear short arrays bigger than one word in an arch-specific way +define_pd_global(intx, InitArrayShortSize, BytesPerLong); + +define_pd_global(intx, InlineSmallCode, 1000); + +#define ARCH_FLAGS(develop, \ + product, \ + notproduct, \ + range, \ + constraint) \ + \ + product(bool, NearCpool, true, \ + "constant pool is close to instructions") \ + product(intx, BlockZeroingLowLimit, 256, \ + "Minimum size in bytes when block zeroing will be used") \ + range(1, max_jint) \ + product(bool, TraceTraps, false, "Trace all traps the signal handler") \ + /* For now we're going to be safe and add the I/O bits to userspace fences. */ \ + product(bool, UseConservativeFence, true, \ + "Extend i for r and o for w in the pred/succ flags of fence;" \ + "Extend fence.i to fence.i + fence.") \ + product(bool, AvoidUnalignedAccesses, true, \ + "Avoid generating unaligned memory accesses") \ + product(bool, UseRVV, false, EXPERIMENTAL, "Use RVV instructions") \ + product(bool, UseRVB, false, EXPERIMENTAL, "Use RVB instructions") \ + product(bool, UseRVC, false, EXPERIMENTAL, "Use RVC instructions") \ + product(bool, UseRVVForBigIntegerShiftIntrinsics, true, \ + "Use RVV instructions for left/right shift of BigInteger") + +#endif // CPU_RISCV_GLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/icBuffer_riscv.cpp b/src/hotspot/cpu/riscv/icBuffer_riscv.cpp new file mode 100644 index 00000000000..cc93103dc55 --- /dev/null +++ b/src/hotspot/cpu/riscv/icBuffer_riscv.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/icBuffer.hpp" +#include "gc/shared/collectedHeap.inline.hpp" +#include "interpreter/bytecodes.hpp" +#include "memory/resourceArea.hpp" +#include "nativeInst_riscv.hpp" +#include "oops/oop.inline.hpp" + +int InlineCacheBuffer::ic_stub_code_size() { + // 6: auipc + ld + auipc + jalr + address(2 * instruction_size) + // 5: auipc + ld + j + address(2 * instruction_size) + return (MacroAssembler::far_branches() ? 6 : 5) * NativeInstruction::instruction_size; +} + +#define __ masm-> + +void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin, void* cached_value, address entry_point) { + assert_cond(code_begin != NULL && entry_point != NULL); + ResourceMark rm; + CodeBuffer code(code_begin, ic_stub_code_size()); + MacroAssembler* masm = new MacroAssembler(&code); + // Note: even though the code contains an embedded value, we do not need reloc info + // because + // (1) the value is old (i.e., doesn't matter for scavenges) + // (2) these ICStubs are removed *before* a GC happens, so the roots disappear + + address start = __ pc(); + Label l; + __ ld(t1, l); + __ far_jump(ExternalAddress(entry_point)); + __ align(wordSize); + __ bind(l); + __ emit_int64((intptr_t)cached_value); + // Only need to invalidate the 1st two instructions - not the whole ic stub + ICache::invalidate_range(code_begin, InlineCacheBuffer::ic_stub_code_size()); + assert(__ pc() - start == ic_stub_code_size(), "must be"); +} + +address InlineCacheBuffer::ic_buffer_entry_point(address code_begin) { + NativeMovConstReg* move = nativeMovConstReg_at(code_begin); // creation also verifies the object + NativeJump* jump = nativeJump_at(move->next_instruction_address()); + return jump->jump_destination(); +} + + +void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) { + // The word containing the cached value is at the end of this IC buffer + uintptr_t *p = (uintptr_t *)(code_begin + ic_stub_code_size() - wordSize); + void* o = (void*)*p; + return o; +} diff --git a/src/hotspot/cpu/riscv/icache_riscv.cpp b/src/hotspot/cpu/riscv/icache_riscv.cpp new file mode 100644 index 00000000000..922a80f9f3e --- /dev/null +++ b/src/hotspot/cpu/riscv/icache_riscv.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "runtime/icache.hpp" + +#define __ _masm-> + +static int icache_flush(address addr, int lines, int magic) { + os::icache_flush((long int) addr, (long int) (addr + (lines << ICache::log2_line_size))); + return magic; +} + +void ICacheStubGenerator::generate_icache_flush(ICache::flush_icache_stub_t* flush_icache_stub) { + address start = (address)icache_flush; + *flush_icache_stub = (ICache::flush_icache_stub_t)start; + + // ICache::invalidate_range() contains explicit condition that the first + // call is invoked on the generated icache flush stub code range. + ICache::invalidate_range(start, 0); + + { + StubCodeMark mark(this, "ICache", "fake_stub_for_inlined_icache_flush"); + __ ret(); + } +} + +#undef __ diff --git a/src/hotspot/cpu/riscv/icache_riscv.hpp b/src/hotspot/cpu/riscv/icache_riscv.hpp new file mode 100644 index 00000000000..5bf40ca8204 --- /dev/null +++ b/src/hotspot/cpu/riscv/icache_riscv.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_ICACHE_RISCV_HPP +#define CPU_RISCV_ICACHE_RISCV_HPP + +// Interface for updating the instruction cache. Whenever the VM +// modifies code, part of the processor instruction cache potentially +// has to be flushed. + +class ICache : public AbstractICache { +public: + enum { + stub_size = 16, // Size of the icache flush stub in bytes + line_size = BytesPerWord, // conservative + log2_line_size = LogBytesPerWord // log2(line_size) + }; +}; + +#endif // CPU_RISCV_ICACHE_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.cpp b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp new file mode 100644 index 00000000000..d12dcb2af19 --- /dev/null +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.cpp @@ -0,0 +1,1940 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "interp_masm_riscv.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "logging/log.hpp" +#include "oops/arrayOop.hpp" +#include "oops/markWord.hpp" +#include "oops/method.hpp" +#include "oops/methodData.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiThreadState.hpp" +#include "runtime/basicLock.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/safepointMechanism.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/thread.inline.hpp" +#include "utilities/powerOfTwo.hpp" + +void InterpreterMacroAssembler::narrow(Register result) { + // Get method->_constMethod->_result_type + ld(t0, Address(fp, frame::interpreter_frame_method_offset * wordSize)); + ld(t0, Address(t0, Method::const_offset())); + lbu(t0, Address(t0, ConstMethod::result_type_offset())); + + Label done, notBool, notByte, notChar; + + // common case first + mv(t1, T_INT); + beq(t0, t1, done); + + // mask integer result to narrower return type. + mv(t1, T_BOOLEAN); + bne(t0, t1, notBool); + + andi(result, result, 0x1); + j(done); + + bind(notBool); + mv(t1, T_BYTE); + bne(t0, t1, notByte); + sign_extend(result, result, 8); + j(done); + + bind(notByte); + mv(t1, T_CHAR); + bne(t0, t1, notChar); + zero_extend(result, result, 16); + j(done); + + bind(notChar); + sign_extend(result, result, 16); + + // Nothing to do for T_INT + bind(done); + addw(result, result, zr); +} + +void InterpreterMacroAssembler::jump_to_entry(address entry) { + assert(entry != NULL, "Entry must have been generated by now"); + j(entry); +} + +void InterpreterMacroAssembler::check_and_handle_popframe(Register java_thread) { + if (JvmtiExport::can_pop_frame()) { + Label L; + // Initiate popframe handling only if it is not already being + // processed. If the flag has the popframe_processing bit set, + // it means that this code is called *during* popframe handling - we + // don't want to reenter. + // This method is only called just after the call into the vm in + // call_VM_base, so the arg registers are available. + lwu(t1, Address(xthread, JavaThread::popframe_condition_offset())); + andi(t0, t1, JavaThread::popframe_pending_bit); + beqz(t0, L); + andi(t0, t1, JavaThread::popframe_processing_bit); + bnez(t0, L); + // Call Interpreter::remove_activation_preserving_args_entry() to get the + // address of the same-named entrypoint in the generated interpreter code. + call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_preserving_args_entry)); + jr(x10); + bind(L); + } +} + + +void InterpreterMacroAssembler::load_earlyret_value(TosState state) { + ld(x12, Address(xthread, JavaThread::jvmti_thread_state_offset())); + const Address tos_addr(x12, JvmtiThreadState::earlyret_tos_offset()); + const Address oop_addr(x12, JvmtiThreadState::earlyret_oop_offset()); + const Address val_addr(x12, JvmtiThreadState::earlyret_value_offset()); + switch (state) { + case atos: + ld(x10, oop_addr); + sd(zr, oop_addr); + verify_oop(x10); + break; + case ltos: + ld(x10, val_addr); + break; + case btos: // fall through + case ztos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: + lwu(x10, val_addr); + break; + case ftos: + flw(f10, val_addr); + break; + case dtos: + fld(f10, val_addr); + break; + case vtos: + /* nothing to do */ + break; + default: + ShouldNotReachHere(); + } + // Clean up tos value in the thread object + mvw(t0, (int) ilgl); + sw(t0, tos_addr); + sw(zr, val_addr); +} + + +void InterpreterMacroAssembler::check_and_handle_earlyret(Register java_thread) { + if (JvmtiExport::can_force_early_return()) { + Label L; + ld(t0, Address(xthread, JavaThread::jvmti_thread_state_offset())); + beqz(t0, L); // if [thread->jvmti_thread_state() == NULL] then exit + + // Initiate earlyret handling only if it is not already being processed. + // If the flag has the earlyret_processing bit set, it means that this code + // is called *during* earlyret handling - we don't want to reenter. + lwu(t0, Address(t0, JvmtiThreadState::earlyret_state_offset())); + mv(t1, JvmtiThreadState::earlyret_pending); + bne(t0, t1, L); + + // Call Interpreter::remove_activation_early_entry() to get the address of the + // same-named entrypoint in the generated interpreter code. + ld(t0, Address(xthread, JavaThread::jvmti_thread_state_offset())); + lwu(t0, Address(t0, JvmtiThreadState::earlyret_tos_offset())); + call_VM_leaf(CAST_FROM_FN_PTR(address, Interpreter::remove_activation_early_entry), t0); + jr(x10); + bind(L); + } +} + +void InterpreterMacroAssembler::get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset) { + assert(bcp_offset >= 0, "bcp is still pointing to start of bytecode"); + lhu(reg, Address(xbcp, bcp_offset)); + revb_h(reg, reg); +} + +void InterpreterMacroAssembler::get_dispatch() { + int32_t offset = 0; + la_patchable(xdispatch, ExternalAddress((address)Interpreter::dispatch_table()), offset); + addi(xdispatch, xdispatch, offset); +} + +void InterpreterMacroAssembler::get_cache_index_at_bcp(Register index, + int bcp_offset, + size_t index_size) { + assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); + if (index_size == sizeof(u2)) { + load_unsigned_short(index, Address(xbcp, bcp_offset)); + } else if (index_size == sizeof(u4)) { + lwu(index, Address(xbcp, bcp_offset)); + // Check if the secondary index definition is still ~x, otherwise + // we have to change the following assembler code to calculate the + // plain index. + assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); + xori(index, index, -1); + addw(index, index, zr); + } else if (index_size == sizeof(u1)) { + load_unsigned_byte(index, Address(xbcp, bcp_offset)); + } else { + ShouldNotReachHere(); + } +} + +// Return +// Rindex: index into constant pool +// Rcache: address of cache entry - ConstantPoolCache::base_offset() +// +// A caller must add ConstantPoolCache::base_offset() to Rcache to get +// the true address of the cache entry. +// +void InterpreterMacroAssembler::get_cache_and_index_at_bcp(Register cache, + Register index, + int bcp_offset, + size_t index_size) { + assert_different_registers(cache, index); + assert_different_registers(cache, xcpool); + get_cache_index_at_bcp(index, bcp_offset, index_size); + assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); + // Convert from field index to ConstantPoolCacheEntry + // riscv already has the cache in xcpool so there is no need to + // install it in cache. Instead we pre-add the indexed offset to + // xcpool and return it in cache. All clients of this method need to + // be modified accordingly. + shadd(cache, index, xcpool, cache, 5); +} + + +void InterpreterMacroAssembler::get_cache_and_index_and_bytecode_at_bcp(Register cache, + Register index, + Register bytecode, + int byte_no, + int bcp_offset, + size_t index_size) { + get_cache_and_index_at_bcp(cache, index, bcp_offset, index_size); + // We use a 32-bit load here since the layout of 64-bit words on + // little-endian machines allow us that. + // n.b. unlike x86 cache already includes the index offset + la(bytecode, Address(cache, + ConstantPoolCache::base_offset() + + ConstantPoolCacheEntry::indices_offset())); + membar(MacroAssembler::AnyAny); + lwu(bytecode, bytecode); + membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + const int shift_count = (1 + byte_no) * BitsPerByte; + slli(bytecode, bytecode, XLEN - (shift_count + BitsPerByte)); + srli(bytecode, bytecode, XLEN - BitsPerByte); +} + +void InterpreterMacroAssembler::get_cache_entry_pointer_at_bcp(Register cache, + Register tmp, + int bcp_offset, + size_t index_size) { + assert(cache != tmp, "must use different register"); + get_cache_index_at_bcp(tmp, bcp_offset, index_size); + assert(sizeof(ConstantPoolCacheEntry) == 4 * wordSize, "adjust code below"); + // Convert from field index to ConstantPoolCacheEntry index + // and from word offset to byte offset + assert(exact_log2(in_bytes(ConstantPoolCacheEntry::size_in_bytes())) == 2 + LogBytesPerWord, + "else change next line"); + ld(cache, Address(fp, frame::interpreter_frame_cache_offset * wordSize)); + // skip past the header + add(cache, cache, in_bytes(ConstantPoolCache::base_offset())); + // construct pointer to cache entry + shadd(cache, tmp, cache, tmp, 2 + LogBytesPerWord); +} + +// Load object from cpool->resolved_references(index) +void InterpreterMacroAssembler::load_resolved_reference_at_index( + Register result, Register index, Register tmp) { + assert_different_registers(result, index); + + get_constant_pool(result); + // Load pointer for resolved_references[] objArray + ld(result, Address(result, ConstantPool::cache_offset_in_bytes())); + ld(result, Address(result, ConstantPoolCache::resolved_references_offset_in_bytes())); + resolve_oop_handle(result, tmp); + // Add in the index + addi(index, index, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop); + shadd(result, index, result, index, LogBytesPerHeapOop); + load_heap_oop(result, Address(result, 0)); +} + +void InterpreterMacroAssembler::load_resolved_klass_at_offset( + Register cpool, Register index, Register klass, Register temp) { + shadd(temp, index, cpool, temp, LogBytesPerWord); + lhu(temp, Address(temp, sizeof(ConstantPool))); // temp = resolved_klass_index + ld(klass, Address(cpool, ConstantPool::resolved_klasses_offset_in_bytes())); // klass = cpool->_resolved_klasses + shadd(klass, temp, klass, temp, LogBytesPerWord); + ld(klass, Address(klass, Array::base_offset_in_bytes())); +} + +void InterpreterMacroAssembler::load_resolved_method_at_index(int byte_no, + Register method, + Register cache) { + const int method_offset = in_bytes( + ConstantPoolCache::base_offset() + + ((byte_no == TemplateTable::f2_byte) + ? ConstantPoolCacheEntry::f2_offset() + : ConstantPoolCacheEntry::f1_offset())); + + ld(method, Address(cache, method_offset)); // get f1 Method* +} + +// Generate a subtype check: branch to ok_is_subtype if sub_klass is a +// subtype of super_klass. +// +// Args: +// x10: superklass +// Rsub_klass: subklass +// +// Kills: +// x12, x15 +void InterpreterMacroAssembler::gen_subtype_check(Register Rsub_klass, + Label& ok_is_subtype) { + assert(Rsub_klass != x10, "x10 holds superklass"); + assert(Rsub_klass != x12, "x12 holds 2ndary super array length"); + assert(Rsub_klass != x15, "x15 holds 2ndary super array scan ptr"); + + // Profile the not-null value's klass. + profile_typecheck(x12, Rsub_klass, x15); // blows x12, reloads x15 + + // Do the check. + check_klass_subtype(Rsub_klass, x10, x12, ok_is_subtype); // blows x12 + + // Profile the failure of the check. + profile_typecheck_failed(x12); // blows x12 +} + +// Java Expression Stack + +void InterpreterMacroAssembler::pop_ptr(Register r) { + ld(r, Address(esp, 0)); + addi(esp, esp, wordSize); +} + +void InterpreterMacroAssembler::pop_i(Register r) { + lw(r, Address(esp, 0)); // lw do signed extended + addi(esp, esp, wordSize); +} + +void InterpreterMacroAssembler::pop_l(Register r) { + ld(r, Address(esp, 0)); + addi(esp, esp, 2 * Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::push_ptr(Register r) { + addi(esp, esp, -wordSize); + sd(r, Address(esp, 0)); +} + +void InterpreterMacroAssembler::push_i(Register r) { + addi(esp, esp, -wordSize); + addw(r, r, zr); // signed extended + sd(r, Address(esp, 0)); +} + +void InterpreterMacroAssembler::push_l(Register r) { + addi(esp, esp, -2 * wordSize); + sd(zr, Address(esp, wordSize)); + sd(r, Address(esp)); +} + +void InterpreterMacroAssembler::pop_f(FloatRegister r) { + flw(r, esp, 0); + addi(esp, esp, wordSize); +} + +void InterpreterMacroAssembler::pop_d(FloatRegister r) { + fld(r, esp, 0); + addi(esp, esp, 2 * Interpreter::stackElementSize); +} + +void InterpreterMacroAssembler::push_f(FloatRegister r) { + addi(esp, esp, -wordSize); + fsw(r, Address(esp, 0)); +} + +void InterpreterMacroAssembler::push_d(FloatRegister r) { + addi(esp, esp, -2 * wordSize); + fsd(r, Address(esp, 0)); +} + +void InterpreterMacroAssembler::pop(TosState state) { + switch (state) { + case atos: + pop_ptr(); + verify_oop(x10); + break; + case btos: // fall through + case ztos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: + pop_i(); + break; + case ltos: + pop_l(); + break; + case ftos: + pop_f(); + break; + case dtos: + pop_d(); + break; + case vtos: + /* nothing to do */ + break; + default: + ShouldNotReachHere(); + } +} + +void InterpreterMacroAssembler::push(TosState state) { + switch (state) { + case atos: + verify_oop(x10); + push_ptr(); + break; + case btos: // fall through + case ztos: // fall through + case ctos: // fall through + case stos: // fall through + case itos: + push_i(); + break; + case ltos: + push_l(); + break; + case ftos: + push_f(); + break; + case dtos: + push_d(); + break; + case vtos: + /* nothing to do */ + break; + default: + ShouldNotReachHere(); + } +} + +// Helpers for swap and dup +void InterpreterMacroAssembler::load_ptr(int n, Register val) { + ld(val, Address(esp, Interpreter::expr_offset_in_bytes(n))); +} + +void InterpreterMacroAssembler::store_ptr(int n, Register val) { + sd(val, Address(esp, Interpreter::expr_offset_in_bytes(n))); +} + +void InterpreterMacroAssembler::load_float(Address src) { + flw(f10, src); +} + +void InterpreterMacroAssembler::load_double(Address src) { + fld(f10, src); +} + +void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() { + // set sender sp + mv(x30, sp); + // record last_sp + sd(esp, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); +} + +// Jump to from_interpreted entry of a call unless single stepping is possible +// in this thread in which case we must call the i2i entry +void InterpreterMacroAssembler::jump_from_interpreted(Register method) { + prepare_to_jump_from_interpreted(); + if (JvmtiExport::can_post_interpreter_events()) { + Label run_compiled_code; + // JVMTI events, such as single-stepping, are implemented partly by avoiding running + // compiled code in threads for which the event is enabled. Check here for + // interp_only_mode if these events CAN be enabled. + lwu(t0, Address(xthread, JavaThread::interp_only_mode_offset())); + beqz(t0, run_compiled_code); + ld(t0, Address(method, Method::interpreter_entry_offset())); + jr(t0); + bind(run_compiled_code); + } + + ld(t0, Address(method, Method::from_interpreted_offset())); + jr(t0); +} + +// The following two routines provide a hook so that an implementation +// can schedule the dispatch in two parts. amd64 does not do this. +void InterpreterMacroAssembler::dispatch_prolog(TosState state, int step) { +} + +void InterpreterMacroAssembler::dispatch_epilog(TosState state, int step) { + dispatch_next(state, step); +} + +void InterpreterMacroAssembler::dispatch_base(TosState state, + address* table, + bool verifyoop, + bool generate_poll, + Register Rs) { + // Pay attention to the argument Rs, which is acquiesce in t0. + if (VerifyActivationFrameSize) { + Unimplemented(); + } + if (verifyoop && state == atos) { + verify_oop(x10); + } + + Label safepoint; + address* const safepoint_table = Interpreter::safept_table(state); + bool needs_thread_local_poll = generate_poll && table != safepoint_table; + + if (needs_thread_local_poll) { + NOT_PRODUCT(block_comment("Thread-local Safepoint poll")); + ld(t1, Address(xthread, JavaThread::polling_word_offset())); + andi(t1, t1, SafepointMechanism::poll_bit()); + bnez(t1, safepoint); + } + if (table == Interpreter::dispatch_table(state)) { + li(t1, Interpreter::distance_from_dispatch_table(state)); + add(t1, Rs, t1); + shadd(t1, t1, xdispatch, t1, 3); + } else { + mv(t1, (address)table); + shadd(t1, Rs, t1, Rs, 3); + } + ld(t1, Address(t1)); + jr(t1); + + if (needs_thread_local_poll) { + bind(safepoint); + la(t1, ExternalAddress((address)safepoint_table)); + shadd(t1, Rs, t1, Rs, 3); + ld(t1, Address(t1)); + jr(t1); + } +} + +void InterpreterMacroAssembler::dispatch_only(TosState state, bool generate_poll, Register Rs) { + dispatch_base(state, Interpreter::dispatch_table(state), true, generate_poll, Rs); +} + +void InterpreterMacroAssembler::dispatch_only_normal(TosState state, Register Rs) { + dispatch_base(state, Interpreter::normal_table(state), Rs); +} + +void InterpreterMacroAssembler::dispatch_only_noverify(TosState state, Register Rs) { + dispatch_base(state, Interpreter::normal_table(state), false, Rs); +} + +void InterpreterMacroAssembler::dispatch_next(TosState state, int step, bool generate_poll) { + // load next bytecode + load_unsigned_byte(t0, Address(xbcp, step)); + add(xbcp, xbcp, step); + dispatch_base(state, Interpreter::dispatch_table(state), true, generate_poll); +} + +void InterpreterMacroAssembler::dispatch_via(TosState state, address* table) { + // load current bytecode + lbu(t0, Address(xbcp, 0)); + dispatch_base(state, table); +} + +// remove activation +// +// Apply stack watermark barrier. +// Unlock the receiver if this is a synchronized method. +// Unlock any Java monitors from syncronized blocks. +// Remove the activation from the stack. +// +// If there are locked Java monitors +// If throw_monitor_exception +// throws IllegalMonitorStateException +// Else if install_monitor_exception +// installs IllegalMonitorStateException +// Else +// no error processing +void InterpreterMacroAssembler::remove_activation( + TosState state, + bool throw_monitor_exception, + bool install_monitor_exception, + bool notify_jvmdi) { + // Note: Registers x13 may be in use for the + // result check if synchronized method + Label unlocked, unlock, no_unlock; + + // The below poll is for the stack watermark barrier. It allows fixing up frames lazily, + // that would normally not be safe to use. Such bad returns into unsafe territory of + // the stack, will call InterpreterRuntime::at_unwind. + Label slow_path; + Label fast_path; + safepoint_poll(slow_path, true /* at_return */, false /* acquire */, false /* in_nmethod */); + j(fast_path); + + bind(slow_path); + push(state); + set_last_Java_frame(esp, fp, (address)pc(), t0); + super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), xthread); + reset_last_Java_frame(true); + pop(state); + + bind(fast_path); + + // get the value of _do_not_unlock_if_synchronized into x13 + const Address do_not_unlock_if_synchronized(xthread, + in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); + lbu(x13, do_not_unlock_if_synchronized); + sb(zr, do_not_unlock_if_synchronized); // reset the flag + + // get method access flags + ld(x11, Address(fp, frame::interpreter_frame_method_offset * wordSize)); + ld(x12, Address(x11, Method::access_flags_offset())); + andi(t0, x12, JVM_ACC_SYNCHRONIZED); + beqz(t0, unlocked); + + // Don't unlock anything if the _do_not_unlock_if_synchronized flag + // is set. + bnez(x13, no_unlock); + + // unlock monitor + push(state); // save result + + // BasicObjectLock will be first in list, since this is a + // synchronized method. However, need to check that the object has + // not been unlocked by an explicit monitorexit bytecode. + const Address monitor(fp, frame::interpreter_frame_initial_sp_offset * + wordSize - (int) sizeof(BasicObjectLock)); + // We use c_rarg1 so that if we go slow path it will be the correct + // register for unlock_object to pass to VM directly + la(c_rarg1, monitor); // address of first monitor + + ld(x10, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes())); + bnez(x10, unlock); + + pop(state); + if (throw_monitor_exception) { + // Entry already unlocked, need to throw exception + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_illegal_monitor_state_exception)); + should_not_reach_here(); + } else { + // Monitor already unlocked during a stack unroll. If requested, + // install an illegal_monitor_state_exception. Continue with + // stack unrolling. + if (install_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::new_illegal_monitor_state_exception)); + } + j(unlocked); + } + + bind(unlock); + unlock_object(c_rarg1); + pop(state); + + // Check that for block-structured locking (i.e., that all locked + // objects has been unlocked) + bind(unlocked); + + // x10: Might contain return value + + // Check that all monitors are unlocked + { + Label loop, exception, entry, restart; + const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + const Address monitor_block_top( + fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); + const Address monitor_block_bot( + fp, frame::interpreter_frame_initial_sp_offset * wordSize); + + bind(restart); + // We use c_rarg1 so that if we go slow path it will be the correct + // register for unlock_object to pass to VM directly + ld(c_rarg1, monitor_block_top); // points to current entry, starting + // with top-most entry + la(x9, monitor_block_bot); // points to word before bottom of + // monitor block + + j(entry); + + // Entry already locked, need to throw exception + bind(exception); + + if (throw_monitor_exception) { + // Throw exception + MacroAssembler::call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime:: + throw_illegal_monitor_state_exception)); + + should_not_reach_here(); + } else { + // Stack unrolling. Unlock object and install illegal_monitor_exception. + // Unlock does not block, so don't have to worry about the frame. + // We don't have to preserve c_rarg1 since we are going to throw an exception. + + push(state); + unlock_object(c_rarg1); + pop(state); + + if (install_monitor_exception) { + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime:: + new_illegal_monitor_state_exception)); + } + + j(restart); + } + + bind(loop); + // check if current entry is used + add(t0, c_rarg1, BasicObjectLock::obj_offset_in_bytes()); + ld(t0, Address(t0, 0)); + bnez(t0, exception); + + add(c_rarg1, c_rarg1, entry_size); // otherwise advance to next entry + bind(entry); + bne(c_rarg1, x9, loop); // check if bottom reached if not at bottom then check this entry + } + + bind(no_unlock); + + // jvmti support + if (notify_jvmdi) { + notify_method_exit(state, NotifyJVMTI); // preserve TOSCA + + } else { + notify_method_exit(state, SkipNotifyJVMTI); // preserve TOSCA + } + + // remove activation + // get sender esp + ld(t1, + Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); + if (StackReservedPages > 0) { + // testing if reserved zone needs to be re-enabled + Label no_reserved_zone_enabling; + + ld(t0, Address(xthread, JavaThread::reserved_stack_activation_offset())); + ble(t1, t0, no_reserved_zone_enabling); + + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), xthread); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_delayed_StackOverflowError)); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); + } + + // restore sender esp + mv(esp, t1); + + // remove frame anchor + leave(); + // If we're returning to interpreted code we will shortly be + // adjusting SP to allow some space for ESP. If we're returning to + // compiled code the saved sender SP was saved in sender_sp, so this + // restores it. + andi(sp, esp, -16); +} + +// Lock object +// +// Args: +// c_rarg1: BasicObjectLock to be used for locking +// +// Kills: +// x10 +// c_rarg0, c_rarg1, c_rarg2, c_rarg3, .. (param regs) +// t0, t1 (temp regs) +void InterpreterMacroAssembler::lock_object(Register lock_reg) +{ + assert(lock_reg == c_rarg1, "The argument is only for looks. It must be c_rarg1"); + if (UseHeavyMonitors) { + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); + } else { + Label done; + + const Register swap_reg = x10; + const Register tmp = c_rarg2; + const Register obj_reg = c_rarg3; // Will contain the oop + + const int obj_offset = BasicObjectLock::obj_offset_in_bytes(); + const int lock_offset = BasicObjectLock::lock_offset_in_bytes (); + const int mark_offset = lock_offset + + BasicLock::displaced_header_offset_in_bytes(); + + Label slow_case; + + // Load object pointer into obj_reg c_rarg3 + ld(obj_reg, Address(lock_reg, obj_offset)); + + if (DiagnoseSyncOnValueBasedClasses != 0) { + load_klass(tmp, obj_reg); + lwu(tmp, Address(tmp, Klass::access_flags_offset())); + andi(tmp, tmp, JVM_ACC_IS_VALUE_BASED_CLASS); + bnez(tmp, slow_case); + } + + // Load (object->mark() | 1) into swap_reg + ld(t0, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + ori(swap_reg, t0, 1); + + // Save (object->mark() | 1) into BasicLock's displaced header + sd(swap_reg, Address(lock_reg, mark_offset)); + + assert(lock_offset == 0, + "displached header must be first word in BasicObjectLock"); + + cmpxchg_obj_header(swap_reg, lock_reg, obj_reg, t0, done, /*fallthrough*/NULL); + + // Test if the oopMark is an obvious stack pointer, i.e., + // 1) (mark & 7) == 0, and + // 2) sp <= mark < mark + os::pagesize() + // + // These 3 tests can be done by evaluating the following + // expression: ((mark - sp) & (7 - os::vm_page_size())), + // assuming both stack pointer and pagesize have their + // least significant 3 bits clear. + // NOTE: the oopMark is in swap_reg x10 as the result of cmpxchg + sub(swap_reg, swap_reg, sp); + li(t0, (int64_t)(7 - os::vm_page_size())); + andr(swap_reg, swap_reg, t0); + + // Save the test result, for recursive case, the result is zero + sd(swap_reg, Address(lock_reg, mark_offset)); + beqz(swap_reg, done); + + bind(slow_case); + + // Call the runtime routine for slow case + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorenter), + lock_reg); + + bind(done); + } +} + + +// Unlocks an object. Used in monitorexit bytecode and +// remove_activation. Throws an IllegalMonitorException if object is +// not locked by current thread. +// +// Args: +// c_rarg1: BasicObjectLock for lock +// +// Kills: +// x10 +// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ... (param regs) +// t0, t1 (temp regs) +void InterpreterMacroAssembler::unlock_object(Register lock_reg) +{ + assert(lock_reg == c_rarg1, "The argument is only for looks. It must be rarg1"); + + if (UseHeavyMonitors) { + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + } else { + Label done; + + const Register swap_reg = x10; + const Register header_reg = c_rarg2; // Will contain the old oopMark + const Register obj_reg = c_rarg3; // Will contain the oop + + save_bcp(); // Save in case of exception + + // Convert from BasicObjectLock structure to object and BasicLock + // structure Store the BasicLock address into x10 + la(swap_reg, Address(lock_reg, BasicObjectLock::lock_offset_in_bytes())); + + // Load oop into obj_reg(c_rarg3) + ld(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); + + // Free entry + sd(zr, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); + + // Load the old header from BasicLock structure + ld(header_reg, Address(swap_reg, + BasicLock::displaced_header_offset_in_bytes())); + + // Test for recursion + beqz(header_reg, done); + + // Atomic swap back the old header + cmpxchg_obj_header(swap_reg, header_reg, obj_reg, t0, done, /*fallthrough*/NULL); + + // Call the runtime routine for slow case. + sd(obj_reg, Address(lock_reg, BasicObjectLock::obj_offset_in_bytes())); // restore obj + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::monitorexit), lock_reg); + + bind(done); + + restore_bcp(); + } +} + + +void InterpreterMacroAssembler::test_method_data_pointer(Register mdp, + Label& zero_continue) { + assert(ProfileInterpreter, "must be profiling interpreter"); + ld(mdp, Address(fp, frame::interpreter_frame_mdp_offset * wordSize)); + beqz(mdp, zero_continue); +} + +// Set the method data pointer for the current bcp. +void InterpreterMacroAssembler::set_method_data_pointer_for_bcp() { + assert(ProfileInterpreter, "must be profiling interpreter"); + Label set_mdp; + push_reg(0xc00, sp); // save x10, x11 + + // Test MDO to avoid the call if it is NULL. + ld(x10, Address(xmethod, in_bytes(Method::method_data_offset()))); + beqz(x10, set_mdp); + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::bcp_to_di), xmethod, xbcp); + // x10: mdi + // mdo is guaranteed to be non-zero here, we checked for it before the call. + ld(x11, Address(xmethod, in_bytes(Method::method_data_offset()))); + la(x11, Address(x11, in_bytes(MethodData::data_offset()))); + add(x10, x11, x10); + sd(x10, Address(fp, frame::interpreter_frame_mdp_offset * wordSize)); + bind(set_mdp); + pop_reg(0xc00, sp); +} + +void InterpreterMacroAssembler::verify_method_data_pointer() { + assert(ProfileInterpreter, "must be profiling interpreter"); +#ifdef ASSERT + Label verify_continue; + add(sp, sp, -4 * wordSize); + sd(x10, Address(sp, 0)); + sd(x11, Address(sp, wordSize)); + sd(x12, Address(sp, 2 * wordSize)); + sd(x13, Address(sp, 3 * wordSize)); + test_method_data_pointer(x13, verify_continue); // If mdp is zero, continue + get_method(x11); + + // If the mdp is valid, it will point to a DataLayout header which is + // consistent with the bcp. The converse is highly probable also. + lh(x12, Address(x13, in_bytes(DataLayout::bci_offset()))); + ld(t0, Address(x11, Method::const_offset())); + add(x12, x12, t0); + la(x12, Address(x12, ConstMethod::codes_offset())); + beq(x12, xbcp, verify_continue); + // x10: method + // xbcp: bcp // xbcp == 22 + // x13: mdp + call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::verify_mdp), + x11, xbcp, x13); + bind(verify_continue); + ld(x10, Address(sp, 0)); + ld(x11, Address(sp, wordSize)); + ld(x12, Address(sp, 2 * wordSize)); + ld(x13, Address(sp, 3 * wordSize)); + add(sp, sp, 4 * wordSize); +#endif // ASSERT +} + + +void InterpreterMacroAssembler::set_mdp_data_at(Register mdp_in, + int constant, + Register value) { + assert(ProfileInterpreter, "must be profiling interpreter"); + Address data(mdp_in, constant); + sd(value, data); +} + + +void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, + int constant, + bool decrement) { + increment_mdp_data_at(mdp_in, noreg, constant, decrement); +} + +void InterpreterMacroAssembler::increment_mdp_data_at(Register mdp_in, + Register reg, + int constant, + bool decrement) { + assert(ProfileInterpreter, "must be profiling interpreter"); + // %%% this does 64bit counters at best it is wasting space + // at worst it is a rare bug when counters overflow + + assert_different_registers(t1, t0, mdp_in, reg); + + Address addr1(mdp_in, constant); + Address addr2(t1, 0); + Address &addr = addr1; + if (reg != noreg) { + la(t1, addr1); + add(t1, t1, reg); + addr = addr2; + } + + if (decrement) { + ld(t0, addr); + addi(t0, t0, -DataLayout::counter_increment); + Label L; + bltz(t0, L); // skip store if counter underflow + sd(t0, addr); + bind(L); + } else { + assert(DataLayout::counter_increment == 1, + "flow-free idiom only works with 1"); + ld(t0, addr); + addi(t0, t0, DataLayout::counter_increment); + Label L; + blez(t0, L); // skip store if counter overflow + sd(t0, addr); + bind(L); + } +} + +void InterpreterMacroAssembler::set_mdp_flag_at(Register mdp_in, + int flag_byte_constant) { + assert(ProfileInterpreter, "must be profiling interpreter"); + int flags_offset = in_bytes(DataLayout::flags_offset()); + // Set the flag + lbu(t1, Address(mdp_in, flags_offset)); + ori(t1, t1, flag_byte_constant); + sb(t1, Address(mdp_in, flags_offset)); +} + + +void InterpreterMacroAssembler::test_mdp_data_at(Register mdp_in, + int offset, + Register value, + Register test_value_out, + Label& not_equal_continue) { + assert(ProfileInterpreter, "must be profiling interpreter"); + if (test_value_out == noreg) { + ld(t1, Address(mdp_in, offset)); + bne(value, t1, not_equal_continue); + } else { + // Put the test value into a register, so caller can use it: + ld(test_value_out, Address(mdp_in, offset)); + bne(value, test_value_out, not_equal_continue); + } +} + + +void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, + int offset_of_disp) { + assert(ProfileInterpreter, "must be profiling interpreter"); + ld(t1, Address(mdp_in, offset_of_disp)); + add(mdp_in, mdp_in, t1); + sd(mdp_in, Address(fp, frame::interpreter_frame_mdp_offset * wordSize)); +} + +void InterpreterMacroAssembler::update_mdp_by_offset(Register mdp_in, + Register reg, + int offset_of_disp) { + assert(ProfileInterpreter, "must be profiling interpreter"); + add(t1, mdp_in, reg); + ld(t1, Address(t1, offset_of_disp)); + add(mdp_in, mdp_in, t1); + sd(mdp_in, Address(fp, frame::interpreter_frame_mdp_offset * wordSize)); +} + + +void InterpreterMacroAssembler::update_mdp_by_constant(Register mdp_in, + int constant) { + assert(ProfileInterpreter, "must be profiling interpreter"); + addi(mdp_in, mdp_in, (unsigned)constant); + sd(mdp_in, Address(fp, frame::interpreter_frame_mdp_offset * wordSize)); +} + + +void InterpreterMacroAssembler::update_mdp_for_ret(Register return_bci) { + assert(ProfileInterpreter, "must be profiling interpreter"); + + // save/restore across call_VM + addi(sp, sp, -2 * wordSize); + sd(zr, Address(sp, 0)); + sd(return_bci, Address(sp, wordSize)); + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::update_mdp_for_ret), + return_bci); + ld(zr, Address(sp, 0)); + ld(return_bci, Address(sp, wordSize)); + addi(sp, sp, 2 * wordSize); +} + +void InterpreterMacroAssembler::profile_taken_branch(Register mdp, + Register bumped_count) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + // Otherwise, assign to mdp + test_method_data_pointer(mdp, profile_continue); + + // We are taking a branch. Increment the taken count. + Address data(mdp, in_bytes(JumpData::taken_offset())); + ld(bumped_count, data); + assert(DataLayout::counter_increment == 1, + "flow-free idiom only works with 1"); + addi(bumped_count, bumped_count, DataLayout::counter_increment); + Label L; + // eg: bumped_count=0x7fff ffff ffff ffff + 1 < 0. so we use <= 0; + blez(bumped_count, L); // skip store if counter overflow, + sd(bumped_count, data); + bind(L); + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_offset(mdp, in_bytes(JumpData::displacement_offset())); + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_not_taken_branch(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // We are taking a branch. Increment the not taken count. + increment_mdp_data_at(mdp, in_bytes(BranchData::not_taken_offset())); + + // The method data pointer needs to be updated to correspond to + // the next bytecode + update_mdp_by_constant(mdp, in_bytes(BranchData::branch_data_size())); + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_call(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // We are making a call. Increment the count. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(mdp, in_bytes(CounterData::counter_data_size())); + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_final_call(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // We are making a call. Increment the count. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_constant(mdp, + in_bytes(VirtualCallData:: + virtual_call_data_size())); + bind(profile_continue); + } +} + + +void InterpreterMacroAssembler::profile_virtual_call(Register receiver, + Register mdp, + Register reg2, + bool receiver_can_be_null) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + Label skip_receiver_profile; + if (receiver_can_be_null) { + Label not_null; + // We are making a call. Increment the count for null receiver. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + j(skip_receiver_profile); + bind(not_null); + } + + // Record the receiver type. + record_klass_in_profile(receiver, mdp, reg2, true); + bind(skip_receiver_profile); + + // The method data pointer needs to be updated to reflect the new target. + + update_mdp_by_constant(mdp, + in_bytes(VirtualCallData:: + virtual_call_data_size())); + bind(profile_continue); + } +} + +// This routine creates a state machine for updating the multi-row +// type profile at a virtual call site (or other type-sensitive bytecode). +// The machine visits each row (of receiver/count) until the receiver type +// is found, or until it runs out of rows. At the same time, it remembers +// the location of the first empty row. (An empty row records null for its +// receiver, and can be allocated for a newly-observed receiver type.) +// Because there are two degrees of freedom in the state, a simple linear +// search will not work; it must be a decision tree. Hence this helper +// function is recursive, to generate the required tree structured code. +// It's the interpreter, so we are trading off code space for speed. +// See below for example code. +void InterpreterMacroAssembler::record_klass_in_profile_helper( + Register receiver, Register mdp, + Register reg2, + Label& done, bool is_virtual_call) { + if (TypeProfileWidth == 0) { + if (is_virtual_call) { + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + } + + } else { + int non_profiled_offset = -1; + if (is_virtual_call) { + non_profiled_offset = in_bytes(CounterData::count_offset()); + } + + record_item_in_profile_helper(receiver, mdp, reg2, 0, done, TypeProfileWidth, + &VirtualCallData::receiver_offset, &VirtualCallData::receiver_count_offset, non_profiled_offset); + } +} + +void InterpreterMacroAssembler::record_item_in_profile_helper( + Register item, Register mdp, Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, int non_profiled_offset) { + int last_row = total_rows - 1; + assert(start_row <= last_row, "must be work left to do"); + // Test this row for both the item and for null. + // Take any of three different outcomes: + // 1. found item => increment count and goto done + // 2. found null => keep looking for case 1, maybe allocate this cell + // 3. found something else => keep looking for cases 1 and 2 + // Case 3 is handled by a recursive call. + for (int row = start_row; row <= last_row; row++) { + Label next_test; + bool test_for_null_also = (row == start_row); + + // See if the item is item[n]. + int item_offset = in_bytes(item_offset_fn(row)); + test_mdp_data_at(mdp, item_offset, item, + (test_for_null_also ? reg2 : noreg), + next_test); + // (Reg2 now contains the item from the CallData.) + + // The item is item[n]. Increment count[n]. + int count_offset = in_bytes(item_count_offset_fn(row)); + increment_mdp_data_at(mdp, count_offset); + j(done); + bind(next_test); + + if (test_for_null_also) { + Label found_null; + // Failed the equality check on item[n]... Test for null. + if (start_row == last_row) { + // The only thing left to do is handle the null case. + if (non_profiled_offset >= 0) { + beqz(reg2, found_null); + // Item did not match any saved item and there is no empty row for it. + // Increment total counter to indicate polymorphic case. + increment_mdp_data_at(mdp, non_profiled_offset); + j(done); + bind(found_null); + } else { + bnez(reg2, done); + } + break; + } + // Since null is rare, make it be the branch-taken case. + beqz(reg2, found_null); + + // Put all the "Case 3" tests here. + record_item_in_profile_helper(item, mdp, reg2, start_row + 1, done, total_rows, + item_offset_fn, item_count_offset_fn, non_profiled_offset); + + // Found a null. Keep searching for a matching item, + // but remember that this is an empty (unused) slot. + bind(found_null); + } + } + + // In the fall-through case, we found no matching item, but we + // observed the item[start_row] is NULL. + // Fill in the item field and increment the count. + int item_offset = in_bytes(item_offset_fn(start_row)); + set_mdp_data_at(mdp, item_offset, item); + int count_offset = in_bytes(item_count_offset_fn(start_row)); + mv(reg2, DataLayout::counter_increment); + set_mdp_data_at(mdp, count_offset, reg2); + if (start_row > 0) { + j(done); + } +} + +// Example state machine code for three profile rows: +// # main copy of decision tree, rooted at row[1] +// if (row[0].rec == rec) then [ +// row[0].incr() +// goto done +// ] +// if (row[0].rec != NULL) then [ +// # inner copy of decision tree, rooted at row[1] +// if (row[1].rec == rec) then [ +// row[1].incr() +// goto done +// ] +// if (row[1].rec != NULL) then [ +// # degenerate decision tree, rooted at row[2] +// if (row[2].rec == rec) then [ +// row[2].incr() +// goto done +// ] +// if (row[2].rec != NULL) then [ +// count.incr() +// goto done +// ] # overflow +// row[2].init(rec) +// goto done +// ] else [ +// # remember row[1] is empty +// if (row[2].rec == rec) then [ +// row[2].incr() +// goto done +// ] +// row[1].init(rec) +// goto done +// ] +// else [ +// # remember row[0] is empty +// if (row[1].rec == rec) then [ +// row[1].incr() +// goto done +// ] +// if (row[2].rec == rec) then [ +// row[2].incr() +// goto done +// ] +// row[0].init(rec) +// goto done +// ] +// done: + +void InterpreterMacroAssembler::record_klass_in_profile(Register receiver, + Register mdp, Register reg2, + bool is_virtual_call) { + assert(ProfileInterpreter, "must be profiling"); + Label done; + + record_klass_in_profile_helper(receiver, mdp, reg2, done, is_virtual_call); + + bind(done); +} + +void InterpreterMacroAssembler::profile_ret(Register return_bci, Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // Update the total ret count. + increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset())); + + for (uint row = 0; row < RetData::row_limit(); row++) { + Label next_test; + + // See if return_bci is equal to bci[n]: + test_mdp_data_at(mdp, + in_bytes(RetData::bci_offset(row)), + return_bci, noreg, + next_test); + + // return_bci is equal to bci[n]. Increment the count. + increment_mdp_data_at(mdp, in_bytes(RetData::bci_count_offset(row))); + + // The method data pointer needs to be updated to reflect the new target. + update_mdp_by_offset(mdp, + in_bytes(RetData::bci_displacement_offset(row))); + j(profile_continue); + bind(next_test); + } + + update_mdp_for_ret(return_bci); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_null_seen(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + set_mdp_flag_at(mdp, BitData::null_seen_byte_constant()); + + // The method data pointer needs to be updated. + int mdp_delta = in_bytes(BitData::bit_data_size()); + if (TypeProfileCasts) { + mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + } + update_mdp_by_constant(mdp, mdp_delta); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_typecheck_failed(Register mdp) { + if (ProfileInterpreter && TypeProfileCasts) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + int count_offset = in_bytes(CounterData::count_offset()); + // Back up the address, since we have already bumped the mdp. + count_offset -= in_bytes(VirtualCallData::virtual_call_data_size()); + + // *Decrement* the counter. We expect to see zero or small negatives. + increment_mdp_data_at(mdp, count_offset, true); + + bind (profile_continue); + } +} + +void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass, Register reg2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // The method data pointer needs to be updated. + int mdp_delta = in_bytes(BitData::bit_data_size()); + if (TypeProfileCasts) { + mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size()); + + // Record the object type. + record_klass_in_profile(klass, mdp, reg2, false); + } + update_mdp_by_constant(mdp, mdp_delta); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_switch_default(Register mdp) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // Update the default case count + increment_mdp_data_at(mdp, + in_bytes(MultiBranchData::default_count_offset())); + + // The method data pointer needs to be updated. + update_mdp_by_offset(mdp, + in_bytes(MultiBranchData:: + default_displacement_offset())); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_switch_case(Register index, + Register mdp, + Register reg2) { + if (ProfileInterpreter) { + Label profile_continue; + + // If no method data exists, go to profile_continue. + test_method_data_pointer(mdp, profile_continue); + + // Build the base (index * per_case_size_in_bytes()) + + // case_array_offset_in_bytes() + mvw(reg2, in_bytes(MultiBranchData::per_case_size())); + mvw(t0, in_bytes(MultiBranchData::case_array_offset())); + Assembler::mul(index, index, reg2); + Assembler::add(index, index, t0); + + // Update the case count + increment_mdp_data_at(mdp, + index, + in_bytes(MultiBranchData::relative_count_offset())); + + // The method data pointer need to be updated. + update_mdp_by_offset(mdp, + index, + in_bytes(MultiBranchData:: + relative_displacement_offset())); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::verify_FPU(int stack_depth, TosState state) { ; } + +void InterpreterMacroAssembler::notify_method_entry() { + // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to + // track stack depth. If it is possible to enter interp_only_mode we add + // the code to check if the event should be sent. + if (JvmtiExport::can_post_interpreter_events()) { + Label L; + lwu(x13, Address(xthread, JavaThread::interp_only_mode_offset())); + beqz(x13, L); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::post_method_entry)); + bind(L); + } + + { + SkipIfEqual skip(this, &DTraceMethodProbes, false); + get_method(c_rarg1); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), + xthread, c_rarg1); + } + + // RedefineClasses() tracing support for obsolete method entry + if (log_is_enabled(Trace, redefine, class, obsolete)) { + get_method(c_rarg1); + call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + xthread, c_rarg1); + } +} + + +void InterpreterMacroAssembler::notify_method_exit( + TosState state, NotifyMethodExitMode mode) { + // Whenever JVMTI is interp_only_mode, method entry/exit events are sent to + // track stack depth. If it is possible to enter interp_only_mode we add + // the code to check if the event should be sent. + if (mode == NotifyJVMTI && JvmtiExport::can_post_interpreter_events()) { + Label L; + // Note: frame::interpreter_frame_result has a dependency on how the + // method result is saved across the call to post_method_exit. If this + // is changed then the interpreter_frame_result implementation will + // need to be updated too. + + // template interpreter will leave the result on the top of the stack. + push(state); + lwu(x13, Address(xthread, JavaThread::interp_only_mode_offset())); + beqz(x13, L); + call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::post_method_exit)); + bind(L); + pop(state); + } + + { + SkipIfEqual skip(this, &DTraceMethodProbes, false); + push(state); + get_method(c_rarg1); + call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), + xthread, c_rarg1); + pop(state); + } +} + + +// Jump if ((*counter_addr += increment) & mask) satisfies the condition. +void InterpreterMacroAssembler::increment_mask_and_jump(Address counter_addr, + int increment, Address mask, + Register tmp1, Register tmp2, + bool preloaded, Label* where) { + Label done; + if (!preloaded) { + lwu(tmp1, counter_addr); + } + add(tmp1, tmp1, increment); + sw(tmp1, counter_addr); + lwu(tmp2, mask); + andr(tmp1, tmp1, tmp2); + bnez(tmp1, done); + j(*where); // offset is too large so we have to use j instead of beqz here + bind(done); +} + +void InterpreterMacroAssembler::call_VM_leaf_base(address entry_point, + int number_of_arguments) { + // interpreter specific + // + // Note: No need to save/restore rbcp & rlocals pointer since these + // are callee saved registers and no blocking/ GC can happen + // in leaf calls. +#ifdef ASSERT + { + Label L; + ld(t0, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + beqz(t0, L); + stop("InterpreterMacroAssembler::call_VM_leaf_base:" + " last_sp != NULL"); + bind(L); + } +#endif /* ASSERT */ + // super call + MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments); +} + +void InterpreterMacroAssembler::call_VM_base(Register oop_result, + Register java_thread, + Register last_java_sp, + address entry_point, + int number_of_arguments, + bool check_exceptions) { + // interpreter specific + // + // Note: Could avoid restoring locals ptr (callee saved) - however doesn't + // really make a difference for these runtime calls, since they are + // slow anyway. Btw., bcp must be saved/restored since it may change + // due to GC. + save_bcp(); +#ifdef ASSERT + { + Label L; + ld(t0, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + beqz(t0, L); + stop("InterpreterMacroAssembler::call_VM_base:" + " last_sp != NULL"); + bind(L); + } +#endif /* ASSERT */ + // super call + MacroAssembler::call_VM_base(oop_result, noreg, last_java_sp, + entry_point, number_of_arguments, + check_exceptions); +// interpreter specific + restore_bcp(); + restore_locals(); +} + +void InterpreterMacroAssembler::profile_obj_type(Register obj, const Address& mdo_addr, Register tmp) { + assert_different_registers(obj, tmp, t0, mdo_addr.base()); + Label update, next, none; + + verify_oop(obj); + + bnez(obj, update); + orptr(mdo_addr, TypeEntries::null_seen, t0, tmp); + j(next); + + bind(update); + load_klass(obj, obj); + + ld(t0, mdo_addr); + xorr(obj, obj, t0); + andi(t0, obj, TypeEntries::type_klass_mask); + beqz(t0, next); // klass seen before, nothing to + // do. The unknown bit may have been + // set already but no need to check. + + andi(t0, obj, TypeEntries::type_unknown); + bnez(t0, next); + // already unknown. Nothing to do anymore. + + ld(t0, mdo_addr); + beqz(t0, none); + li(tmp, (u1)TypeEntries::null_seen); + beq(t0, tmp, none); + // There is a chance that the checks above (re-reading profiling + // data from memory) fail if another thread has just set the + // profiling to this obj's klass + ld(t0, mdo_addr); + xorr(obj, obj, t0); + andi(t0, obj, TypeEntries::type_klass_mask); + beqz(t0, next); + + // different than before. Cannot keep accurate profile. + orptr(mdo_addr, TypeEntries::type_unknown, t0, tmp); + j(next); + + bind(none); + // first time here. Set profile type. + sd(obj, mdo_addr); + + bind(next); +} + +void InterpreterMacroAssembler::profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual) { + if (!ProfileInterpreter) { + return; + } + + if (MethodData::profile_arguments() || MethodData::profile_return()) { + Label profile_continue; + + test_method_data_pointer(mdp, profile_continue); + + int off_to_start = is_virtual ? in_bytes(VirtualCallData::virtual_call_data_size()) : in_bytes(CounterData::counter_data_size()); + + lbu(t0, Address(mdp, in_bytes(DataLayout::tag_offset()) - off_to_start)); + if (is_virtual) { + li(tmp, (u1)DataLayout::virtual_call_type_data_tag); + bne(t0, tmp, profile_continue); + } else { + li(tmp, (u1)DataLayout::call_type_data_tag); + bne(t0, tmp, profile_continue); + } + + // calculate slot step + static int stack_slot_offset0 = in_bytes(TypeEntriesAtCall::stack_slot_offset(0)); + static int slot_step = in_bytes(TypeEntriesAtCall::stack_slot_offset(1)) - stack_slot_offset0; + + // calculate type step + static int argument_type_offset0 = in_bytes(TypeEntriesAtCall::argument_type_offset(0)); + static int type_step = in_bytes(TypeEntriesAtCall::argument_type_offset(1)) - argument_type_offset0; + + if (MethodData::profile_arguments()) { + Label done, loop, loopEnd, profileArgument, profileReturnType; + RegSet pushed_registers; + pushed_registers += x15; + pushed_registers += x16; + pushed_registers += x17; + Register mdo_addr = x15; + Register index = x16; + Register off_to_args = x17; + push_reg(pushed_registers, sp); + + mv(off_to_args, in_bytes(TypeEntriesAtCall::args_data_offset())); + mv(t0, TypeProfileArgsLimit); + beqz(t0, loopEnd); + + mv(index, zr); // index < TypeProfileArgsLimit + bind(loop); + bgtz(index, profileReturnType); + li(t0, (int)MethodData::profile_return()); + beqz(t0, profileArgument); // (index > 0 || MethodData::profile_return()) == false + bind(profileReturnType); + // If return value type is profiled we may have no argument to profile + ld(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset()))); + mv(t1, - TypeStackSlotEntries::per_arg_count()); + mul(t1, index, t1); + add(tmp, tmp, t1); + li(t1, TypeStackSlotEntries::per_arg_count()); + add(t0, mdp, off_to_args); + blt(tmp, t1, done); + + bind(profileArgument); + + ld(tmp, Address(callee, Method::const_offset())); + load_unsigned_short(tmp, Address(tmp, ConstMethod::size_of_parameters_offset())); + // stack offset o (zero based) from the start of the argument + // list, for n arguments translates into offset n - o - 1 from + // the end of the argument list + li(t0, stack_slot_offset0); + li(t1, slot_step); + mul(t1, index, t1); + add(t0, t0, t1); + add(t0, mdp, t0); + ld(t0, Address(t0)); + sub(tmp, tmp, t0); + addi(tmp, tmp, -1); + Address arg_addr = argument_address(tmp); + ld(tmp, arg_addr); + + li(t0, argument_type_offset0); + li(t1, type_step); + mul(t1, index, t1); + add(t0, t0, t1); + add(mdo_addr, mdp, t0); + Address mdo_arg_addr(mdo_addr, 0); + profile_obj_type(tmp, mdo_arg_addr, t1); + + int to_add = in_bytes(TypeStackSlotEntries::per_arg_size()); + addi(off_to_args, off_to_args, to_add); + + // increment index by 1 + addi(index, index, 1); + li(t1, TypeProfileArgsLimit); + blt(index, t1, loop); + bind(loopEnd); + + if (MethodData::profile_return()) { + ld(tmp, Address(mdp, in_bytes(TypeEntriesAtCall::cell_count_offset()))); + addi(tmp, tmp, -TypeProfileArgsLimit*TypeStackSlotEntries::per_arg_count()); + } + + add(t0, mdp, off_to_args); + bind(done); + mv(mdp, t0); + + // unspill the clobbered registers + pop_reg(pushed_registers, sp); + + if (MethodData::profile_return()) { + // We're right after the type profile for the last + // argument. tmp is the number of cells left in the + // CallTypeData/VirtualCallTypeData to reach its end. Non null + // if there's a return to profile. + assert(ReturnTypeEntry::static_cell_count() < TypeStackSlotEntries::per_arg_count(), "can't move past ret type"); + shadd(mdp, tmp, mdp, tmp, exact_log2(DataLayout::cell_size)); + } + sd(mdp, Address(fp, frame::interpreter_frame_mdp_offset * wordSize)); + } else { + assert(MethodData::profile_return(), "either profile call args or call ret"); + update_mdp_by_constant(mdp, in_bytes(TypeEntriesAtCall::return_only_size())); + } + + // mdp points right after the end of the + // CallTypeData/VirtualCallTypeData, right after the cells for the + // return value type if there's one + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_return_type(Register mdp, Register ret, Register tmp) { + assert_different_registers(mdp, ret, tmp, xbcp, t0, t1); + if (ProfileInterpreter && MethodData::profile_return()) { + Label profile_continue, done; + + test_method_data_pointer(mdp, profile_continue); + + if (MethodData::profile_return_jsr292_only()) { + assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2"); + + // If we don't profile all invoke bytecodes we must make sure + // it's a bytecode we indeed profile. We can't go back to the + // begining of the ProfileData we intend to update to check its + // type because we're right after it and we don't known its + // length + Label do_profile; + lbu(t0, Address(xbcp, 0)); + li(tmp, (u1)Bytecodes::_invokedynamic); + beq(t0, tmp, do_profile); + li(tmp, (u1)Bytecodes::_invokehandle); + beq(t0, tmp, do_profile); + get_method(tmp); + lhu(t0, Address(tmp, Method::intrinsic_id_offset_in_bytes())); + li(t1, static_cast(vmIntrinsics::_compiledLambdaForm)); + bne(t0, t1, profile_continue); + bind(do_profile); + } + + Address mdo_ret_addr(mdp, -in_bytes(ReturnTypeEntry::size())); + mv(tmp, ret); + profile_obj_type(tmp, mdo_ret_addr, t1); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::profile_parameters_type(Register mdp, Register tmp1, Register tmp2, Register tmp3) { + assert_different_registers(t0, t1, mdp, tmp1, tmp2, tmp3); + if (ProfileInterpreter && MethodData::profile_parameters()) { + Label profile_continue, done; + + test_method_data_pointer(mdp, profile_continue); + + // Load the offset of the area within the MDO used for + // parameters. If it's negative we're not profiling any parameters + lwu(tmp1, Address(mdp, in_bytes(MethodData::parameters_type_data_di_offset()) - in_bytes(MethodData::data_offset()))); + srli(tmp2, tmp1, 31); + bnez(tmp2, profile_continue); // i.e. sign bit set + + // Compute a pointer to the area for parameters from the offset + // and move the pointer to the slot for the last + // parameters. Collect profiling from last parameter down. + // mdo start + parameters offset + array length - 1 + add(mdp, mdp, tmp1); + ld(tmp1, Address(mdp, ArrayData::array_len_offset())); + add(tmp1, tmp1, - TypeStackSlotEntries::per_arg_count()); + + Label loop; + bind(loop); + + int off_base = in_bytes(ParametersTypeData::stack_slot_offset(0)); + int type_base = in_bytes(ParametersTypeData::type_offset(0)); + int per_arg_scale = exact_log2(DataLayout::cell_size); + add(t0, mdp, off_base); + add(t1, mdp, type_base); + + shadd(tmp2, tmp1, t0, tmp2, per_arg_scale); + // load offset on the stack from the slot for this parameter + ld(tmp2, Address(tmp2, 0)); + neg(tmp2, tmp2); + + // read the parameter from the local area + shadd(tmp2, tmp2, xlocals, tmp2, Interpreter::logStackElementSize); + ld(tmp2, Address(tmp2, 0)); + + // profile the parameter + shadd(t1, tmp1, t1, t0, per_arg_scale); + Address arg_type(t1, 0); + profile_obj_type(tmp2, arg_type, tmp3); + + // go to next parameter + add(tmp1, tmp1, - TypeStackSlotEntries::per_arg_count()); + bgez(tmp1, loop); + + bind(profile_continue); + } +} + +void InterpreterMacroAssembler::get_method_counters(Register method, + Register mcs, Label& skip) { + Label has_counters; + ld(mcs, Address(method, Method::method_counters_offset())); + bnez(mcs, has_counters); + call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), method); + ld(mcs, Address(method, Method::method_counters_offset())); + beqz(mcs, skip); // No MethodCounters allocated, OutOfMemory + bind(has_counters); +} + +#ifdef ASSERT +void InterpreterMacroAssembler::verify_access_flags(Register access_flags, uint32_t flag_bits, + const char* msg, bool stop_by_hit) { + Label L; + andi(t0, access_flags, flag_bits); + if (stop_by_hit) { + beqz(t0, L); + } else { + bnez(t0, L); + } + stop(msg); + bind(L); +} + +void InterpreterMacroAssembler::verify_frame_setup() { + Label L; + const Address monitor_block_top(fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); + ld(t0, monitor_block_top); + beq(esp, t0, L); + stop("broken stack frame setup in interpreter"); + bind(L); +} +#endif diff --git a/src/hotspot/cpu/riscv/interp_masm_riscv.hpp b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp new file mode 100644 index 00000000000..4d8cb086f82 --- /dev/null +++ b/src/hotspot/cpu/riscv/interp_masm_riscv.hpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_INTERP_MASM_RISCV_HPP +#define CPU_RISCV_INTERP_MASM_RISCV_HPP + +#include "asm/macroAssembler.hpp" +#include "interpreter/invocationCounter.hpp" +#include "runtime/frame.hpp" + +// This file specializes the assember with interpreter-specific macros + +typedef ByteSize (*OffsetFunction)(uint); + +class InterpreterMacroAssembler: public MacroAssembler { + protected: + // Interpreter specific version of call_VM_base + using MacroAssembler::call_VM_leaf_base; + + virtual void call_VM_leaf_base(address entry_point, + int number_of_arguments); + + virtual void call_VM_base(Register oop_result, + Register java_thread, + Register last_java_sp, + address entry_point, + int number_of_arguments, + bool check_exceptions); + + // base routine for all dispatches + void dispatch_base(TosState state, address* table, bool verifyoop = true, + bool generate_poll = false, Register Rs = t0); + + public: + InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} + virtual ~InterpreterMacroAssembler() {} + + void load_earlyret_value(TosState state); + + void jump_to_entry(address entry); + + virtual void check_and_handle_popframe(Register java_thread); + virtual void check_and_handle_earlyret(Register java_thread); + + // Interpreter-specific registers + void save_bcp() { + sd(xbcp, Address(fp, frame::interpreter_frame_bcp_offset * wordSize)); + } + + void restore_bcp() { + ld(xbcp, Address(fp, frame::interpreter_frame_bcp_offset * wordSize)); + } + + void restore_locals() { + ld(xlocals, Address(fp, frame::interpreter_frame_locals_offset * wordSize)); + } + + void restore_constant_pool_cache() { + ld(xcpool, Address(fp, frame::interpreter_frame_cache_offset * wordSize)); + } + + void get_dispatch(); + + // Helpers for runtime call arguments/results + void get_method(Register reg) { + ld(reg, Address(fp, frame::interpreter_frame_method_offset * wordSize)); + } + + void get_const(Register reg) { + get_method(reg); + ld(reg, Address(reg, in_bytes(Method::const_offset()))); + } + + void get_constant_pool(Register reg) { + get_const(reg); + ld(reg, Address(reg, in_bytes(ConstMethod::constants_offset()))); + } + + void get_constant_pool_cache(Register reg) { + get_constant_pool(reg); + ld(reg, Address(reg, ConstantPool::cache_offset_in_bytes())); + } + + void get_cpool_and_tags(Register cpool, Register tags) { + get_constant_pool(cpool); + ld(tags, Address(cpool, ConstantPool::tags_offset_in_bytes())); + } + + void get_unsigned_2_byte_index_at_bcp(Register reg, int bcp_offset); + void get_cache_and_index_at_bcp(Register cache, Register index, int bcp_offset, size_t index_size = sizeof(u2)); + void get_cache_and_index_and_bytecode_at_bcp(Register cache, Register index, Register bytecode, int byte_no, int bcp_offset, size_t index_size = sizeof(u2)); + void get_cache_entry_pointer_at_bcp(Register cache, Register tmp, int bcp_offset, size_t index_size = sizeof(u2)); + void get_cache_index_at_bcp(Register index, int bcp_offset, size_t index_size = sizeof(u2)); + void get_method_counters(Register method, Register mcs, Label& skip); + + // Load cpool->resolved_references(index). + void load_resolved_reference_at_index(Register result, Register index, Register tmp = x15); + + // Load cpool->resolved_klass_at(index). + void load_resolved_klass_at_offset(Register cpool, Register index, Register klass, Register temp); + + void load_resolved_method_at_index(int byte_no, Register method, Register cache); + + void pop_ptr(Register r = x10); + void pop_i(Register r = x10); + void pop_l(Register r = x10); + void pop_f(FloatRegister r = f10); + void pop_d(FloatRegister r = f10); + void push_ptr(Register r = x10); + void push_i(Register r = x10); + void push_l(Register r = x10); + void push_f(FloatRegister r = f10); + void push_d(FloatRegister r = f10); + + void pop(TosState state); // transition vtos -> state + void push(TosState state); // transition state -> vtos + + void empty_expression_stack() { + ld(esp, Address(fp, frame::interpreter_frame_monitor_block_top_offset * wordSize)); + // NULL last_sp until next java call + sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + } + + // Helpers for swap and dup + void load_ptr(int n, Register val); + void store_ptr(int n, Register val); + + // Load float value from 'address'. The value is loaded onto the FPU register v0. + void load_float(Address src); + void load_double(Address src); + + // Generate a subtype check: branch to ok_is_subtype if sub_klass is + // a subtype of super_klass. + void gen_subtype_check( Register sub_klass, Label &ok_is_subtype ); + + // Dispatching + void dispatch_prolog(TosState state, int step = 0); + void dispatch_epilog(TosState state, int step = 0); + // dispatch via t0 + void dispatch_only(TosState state, bool generate_poll = false, Register Rs = t0); + // dispatch normal table via t0 (assume t0 is loaded already) + void dispatch_only_normal(TosState state, Register Rs = t0); + void dispatch_only_noverify(TosState state, Register Rs = t0); + // load t0 from [xbcp + step] and dispatch via t0 + void dispatch_next(TosState state, int step = 0, bool generate_poll = false); + // load t0 from [xbcp] and dispatch via t0 and table + void dispatch_via (TosState state, address* table); + + // jump to an invoked target + void prepare_to_jump_from_interpreted(); + void jump_from_interpreted(Register method); + + + // Returning from interpreted functions + // + // Removes the current activation (incl. unlocking of monitors) + // and sets up the return address. This code is also used for + // exception unwindwing. In that case, we do not want to throw + // IllegalMonitorStateExceptions, since that might get us into an + // infinite rethrow exception loop. + // Additionally this code is used for popFrame and earlyReturn. + // In popFrame case we want to skip throwing an exception, + // installing an exception, and notifying jvmdi. + // In earlyReturn case we only want to skip throwing an exception + // and installing an exception. + void remove_activation(TosState state, + bool throw_monitor_exception = true, + bool install_monitor_exception = true, + bool notify_jvmdi = true); + + // FIXME: Give us a valid frame at a null check. + virtual void null_check(Register reg, int offset = -1) { + MacroAssembler::null_check(reg, offset); + } + + // Object locking + void lock_object (Register lock_reg); + void unlock_object(Register lock_reg); + + // Interpreter profiling operations + void set_method_data_pointer_for_bcp(); + void test_method_data_pointer(Register mdp, Label& zero_continue); + void verify_method_data_pointer(); + + void set_mdp_data_at(Register mdp_in, int constant, Register value); + void increment_mdp_data_at(Address data, bool decrement = false); + void increment_mdp_data_at(Register mdp_in, int constant, + bool decrement = false); + void increment_mdp_data_at(Register mdp_in, Register reg, int constant, + bool decrement = false); + void increment_mask_and_jump(Address counter_addr, + int increment, Address mask, + Register tmp1, Register tmp2, + bool preloaded, Label* where); + + void set_mdp_flag_at(Register mdp_in, int flag_constant); + void test_mdp_data_at(Register mdp_in, int offset, Register value, + Register test_value_out, + Label& not_equal_continue); + + void record_klass_in_profile(Register receiver, Register mdp, + Register reg2, bool is_virtual_call); + void record_klass_in_profile_helper(Register receiver, Register mdp, + Register reg2, + Label& done, bool is_virtual_call); + void record_item_in_profile_helper(Register item, Register mdp, + Register reg2, int start_row, Label& done, int total_rows, + OffsetFunction item_offset_fn, OffsetFunction item_count_offset_fn, + int non_profiled_offset); + + void update_mdp_by_offset(Register mdp_in, int offset_of_offset); + void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp); + void update_mdp_by_constant(Register mdp_in, int constant); + void update_mdp_for_ret(Register return_bci); + + // narrow int return value + void narrow(Register result); + + void profile_taken_branch(Register mdp, Register bumped_count); + void profile_not_taken_branch(Register mdp); + void profile_call(Register mdp); + void profile_final_call(Register mdp); + void profile_virtual_call(Register receiver, Register mdp, + Register t1, + bool receiver_can_be_null = false); + void profile_ret(Register return_bci, Register mdp); + void profile_null_seen(Register mdp); + void profile_typecheck(Register mdp, Register klass, Register temp); + void profile_typecheck_failed(Register mdp); + void profile_switch_default(Register mdp); + void profile_switch_case(Register index_in_scratch, Register mdp, + Register temp); + + void profile_obj_type(Register obj, const Address& mdo_addr, Register tmp); + void profile_arguments_type(Register mdp, Register callee, Register tmp, bool is_virtual); + void profile_return_type(Register mdp, Register ret, Register tmp); + void profile_parameters_type(Register mdp, Register tmp1, Register tmp2, Register tmp3); + + // Debugging + // only if +VerifyFPU && (state == ftos || state == dtos) + void verify_FPU(int stack_depth, TosState state = ftos); + + typedef enum { NotifyJVMTI, SkipNotifyJVMTI } NotifyMethodExitMode; + + // support for jvmti/dtrace + void notify_method_entry(); + void notify_method_exit(TosState state, NotifyMethodExitMode mode); + + virtual void _call_Unimplemented(address call_site) { + save_bcp(); + set_last_Java_frame(esp, fp, (address) pc(), t0); + MacroAssembler::_call_Unimplemented(call_site); + } + +#ifdef ASSERT + void verify_access_flags(Register access_flags, uint32_t flag_bits, + const char* msg, bool stop_by_hit = true); + void verify_frame_setup(); +#endif +}; + +#endif // CPU_RISCV_INTERP_MASM_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp b/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp new file mode 100644 index 00000000000..d93530d8564 --- /dev/null +++ b/src/hotspot/cpu/riscv/interpreterRT_riscv.cpp @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "memory/allocation.inline.hpp" +#include "memory/universe.hpp" +#include "oops/method.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/icache.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/signature.hpp" + +#define __ _masm-> + +// Implementation of SignatureHandlerGenerator +Register InterpreterRuntime::SignatureHandlerGenerator::from() { return xlocals; } +Register InterpreterRuntime::SignatureHandlerGenerator::to() { return sp; } +Register InterpreterRuntime::SignatureHandlerGenerator::temp() { return t0; } + +Register InterpreterRuntime::SignatureHandlerGenerator::next_gpr() { + if (_num_reg_int_args < Argument::n_int_register_parameters_c - 1) { + return g_INTArgReg[++_num_reg_int_args]; + } + return noreg; +} + +FloatRegister InterpreterRuntime::SignatureHandlerGenerator::next_fpr() { + if (_num_reg_fp_args < Argument::n_float_register_parameters_c) { + return g_FPArgReg[_num_reg_fp_args++]; + } else { + return fnoreg; + } +} + +int InterpreterRuntime::SignatureHandlerGenerator::next_stack_offset() { + int ret = _stack_offset; + _stack_offset += wordSize; + return ret; +} + +InterpreterRuntime::SignatureHandlerGenerator::SignatureHandlerGenerator( + const methodHandle& method, CodeBuffer* buffer) : NativeSignatureIterator(method) { + _masm = new MacroAssembler(buffer); // allocate on resourse area by default + _num_reg_int_args = (method->is_static() ? 1 : 0); + _num_reg_fp_args = 0; + _stack_offset = 0; +} + +void InterpreterRuntime::SignatureHandlerGenerator::pass_int() { + const Address src(from(), Interpreter::local_offset_in_bytes(offset())); + + Register reg = next_gpr(); + if (reg != noreg) { + __ lw(reg, src); + } else { + __ lw(x10, src); + __ sw(x10, Address(to(), next_stack_offset())); + } +} + +void InterpreterRuntime::SignatureHandlerGenerator::pass_long() { + const Address src(from(), Interpreter::local_offset_in_bytes(offset() + 1)); + + Register reg = next_gpr(); + if (reg != noreg) { + __ ld(reg, src); + } else { + __ ld(x10, src); + __ sd(x10, Address(to(), next_stack_offset())); + } +} + +void InterpreterRuntime::SignatureHandlerGenerator::pass_float() { + const Address src(from(), Interpreter::local_offset_in_bytes(offset())); + + FloatRegister reg = next_fpr(); + if (reg != fnoreg) { + __ flw(reg, src); + } else { + // a floating-point argument is passed according to the integer calling + // convention if no floating-point argument register available + pass_int(); + } +} + +void InterpreterRuntime::SignatureHandlerGenerator::pass_double() { + const Address src(from(), Interpreter::local_offset_in_bytes(offset() + 1)); + + FloatRegister reg = next_fpr(); + if (reg != fnoreg) { + __ fld(reg, src); + } else { + // a floating-point argument is passed according to the integer calling + // convention if no floating-point argument register available + pass_long(); + } +} + +void InterpreterRuntime::SignatureHandlerGenerator::pass_object() { + Register reg = next_gpr(); + if (reg == c_rarg1) { + assert(offset() == 0, "argument register 1 can only be (non-null) receiver"); + __ addi(c_rarg1, from(), Interpreter::local_offset_in_bytes(offset())); + } else if (reg != noreg) { + // c_rarg2-c_rarg7 + __ addi(x10, from(), Interpreter::local_offset_in_bytes(offset())); + __ mv(reg, zr); //_num_reg_int_args:c_rarg -> 1:c_rarg2, 2:c_rarg3... + __ ld(temp(), x10); + Label L; + __ beqz(temp(), L); + __ mv(reg, x10); + __ bind(L); + } else { + //to stack + __ addi(x10, from(), Interpreter::local_offset_in_bytes(offset())); + __ ld(temp(), x10); + Label L; + __ bnez(temp(), L); + __ mv(x10, zr); + __ bind(L); + assert(sizeof(jobject) == wordSize, ""); + __ sd(x10, Address(to(), next_stack_offset())); + } +} + +void InterpreterRuntime::SignatureHandlerGenerator::generate(uint64_t fingerprint) { + // generate code to handle arguments + iterate(fingerprint); + + // return result handler + __ la(x10, ExternalAddress(Interpreter::result_handler(method()->result_type()))); + __ ret(); + + __ flush(); +} + + +// Implementation of SignatureHandlerLibrary + +void SignatureHandlerLibrary::pd_set_handler(address handler) {} + + +class SlowSignatureHandler + : public NativeSignatureIterator { + private: + address _from; + intptr_t* _to; + intptr_t* _int_args; + intptr_t* _fp_args; + intptr_t* _fp_identifiers; + unsigned int _num_reg_int_args; + unsigned int _num_reg_fp_args; + + intptr_t* single_slot_addr() { + intptr_t* from_addr = (intptr_t*)(_from + Interpreter::local_offset_in_bytes(0)); + _from -= Interpreter::stackElementSize; + return from_addr; + } + + intptr_t* double_slot_addr() { + intptr_t* from_addr = (intptr_t*)(_from + Interpreter::local_offset_in_bytes(1)); + _from -= 2 * Interpreter::stackElementSize; + return from_addr; + } + + int pass_gpr(intptr_t value) { + if (_num_reg_int_args < Argument::n_int_register_parameters_c - 1) { + *_int_args++ = value; + return _num_reg_int_args++; + } + return -1; + } + + int pass_fpr(intptr_t value) { + if (_num_reg_fp_args < Argument::n_float_register_parameters_c) { + *_fp_args++ = value; + return _num_reg_fp_args++; + } + return -1; + } + + void pass_stack(intptr_t value) { + *_to++ = value; + } + + virtual void pass_int() { + jint value = *(jint*)single_slot_addr(); + if (pass_gpr(value) < 0) { + pass_stack(value); + } + } + + virtual void pass_long() { + intptr_t value = *double_slot_addr(); + if (pass_gpr(value) < 0) { + pass_stack(value); + } + } + + virtual void pass_object() { + intptr_t* addr = single_slot_addr(); + intptr_t value = *addr == 0 ? NULL : (intptr_t)addr; + if (pass_gpr(value) < 0) { + pass_stack(value); + } + } + + virtual void pass_float() { + jint value = *(jint*) single_slot_addr(); + // a floating-point argument is passed according to the integer calling + // convention if no floating-point argument register available + if (pass_fpr(value) < 0 && pass_gpr(value) < 0) { + pass_stack(value); + } + } + + virtual void pass_double() { + intptr_t value = *double_slot_addr(); + int arg = pass_fpr(value); + if (0 <= arg) { + *_fp_identifiers |= (1ull << arg); // mark as double + } else if (pass_gpr(value) < 0) { // no need to mark if passing by integer registers or stack + pass_stack(value); + } + } + + public: + SlowSignatureHandler(const methodHandle& method, address from, intptr_t* to) + : NativeSignatureIterator(method) + { + _from = from; + _to = to; + + _int_args = to - (method->is_static() ? 16 : 17); + _fp_args = to - 8; + _fp_identifiers = to - 9; + *(int*) _fp_identifiers = 0; + _num_reg_int_args = (method->is_static() ? 1 : 0); + _num_reg_fp_args = 0; + } + + ~SlowSignatureHandler() + { + _from = NULL; + _to = NULL; + _int_args = NULL; + _fp_args = NULL; + _fp_identifiers = NULL; + } +}; + + +JRT_ENTRY(address, + InterpreterRuntime::slow_signature_handler(JavaThread* current, + Method* method, + intptr_t* from, + intptr_t* to)) + methodHandle m(current, (Method*)method); + assert(m->is_native(), "sanity check"); + + // handle arguments + SlowSignatureHandler ssh(m, (address)from, to); + ssh.iterate(UCONST64(-1)); + + // return result handler + return Interpreter::result_handler(m->result_type()); +JRT_END diff --git a/src/hotspot/cpu/riscv/interpreterRT_riscv.hpp b/src/hotspot/cpu/riscv/interpreterRT_riscv.hpp new file mode 100644 index 00000000000..05df63ba2ae --- /dev/null +++ b/src/hotspot/cpu/riscv/interpreterRT_riscv.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_INTERPRETERRT_RISCV_HPP +#define CPU_RISCV_INTERPRETERRT_RISCV_HPP + +// This is included in the middle of class Interpreter. +// Do not include files here. + +// native method calls + +class SignatureHandlerGenerator: public NativeSignatureIterator { + private: + MacroAssembler* _masm; + unsigned int _num_reg_fp_args; + unsigned int _num_reg_int_args; + int _stack_offset; + + void pass_int(); + void pass_long(); + void pass_float(); + void pass_double(); + void pass_object(); + + Register next_gpr(); + FloatRegister next_fpr(); + int next_stack_offset(); + + public: + // Creation + SignatureHandlerGenerator(const methodHandle& method, CodeBuffer* buffer); + virtual ~SignatureHandlerGenerator() { + _masm = NULL; + } + + // Code generation + void generate(uint64_t fingerprint); + + // Code generation support + static Register from(); + static Register to(); + static Register temp(); +}; + +#endif // CPU_RISCV_INTERPRETERRT_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/javaFrameAnchor_riscv.hpp b/src/hotspot/cpu/riscv/javaFrameAnchor_riscv.hpp new file mode 100644 index 00000000000..9a6084afa1d --- /dev/null +++ b/src/hotspot/cpu/riscv/javaFrameAnchor_riscv.hpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_JAVAFRAMEANCHOR_RISCV_HPP +#define CPU_RISCV_JAVAFRAMEANCHOR_RISCV_HPP + +private: + + // FP value associated with _last_Java_sp: + intptr_t* volatile _last_Java_fp; // pointer is volatile not what it points to + +public: + // Each arch must define reset, save, restore + // These are used by objects that only care about: + // 1 - initializing a new state (thread creation, javaCalls) + // 2 - saving a current state (javaCalls) + // 3 - restoring an old state (javaCalls) + + void clear(void) { + // clearing _last_Java_sp must be first + _last_Java_sp = NULL; + OrderAccess::release(); + _last_Java_fp = NULL; + _last_Java_pc = NULL; + } + + void copy(JavaFrameAnchor* src) { + // In order to make sure the transition state is valid for "this" + // We must clear _last_Java_sp before copying the rest of the new data + // + // Hack Alert: Temporary bugfix for 4717480/4721647 + // To act like previous version (pd_cache_state) don't NULL _last_Java_sp + // unless the value is changing + // + assert(src != NULL, "Src should not be NULL."); + if (_last_Java_sp != src->_last_Java_sp) { + _last_Java_sp = NULL; + OrderAccess::release(); + } + _last_Java_fp = src->_last_Java_fp; + _last_Java_pc = src->_last_Java_pc; + // Must be last so profiler will always see valid frame if has_last_frame() is true + _last_Java_sp = src->_last_Java_sp; + } + + bool walkable(void) { return _last_Java_sp != NULL && _last_Java_pc != NULL; } + void make_walkable(JavaThread* thread); + void capture_last_Java_pc(void); + + intptr_t* last_Java_sp(void) const { return _last_Java_sp; } + + const address last_Java_pc(void) { return _last_Java_pc; } + +private: + + static ByteSize last_Java_fp_offset() { return byte_offset_of(JavaFrameAnchor, _last_Java_fp); } + +public: + + void set_last_Java_sp(intptr_t* java_sp) { _last_Java_sp = java_sp; OrderAccess::release(); } + + intptr_t* last_Java_fp(void) { return _last_Java_fp; } + +#endif // CPU_RISCV_JAVAFRAMEANCHOR_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp new file mode 100644 index 00000000000..814ed23e471 --- /dev/null +++ b/src/hotspot/cpu/riscv/jniFastGetField_riscv.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "memory/resourceArea.hpp" +#include "prims/jniFastGetField.hpp" +#include "prims/jvm_misc.hpp" +#include "prims/jvmtiExport.hpp" +#include "runtime/safepoint.hpp" + +#define __ masm-> + +#define BUFFER_SIZE 30*wordSize + +// Instead of issuing a LoadLoad barrier we create an address +// dependency between loads; this might be more efficient. + +// Common register usage: +// x10/f10: result +// c_rarg0: jni env +// c_rarg1: obj +// c_rarg2: jfield id + +static const Register robj = x13; +static const Register rcounter = x14; +static const Register roffset = x15; +static const Register rcounter_addr = x16; +static const Register result = x17; + +address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { + const char *name; + switch (type) { + case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break; + case T_BYTE: name = "jni_fast_GetByteField"; break; + case T_CHAR: name = "jni_fast_GetCharField"; break; + case T_SHORT: name = "jni_fast_GetShortField"; break; + case T_INT: name = "jni_fast_GetIntField"; break; + case T_LONG: name = "jni_fast_GetLongField"; break; + case T_FLOAT: name = "jni_fast_GetFloatField"; break; + case T_DOUBLE: name = "jni_fast_GetDoubleField"; break; + default: ShouldNotReachHere(); + name = NULL; // unreachable + } + ResourceMark rm; + BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); + CodeBuffer cbuf(blob); + MacroAssembler* masm = new MacroAssembler(&cbuf); + address fast_entry = __ pc(); + + Label slow; + int32_t offset = 0; + __ la_patchable(rcounter_addr, SafepointSynchronize::safepoint_counter_addr(), offset); + __ addi(rcounter_addr, rcounter_addr, offset); + + Address safepoint_counter_addr(rcounter_addr, 0); + __ lwu(rcounter, safepoint_counter_addr); + // An even value means there are no ongoing safepoint operations + __ andi(t0, rcounter, 1); + __ bnez(t0, slow); + + if (JvmtiExport::can_post_field_access()) { + // Using barrier to order wrt. JVMTI check and load of result. + __ membar(MacroAssembler::LoadLoad); + + // Check to see if a field access watch has been set before we + // take the fast path. + int32_t offset2; + __ la_patchable(result, + ExternalAddress((address) JvmtiExport::get_field_access_count_addr()), + offset2); + __ lwu(result, Address(result, offset2)); + __ bnez(result, slow); + + __ mv(robj, c_rarg1); + } else { + // Using address dependency to order wrt. load of result. + __ xorr(robj, c_rarg1, rcounter); + __ xorr(robj, robj, rcounter); // obj, since + // robj ^ rcounter ^ rcounter == robj + // robj is address dependent on rcounter. + } + + // Both robj and t0 are clobbered by try_resolve_jobject_in_native. + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + assert_cond(bs != NULL); + bs->try_resolve_jobject_in_native(masm, c_rarg0, robj, t0, slow); + + __ srli(roffset, c_rarg2, 2); // offset + + assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); + speculative_load_pclist[count] = __ pc(); // Used by the segfault handler + __ add(roffset, robj, roffset); + + switch (type) { + case T_BOOLEAN: __ lbu(result, Address(roffset, 0)); break; + case T_BYTE: __ lb(result, Address(roffset, 0)); break; + case T_CHAR: __ lhu(result, Address(roffset, 0)); break; + case T_SHORT: __ lh(result, Address(roffset, 0)); break; + case T_INT: __ lw(result, Address(roffset, 0)); break; + case T_LONG: __ ld(result, Address(roffset, 0)); break; + case T_FLOAT: { + __ flw(f28, Address(roffset, 0)); // f28 as temporaries + __ fmv_x_w(result, f28); // f{31--0}-->x + break; + } + case T_DOUBLE: { + __ fld(f28, Address(roffset, 0)); // f28 as temporaries + __ fmv_x_d(result, f28); // d{63--0}-->x + break; + } + default: ShouldNotReachHere(); + } + + // Using acquire: Order JVMTI check and load of result wrt. succeeding check + // (LoadStore for volatile field). + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + + __ lw(t0, safepoint_counter_addr); + __ bne(rcounter, t0, slow); + + switch (type) { + case T_FLOAT: __ fmv_w_x(f10, result); break; + case T_DOUBLE: __ fmv_d_x(f10, result); break; + default: __ mv(x10, result); break; + } + __ ret(); + + slowcase_entry_pclist[count++] = __ pc(); + __ bind(slow); + address slow_case_addr; + switch (type) { + case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break; + case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break; + case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break; + case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break; + case T_INT: slow_case_addr = jni_GetIntField_addr(); break; + case T_LONG: slow_case_addr = jni_GetLongField_addr(); break; + case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; + case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; + default: ShouldNotReachHere(); + slow_case_addr = NULL; // unreachable + } + + { + __ enter(); + int32_t tmp_offset = 0; + __ la_patchable(t0, ExternalAddress(slow_case_addr), tmp_offset); + __ jalr(x1, t0, tmp_offset); + __ leave(); + __ ret(); + } + __ flush(); + + return fast_entry; +} + + +address JNI_FastGetField::generate_fast_get_boolean_field() { + return generate_fast_get_int_field0(T_BOOLEAN); +} + +address JNI_FastGetField::generate_fast_get_byte_field() { + return generate_fast_get_int_field0(T_BYTE); +} + +address JNI_FastGetField::generate_fast_get_char_field() { + return generate_fast_get_int_field0(T_CHAR); +} + +address JNI_FastGetField::generate_fast_get_short_field() { + return generate_fast_get_int_field0(T_SHORT); +} + +address JNI_FastGetField::generate_fast_get_int_field() { + return generate_fast_get_int_field0(T_INT); +} + +address JNI_FastGetField::generate_fast_get_long_field() { + return generate_fast_get_int_field0(T_LONG); +} + +address JNI_FastGetField::generate_fast_get_float_field() { + return generate_fast_get_int_field0(T_FLOAT); +} + +address JNI_FastGetField::generate_fast_get_double_field() { + return generate_fast_get_int_field0(T_DOUBLE); +} diff --git a/src/hotspot/cpu/riscv/jniTypes_riscv.hpp b/src/hotspot/cpu/riscv/jniTypes_riscv.hpp new file mode 100644 index 00000000000..83ffcc55d83 --- /dev/null +++ b/src/hotspot/cpu/riscv/jniTypes_riscv.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_JNITYPES_RISCV_HPP +#define CPU_RISCV_JNITYPES_RISCV_HPP + +#include "jni.h" +#include "memory/allStatic.hpp" +#include "oops/oop.hpp" + +// This file holds platform-dependent routines used to write primitive jni +// types to the array of arguments passed into JavaCalls::call + +class JNITypes : private AllStatic { + // These functions write a java primitive type (in native format) + // to a java stack slot array to be passed as an argument to JavaCalls:calls. + // I.e., they are functionally 'push' operations if they have a 'pos' + // formal parameter. Note that jlong's and jdouble's are written + // _in reverse_ of the order in which they appear in the interpreter + // stack. This is because call stubs (see stubGenerator_sparc.cpp) + // reverse the argument list constructed by JavaCallArguments (see + // javaCalls.hpp). + +public: + // Ints are stored in native format in one JavaCallArgument slot at *to. + static inline void put_int(jint from, intptr_t *to) { *(jint *)(to + 0 ) = from; } + static inline void put_int(jint from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = from; } + static inline void put_int(jint *from, intptr_t *to, int& pos) { *(jint *)(to + pos++) = *from; } + + // Longs are stored in native format in one JavaCallArgument slot at + // *(to+1). + static inline void put_long(jlong from, intptr_t *to) { + *(jlong*) (to + 1) = from; + } + + static inline void put_long(jlong from, intptr_t *to, int& pos) { + *(jlong*) (to + 1 + pos) = from; + pos += 2; + } + + static inline void put_long(jlong *from, intptr_t *to, int& pos) { + *(jlong*) (to + 1 + pos) = *from; + pos += 2; + } + + // Oops are stored in native format in one JavaCallArgument slot at *to. + static inline void put_obj(const Handle& from_handle, intptr_t *to, int& pos) { *(to + pos++) = (intptr_t)from_handle.raw_value(); } + static inline void put_obj(jobject from_handle, intptr_t *to, int& pos) { *(to + pos++) = (intptr_t)from_handle; } + + // Floats are stored in native format in one JavaCallArgument slot at *to. + static inline void put_float(jfloat from, intptr_t *to) { *(jfloat *)(to + 0 ) = from; } + static inline void put_float(jfloat from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) = from; } + static inline void put_float(jfloat *from, intptr_t *to, int& pos) { *(jfloat *)(to + pos++) = *from; } + +#undef _JNI_SLOT_OFFSET +#define _JNI_SLOT_OFFSET 1 + // Doubles are stored in native word format in one JavaCallArgument + // slot at *(to+1). + static inline void put_double(jdouble from, intptr_t *to) { + *(jdouble*) (to + 1) = from; + } + + static inline void put_double(jdouble from, intptr_t *to, int& pos) { + *(jdouble*) (to + 1 + pos) = from; + pos += 2; + } + + static inline void put_double(jdouble *from, intptr_t *to, int& pos) { + *(jdouble*) (to + 1 + pos) = *from; + pos += 2; + } + + // The get_xxx routines, on the other hand, actually _do_ fetch + // java primitive types from the interpreter stack. + // No need to worry about alignment on Intel. + static inline jint get_int (intptr_t *from) { return *(jint *) from; } + static inline jlong get_long (intptr_t *from) { return *(jlong *) (from + _JNI_SLOT_OFFSET); } + static inline oop get_obj (intptr_t *from) { return *(oop *) from; } + static inline jfloat get_float (intptr_t *from) { return *(jfloat *) from; } + static inline jdouble get_double(intptr_t *from) { return *(jdouble *)(from + _JNI_SLOT_OFFSET); } +#undef _JNI_SLOT_OFFSET +}; + +#endif // CPU_RISCV_JNITYPES_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp new file mode 100644 index 00000000000..86710295444 --- /dev/null +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -0,0 +1,4016 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "asm/assembler.inline.hpp" +#include "compiler/disassembler.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "gc/shared/cardTable.hpp" +#include "gc/shared/cardTableBarrierSet.hpp" +#include "interpreter/bytecodeHistogram.hpp" +#include "interpreter/interpreter.hpp" +#include "memory/resourceArea.hpp" +#include "memory/universe.hpp" +#include "nativeInst_riscv.hpp" +#include "oops/accessDecorators.hpp" +#include "oops/compressedOops.inline.hpp" +#include "oops/klass.inline.hpp" +#include "oops/oop.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/jniHandles.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/thread.hpp" +#include "utilities/powerOfTwo.hpp" +#ifdef COMPILER2 +#include "opto/compile.hpp" +#include "opto/node.hpp" +#include "opto/output.hpp" +#endif + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) block_comment(str) +#endif +#define BIND(label) bind(label); __ BLOCK_COMMENT(#label ":") + +static void pass_arg0(MacroAssembler* masm, Register arg) { + if (c_rarg0 != arg) { + assert_cond(masm != NULL); + masm->mv(c_rarg0, arg); + } +} + +static void pass_arg1(MacroAssembler* masm, Register arg) { + if (c_rarg1 != arg) { + assert_cond(masm != NULL); + masm->mv(c_rarg1, arg); + } +} + +static void pass_arg2(MacroAssembler* masm, Register arg) { + if (c_rarg2 != arg) { + assert_cond(masm != NULL); + masm->mv(c_rarg2, arg); + } +} + +static void pass_arg3(MacroAssembler* masm, Register arg) { + if (c_rarg3 != arg) { + assert_cond(masm != NULL); + masm->mv(c_rarg3, arg); + } +} + +void MacroAssembler::align(int modulus, int extra_offset) { + CompressibleRegion cr(this); + while ((offset() + extra_offset) % modulus != 0) { nop(); } +} + +void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) { + call_VM_base(oop_result, noreg, noreg, entry_point, number_of_arguments, check_exceptions); +} + +// Implementation of call_VM versions + +void MacroAssembler::call_VM(Register oop_result, + address entry_point, + bool check_exceptions) { + call_VM_helper(oop_result, entry_point, 0, check_exceptions); +} + +void MacroAssembler::call_VM(Register oop_result, + address entry_point, + Register arg_1, + bool check_exceptions) { + pass_arg1(this, arg_1); + call_VM_helper(oop_result, entry_point, 1, check_exceptions); +} + +void MacroAssembler::call_VM(Register oop_result, + address entry_point, + Register arg_1, + Register arg_2, + bool check_exceptions) { + assert(arg_1 != c_rarg2, "smashed arg"); + pass_arg2(this, arg_2); + pass_arg1(this, arg_1); + call_VM_helper(oop_result, entry_point, 2, check_exceptions); +} + +void MacroAssembler::call_VM(Register oop_result, + address entry_point, + Register arg_1, + Register arg_2, + Register arg_3, + bool check_exceptions) { + assert(arg_1 != c_rarg3, "smashed arg"); + assert(arg_2 != c_rarg3, "smashed arg"); + pass_arg3(this, arg_3); + + assert(arg_1 != c_rarg2, "smashed arg"); + pass_arg2(this, arg_2); + + pass_arg1(this, arg_1); + call_VM_helper(oop_result, entry_point, 3, check_exceptions); +} + +void MacroAssembler::call_VM(Register oop_result, + Register last_java_sp, + address entry_point, + int number_of_arguments, + bool check_exceptions) { + call_VM_base(oop_result, xthread, last_java_sp, entry_point, number_of_arguments, check_exceptions); +} + +void MacroAssembler::call_VM(Register oop_result, + Register last_java_sp, + address entry_point, + Register arg_1, + bool check_exceptions) { + pass_arg1(this, arg_1); + call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions); +} + +void MacroAssembler::call_VM(Register oop_result, + Register last_java_sp, + address entry_point, + Register arg_1, + Register arg_2, + bool check_exceptions) { + + assert(arg_1 != c_rarg2, "smashed arg"); + pass_arg2(this, arg_2); + pass_arg1(this, arg_1); + call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions); +} + +void MacroAssembler::call_VM(Register oop_result, + Register last_java_sp, + address entry_point, + Register arg_1, + Register arg_2, + Register arg_3, + bool check_exceptions) { + assert(arg_1 != c_rarg3, "smashed arg"); + assert(arg_2 != c_rarg3, "smashed arg"); + pass_arg3(this, arg_3); + assert(arg_1 != c_rarg2, "smashed arg"); + pass_arg2(this, arg_2); + pass_arg1(this, arg_1); + call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions); +} + +// these are no-ops overridden by InterpreterMacroAssembler +void MacroAssembler::check_and_handle_earlyret(Register java_thread) {} +void MacroAssembler::check_and_handle_popframe(Register java_thread) {} + +// Calls to C land +// +// When entering C land, the fp, & esp of the last Java frame have to be recorded +// in the (thread-local) JavaThread object. When leaving C land, the last Java fp +// has to be reset to 0. This is required to allow proper stack traversal. +void MacroAssembler::set_last_Java_frame(Register last_java_sp, + Register last_java_fp, + Register last_java_pc, + Register tmp) { + + if (last_java_pc->is_valid()) { + sd(last_java_pc, Address(xthread, + JavaThread::frame_anchor_offset() + + JavaFrameAnchor::last_Java_pc_offset())); + } + + // determine last_java_sp register + if (last_java_sp == sp) { + mv(tmp, sp); + last_java_sp = tmp; + } else if (!last_java_sp->is_valid()) { + last_java_sp = esp; + } + + sd(last_java_sp, Address(xthread, JavaThread::last_Java_sp_offset())); + + // last_java_fp is optional + if (last_java_fp->is_valid()) { + sd(last_java_fp, Address(xthread, JavaThread::last_Java_fp_offset())); + } +} + +void MacroAssembler::set_last_Java_frame(Register last_java_sp, + Register last_java_fp, + address last_java_pc, + Register tmp) { + assert(last_java_pc != NULL, "must provide a valid PC"); + + la(tmp, last_java_pc); + sd(tmp, Address(xthread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset())); + + set_last_Java_frame(last_java_sp, last_java_fp, noreg, tmp); +} + +void MacroAssembler::set_last_Java_frame(Register last_java_sp, + Register last_java_fp, + Label &L, + Register tmp) { + if (L.is_bound()) { + set_last_Java_frame(last_java_sp, last_java_fp, target(L), tmp); + } else { + InstructionMark im(this); + L.add_patch_at(code(), locator()); + set_last_Java_frame(last_java_sp, last_java_fp, pc() /* Patched later */, tmp); + } +} + +void MacroAssembler::reset_last_Java_frame(bool clear_fp) { + // we must set sp to zero to clear frame + sd(zr, Address(xthread, JavaThread::last_Java_sp_offset())); + + // must clear fp, so that compiled frames are not confused; it is + // possible that we need it only for debugging + if (clear_fp) { + sd(zr, Address(xthread, JavaThread::last_Java_fp_offset())); + } + + // Always clear the pc because it could have been set by make_walkable() + sd(zr, Address(xthread, JavaThread::last_Java_pc_offset())); +} + +void MacroAssembler::call_VM_base(Register oop_result, + Register java_thread, + Register last_java_sp, + address entry_point, + int number_of_arguments, + bool check_exceptions) { + // determine java_thread register + if (!java_thread->is_valid()) { + java_thread = xthread; + } + // determine last_java_sp register + if (!last_java_sp->is_valid()) { + last_java_sp = esp; + } + + // debugging support + assert(number_of_arguments >= 0 , "cannot have negative number of arguments"); + assert(java_thread == xthread, "unexpected register"); + + assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result"); + assert(java_thread != last_java_sp, "cannot use the same register for java_thread & last_java_sp"); + + // push java thread (becomes first argument of C function) + mv(c_rarg0, java_thread); + + // set last Java frame before call + assert(last_java_sp != fp, "can't use fp"); + + Label l; + set_last_Java_frame(last_java_sp, fp, l, t0); + + // do the call, remove parameters + MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments, &l); + + // reset last Java frame + // Only interpreter should have to clear fp + reset_last_Java_frame(true); + + // C++ interp handles this in the interpreter + check_and_handle_popframe(java_thread); + check_and_handle_earlyret(java_thread); + + if (check_exceptions) { + // check for pending exceptions (java_thread is set upon return) + ld(t0, Address(java_thread, in_bytes(Thread::pending_exception_offset()))); + Label ok; + beqz(t0, ok); + int32_t offset = 0; + la_patchable(t0, RuntimeAddress(StubRoutines::forward_exception_entry()), offset); + jalr(x0, t0, offset); + bind(ok); + } + + // get oop result if there is one and reset the value in the thread + if (oop_result->is_valid()) { + get_vm_result(oop_result, java_thread); + } +} + +void MacroAssembler::get_vm_result(Register oop_result, Register java_thread) { + ld(oop_result, Address(java_thread, JavaThread::vm_result_offset())); + sd(zr, Address(java_thread, JavaThread::vm_result_offset())); + verify_oop(oop_result, "broken oop in call_VM_base"); +} + +void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thread) { + ld(metadata_result, Address(java_thread, JavaThread::vm_result_2_offset())); + sd(zr, Address(java_thread, JavaThread::vm_result_2_offset())); +} + +void MacroAssembler::clinit_barrier(Register klass, Register tmp, Label* L_fast_path, Label* L_slow_path) { + assert(L_fast_path != NULL || L_slow_path != NULL, "at least one is required"); + assert_different_registers(klass, xthread, tmp); + + Label L_fallthrough, L_tmp; + if (L_fast_path == NULL) { + L_fast_path = &L_fallthrough; + } else if (L_slow_path == NULL) { + L_slow_path = &L_fallthrough; + } + + // Fast path check: class is fully initialized + lbu(tmp, Address(klass, InstanceKlass::init_state_offset())); + sub(tmp, tmp, InstanceKlass::fully_initialized); + beqz(tmp, *L_fast_path); + + // Fast path check: current thread is initializer thread + ld(tmp, Address(klass, InstanceKlass::init_thread_offset())); + + if (L_slow_path == &L_fallthrough) { + beq(xthread, tmp, *L_fast_path); + bind(*L_slow_path); + } else if (L_fast_path == &L_fallthrough) { + bne(xthread, tmp, *L_slow_path); + bind(*L_fast_path); + } else { + Unimplemented(); + } +} + +void MacroAssembler::verify_oop(Register reg, const char* s) { + if (!VerifyOops) { return; } + + // Pass register number to verify_oop_subroutine + const char* b = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("verify_oop: %s: %s", reg->name(), s); + b = code_string(ss.as_string()); + } + BLOCK_COMMENT("verify_oop {"); + + push_reg(RegSet::of(ra, t0, t1, c_rarg0), sp); + + mv(c_rarg0, reg); // c_rarg0 : x10 + li(t0, (uintptr_t)(address)b); + + // call indirectly to solve generation ordering problem + int32_t offset = 0; + la_patchable(t1, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()), offset); + ld(t1, Address(t1, offset)); + jalr(t1); + + pop_reg(RegSet::of(ra, t0, t1, c_rarg0), sp); + + BLOCK_COMMENT("} verify_oop"); +} + +void MacroAssembler::verify_oop_addr(Address addr, const char* s) { + if (!VerifyOops) { + return; + } + + const char* b = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("verify_oop_addr: %s", s); + b = code_string(ss.as_string()); + } + BLOCK_COMMENT("verify_oop_addr {"); + + push_reg(RegSet::of(ra, t0, t1, c_rarg0), sp); + + if (addr.uses(sp)) { + la(x10, addr); + ld(x10, Address(x10, 4 * wordSize)); + } else { + ld(x10, addr); + } + + li(t0, (uintptr_t)(address)b); + + // call indirectly to solve generation ordering problem + int32_t offset = 0; + la_patchable(t1, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()), offset); + ld(t1, Address(t1, offset)); + jalr(t1); + + pop_reg(RegSet::of(ra, t0, t1, c_rarg0), sp); + + BLOCK_COMMENT("} verify_oop_addr"); +} + +Address MacroAssembler::argument_address(RegisterOrConstant arg_slot, + int extra_slot_offset) { + // cf. TemplateTable::prepare_invoke(), if (load_receiver). + int stackElementSize = Interpreter::stackElementSize; + int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0); +#ifdef ASSERT + int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1); + assert(offset1 - offset == stackElementSize, "correct arithmetic"); +#endif + if (arg_slot.is_constant()) { + return Address(esp, arg_slot.as_constant() * stackElementSize + offset); + } else { + assert_different_registers(t0, arg_slot.as_register()); + shadd(t0, arg_slot.as_register(), esp, t0, exact_log2(stackElementSize)); + return Address(t0, offset); + } +} + +#ifndef PRODUCT +extern "C" void findpc(intptr_t x); +#endif + +void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) +{ + // In order to get locks to work, we need to fake a in_VM state + if (ShowMessageBoxOnError) { + JavaThread* thread = JavaThread::current(); + JavaThreadState saved_state = thread->thread_state(); + thread->set_thread_state(_thread_in_vm); +#ifndef PRODUCT + if (CountBytecodes || TraceBytecodes || StopInterpreterAt) { + ttyLocker ttyl; + BytecodeCounter::print(); + } +#endif + if (os::message_box(msg, "Execution stopped, print registers?")) { + ttyLocker ttyl; + tty->print_cr(" pc = 0x%016lx", pc); +#ifndef PRODUCT + tty->cr(); + findpc(pc); + tty->cr(); +#endif + tty->print_cr(" x0 = 0x%016lx", regs[0]); + tty->print_cr(" x1 = 0x%016lx", regs[1]); + tty->print_cr(" x2 = 0x%016lx", regs[2]); + tty->print_cr(" x3 = 0x%016lx", regs[3]); + tty->print_cr(" x4 = 0x%016lx", regs[4]); + tty->print_cr(" x5 = 0x%016lx", regs[5]); + tty->print_cr(" x6 = 0x%016lx", regs[6]); + tty->print_cr(" x7 = 0x%016lx", regs[7]); + tty->print_cr(" x8 = 0x%016lx", regs[8]); + tty->print_cr(" x9 = 0x%016lx", regs[9]); + tty->print_cr("x10 = 0x%016lx", regs[10]); + tty->print_cr("x11 = 0x%016lx", regs[11]); + tty->print_cr("x12 = 0x%016lx", regs[12]); + tty->print_cr("x13 = 0x%016lx", regs[13]); + tty->print_cr("x14 = 0x%016lx", regs[14]); + tty->print_cr("x15 = 0x%016lx", regs[15]); + tty->print_cr("x16 = 0x%016lx", regs[16]); + tty->print_cr("x17 = 0x%016lx", regs[17]); + tty->print_cr("x18 = 0x%016lx", regs[18]); + tty->print_cr("x19 = 0x%016lx", regs[19]); + tty->print_cr("x20 = 0x%016lx", regs[20]); + tty->print_cr("x21 = 0x%016lx", regs[21]); + tty->print_cr("x22 = 0x%016lx", regs[22]); + tty->print_cr("x23 = 0x%016lx", regs[23]); + tty->print_cr("x24 = 0x%016lx", regs[24]); + tty->print_cr("x25 = 0x%016lx", regs[25]); + tty->print_cr("x26 = 0x%016lx", regs[26]); + tty->print_cr("x27 = 0x%016lx", regs[27]); + tty->print_cr("x28 = 0x%016lx", regs[28]); + tty->print_cr("x30 = 0x%016lx", regs[30]); + tty->print_cr("x31 = 0x%016lx", regs[31]); + BREAKPOINT; + } + } + fatal("DEBUG MESSAGE: %s", msg); +} + +void MacroAssembler::resolve_jobject(Register value, Register thread, Register tmp) { + Label done, not_weak; + beqz(value, done); // Use NULL as-is. + + // Test for jweak tag. + andi(t0, value, JNIHandles::weak_tag_mask); + beqz(t0, not_weak); + + // Resolve jweak. + access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, value, + Address(value, -JNIHandles::weak_tag_value), tmp, thread); + verify_oop(value); + j(done); + + bind(not_weak); + // Resolve (untagged) jobject. + access_load_at(T_OBJECT, IN_NATIVE, value, Address(value, 0), tmp, thread); + verify_oop(value); + bind(done); +} + +void MacroAssembler::stop(const char* msg) { + address ip = pc(); + pusha(); + li(c_rarg0, (uintptr_t)(address)msg); + li(c_rarg1, (uintptr_t)(address)ip); + mv(c_rarg2, sp); + mv(c_rarg3, CAST_FROM_FN_PTR(address, MacroAssembler::debug64)); + jalr(c_rarg3); + ebreak(); +} + +void MacroAssembler::unimplemented(const char* what) { + const char* buf = NULL; + { + ResourceMark rm; + stringStream ss; + ss.print("unimplemented: %s", what); + buf = code_string(ss.as_string()); + } + stop(buf); +} + +void MacroAssembler::emit_static_call_stub() { + // CompiledDirectStaticCall::set_to_interpreted knows the + // exact layout of this stub. + + ifence(); + mov_metadata(xmethod, (Metadata*)NULL); + + // Jump to the entry point of the i2c stub. + int32_t offset = 0; + movptr_with_offset(t0, 0, offset); + jalr(x0, t0, offset); +} + +void MacroAssembler::call_VM_leaf_base(address entry_point, + int number_of_arguments, + Label *retaddr) { + call_native_base(entry_point, retaddr); +} + +void MacroAssembler::call_native(address entry_point, Register arg_0) { + pass_arg0(this, arg_0); + call_native_base(entry_point); +} + +void MacroAssembler::call_native_base(address entry_point, Label *retaddr) { + Label E, L; + int32_t offset = 0; + push_reg(0x80000040, sp); // push << t0 & xmethod >> to sp + movptr_with_offset(t0, entry_point, offset); + jalr(x1, t0, offset); + if (retaddr != NULL) { + bind(*retaddr); + } + pop_reg(0x80000040, sp); // pop << t0 & xmethod >> from sp +} + +void MacroAssembler::call_VM_leaf(address entry_point, int number_of_arguments) { + call_VM_leaf_base(entry_point, number_of_arguments); +} + +void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0) { + pass_arg0(this, arg_0); + call_VM_leaf_base(entry_point, 1); +} + +void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1) { + pass_arg0(this, arg_0); + pass_arg1(this, arg_1); + call_VM_leaf_base(entry_point, 2); +} + +void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, + Register arg_1, Register arg_2) { + pass_arg0(this, arg_0); + pass_arg1(this, arg_1); + pass_arg2(this, arg_2); + call_VM_leaf_base(entry_point, 3); +} + +void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0) { + pass_arg0(this, arg_0); + MacroAssembler::call_VM_leaf_base(entry_point, 1); +} + +void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1) { + + assert(arg_0 != c_rarg1, "smashed arg"); + pass_arg1(this, arg_1); + pass_arg0(this, arg_0); + MacroAssembler::call_VM_leaf_base(entry_point, 2); +} + +void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) { + assert(arg_0 != c_rarg2, "smashed arg"); + assert(arg_1 != c_rarg2, "smashed arg"); + pass_arg2(this, arg_2); + assert(arg_0 != c_rarg1, "smashed arg"); + pass_arg1(this, arg_1); + pass_arg0(this, arg_0); + MacroAssembler::call_VM_leaf_base(entry_point, 3); +} + +void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3) { + assert(arg_0 != c_rarg3, "smashed arg"); + assert(arg_1 != c_rarg3, "smashed arg"); + assert(arg_2 != c_rarg3, "smashed arg"); + pass_arg3(this, arg_3); + assert(arg_0 != c_rarg2, "smashed arg"); + assert(arg_1 != c_rarg2, "smashed arg"); + pass_arg2(this, arg_2); + assert(arg_0 != c_rarg1, "smashed arg"); + pass_arg1(this, arg_1); + pass_arg0(this, arg_0); + MacroAssembler::call_VM_leaf_base(entry_point, 4); +} + +void MacroAssembler::nop() { + addi(x0, x0, 0); +} + +void MacroAssembler::mv(Register Rd, Register Rs) { + if (Rd != Rs) { + addi(Rd, Rs, 0); + } +} + +void MacroAssembler::notr(Register Rd, Register Rs) { + xori(Rd, Rs, -1); +} + +void MacroAssembler::neg(Register Rd, Register Rs) { + sub(Rd, x0, Rs); +} + +void MacroAssembler::negw(Register Rd, Register Rs) { + subw(Rd, x0, Rs); +} + +void MacroAssembler::sext_w(Register Rd, Register Rs) { + addiw(Rd, Rs, 0); +} + +void MacroAssembler::zext_b(Register Rd, Register Rs) { + andi(Rd, Rs, 0xFF); +} + +void MacroAssembler::seqz(Register Rd, Register Rs) { + sltiu(Rd, Rs, 1); +} + +void MacroAssembler::snez(Register Rd, Register Rs) { + sltu(Rd, x0, Rs); +} + +void MacroAssembler::sltz(Register Rd, Register Rs) { + slt(Rd, Rs, x0); +} + +void MacroAssembler::sgtz(Register Rd, Register Rs) { + slt(Rd, x0, Rs); +} + +void MacroAssembler::fmv_s(FloatRegister Rd, FloatRegister Rs) { + if (Rd != Rs) { + fsgnj_s(Rd, Rs, Rs); + } +} + +void MacroAssembler::fabs_s(FloatRegister Rd, FloatRegister Rs) { + fsgnjx_s(Rd, Rs, Rs); +} + +void MacroAssembler::fneg_s(FloatRegister Rd, FloatRegister Rs) { + fsgnjn_s(Rd, Rs, Rs); +} + +void MacroAssembler::fmv_d(FloatRegister Rd, FloatRegister Rs) { + if (Rd != Rs) { + fsgnj_d(Rd, Rs, Rs); + } +} + +void MacroAssembler::fabs_d(FloatRegister Rd, FloatRegister Rs) { + fsgnjx_d(Rd, Rs, Rs); +} + +void MacroAssembler::fneg_d(FloatRegister Rd, FloatRegister Rs) { + fsgnjn_d(Rd, Rs, Rs); +} + +void MacroAssembler::vmnot_m(VectorRegister vd, VectorRegister vs) { + vmnand_mm(vd, vs, vs); +} + +void MacroAssembler::vncvt_x_x_w(VectorRegister vd, VectorRegister vs, VectorMask vm) { + vnsrl_wx(vd, vs, x0, vm); +} + +void MacroAssembler::vfneg_v(VectorRegister vd, VectorRegister vs) { + vfsgnjn_vv(vd, vs, vs); +} + +void MacroAssembler::la(Register Rd, const address &dest) { + int64_t offset = dest - pc(); + if (is_offset_in_range(offset, 32)) { + auipc(Rd, (int32_t)offset + 0x800); //0x800, Note:the 11th sign bit + addi(Rd, Rd, ((int64_t)offset << 52) >> 52); + } else { + movptr(Rd, dest); + } +} + +void MacroAssembler::la(Register Rd, const Address &adr) { + InstructionMark im(this); + code_section()->relocate(inst_mark(), adr.rspec()); + relocInfo::relocType rtype = adr.rspec().reloc()->type(); + + switch (adr.getMode()) { + case Address::literal: { + if (rtype == relocInfo::none) { + li(Rd, (intptr_t)(adr.target())); + } else { + movptr(Rd, adr.target()); + } + break; + } + case Address::base_plus_offset: { + int32_t offset = 0; + baseOffset(Rd, adr, offset); + addi(Rd, Rd, offset); + break; + } + default: + ShouldNotReachHere(); + } +} + +void MacroAssembler::la(Register Rd, Label &label) { + la(Rd, target(label)); +} + +#define INSN(NAME) \ + void MacroAssembler::NAME##z(Register Rs, const address &dest) { \ + NAME(Rs, zr, dest); \ + } \ + void MacroAssembler::NAME##z(Register Rs, Label &l, bool is_far) { \ + NAME(Rs, zr, l, is_far); \ + } \ + + INSN(beq); + INSN(bne); + INSN(blt); + INSN(ble); + INSN(bge); + INSN(bgt); + +#undef INSN + +// Float compare branch instructions + +#define INSN(NAME, FLOATCMP, BRANCH) \ + void MacroAssembler::float_##NAME(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far, bool is_unordered) { \ + FLOATCMP##_s(t0, Rs1, Rs2); \ + BRANCH(t0, l, is_far); \ + } \ + void MacroAssembler::double_##NAME(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far, bool is_unordered) { \ + FLOATCMP##_d(t0, Rs1, Rs2); \ + BRANCH(t0, l, is_far); \ + } + + INSN(beq, feq, bnez); + INSN(bne, feq, beqz); + +#undef INSN + + +#define INSN(NAME, FLOATCMP1, FLOATCMP2) \ + void MacroAssembler::float_##NAME(FloatRegister Rs1, FloatRegister Rs2, Label &l, \ + bool is_far, bool is_unordered) { \ + if (is_unordered) { \ + /* jump if either source is NaN or condition is expected */ \ + FLOATCMP2##_s(t0, Rs2, Rs1); \ + beqz(t0, l, is_far); \ + } else { \ + /* jump if no NaN in source and condition is expected */ \ + FLOATCMP1##_s(t0, Rs1, Rs2); \ + bnez(t0, l, is_far); \ + } \ + } \ + void MacroAssembler::double_##NAME(FloatRegister Rs1, FloatRegister Rs2, Label &l, \ + bool is_far, bool is_unordered) { \ + if (is_unordered) { \ + /* jump if either source is NaN or condition is expected */ \ + FLOATCMP2##_d(t0, Rs2, Rs1); \ + beqz(t0, l, is_far); \ + } else { \ + /* jump if no NaN in source and condition is expected */ \ + FLOATCMP1##_d(t0, Rs1, Rs2); \ + bnez(t0, l, is_far); \ + } \ + } + + INSN(ble, fle, flt); + INSN(blt, flt, fle); + +#undef INSN + +#define INSN(NAME, CMP) \ + void MacroAssembler::float_##NAME(FloatRegister Rs1, FloatRegister Rs2, Label &l, \ + bool is_far, bool is_unordered) { \ + float_##CMP(Rs2, Rs1, l, is_far, is_unordered); \ + } \ + void MacroAssembler::double_##NAME(FloatRegister Rs1, FloatRegister Rs2, Label &l, \ + bool is_far, bool is_unordered) { \ + double_##CMP(Rs2, Rs1, l, is_far, is_unordered); \ + } + + INSN(bgt, blt); + INSN(bge, ble); + +#undef INSN + + +#define INSN(NAME, CSR) \ + void MacroAssembler::NAME(Register Rd) { \ + csrr(Rd, CSR); \ + } + + INSN(rdinstret, CSR_INSTERT); + INSN(rdcycle, CSR_CYCLE); + INSN(rdtime, CSR_TIME); + INSN(frcsr, CSR_FCSR); + INSN(frrm, CSR_FRM); + INSN(frflags, CSR_FFLAGS); + +#undef INSN + +void MacroAssembler::csrr(Register Rd, unsigned csr) { + csrrs(Rd, csr, x0); +} + +#define INSN(NAME, OPFUN) \ + void MacroAssembler::NAME(unsigned csr, Register Rs) { \ + OPFUN(x0, csr, Rs); \ + } + + INSN(csrw, csrrw); + INSN(csrs, csrrs); + INSN(csrc, csrrc); + +#undef INSN + +#define INSN(NAME, OPFUN) \ + void MacroAssembler::NAME(unsigned csr, unsigned imm) { \ + OPFUN(x0, csr, imm); \ + } + + INSN(csrwi, csrrwi); + INSN(csrsi, csrrsi); + INSN(csrci, csrrci); + +#undef INSN + +#define INSN(NAME, CSR) \ + void MacroAssembler::NAME(Register Rd, Register Rs) { \ + csrrw(Rd, CSR, Rs); \ + } + + INSN(fscsr, CSR_FCSR); + INSN(fsrm, CSR_FRM); + INSN(fsflags, CSR_FFLAGS); + +#undef INSN + +#define INSN(NAME) \ + void MacroAssembler::NAME(Register Rs) { \ + NAME(x0, Rs); \ + } + + INSN(fscsr); + INSN(fsrm); + INSN(fsflags); + +#undef INSN + +void MacroAssembler::fsrmi(Register Rd, unsigned imm) { + guarantee(imm < 5, "Rounding Mode is invalid in Rounding Mode register"); + csrrwi(Rd, CSR_FRM, imm); +} + +void MacroAssembler::fsflagsi(Register Rd, unsigned imm) { + csrrwi(Rd, CSR_FFLAGS, imm); +} + +#define INSN(NAME) \ + void MacroAssembler::NAME(unsigned imm) { \ + NAME(x0, imm); \ + } + + INSN(fsrmi); + INSN(fsflagsi); + +#undef INSN + +void MacroAssembler::push_reg(Register Rs) +{ + addi(esp, esp, 0 - wordSize); + sd(Rs, Address(esp, 0)); +} + +void MacroAssembler::pop_reg(Register Rd) +{ + ld(Rd, esp, 0); + addi(esp, esp, wordSize); +} + +int MacroAssembler::bitset_to_regs(unsigned int bitset, unsigned char* regs) { + int count = 0; + // Scan bitset to accumulate register pairs + for (int reg = 31; reg >= 0; reg--) { + if ((1U << 31) & bitset) { + regs[count++] = reg; + } + bitset <<= 1; + } + return count; +} + +// Push lots of registers in the bit set supplied. Don't push sp. +// Return the number of words pushed +int MacroAssembler::push_reg(unsigned int bitset, Register stack) { + DEBUG_ONLY(int words_pushed = 0;) + CompressibleRegion cr(this); + + unsigned char regs[32]; + int count = bitset_to_regs(bitset, regs); + // reserve one slot to align for odd count + int offset = is_even(count) ? 0 : wordSize; + + if (count) { + addi(stack, stack, - count * wordSize - offset); + } + for (int i = count - 1; i >= 0; i--) { + sd(as_Register(regs[i]), Address(stack, (count - 1 - i) * wordSize + offset)); + DEBUG_ONLY(words_pushed ++;) + } + + assert(words_pushed == count, "oops, pushed != count"); + + return count; +} + +int MacroAssembler::pop_reg(unsigned int bitset, Register stack) { + DEBUG_ONLY(int words_popped = 0;) + CompressibleRegion cr(this); + + unsigned char regs[32]; + int count = bitset_to_regs(bitset, regs); + // reserve one slot to align for odd count + int offset = is_even(count) ? 0 : wordSize; + + for (int i = count - 1; i >= 0; i--) { + ld(as_Register(regs[i]), Address(stack, (count - 1 - i) * wordSize + offset)); + DEBUG_ONLY(words_popped ++;) + } + + if (count) { + addi(stack, stack, count * wordSize + offset); + } + assert(words_popped == count, "oops, popped != count"); + + return count; +} + +// Push float registers in the bitset, except sp. +// Return the number of heapwords pushed. +int MacroAssembler::push_fp(unsigned int bitset, Register stack) { + CompressibleRegion cr(this); + int words_pushed = 0; + unsigned char regs[32]; + int count = bitset_to_regs(bitset, regs); + int push_slots = count + (count & 1); + + if (count) { + addi(stack, stack, -push_slots * wordSize); + } + + for (int i = count - 1; i >= 0; i--) { + fsd(as_FloatRegister(regs[i]), Address(stack, (push_slots - 1 - i) * wordSize)); + words_pushed++; + } + + assert(words_pushed == count, "oops, pushed(%d) != count(%d)", words_pushed, count); + return count; +} + +int MacroAssembler::pop_fp(unsigned int bitset, Register stack) { + CompressibleRegion cr(this); + int words_popped = 0; + unsigned char regs[32]; + int count = bitset_to_regs(bitset, regs); + int pop_slots = count + (count & 1); + + for (int i = count - 1; i >= 0; i--) { + fld(as_FloatRegister(regs[i]), Address(stack, (pop_slots - 1 - i) * wordSize)); + words_popped++; + } + + if (count) { + addi(stack, stack, pop_slots * wordSize); + } + + assert(words_popped == count, "oops, popped(%d) != count(%d)", words_popped, count); + return count; +} + +#ifdef COMPILER2 +int MacroAssembler::push_vp(unsigned int bitset, Register stack) { + CompressibleRegion cr(this); + int vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); + + // Scan bitset to accumulate register pairs + unsigned char regs[32]; + int count = 0; + for (int reg = 31; reg >= 0; reg--) { + if ((1U << 31) & bitset) { + regs[count++] = reg; + } + bitset <<= 1; + } + + for (int i = 0; i < count; i++) { + sub(stack, stack, vector_size_in_bytes); + vs1r_v(as_VectorRegister(regs[i]), stack); + } + + return count * vector_size_in_bytes / wordSize; +} + +int MacroAssembler::pop_vp(unsigned int bitset, Register stack) { + CompressibleRegion cr(this); + int vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); + + // Scan bitset to accumulate register pairs + unsigned char regs[32]; + int count = 0; + for (int reg = 31; reg >= 0; reg--) { + if ((1U << 31) & bitset) { + regs[count++] = reg; + } + bitset <<= 1; + } + + for (int i = count - 1; i >= 0; i--) { + vl1r_v(as_VectorRegister(regs[i]), stack); + add(stack, stack, vector_size_in_bytes); + } + + return count * vector_size_in_bytes / wordSize; +} +#endif // COMPILER2 + +void MacroAssembler::push_call_clobbered_registers_except(RegSet exclude) { + CompressibleRegion cr(this); + // Push integer registers x7, x10-x17, x28-x31. + push_reg(RegSet::of(x7) + RegSet::range(x10, x17) + RegSet::range(x28, x31) - exclude, sp); + + // Push float registers f0-f7, f10-f17, f28-f31. + addi(sp, sp, - wordSize * 20); + int offset = 0; + for (int i = 0; i < 32; i++) { + if (i <= f7->encoding() || i >= f28->encoding() || (i >= f10->encoding() && i <= f17->encoding())) { + fsd(as_FloatRegister(i), Address(sp, wordSize * (offset ++))); + } + } +} + +void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude) { + CompressibleRegion cr(this); + int offset = 0; + for (int i = 0; i < 32; i++) { + if (i <= f7->encoding() || i >= f28->encoding() || (i >= f10->encoding() && i <= f17->encoding())) { + fld(as_FloatRegister(i), Address(sp, wordSize * (offset ++))); + } + } + addi(sp, sp, wordSize * 20); + + pop_reg(RegSet::of(x7) + RegSet::range(x10, x17) + RegSet::range(x28, x31) - exclude, sp); +} + +// Push all the integer registers, except zr(x0) & sp(x2) & gp(x3) & tp(x4). +void MacroAssembler::pusha() { + CompressibleRegion cr(this); + push_reg(0xffffffe2, sp); +} + +// Pop all the integer registers, except zr(x0) & sp(x2) & gp(x3) & tp(x4). +void MacroAssembler::popa() { + CompressibleRegion cr(this); + pop_reg(0xffffffe2, sp); +} + +void MacroAssembler::push_CPU_state(bool save_vectors, int vector_size_in_bytes) { + CompressibleRegion cr(this); + // integer registers, except zr(x0) & ra(x1) & sp(x2) & gp(x3) & tp(x4) + push_reg(0xffffffe0, sp); + + // float registers + addi(sp, sp, - 32 * wordSize); + for (int i = 0; i < 32; i++) { + fsd(as_FloatRegister(i), Address(sp, i * wordSize)); + } + + // vector registers + if (save_vectors) { + sub(sp, sp, vector_size_in_bytes * VectorRegisterImpl::number_of_registers); + vsetvli(t0, x0, Assembler::e64, Assembler::m8); + for (int i = 0; i < VectorRegisterImpl::number_of_registers; i += 8) { + add(t0, sp, vector_size_in_bytes * i); + vse64_v(as_VectorRegister(i), t0); + } + } +} + +void MacroAssembler::pop_CPU_state(bool restore_vectors, int vector_size_in_bytes) { + CompressibleRegion cr(this); + // vector registers + if (restore_vectors) { + vsetvli(t0, x0, Assembler::e64, Assembler::m8); + for (int i = 0; i < VectorRegisterImpl::number_of_registers; i += 8) { + vle64_v(as_VectorRegister(i), sp); + add(sp, sp, vector_size_in_bytes * 8); + } + } + + // float registers + for (int i = 0; i < 32; i++) { + fld(as_FloatRegister(i), Address(sp, i * wordSize)); + } + addi(sp, sp, 32 * wordSize); + + // integer registers, except zr(x0) & ra(x1) & sp(x2) & gp(x3) & tp(x4) + pop_reg(0xffffffe0, sp); +} + +static int patch_offset_in_jal(address branch, int64_t offset) { + assert(is_imm_in_range(offset, 20, 1), "offset is too large to be patched in one jal insrusction!\n"); + Assembler::patch(branch, 31, 31, (offset >> 20) & 0x1); // offset[20] ==> branch[31] + Assembler::patch(branch, 30, 21, (offset >> 1) & 0x3ff); // offset[10:1] ==> branch[30:21] + Assembler::patch(branch, 20, 20, (offset >> 11) & 0x1); // offset[11] ==> branch[20] + Assembler::patch(branch, 19, 12, (offset >> 12) & 0xff); // offset[19:12] ==> branch[19:12] + return NativeInstruction::instruction_size; // only one instruction +} + +static int patch_offset_in_conditional_branch(address branch, int64_t offset) { + assert(is_imm_in_range(offset, 12, 1), "offset is too large to be patched in one beq/bge/bgeu/blt/bltu/bne insrusction!\n"); + Assembler::patch(branch, 31, 31, (offset >> 12) & 0x1); // offset[12] ==> branch[31] + Assembler::patch(branch, 30, 25, (offset >> 5) & 0x3f); // offset[10:5] ==> branch[30:25] + Assembler::patch(branch, 7, 7, (offset >> 11) & 0x1); // offset[11] ==> branch[7] + Assembler::patch(branch, 11, 8, (offset >> 1) & 0xf); // offset[4:1] ==> branch[11:8] + return NativeInstruction::instruction_size; // only one instruction +} + +static int patch_offset_in_pc_relative(address branch, int64_t offset) { + const int PC_RELATIVE_INSTRUCTION_NUM = 2; // auipc, addi/jalr/load + Assembler::patch(branch, 31, 12, ((offset + 0x800) >> 12) & 0xfffff); // Auipc. offset[31:12] ==> branch[31:12] + Assembler::patch(branch + 4, 31, 20, offset & 0xfff); // Addi/Jalr/Load. offset[11:0] ==> branch[31:20] + return PC_RELATIVE_INSTRUCTION_NUM * NativeInstruction::instruction_size; +} + +static int patch_addr_in_movptr(address branch, address target) { + const int MOVPTR_INSTRUCTIONS_NUM = 6; // lui + addi + slli + addi + slli + addi/jalr/load + int32_t lower = ((intptr_t)target << 36) >> 36; + int64_t upper = ((intptr_t)target - lower) >> 28; + Assembler::patch(branch + 0, 31, 12, upper & 0xfffff); // Lui. target[47:28] + target[27] ==> branch[31:12] + Assembler::patch(branch + 4, 31, 20, (lower >> 16) & 0xfff); // Addi. target[27:16] ==> branch[31:20] + Assembler::patch(branch + 12, 31, 20, (lower >> 5) & 0x7ff); // Addi. target[15: 5] ==> branch[31:20] + Assembler::patch(branch + 20, 31, 20, lower & 0x1f); // Addi/Jalr/Load. target[ 4: 0] ==> branch[31:20] + return MOVPTR_INSTRUCTIONS_NUM * NativeInstruction::instruction_size; +} + +static int patch_imm_in_li64(address branch, address target) { + const int LI64_INSTRUCTIONS_NUM = 8; // lui + addi + slli + addi + slli + addi + slli + addi + int64_t lower = (intptr_t)target & 0xffffffff; + lower = lower - ((lower << 44) >> 44); + int64_t tmp_imm = ((uint64_t)((intptr_t)target & 0xffffffff00000000)) + (uint64_t)lower; + int32_t upper = (tmp_imm - (int32_t)lower) >> 32; + int64_t tmp_upper = upper, tmp_lower = upper; + tmp_lower = (tmp_lower << 52) >> 52; + tmp_upper -= tmp_lower; + tmp_upper >>= 12; + // Load upper 32 bits. Upper = target[63:32], but if target[31] = 1 or (target[31:28] == 0x7ff && target[19] == 1), + // upper = target[63:32] + 1. + Assembler::patch(branch + 0, 31, 12, tmp_upper & 0xfffff); // Lui. + Assembler::patch(branch + 4, 31, 20, tmp_lower & 0xfff); // Addi. + // Load the rest 32 bits. + Assembler::patch(branch + 12, 31, 20, ((int32_t)lower >> 20) & 0xfff); // Addi. + Assembler::patch(branch + 20, 31, 20, (((intptr_t)target << 44) >> 52) & 0xfff); // Addi. + Assembler::patch(branch + 28, 31, 20, (intptr_t)target & 0xff); // Addi. + return LI64_INSTRUCTIONS_NUM * NativeInstruction::instruction_size; +} + +static int patch_imm_in_li32(address branch, int32_t target) { + const int LI32_INSTRUCTIONS_NUM = 2; // lui + addiw + int64_t upper = (intptr_t)target; + int32_t lower = (((int32_t)target) << 20) >> 20; + upper -= lower; + upper = (int32_t)upper; + Assembler::patch(branch + 0, 31, 12, (upper >> 12) & 0xfffff); // Lui. + Assembler::patch(branch + 4, 31, 20, lower & 0xfff); // Addiw. + return LI32_INSTRUCTIONS_NUM * NativeInstruction::instruction_size; +} + +static long get_offset_of_jal(address insn_addr) { + assert_cond(insn_addr != NULL); + long offset = 0; + unsigned insn = *(unsigned*)insn_addr; + long val = (long)Assembler::sextract(insn, 31, 12); + offset |= ((val >> 19) & 0x1) << 20; + offset |= (val & 0xff) << 12; + offset |= ((val >> 8) & 0x1) << 11; + offset |= ((val >> 9) & 0x3ff) << 1; + offset = (offset << 43) >> 43; + return offset; +} + +static long get_offset_of_conditional_branch(address insn_addr) { + long offset = 0; + assert_cond(insn_addr != NULL); + unsigned insn = *(unsigned*)insn_addr; + offset = (long)Assembler::sextract(insn, 31, 31); + offset = (offset << 12) | (((long)(Assembler::sextract(insn, 7, 7) & 0x1)) << 11); + offset = offset | (((long)(Assembler::sextract(insn, 30, 25) & 0x3f)) << 5); + offset = offset | (((long)(Assembler::sextract(insn, 11, 8) & 0xf)) << 1); + offset = (offset << 41) >> 41; + return offset; +} + +static long get_offset_of_pc_relative(address insn_addr) { + long offset = 0; + assert_cond(insn_addr != NULL); + offset = ((long)(Assembler::sextract(((unsigned*)insn_addr)[0], 31, 12))) << 12; // Auipc. + offset += ((long)Assembler::sextract(((unsigned*)insn_addr)[1], 31, 20)); // Addi/Jalr/Load. + offset = (offset << 32) >> 32; + return offset; +} + +static address get_target_of_movptr(address insn_addr) { + assert_cond(insn_addr != NULL); + intptr_t target_address = (((int64_t)Assembler::sextract(((unsigned*)insn_addr)[0], 31, 12)) & 0xfffff) << 28; // Lui. + target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[1], 31, 20)) << 16; // Addi. + target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[3], 31, 20)) << 5; // Addi. + target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[5], 31, 20)); // Addi/Jalr/Load. + return (address) target_address; +} + +static address get_target_of_li64(address insn_addr) { + assert_cond(insn_addr != NULL); + intptr_t target_address = (((int64_t)Assembler::sextract(((unsigned*)insn_addr)[0], 31, 12)) & 0xfffff) << 44; // Lui. + target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[1], 31, 20)) << 32; // Addi. + target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[3], 31, 20)) << 20; // Addi. + target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[5], 31, 20)) << 8; // Addi. + target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[7], 31, 20)); // Addi. + return (address)target_address; +} + +static address get_target_of_li32(address insn_addr) { + assert_cond(insn_addr != NULL); + intptr_t target_address = (((int64_t)Assembler::sextract(((unsigned*)insn_addr)[0], 31, 12)) & 0xfffff) << 12; // Lui. + target_address += ((int64_t)Assembler::sextract(((unsigned*)insn_addr)[1], 31, 20)); // Addiw. + return (address)target_address; +} + +// Patch any kind of instruction; there may be several instructions. +// Return the total length (in bytes) of the instructions. +int MacroAssembler::pd_patch_instruction_size(address branch, address target) { + assert_cond(branch != NULL); + int64_t offset = target - branch; + if (NativeInstruction::is_jal_at(branch)) { // jal + return patch_offset_in_jal(branch, offset); + } else if (NativeInstruction::is_branch_at(branch)) { // beq/bge/bgeu/blt/bltu/bne + return patch_offset_in_conditional_branch(branch, offset); + } else if (NativeInstruction::is_pc_relative_at(branch)) { // auipc, addi/jalr/load + return patch_offset_in_pc_relative(branch, offset); + } else if (NativeInstruction::is_movptr_at(branch)) { // movptr + return patch_addr_in_movptr(branch, target); + } else if (NativeInstruction::is_li64_at(branch)) { // li64 + return patch_imm_in_li64(branch, target); + } else if (NativeInstruction::is_li32_at(branch)) { // li32 + int64_t imm = (intptr_t)target; + return patch_imm_in_li32(branch, (int32_t)imm); + } else { +#ifdef ASSERT + tty->print_cr("pd_patch_instruction_size: instruction 0x%x at " INTPTR_FORMAT " could not be patched!\n", + *(unsigned*)branch, p2i(branch)); + Disassembler::decode(branch - 16, branch + 16); +#endif + ShouldNotReachHere(); + return -1; + } +} + +address MacroAssembler::target_addr_for_insn(address insn_addr) { + long offset = 0; + assert_cond(insn_addr != NULL); + if (NativeInstruction::is_jal_at(insn_addr)) { // jal + offset = get_offset_of_jal(insn_addr); + } else if (NativeInstruction::is_branch_at(insn_addr)) { // beq/bge/bgeu/blt/bltu/bne + offset = get_offset_of_conditional_branch(insn_addr); + } else if (NativeInstruction::is_pc_relative_at(insn_addr)) { // auipc, addi/jalr/load + offset = get_offset_of_pc_relative(insn_addr); + } else if (NativeInstruction::is_movptr_at(insn_addr)) { // movptr + return get_target_of_movptr(insn_addr); + } else if (NativeInstruction::is_li64_at(insn_addr)) { // li64 + return get_target_of_li64(insn_addr); + } else if (NativeInstruction::is_li32_at(insn_addr)) { // li32 + return get_target_of_li32(insn_addr); + } else { + ShouldNotReachHere(); + } + return address(((uintptr_t)insn_addr + offset)); +} + +int MacroAssembler::patch_oop(address insn_addr, address o) { + // OOPs are either narrow (32 bits) or wide (48 bits). We encode + // narrow OOPs by setting the upper 16 bits in the first + // instruction. + if (NativeInstruction::is_li32_at(insn_addr)) { + // Move narrow OOP + uint32_t n = CompressedOops::narrow_oop_value(cast_to_oop(o)); + return patch_imm_in_li32(insn_addr, (int32_t)n); + } else if (NativeInstruction::is_movptr_at(insn_addr)) { + // Move wide OOP + return patch_addr_in_movptr(insn_addr, o); + } + ShouldNotReachHere(); + return -1; +} + +void MacroAssembler::reinit_heapbase() { + if (UseCompressedOops) { + if (Universe::is_fully_initialized()) { + mv(xheapbase, CompressedOops::ptrs_base()); + } else { + int32_t offset = 0; + la_patchable(xheapbase, ExternalAddress((address)CompressedOops::ptrs_base_addr()), offset); + ld(xheapbase, Address(xheapbase, offset)); + } + } +} + +void MacroAssembler::mv(Register Rd, Address dest) { + assert(dest.getMode() == Address::literal, "Address mode should be Address::literal"); + code_section()->relocate(pc(), dest.rspec()); + movptr(Rd, dest.target()); +} + +void MacroAssembler::mv(Register Rd, address addr) { + // Here in case of use with relocation, use fix length instruciton + // movptr instead of li + movptr(Rd, addr); +} + +void MacroAssembler::mv(Register Rd, RegisterOrConstant src) { + if (src.is_register()) { + mv(Rd, src.as_register()); + } else { + mv(Rd, src.as_constant()); + } +} + +void MacroAssembler::andrw(Register Rd, Register Rs1, Register Rs2) { + andr(Rd, Rs1, Rs2); + // addw: The result is clipped to 32 bits, then the sign bit is extended, + // and the result is stored in Rd + addw(Rd, Rd, zr); +} + +void MacroAssembler::orrw(Register Rd, Register Rs1, Register Rs2) { + orr(Rd, Rs1, Rs2); + // addw: The result is clipped to 32 bits, then the sign bit is extended, + // and the result is stored in Rd + addw(Rd, Rd, zr); +} + +void MacroAssembler::xorrw(Register Rd, Register Rs1, Register Rs2) { + xorr(Rd, Rs1, Rs2); + // addw: The result is clipped to 32 bits, then the sign bit is extended, + // and the result is stored in Rd + addw(Rd, Rd, zr); +} + +// Note: load_unsigned_short used to be called load_unsigned_word. +int MacroAssembler::load_unsigned_short(Register dst, Address src) { + int off = offset(); + lhu(dst, src); + return off; +} + +int MacroAssembler::load_unsigned_byte(Register dst, Address src) { + int off = offset(); + lbu(dst, src); + return off; +} + +int MacroAssembler::load_signed_short(Register dst, Address src) { + int off = offset(); + lh(dst, src); + return off; +} + +int MacroAssembler::load_signed_byte(Register dst, Address src) { + int off = offset(); + lb(dst, src); + return off; +} + +void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2) { + switch (size_in_bytes) { + case 8: ld(dst, src); break; + case 4: is_signed ? lw(dst, src) : lwu(dst, src); break; + case 2: is_signed ? load_signed_short(dst, src) : load_unsigned_short(dst, src); break; + case 1: is_signed ? load_signed_byte( dst, src) : load_unsigned_byte( dst, src); break; + default: ShouldNotReachHere(); + } +} + +void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2) { + switch (size_in_bytes) { + case 8: sd(src, dst); break; + case 4: sw(src, dst); break; + case 2: sh(src, dst); break; + case 1: sb(src, dst); break; + default: ShouldNotReachHere(); + } +} + +// reverse bytes in halfword in lower 16 bits and sign-extend +// Rd[15:0] = Rs[7:0] Rs[15:8] (sign-extend to 64 bits) +void MacroAssembler::revb_h_h(Register Rd, Register Rs, Register tmp) { + if (UseRVB) { + rev8(Rd, Rs); + srai(Rd, Rd, 48); + return; + } + assert_different_registers(Rs, tmp); + assert_different_registers(Rd, tmp); + srli(tmp, Rs, 8); + andi(tmp, tmp, 0xFF); + slli(Rd, Rs, 56); + srai(Rd, Rd, 48); // sign-extend + orr(Rd, Rd, tmp); +} + +// reverse bytes in lower word and sign-extend +// Rd[31:0] = Rs[7:0] Rs[15:8] Rs[23:16] Rs[31:24] (sign-extend to 64 bits) +void MacroAssembler::revb_w_w(Register Rd, Register Rs, Register tmp1, Register tmp2) { + if (UseRVB) { + rev8(Rd, Rs); + srai(Rd, Rd, 32); + return; + } + assert_different_registers(Rs, tmp1, tmp2); + assert_different_registers(Rd, tmp1, tmp2); + revb_h_w_u(Rd, Rs, tmp1, tmp2); + slli(tmp2, Rd, 48); + srai(tmp2, tmp2, 32); // sign-extend + srli(Rd, Rd, 16); + orr(Rd, Rd, tmp2); +} + +// reverse bytes in halfword in lower 16 bits and zero-extend +// Rd[15:0] = Rs[7:0] Rs[15:8] (zero-extend to 64 bits) +void MacroAssembler::revb_h_h_u(Register Rd, Register Rs, Register tmp) { + if (UseRVB) { + rev8(Rd, Rs); + srli(Rd, Rd, 48); + return; + } + assert_different_registers(Rs, tmp); + assert_different_registers(Rd, tmp); + srli(tmp, Rs, 8); + andi(tmp, tmp, 0xFF); + andi(Rd, Rs, 0xFF); + slli(Rd, Rd, 8); + orr(Rd, Rd, tmp); +} + +// reverse bytes in halfwords in lower 32 bits and zero-extend +// Rd[31:0] = Rs[23:16] Rs[31:24] Rs[7:0] Rs[15:8] (zero-extend to 64 bits) +void MacroAssembler::revb_h_w_u(Register Rd, Register Rs, Register tmp1, Register tmp2) { + if (UseRVB) { + rev8(Rd, Rs); + rori(Rd, Rd, 32); + roriw(Rd, Rd, 16); + zext_w(Rd, Rd); + return; + } + assert_different_registers(Rs, tmp1, tmp2); + assert_different_registers(Rd, tmp1, tmp2); + srli(tmp2, Rs, 16); + revb_h_h_u(tmp2, tmp2, tmp1); + revb_h_h_u(Rd, Rs, tmp1); + slli(tmp2, tmp2, 16); + orr(Rd, Rd, tmp2); +} + +// This method is only used for revb_h +// Rd = Rs[47:0] Rs[55:48] Rs[63:56] +void MacroAssembler::revb_h_helper(Register Rd, Register Rs, Register tmp1, Register tmp2) { + assert_different_registers(Rs, tmp1, tmp2); + assert_different_registers(Rd, tmp1); + srli(tmp1, Rs, 48); + andi(tmp2, tmp1, 0xFF); + slli(tmp2, tmp2, 8); + srli(tmp1, tmp1, 8); + orr(tmp1, tmp1, tmp2); + slli(Rd, Rs, 16); + orr(Rd, Rd, tmp1); +} + +// reverse bytes in each halfword +// Rd[63:0] = Rs[55:48] Rs[63:56] Rs[39:32] Rs[47:40] Rs[23:16] Rs[31:24] Rs[7:0] Rs[15:8] +void MacroAssembler::revb_h(Register Rd, Register Rs, Register tmp1, Register tmp2) { + if (UseRVB) { + assert_different_registers(Rs, tmp1); + assert_different_registers(Rd, tmp1); + rev8(Rd, Rs); + zext_w(tmp1, Rd); + roriw(tmp1, tmp1, 16); + slli(tmp1, tmp1, 32); + srli(Rd, Rd, 32); + roriw(Rd, Rd, 16); + zext_w(Rd, Rd); + orr(Rd, Rd, tmp1); + return; + } + assert_different_registers(Rs, tmp1, tmp2); + assert_different_registers(Rd, tmp1, tmp2); + revb_h_helper(Rd, Rs, tmp1, tmp2); + for (int i = 0; i < 3; ++i) { + revb_h_helper(Rd, Rd, tmp1, tmp2); + } +} + +// reverse bytes in each word +// Rd[63:0] = Rs[39:32] Rs[47:40] Rs[55:48] Rs[63:56] Rs[7:0] Rs[15:8] Rs[23:16] Rs[31:24] +void MacroAssembler::revb_w(Register Rd, Register Rs, Register tmp1, Register tmp2) { + if (UseRVB) { + rev8(Rd, Rs); + rori(Rd, Rd, 32); + return; + } + assert_different_registers(Rs, tmp1, tmp2); + assert_different_registers(Rd, tmp1, tmp2); + revb(Rd, Rs, tmp1, tmp2); + ror_imm(Rd, Rd, 32); +} + +// reverse bytes in doubleword +// Rd[63:0] = Rs[7:0] Rs[15:8] Rs[23:16] Rs[31:24] Rs[39:32] Rs[47,40] Rs[55,48] Rs[63:56] +void MacroAssembler::revb(Register Rd, Register Rs, Register tmp1, Register tmp2) { + if (UseRVB) { + rev8(Rd, Rs); + return; + } + assert_different_registers(Rs, tmp1, tmp2); + assert_different_registers(Rd, tmp1, tmp2); + andi(tmp1, Rs, 0xFF); + slli(tmp1, tmp1, 8); + for (int step = 8; step < 56; step += 8) { + srli(tmp2, Rs, step); + andi(tmp2, tmp2, 0xFF); + orr(tmp1, tmp1, tmp2); + slli(tmp1, tmp1, 8); + } + srli(Rd, Rs, 56); + andi(Rd, Rd, 0xFF); + orr(Rd, tmp1, Rd); +} + +// rotate right with shift bits +void MacroAssembler::ror_imm(Register dst, Register src, uint32_t shift, Register tmp) +{ + if (UseRVB) { + rori(dst, src, shift); + return; + } + + assert_different_registers(dst, tmp); + assert_different_registers(src, tmp); + assert(shift < 64, "shift amount must be < 64"); + slli(tmp, src, 64 - shift); + srli(dst, src, shift); + orr(dst, dst, tmp); +} + +void MacroAssembler::andi(Register Rd, Register Rn, int64_t imm, Register tmp) { + if (is_imm_in_range(imm, 12, 0)) { + and_imm12(Rd, Rn, imm); + } else { + assert_different_registers(Rn, tmp); + li(tmp, imm); + andr(Rd, Rn, tmp); + } +} + +void MacroAssembler::orptr(Address adr, RegisterOrConstant src, Register tmp1, Register tmp2) { + ld(tmp1, adr); + if (src.is_register()) { + orr(tmp1, tmp1, src.as_register()); + } else { + if (is_imm_in_range(src.as_constant(), 12, 0)) { + ori(tmp1, tmp1, src.as_constant()); + } else { + assert_different_registers(tmp1, tmp2); + li(tmp2, src.as_constant()); + orr(tmp1, tmp1, tmp2); + } + } + sd(tmp1, adr); +} + +void MacroAssembler::cmp_klass(Register oop, Register trial_klass, Register tmp, Label &L) { + if (UseCompressedClassPointers) { + lwu(tmp, Address(oop, oopDesc::klass_offset_in_bytes())); + if (CompressedKlassPointers::base() == NULL) { + slli(tmp, tmp, CompressedKlassPointers::shift()); + beq(trial_klass, tmp, L); + return; + } + decode_klass_not_null(tmp); + } else { + ld(tmp, Address(oop, oopDesc::klass_offset_in_bytes())); + } + beq(trial_klass, tmp, L); +} + +// Move an oop into a register. immediate is true if we want +// immediate instructions and nmethod entry barriers are not enabled. +// i.e. we are not going to patch this instruction while the code is being +// executed by another thread. +void MacroAssembler::movoop(Register dst, jobject obj, bool immediate) { + int oop_index; + if (obj == NULL) { + oop_index = oop_recorder()->allocate_oop_index(obj); + } else { +#ifdef ASSERT + { + ThreadInVMfromUnknown tiv; + assert(Universe::heap()->is_in(JNIHandles::resolve(obj)), "should be real oop"); + } +#endif + oop_index = oop_recorder()->find_index(obj); + } + RelocationHolder rspec = oop_Relocation::spec(oop_index); + + // nmethod entry barrier necessitate using the constant pool. They have to be + // ordered with respected to oop access. + // Using immediate literals would necessitate fence.i. + if (BarrierSet::barrier_set()->barrier_set_nmethod() != NULL || !immediate) { + address dummy = address(uintptr_t(pc()) & -wordSize); // A nearby aligned address + ld_constant(dst, Address(dummy, rspec)); + } else + mv(dst, Address((address)obj, rspec)); +} + +// Move a metadata address into a register. +void MacroAssembler::mov_metadata(Register dst, Metadata* obj) { + int oop_index; + if (obj == NULL) { + oop_index = oop_recorder()->allocate_metadata_index(obj); + } else { + oop_index = oop_recorder()->find_index(obj); + } + RelocationHolder rspec = metadata_Relocation::spec(oop_index); + mv(dst, Address((address)obj, rspec)); +} + +// Writes to stack successive pages until offset reached to check for +// stack overflow + shadow pages. This clobbers tmp. +void MacroAssembler::bang_stack_size(Register size, Register tmp) { + assert_different_registers(tmp, size, t0); + // Bang stack for total size given plus shadow page size. + // Bang one page at a time because large size can bang beyond yellow and + // red zones. + mv(t0, os::vm_page_size()); + Label loop; + bind(loop); + sub(tmp, sp, t0); + subw(size, size, t0); + sd(size, Address(tmp)); + bgtz(size, loop); + + // Bang down shadow pages too. + // At this point, (tmp-0) is the last address touched, so don't + // touch it again. (It was touched as (tmp-pagesize) but then tmp + // was post-decremented.) Skip this address by starting at i=1, and + // touch a few more pages below. N.B. It is important to touch all + // the way down to and including i=StackShadowPages. + for (int i = 0; i < (int)(StackOverflow::stack_shadow_zone_size() / os::vm_page_size()) - 1; i++) { + // this could be any sized move but this is can be a debugging crumb + // so the bigger the better. + sub(tmp, tmp, os::vm_page_size()); + sd(size, Address(tmp, 0)); + } +} + +SkipIfEqual::SkipIfEqual(MacroAssembler* masm, const bool* flag_addr, bool value) { + assert_cond(masm != NULL); + int32_t offset = 0; + _masm = masm; + _masm->la_patchable(t0, ExternalAddress((address)flag_addr), offset); + _masm->lbu(t0, Address(t0, offset)); + _masm->beqz(t0, _label); +} + +SkipIfEqual::~SkipIfEqual() { + assert_cond(_masm != NULL); + _masm->bind(_label); + _masm = NULL; +} + +void MacroAssembler::load_mirror(Register dst, Register method, Register tmp) { + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + ld(dst, Address(xmethod, Method::const_offset())); + ld(dst, Address(dst, ConstMethod::constants_offset())); + ld(dst, Address(dst, ConstantPool::pool_holder_offset_in_bytes())); + ld(dst, Address(dst, mirror_offset)); + resolve_oop_handle(dst, tmp); +} + +void MacroAssembler::resolve_oop_handle(Register result, Register tmp) { + // OopHandle::resolve is an indirection. + assert_different_registers(result, tmp); + access_load_at(T_OBJECT, IN_NATIVE, result, Address(result, 0), tmp, noreg); +} + +// ((WeakHandle)result).resolve() +void MacroAssembler::resolve_weak_handle(Register result, Register tmp) { + assert_different_registers(result, tmp); + Label resolved; + + // A null weak handle resolves to null. + beqz(result, resolved); + + // Only 64 bit platforms support GCs that require a tmp register + // Only IN_HEAP loads require a thread_tmp register + // WeakHandle::resolve is an indirection like jweak. + access_load_at(T_OBJECT, IN_NATIVE | ON_PHANTOM_OOP_REF, + result, Address(result), tmp, noreg /* tmp_thread */); + bind(resolved); +} + +void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators, + Register dst, Address src, + Register tmp1, Register thread_tmp) { + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + decorators = AccessInternal::decorator_fixup(decorators); + bool as_raw = (decorators & AS_RAW) != 0; + if (as_raw) { + bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, thread_tmp); + } else { + bs->load_at(this, decorators, type, dst, src, tmp1, thread_tmp); + } +} + +void MacroAssembler::null_check(Register reg, int offset) { + if (needs_explicit_null_check(offset)) { + // provoke OS NULL exception if reg = NULL by + // accessing M[reg] w/o changing any registers + // NOTE: this is plenty to provoke a segv + ld(zr, Address(reg, 0)); + } else { + // nothing to do, (later) access of M[reg + offset] + // will provoke OS NULL exception if reg = NULL + } +} + +void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators, + Address dst, Register src, + Register tmp1, Register thread_tmp) { + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + decorators = AccessInternal::decorator_fixup(decorators); + bool as_raw = (decorators & AS_RAW) != 0; + if (as_raw) { + bs->BarrierSetAssembler::store_at(this, decorators, type, dst, src, tmp1, thread_tmp); + } else { + bs->store_at(this, decorators, type, dst, src, tmp1, thread_tmp); + } +} + +// Algorithm must match CompressedOops::encode. +void MacroAssembler::encode_heap_oop(Register d, Register s) { + verify_oop(s, "broken oop in encode_heap_oop"); + if (CompressedOops::base() == NULL) { + if (CompressedOops::shift() != 0) { + assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); + srli(d, s, LogMinObjAlignmentInBytes); + } else { + mv(d, s); + } + } else { + Label notNull; + sub(d, s, xheapbase); + bgez(d, notNull); + mv(d, zr); + bind(notNull); + if (CompressedOops::shift() != 0) { + assert (LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); + srli(d, d, CompressedOops::shift()); + } + } +} + +void MacroAssembler::load_klass(Register dst, Register src) { + if (UseCompressedClassPointers) { + lwu(dst, Address(src, oopDesc::klass_offset_in_bytes())); + decode_klass_not_null(dst); + } else { + ld(dst, Address(src, oopDesc::klass_offset_in_bytes())); + } +} + +void MacroAssembler::store_klass(Register dst, Register src) { + // FIXME: Should this be a store release? concurrent gcs assumes + // klass length is valid if klass field is not null. + if (UseCompressedClassPointers) { + encode_klass_not_null(src); + sw(src, Address(dst, oopDesc::klass_offset_in_bytes())); + } else { + sd(src, Address(dst, oopDesc::klass_offset_in_bytes())); + } +} + +void MacroAssembler::store_klass_gap(Register dst, Register src) { + if (UseCompressedClassPointers) { + // Store to klass gap in destination + sw(src, Address(dst, oopDesc::klass_gap_offset_in_bytes())); + } +} + +void MacroAssembler::decode_klass_not_null(Register r) { + decode_klass_not_null(r, r); +} + +void MacroAssembler::decode_klass_not_null(Register dst, Register src, Register tmp) { + assert(UseCompressedClassPointers, "should only be used for compressed headers"); + + if (CompressedKlassPointers::base() == NULL) { + if (CompressedKlassPointers::shift() != 0) { + assert(LogKlassAlignmentInBytes == CompressedKlassPointers::shift(), "decode alg wrong"); + slli(dst, src, LogKlassAlignmentInBytes); + } else { + mv(dst, src); + } + return; + } + + Register xbase = dst; + if (dst == src) { + xbase = tmp; + } + + assert_different_registers(src, xbase); + li(xbase, (uintptr_t)CompressedKlassPointers::base()); + + if (CompressedKlassPointers::shift() != 0) { + assert(LogKlassAlignmentInBytes == CompressedKlassPointers::shift(), "decode alg wrong"); + assert_different_registers(t0, xbase); + shadd(dst, src, xbase, t0, LogKlassAlignmentInBytes); + } else { + add(dst, xbase, src); + } + + if (xbase == xheapbase) { reinit_heapbase(); } +} + +void MacroAssembler::encode_klass_not_null(Register r) { + encode_klass_not_null(r, r); +} + +void MacroAssembler::encode_klass_not_null(Register dst, Register src, Register tmp) { + assert(UseCompressedClassPointers, "should only be used for compressed headers"); + + if (CompressedKlassPointers::base() == NULL) { + if (CompressedKlassPointers::shift() != 0) { + assert(LogKlassAlignmentInBytes == CompressedKlassPointers::shift(), "decode alg wrong"); + srli(dst, src, LogKlassAlignmentInBytes); + } else { + mv(dst, src); + } + return; + } + + if (((uint64_t)(uintptr_t)CompressedKlassPointers::base() & 0xffffffff) == 0 && + CompressedKlassPointers::shift() == 0) { + zero_extend(dst, src, 32); + return; + } + + Register xbase = dst; + if (dst == src) { + xbase = tmp; + } + + assert_different_registers(src, xbase); + li(xbase, (intptr_t)CompressedKlassPointers::base()); + sub(dst, src, xbase); + if (CompressedKlassPointers::shift() != 0) { + assert(LogKlassAlignmentInBytes == CompressedKlassPointers::shift(), "decode alg wrong"); + srli(dst, dst, LogKlassAlignmentInBytes); + } + if (xbase == xheapbase) { + reinit_heapbase(); + } +} + +void MacroAssembler::decode_heap_oop_not_null(Register r) { + decode_heap_oop_not_null(r, r); +} + +void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) { + assert(UseCompressedOops, "should only be used for compressed headers"); + assert(Universe::heap() != NULL, "java heap should be initialized"); + // Cannot assert, unverified entry point counts instructions (see .ad file) + // vtableStubs also counts instructions in pd_code_size_limit. + // Also do not verify_oop as this is called by verify_oop. + if (CompressedOops::shift() != 0) { + assert(LogMinObjAlignmentInBytes == CompressedOops::shift(), "decode alg wrong"); + slli(dst, src, LogMinObjAlignmentInBytes); + if (CompressedOops::base() != NULL) { + add(dst, xheapbase, dst); + } + } else { + assert(CompressedOops::base() == NULL, "sanity"); + mv(dst, src); + } +} + +void MacroAssembler::decode_heap_oop(Register d, Register s) { + if (CompressedOops::base() == NULL) { + if (CompressedOops::shift() != 0 || d != s) { + slli(d, s, CompressedOops::shift()); + } + } else { + Label done; + mv(d, s); + beqz(s, done); + shadd(d, s, xheapbase, d, LogMinObjAlignmentInBytes); + bind(done); + } + verify_oop(d, "broken oop in decode_heap_oop"); +} + +void MacroAssembler::store_heap_oop(Address dst, Register src, Register tmp1, + Register thread_tmp, DecoratorSet decorators) { + access_store_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, thread_tmp); +} + +void MacroAssembler::load_heap_oop(Register dst, Address src, Register tmp1, + Register thread_tmp, DecoratorSet decorators) { + access_load_at(T_OBJECT, IN_HEAP | decorators, dst, src, tmp1, thread_tmp); +} + +void MacroAssembler::load_heap_oop_not_null(Register dst, Address src, Register tmp1, + Register thread_tmp, DecoratorSet decorators) { + access_load_at(T_OBJECT, IN_HEAP | IS_NOT_NULL, dst, src, tmp1, thread_tmp); +} + +// Used for storing NULLs. +void MacroAssembler::store_heap_oop_null(Address dst) { + access_store_at(T_OBJECT, IN_HEAP, dst, noreg, noreg, noreg); +} + +int MacroAssembler::corrected_idivl(Register result, Register rs1, Register rs2, + bool want_remainder) +{ + // Full implementation of Java idiv and irem. The function + // returns the (pc) offset of the div instruction - may be needed + // for implicit exceptions. + // + // input : rs1: dividend + // rs2: divisor + // + // result: either + // quotient (= rs1 idiv rs2) + // remainder (= rs1 irem rs2) + + + int idivl_offset = offset(); + if (!want_remainder) { + divw(result, rs1, rs2); + } else { + remw(result, rs1, rs2); // result = rs1 % rs2; + } + return idivl_offset; +} + +int MacroAssembler::corrected_idivq(Register result, Register rs1, Register rs2, + bool want_remainder) +{ + // Full implementation of Java ldiv and lrem. The function + // returns the (pc) offset of the div instruction - may be needed + // for implicit exceptions. + // + // input : rs1: dividend + // rs2: divisor + // + // result: either + // quotient (= rs1 idiv rs2) + // remainder (= rs1 irem rs2) + + int idivq_offset = offset(); + if (!want_remainder) { + div(result, rs1, rs2); + } else { + rem(result, rs1, rs2); // result = rs1 % rs2; + } + return idivq_offset; +} + +// Look up the method for a megamorpic invkkeinterface call. +// The target method is determined by . +// The receiver klass is in recv_klass. +// On success, the result will be in method_result, and execution falls through. +// On failure, execution transfers to the given label. +void MacroAssembler::lookup_interface_method(Register recv_klass, + Register intf_klass, + RegisterOrConstant itable_index, + Register method_result, + Register scan_tmp, + Label& L_no_such_interface, + bool return_method) { + assert_different_registers(recv_klass, intf_klass, scan_tmp); + assert_different_registers(method_result, intf_klass, scan_tmp); + assert(recv_klass != method_result || !return_method, + "recv_klass can be destroyed when mehtid isn't needed"); + assert(itable_index.is_constant() || itable_index.as_register() == method_result, + "caller must be same register for non-constant itable index as for method"); + + // Compute start of first itableOffsetEntry (which is at the end of the vtable). + int vtable_base = in_bytes(Klass::vtable_start_offset()); + int itentry_off = itableMethodEntry::method_offset_in_bytes(); + int scan_step = itableOffsetEntry::size() * wordSize; + int vte_size = vtableEntry::size_in_bytes(); + assert(vte_size == wordSize, "else adjust times_vte_scale"); + + lwu(scan_tmp, Address(recv_klass, Klass::vtable_length_offset())); + + // %%% Could store the aligned, prescaled offset in the klassoop. + shadd(scan_tmp, scan_tmp, recv_klass, scan_tmp, 3); + add(scan_tmp, scan_tmp, vtable_base); + + if (return_method) { + // Adjust recv_klass by scaled itable_index, so we can free itable_index. + assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below"); + if (itable_index.is_register()) { + slli(t0, itable_index.as_register(), 3); + } else { + li(t0, itable_index.as_constant() << 3); + } + add(recv_klass, recv_klass, t0); + if (itentry_off) { + add(recv_klass, recv_klass, itentry_off); + } + } + + Label search, found_method; + + ld(method_result, Address(scan_tmp, itableOffsetEntry::interface_offset_in_bytes())); + beq(intf_klass, method_result, found_method); + bind(search); + // Check that the previous entry is non-null. A null entry means that + // the receiver class doens't implement the interface, and wasn't the + // same as when the caller was compiled. + beqz(method_result, L_no_such_interface, /* is_far */ true); + addi(scan_tmp, scan_tmp, scan_step); + ld(method_result, Address(scan_tmp, itableOffsetEntry::interface_offset_in_bytes())); + bne(intf_klass, method_result, search); + + bind(found_method); + + // Got a hit. + if (return_method) { + lwu(scan_tmp, Address(scan_tmp, itableOffsetEntry::offset_offset_in_bytes())); + add(method_result, recv_klass, scan_tmp); + ld(method_result, Address(method_result)); + } +} + +// virtual method calling +void MacroAssembler::lookup_virtual_method(Register recv_klass, + RegisterOrConstant vtable_index, + Register method_result) { + const int base = in_bytes(Klass::vtable_start_offset()); + assert(vtableEntry::size() * wordSize == 8, + "adjust the scaling in the code below"); + int vtable_offset_in_bytes = base + vtableEntry::method_offset_in_bytes(); + + if (vtable_index.is_register()) { + shadd(method_result, vtable_index.as_register(), recv_klass, method_result, LogBytesPerWord); + ld(method_result, Address(method_result, vtable_offset_in_bytes)); + } else { + vtable_offset_in_bytes += vtable_index.as_constant() * wordSize; + ld(method_result, form_address(method_result, recv_klass, vtable_offset_in_bytes)); + } +} + +void MacroAssembler::membar(uint32_t order_constraint) { + address prev = pc() - NativeMembar::instruction_size; + address last = code()->last_insn(); + + if (last != NULL && nativeInstruction_at(last)->is_membar() && prev == last) { + NativeMembar *bar = NativeMembar_at(prev); + // We are merging two memory barrier instructions. On RISCV we + // can do this simply by ORing them together. + bar->set_kind(bar->get_kind() | order_constraint); + BLOCK_COMMENT("merged membar"); + } else { + code()->set_last_insn(pc()); + + uint32_t predecessor = 0; + uint32_t successor = 0; + + membar_mask_to_pred_succ(order_constraint, predecessor, successor); + fence(predecessor, successor); + } +} + +// Form an addres from base + offset in Rd. Rd my or may not +// actually be used: you must use the Address that is returned. It +// is up to you to ensure that the shift provided mathces the size +// of your data. +Address MacroAssembler::form_address(Register Rd, Register base, long byte_offset) { + if (is_offset_in_range(byte_offset, 12)) { // 12: imm in range 2^12 + return Address(base, byte_offset); + } + + // Do it the hard way + mv(Rd, byte_offset); + add(Rd, base, Rd); + return Address(Rd); +} + +void MacroAssembler::check_klass_subtype(Register sub_klass, + Register super_klass, + Register tmp_reg, + Label& L_success) { + Label L_failure; + check_klass_subtype_fast_path(sub_klass, super_klass, tmp_reg, &L_success, &L_failure, NULL); + check_klass_subtype_slow_path(sub_klass, super_klass, tmp_reg, noreg, &L_success, NULL); + bind(L_failure); +} + +void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool acquire, bool in_nmethod) { + ld(t0, Address(xthread, JavaThread::polling_word_offset())); + if (acquire) { + membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + } + if (at_return) { + bgtu(in_nmethod ? sp : fp, t0, slow_path, true /* is_far */); + } else { + andi(t0, t0, SafepointMechanism::poll_bit()); + bnez(t0, slow_path, true /* is_far */); + } +} + +void MacroAssembler::cmpxchgptr(Register oldv, Register newv, Register addr, Register tmp, + Label &succeed, Label *fail) { + // oldv holds comparison value + // newv holds value to write in exchange + // addr identifies memory word to compare against/update + Label retry_load, nope; + bind(retry_load); + // Load reserved from the memory location + lr_d(tmp, addr, Assembler::aqrl); + // Fail and exit if it is not what we expect + bne(tmp, oldv, nope); + // If the store conditional succeeds, tmp will be zero + sc_d(tmp, newv, addr, Assembler::rl); + beqz(tmp, succeed); + // Retry only when the store conditional failed + j(retry_load); + + bind(nope); + membar(AnyAny); + mv(oldv, tmp); + if (fail != NULL) { + j(*fail); + } +} + +void MacroAssembler::cmpxchg_obj_header(Register oldv, Register newv, Register obj, Register tmp, + Label &succeed, Label *fail) { + assert(oopDesc::mark_offset_in_bytes() == 0, "assumption"); + cmpxchgptr(oldv, newv, obj, tmp, succeed, fail); +} + +void MacroAssembler::load_reserved(Register addr, + enum operand_size size, + Assembler::Aqrl acquire) { + switch (size) { + case int64: + lr_d(t0, addr, acquire); + break; + case int32: + lr_w(t0, addr, acquire); + break; + case uint32: + lr_w(t0, addr, acquire); + zero_extend(t0, t0, 32); + break; + default: + ShouldNotReachHere(); + } +} + +void MacroAssembler::store_conditional(Register addr, + Register new_val, + enum operand_size size, + Assembler::Aqrl release) { + switch (size) { + case int64: + sc_d(t0, new_val, addr, release); + break; + case int32: + case uint32: + sc_w(t0, new_val, addr, release); + break; + default: + ShouldNotReachHere(); + } +} + + +void MacroAssembler::cmpxchg_narrow_value_helper(Register addr, Register expected, + Register new_val, + enum operand_size size, + Register tmp1, Register tmp2, Register tmp3) { + assert(size == int8 || size == int16, "unsupported operand size"); + + Register aligned_addr = t1, shift = tmp1, mask = tmp2, not_mask = tmp3; + + andi(shift, addr, 3); + slli(shift, shift, 3); + + andi(aligned_addr, addr, ~3); + + if (size == int8) { + addi(mask, zr, 0xff); + } else { + // size == int16 case + addi(mask, zr, -1); + zero_extend(mask, mask, 16); + } + sll(mask, mask, shift); + + xori(not_mask, mask, -1); + + sll(expected, expected, shift); + andr(expected, expected, mask); + + sll(new_val, new_val, shift); + andr(new_val, new_val, mask); +} + +// cmpxchg_narrow_value will kill t0, t1, expected, new_val and tmps. +// It's designed to implement compare and swap byte/boolean/char/short by lr.w/sc.w, +// which are forced to work with 4-byte aligned address. +void MacroAssembler::cmpxchg_narrow_value(Register addr, Register expected, + Register new_val, + enum operand_size size, + Assembler::Aqrl acquire, Assembler::Aqrl release, + Register result, bool result_as_bool, + Register tmp1, Register tmp2, Register tmp3) { + Register aligned_addr = t1, shift = tmp1, mask = tmp2, not_mask = tmp3, old = result, tmp = t0; + assert_different_registers(addr, old, mask, not_mask, new_val, expected, shift, tmp); + cmpxchg_narrow_value_helper(addr, expected, new_val, size, tmp1, tmp2, tmp3); + + Label retry, fail, done; + + bind(retry); + lr_w(old, aligned_addr, acquire); + andr(tmp, old, mask); + bne(tmp, expected, fail); + + andr(tmp, old, not_mask); + orr(tmp, tmp, new_val); + sc_w(tmp, tmp, aligned_addr, release); + bnez(tmp, retry); + + if (result_as_bool) { + addi(result, zr, 1); + j(done); + + bind(fail); + mv(result, zr); + + bind(done); + } else { + andr(tmp, old, mask); + + bind(fail); + srl(result, tmp, shift); + + if (size == int8) { + sign_extend(result, result, 8); + } else { + // size == int16 case + sign_extend(result, result, 16); + } + } +} + +// weak_cmpxchg_narrow_value is a weak version of cmpxchg_narrow_value, to implement +// the weak CAS stuff. The major difference is that it just failed when store conditional +// failed. +void MacroAssembler::weak_cmpxchg_narrow_value(Register addr, Register expected, + Register new_val, + enum operand_size size, + Assembler::Aqrl acquire, Assembler::Aqrl release, + Register result, + Register tmp1, Register tmp2, Register tmp3) { + Register aligned_addr = t1, shift = tmp1, mask = tmp2, not_mask = tmp3, old = result, tmp = t0; + assert_different_registers(addr, old, mask, not_mask, new_val, expected, shift, tmp); + cmpxchg_narrow_value_helper(addr, expected, new_val, size, tmp1, tmp2, tmp3); + + Label succ, fail, done; + + lr_w(old, aligned_addr, acquire); + andr(tmp, old, mask); + bne(tmp, expected, fail); + + andr(tmp, old, not_mask); + orr(tmp, tmp, new_val); + sc_w(tmp, tmp, aligned_addr, release); + beqz(tmp, succ); + + bind(fail); + addi(result, zr, 1); + j(done); + + bind(succ); + mv(result, zr); + + bind(done); +} + +void MacroAssembler::cmpxchg(Register addr, Register expected, + Register new_val, + enum operand_size size, + Assembler::Aqrl acquire, Assembler::Aqrl release, + Register result, bool result_as_bool) { + assert(size != int8 && size != int16, "unsupported operand size"); + + Label retry_load, done, ne_done; + bind(retry_load); + load_reserved(addr, size, acquire); + bne(t0, expected, ne_done); + store_conditional(addr, new_val, size, release); + bnez(t0, retry_load); + + // equal, succeed + if (result_as_bool) { + li(result, 1); + } else { + mv(result, expected); + } + j(done); + + // not equal, failed + bind(ne_done); + if (result_as_bool) { + mv(result, zr); + } else { + mv(result, t0); + } + + bind(done); +} + +void MacroAssembler::cmpxchg_weak(Register addr, Register expected, + Register new_val, + enum operand_size size, + Assembler::Aqrl acquire, Assembler::Aqrl release, + Register result) { + Label fail, done, sc_done; + load_reserved(addr, size, acquire); + bne(t0, expected, fail); + store_conditional(addr, new_val, size, release); + beqz(t0, sc_done); + + // fail + bind(fail); + li(result, 1); + j(done); + + // sc_done + bind(sc_done); + mv(result, 0); + bind(done); +} + +#define ATOMIC_OP(NAME, AOP, ACQUIRE, RELEASE) \ +void MacroAssembler::atomic_##NAME(Register prev, RegisterOrConstant incr, Register addr) { \ + prev = prev->is_valid() ? prev : zr; \ + if (incr.is_register()) { \ + AOP(prev, addr, incr.as_register(), (Assembler::Aqrl)(ACQUIRE | RELEASE)); \ + } else { \ + mv(t0, incr.as_constant()); \ + AOP(prev, addr, t0, (Assembler::Aqrl)(ACQUIRE | RELEASE)); \ + } \ + return; \ +} + +ATOMIC_OP(add, amoadd_d, Assembler::relaxed, Assembler::relaxed) +ATOMIC_OP(addw, amoadd_w, Assembler::relaxed, Assembler::relaxed) +ATOMIC_OP(addal, amoadd_d, Assembler::aq, Assembler::rl) +ATOMIC_OP(addalw, amoadd_w, Assembler::aq, Assembler::rl) + +#undef ATOMIC_OP + +#define ATOMIC_XCHG(OP, AOP, ACQUIRE, RELEASE) \ +void MacroAssembler::atomic_##OP(Register prev, Register newv, Register addr) { \ + prev = prev->is_valid() ? prev : zr; \ + AOP(prev, addr, newv, (Assembler::Aqrl)(ACQUIRE | RELEASE)); \ + return; \ +} + +ATOMIC_XCHG(xchg, amoswap_d, Assembler::relaxed, Assembler::relaxed) +ATOMIC_XCHG(xchgw, amoswap_w, Assembler::relaxed, Assembler::relaxed) +ATOMIC_XCHG(xchgal, amoswap_d, Assembler::aq, Assembler::rl) +ATOMIC_XCHG(xchgalw, amoswap_w, Assembler::aq, Assembler::rl) + +#undef ATOMIC_XCHG + +#define ATOMIC_XCHGU(OP1, OP2) \ +void MacroAssembler::atomic_##OP1(Register prev, Register newv, Register addr) { \ + atomic_##OP2(prev, newv, addr); \ + zero_extend(prev, prev, 32); \ + return; \ +} + +ATOMIC_XCHGU(xchgwu, xchgw) +ATOMIC_XCHGU(xchgalwu, xchgalw) + +#undef ATOMIC_XCHGU + +void MacroAssembler::far_jump(Address entry, CodeBuffer *cbuf, Register tmp) { + assert(ReservedCodeCacheSize < 4*G, "branch out of range"); + assert(CodeCache::find_blob(entry.target()) != NULL, + "destination of far call not found in code cache"); + int32_t offset = 0; + if (far_branches()) { + // We can use auipc + jalr here because we know that the total size of + // the code cache cannot exceed 2Gb. + la_patchable(tmp, entry, offset); + if (cbuf != NULL) { cbuf->set_insts_mark(); } + jalr(x0, tmp, offset); + } else { + if (cbuf != NULL) { cbuf->set_insts_mark(); } + j(entry); + } +} + +void MacroAssembler::far_call(Address entry, CodeBuffer *cbuf, Register tmp) { + assert(ReservedCodeCacheSize < 4*G, "branch out of range"); + assert(CodeCache::find_blob(entry.target()) != NULL, + "destination of far call not found in code cache"); + int32_t offset = 0; + if (far_branches()) { + // We can use auipc + jalr here because we know that the total size of + // the code cache cannot exceed 2Gb. + la_patchable(tmp, entry, offset); + if (cbuf != NULL) { cbuf->set_insts_mark(); } + jalr(x1, tmp, offset); // link + } else { + if (cbuf != NULL) { cbuf->set_insts_mark(); } + jal(entry); // link + } +} + +void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register tmp_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + Register super_check_offset) { + assert_different_registers(sub_klass, super_klass, tmp_reg); + bool must_load_sco = (super_check_offset == noreg); + if (must_load_sco) { + assert(tmp_reg != noreg, "supply either a temp or a register offset"); + } else { + assert_different_registers(sub_klass, super_klass, super_check_offset); + } + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; } + assert(label_nulls <= 1, "at most one NULL in batch"); + + int sc_offset = in_bytes(Klass::secondary_super_cache_offset()); + int sco_offset = in_bytes(Klass::super_check_offset_offset()); + Address super_check_offset_addr(super_klass, sco_offset); + + // Hacked jmp, which may only be used just before L_fallthrough. +#define final_jmp(label) \ + if (&(label) == &L_fallthrough) { /*do nothing*/ } \ + else j(label) /*omit semi*/ + + // If the pointers are equal, we are done (e.g., String[] elements). + // This self-check enables sharing of secondary supertype arrays among + // non-primary types such as array-of-interface. Otherwise, each such + // type would need its own customized SSA. + // We move this check to the front fo the fast path because many + // type checks are in fact trivially successful in this manner, + // so we get a nicely predicted branch right at the start of the check. + beq(sub_klass, super_klass, *L_success); + + // Check the supertype display: + if (must_load_sco) { + lwu(tmp_reg, super_check_offset_addr); + super_check_offset = tmp_reg; + } + add(t0, sub_klass, super_check_offset); + Address super_check_addr(t0); + ld(t0, super_check_addr); // load displayed supertype + + // Ths check has worked decisively for primary supers. + // Secondary supers are sought in the super_cache ('super_cache_addr'). + // (Secondary supers are interfaces and very deeply nested subtypes.) + // This works in the same check above because of a tricky aliasing + // between the super_Cache and the primary super dispaly elements. + // (The 'super_check_addr' can address either, as the case requires.) + // Note that the cache is updated below if it does not help us find + // what we need immediately. + // So if it was a primary super, we can just fail immediately. + // Otherwise, it's the slow path for us (no success at this point). + + beq(super_klass, t0, *L_success); + mv(t1, sc_offset); + if (L_failure == &L_fallthrough) { + beq(super_check_offset, t1, *L_slow_path); + } else { + bne(super_check_offset, t1, *L_failure, /* is_far */ true); + final_jmp(*L_slow_path); + } + + bind(L_fallthrough); + +#undef final_jmp +} + +// Scans count pointer sized words at [addr] for occurence of value, +// generic +void MacroAssembler::repne_scan(Register addr, Register value, Register count, + Register tmp) { + Label Lloop, Lexit; + beqz(count, Lexit); + bind(Lloop); + ld(tmp, addr); + beq(value, tmp, Lexit); + add(addr, addr, wordSize); + sub(count, count, 1); + bnez(count, Lloop); + bind(Lexit); +} + +void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register tmp1_reg, + Register tmp2_reg, + Label* L_success, + Label* L_failure) { + assert_different_registers(sub_klass, super_klass, tmp1_reg); + if (tmp2_reg != noreg) { + assert_different_registers(sub_klass, super_klass, tmp1_reg, tmp2_reg, t0); + } +#define IS_A_TEMP(reg) ((reg) == tmp1_reg || (reg) == tmp2_reg) + + Label L_fallthrough; + int label_nulls = 0; + if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; } + if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; } + + assert(label_nulls <= 1, "at most one NULL in the batch"); + + // A couple of usefule fields in sub_klass: + int ss_offset = in_bytes(Klass::secondary_supers_offset()); + int sc_offset = in_bytes(Klass::secondary_super_cache_offset()); + Address secondary_supers_addr(sub_klass, ss_offset); + Address super_cache_addr( sub_klass, sc_offset); + + BLOCK_COMMENT("check_klass_subtype_slow_path"); + + // Do a linear scan of the secondary super-klass chain. + // This code is rarely used, so simplicity is a virtue here. + // The repne_scan instruction uses fixed registers, which we must spill. + // Don't worry too much about pre-existing connecitons with the input regs. + + assert(sub_klass != x10, "killed reg"); // killed by mv(x10, super) + assert(sub_klass != x12, "killed reg"); // killed by la(x12, &pst_counter) + + RegSet pushed_registers; + if (!IS_A_TEMP(x12)) { + pushed_registers += x12; + } + if (!IS_A_TEMP(x15)) { + pushed_registers += x15; + } + + if (super_klass != x10 || UseCompressedOops) { + if (!IS_A_TEMP(x10)) { + pushed_registers += x10; + } + } + + push_reg(pushed_registers, sp); + + // Get super_klass value into x10 (even if it was in x15 or x12) + mv(x10, super_klass); + +#ifndef PRODUCT + mv(t1, (address)&SharedRuntime::_partial_subtype_ctr); + Address pst_counter_addr(t1); + ld(t0, pst_counter_addr); + add(t0, t0, 1); + sd(t0, pst_counter_addr); +#endif // PRODUCT + + // We will consult the secondary-super array. + ld(x15, secondary_supers_addr); + // Load the array length. + lwu(x12, Address(x15, Array::length_offset_in_bytes())); + // Skip to start of data. + add(x15, x15, Array::base_offset_in_bytes()); + + // Set t0 to an obvious invalid value, falling through by default + li(t0, -1); + // Scan X12 words at [X15] for an occurrence of X10. + repne_scan(x15, x10, x12, t0); + + // pop will restore x10, so we should use a temp register to keep its value + mv(t1, x10); + + // Unspill the temp registers: + pop_reg(pushed_registers, sp); + + bne(t1, t0, *L_failure); + + // Success. Cache the super we found an proceed in triumph. + sd(super_klass, super_cache_addr); + + if (L_success != &L_fallthrough) { + j(*L_success); + } + +#undef IS_A_TEMP + + bind(L_fallthrough); +} + +// Defines obj, preserves var_size_in_bytes, okay for tmp2 == var_size_in_bytes. +void MacroAssembler::tlab_allocate(Register obj, + Register var_size_in_bytes, + int con_size_in_bytes, + Register tmp1, + Register tmp2, + Label& slow_case, + bool is_far) { + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->tlab_allocate(this, obj, var_size_in_bytes, con_size_in_bytes, tmp1, tmp2, slow_case, is_far); +} + +// Defines obj, preserves var_size_in_bytes +void MacroAssembler::eden_allocate(Register obj, + Register var_size_in_bytes, + int con_size_in_bytes, + Register tmp, + Label& slow_case, + bool is_far) { + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->eden_allocate(this, obj, var_size_in_bytes, con_size_in_bytes, tmp, slow_case, is_far); +} + + +// get_thread() can be called anywhere inside generated code so we +// need to save whatever non-callee save context might get clobbered +// by the call to Thread::current() or, indeed, the call setup code. +void MacroAssembler::get_thread(Register thread) { + // save all call-clobbered regs except thread + RegSet saved_regs = RegSet::range(x5, x7) + RegSet::range(x10, x17) + + RegSet::range(x28, x31) + ra - thread; + push_reg(saved_regs, sp); + + int32_t offset = 0; + movptr_with_offset(ra, CAST_FROM_FN_PTR(address, Thread::current), offset); + jalr(ra, ra, offset); + if (thread != x10) { + mv(thread, x10); + } + + // restore pushed registers + pop_reg(saved_regs, sp); +} + +void MacroAssembler::load_byte_map_base(Register reg) { + CardTable::CardValue* byte_map_base = + ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base(); + li(reg, (uint64_t)byte_map_base); +} + +void MacroAssembler::la_patchable(Register reg1, const Address &dest, int32_t &offset) { + relocInfo::relocType rtype = dest.rspec().reloc()->type(); + unsigned long low_address = (uintptr_t)CodeCache::low_bound(); + unsigned long high_address = (uintptr_t)CodeCache::high_bound(); + unsigned long dest_address = (uintptr_t)dest.target(); + long offset_low = dest_address - low_address; + long offset_high = dest_address - high_address; + + assert(is_valid_riscv64_address(dest.target()), "bad address"); + assert(dest.getMode() == Address::literal, "la_patchable must be applied to a literal address"); + + InstructionMark im(this); + code_section()->relocate(inst_mark(), dest.rspec()); + // RISC-V doesn't compute a page-aligned address, in order to partially + // compensate for the use of *signed* offsets in its base+disp12 + // addressing mode (RISC-V's PC-relative reach remains asymmetric + // [-(2G + 2K), 2G - 2k). + if (offset_high >= -((1L << 31) + (1L << 11)) && offset_low < (1L << 31) - (1L << 11)) { + int64_t distance = dest.target() - pc(); + auipc(reg1, (int32_t)distance + 0x800); + offset = ((int32_t)distance << 20) >> 20; + } else { + movptr_with_offset(reg1, dest.target(), offset); + } +} + +void MacroAssembler::build_frame(int framesize) { + assert(framesize >= 2, "framesize must include space for FP/RA"); + assert(framesize % (2*wordSize) == 0, "must preserve 2*wordSize alignment"); + sub(sp, sp, framesize); + sd(fp, Address(sp, framesize - 2 * wordSize)); + sd(ra, Address(sp, framesize - wordSize)); + if (PreserveFramePointer) { add(fp, sp, framesize); } + verify_cross_modify_fence_not_required(); +} + +void MacroAssembler::remove_frame(int framesize) { + assert(framesize >= 2, "framesize must include space for FP/RA"); + assert(framesize % (2*wordSize) == 0, "must preserve 2*wordSize alignment"); + ld(fp, Address(sp, framesize - 2 * wordSize)); + ld(ra, Address(sp, framesize - wordSize)); + add(sp, sp, framesize); +} + +void MacroAssembler::reserved_stack_check() { + // testing if reserved zone needs to be enabled + Label no_reserved_zone_enabling; + + ld(t0, Address(xthread, JavaThread::reserved_stack_activation_offset())); + bltu(sp, t0, no_reserved_zone_enabling); + + enter(); // RA and FP are live. + mv(c_rarg0, xthread); + int32_t offset = 0; + la_patchable(t0, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone)), offset); + jalr(x1, t0, offset); + leave(); + + // We have already removed our own frame. + // throw_delayed_StackOverflowError will think that it's been + // called by our caller. + offset = 0; + la_patchable(t0, RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry()), offset); + jalr(x0, t0, offset); + should_not_reach_here(); + + bind(no_reserved_zone_enabling); +} + +// Move the address of the polling page into dest. +void MacroAssembler::get_polling_page(Register dest, relocInfo::relocType rtype) { + ld(dest, Address(xthread, JavaThread::polling_page_offset())); +} + +// Read the polling page. The address of the polling page must +// already be in r. +address MacroAssembler::read_polling_page(Register r, int32_t offset, relocInfo::relocType rtype) { + address mark; + { + InstructionMark im(this); + code_section()->relocate(inst_mark(), rtype); + lwu(zr, Address(r, offset)); + mark = inst_mark(); + } + verify_cross_modify_fence_not_required(); + return mark; +} + +void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { +#ifdef ASSERT + { + ThreadInVMfromUnknown tiv; + assert (UseCompressedOops, "should only be used for compressed oops"); + assert (Universe::heap() != NULL, "java heap should be initialized"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + assert(Universe::heap()->is_in(JNIHandles::resolve(obj)), "should be real oop"); + } +#endif + int oop_index = oop_recorder()->find_index(obj); + InstructionMark im(this); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + code_section()->relocate(inst_mark(), rspec); + li32(dst, 0xDEADBEEF); + zero_extend(dst, dst, 32); +} + +void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { + assert (UseCompressedClassPointers, "should only be used for compressed headers"); + assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); + int index = oop_recorder()->find_index(k); + assert(!Universe::heap()->is_in(k), "should not be an oop"); + + InstructionMark im(this); + RelocationHolder rspec = metadata_Relocation::spec(index); + code_section()->relocate(inst_mark(), rspec); + narrowKlass nk = CompressedKlassPointers::encode(k); + li32(dst, nk); + zero_extend(dst, dst, 32); +} + +// Maybe emit a call via a trampoline. If the code cache is small +// trampolines won't be emitted. +address MacroAssembler::trampoline_call(Address entry, CodeBuffer* cbuf) { + assert(JavaThread::current()->is_Compiler_thread(), "just checking"); + assert(entry.rspec().type() == relocInfo::runtime_call_type || + entry.rspec().type() == relocInfo::opt_virtual_call_type || + entry.rspec().type() == relocInfo::static_call_type || + entry.rspec().type() == relocInfo::virtual_call_type, "wrong reloc type"); + + // We need a trampoline if branches are far. + if (far_branches()) { + bool in_scratch_emit_size = false; +#ifdef COMPILER2 + // We don't want to emit a trampoline if C2 is generating dummy + // code during its branch shortening phase. + CompileTask* task = ciEnv::current()->task(); + in_scratch_emit_size = + (task != NULL && is_c2_compile(task->comp_level()) && + Compile::current()->output()->in_scratch_emit_size()); +#endif + if (!in_scratch_emit_size) { + address stub = emit_trampoline_stub(offset(), entry.target()); + if (stub == NULL) { + postcond(pc() == badAddress); + return NULL; // CodeCache is full + } + } + } + + if (cbuf != NULL) { cbuf->set_insts_mark(); } + relocate(entry.rspec()); + if (!far_branches()) { + jal(entry.target()); + } else { + jal(pc()); + } + // just need to return a non-null address + postcond(pc() != badAddress); + return pc(); +} + +address MacroAssembler::ic_call(address entry, jint method_index) { + RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index); + movptr(t1, (address)Universe::non_oop_word()); + assert_cond(entry != NULL); + return trampoline_call(Address(entry, rh)); +} + +// Emit a trampoline stub for a call to a target which is too far away. +// +// code sequences: +// +// call-site: +// branch-and-link to or +// +// Related trampoline stub for this call site in the stub section: +// load the call target from the constant pool +// branch (RA still points to the call site above) + +address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, + address dest) { + address stub = start_a_stub(NativeInstruction::instruction_size + + NativeCallTrampolineStub::instruction_size); + if (stub == NULL) { + return NULL; // CodeBuffer::expand failed + } + + // Create a trampoline stub relocation which relates this trampoline stub + // with the call instruction at insts_call_instruction_offset in the + // instructions code-section. + + // make sure 4 byte aligned here, so that the destination address would be + // 8 byte aligned after 3 intructions + // when we reach here we may get a 2-byte alignment so need to align it + align(wordSize, NativeCallTrampolineStub::data_offset); + + relocate(trampoline_stub_Relocation::spec(code()->insts()->start() + + insts_call_instruction_offset)); + const int stub_start_offset = offset(); + + // Now, create the trampoline stub's code: + // - load the call + // - call + Label target; + ld(t0, target); // auipc + ld + jr(t0); // jalr + bind(target); + assert(offset() - stub_start_offset == NativeCallTrampolineStub::data_offset, + "should be"); + assert(offset() % wordSize == 0, "bad alignment"); + emit_int64((intptr_t)dest); + + const address stub_start_addr = addr_at(stub_start_offset); + + assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline"); + + end_a_stub(); + return stub_start_addr; +} + +Address MacroAssembler::add_memory_helper(const Address dst) { + switch (dst.getMode()) { + case Address::base_plus_offset: + // This is the expected mode, although we allow all the other + // forms below. + return form_address(t1, dst.base(), dst.offset()); + default: + la(t1, dst); + return Address(t1); + } +} + +void MacroAssembler::add_memory_int64(const Address dst, int64_t imm) { + Address adr = add_memory_helper(dst); + assert_different_registers(adr.base(), t0); + ld(t0, adr); + addi(t0, t0, imm); + sd(t0, adr); +} + +void MacroAssembler::add_memory_int32(const Address dst, int32_t imm) { + Address adr = add_memory_helper(dst); + assert_different_registers(adr.base(), t0); + lwu(t0, adr); + addiw(t0, t0, imm); + sw(t0, adr); +} + +void MacroAssembler::cmpptr(Register src1, Address src2, Label& equal) { + assert_different_registers(src1, t0); + int32_t offset; + la_patchable(t0, src2, offset); + ld(t0, Address(t0, offset)); + beq(src1, t0, equal); +} + +void MacroAssembler::load_method_holder_cld(Register result, Register method) { + load_method_holder(result, method); + ld(result, Address(result, InstanceKlass::class_loader_data_offset())); +} + +void MacroAssembler::load_method_holder(Register holder, Register method) { + ld(holder, Address(method, Method::const_offset())); // ConstMethod* + ld(holder, Address(holder, ConstMethod::constants_offset())); // ConstantPool* + ld(holder, Address(holder, ConstantPool::pool_holder_offset_in_bytes())); // InstanceKlass* +} + +// string indexof +// compute index by trailing zeros +void MacroAssembler::compute_index(Register haystack, Register trailing_zeros, + Register match_mask, Register result, + Register ch2, Register tmp, + bool haystack_isL) +{ + int haystack_chr_shift = haystack_isL ? 0 : 1; + srl(match_mask, match_mask, trailing_zeros); + srli(match_mask, match_mask, 1); + srli(tmp, trailing_zeros, LogBitsPerByte); + if (!haystack_isL) andi(tmp, tmp, 0xE); + add(haystack, haystack, tmp); + ld(ch2, Address(haystack)); + if (!haystack_isL) srli(tmp, tmp, haystack_chr_shift); + add(result, result, tmp); +} + +// string indexof +// Find pattern element in src, compute match mask, +// only the first occurrence of 0x80/0x8000 at low bits is the valid match index +// match mask patterns and corresponding indices would be like: +// - 0x8080808080808080 (Latin1) +// - 7 6 5 4 3 2 1 0 (match index) +// - 0x8000800080008000 (UTF16) +// - 3 2 1 0 (match index) +void MacroAssembler::compute_match_mask(Register src, Register pattern, Register match_mask, + Register mask1, Register mask2) +{ + xorr(src, pattern, src); + sub(match_mask, src, mask1); + orr(src, src, mask2); + notr(src, src); + andr(match_mask, match_mask, src); +} + +#ifdef COMPILER2 +// Code for BigInteger::mulAdd instrinsic +// out = x10 +// in = x11 +// offset = x12 (already out.length-offset) +// len = x13 +// k = x14 +// tmp = x28 +// +// pseudo code from java implementation: +// long kLong = k & LONG_MASK; +// carry = 0; +// offset = out.length-offset - 1; +// for (int j = len - 1; j >= 0; j--) { +// product = (in[j] & LONG_MASK) * kLong + (out[offset] & LONG_MASK) + carry; +// out[offset--] = (int)product; +// carry = product >>> 32; +// } +// return (int)carry; +void MacroAssembler::mul_add(Register out, Register in, Register offset, + Register len, Register k, Register tmp) { + Label L_tail_loop, L_unroll, L_end; + mv(tmp, out); + mv(out, zr); + blez(len, L_end); + zero_extend(k, k, 32); + slliw(t0, offset, LogBytesPerInt); + add(offset, tmp, t0); + slliw(t0, len, LogBytesPerInt); + add(in, in, t0); + + const int unroll = 8; + li(tmp, unroll); + blt(len, tmp, L_tail_loop); + bind(L_unroll); + for (int i = 0; i < unroll; i++) { + sub(in, in, BytesPerInt); + lwu(t0, Address(in, 0)); + mul(t1, t0, k); + add(t0, t1, out); + sub(offset, offset, BytesPerInt); + lwu(t1, Address(offset, 0)); + add(t0, t0, t1); + sw(t0, Address(offset, 0)); + srli(out, t0, 32); + } + subw(len, len, tmp); + bge(len, tmp, L_unroll); + + bind(L_tail_loop); + blez(len, L_end); + sub(in, in, BytesPerInt); + lwu(t0, Address(in, 0)); + mul(t1, t0, k); + add(t0, t1, out); + sub(offset, offset, BytesPerInt); + lwu(t1, Address(offset, 0)); + add(t0, t0, t1); + sw(t0, Address(offset, 0)); + srli(out, t0, 32); + subw(len, len, 1); + j(L_tail_loop); + + bind(L_end); +} + +// add two unsigned input and output carry +void MacroAssembler::cad(Register dst, Register src1, Register src2, Register carry) +{ + assert_different_registers(dst, carry); + assert_different_registers(dst, src2); + add(dst, src1, src2); + sltu(carry, dst, src2); +} + +// add two input with carry +void MacroAssembler::adc(Register dst, Register src1, Register src2, Register carry) +{ + assert_different_registers(dst, carry); + add(dst, src1, src2); + add(dst, dst, carry); +} + +// add two unsigned input with carry and output carry +void MacroAssembler::cadc(Register dst, Register src1, Register src2, Register carry) +{ + assert_different_registers(dst, src2); + adc(dst, src1, src2, carry); + sltu(carry, dst, src2); +} + +void MacroAssembler::add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo, + Register src1, Register src2, Register carry) +{ + cad(dest_lo, dest_lo, src1, carry); + add(dest_hi, dest_hi, carry); + cad(dest_lo, dest_lo, src2, carry); + add(final_dest_hi, dest_hi, carry); +} + +/** + * Multiply 32 bit by 32 bit first loop. + */ +void MacroAssembler::multiply_32_x_32_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx) +{ + // jlong carry, x[], y[], z[]; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx--, kdx--) { + // long product = y[idx] * x[xstart] + carry; + // z[kdx] = (int)product; + // carry = product >>> 32; + // } + // z[xstart] = (int)carry; + + Label L_first_loop, L_first_loop_exit; + blez(idx, L_first_loop_exit); + + shadd(t0, xstart, x, t0, LogBytesPerInt); + lwu(x_xstart, Address(t0, 0)); + + bind(L_first_loop); + subw(idx, idx, 1); + shadd(t0, idx, y, t0, LogBytesPerInt); + lwu(y_idx, Address(t0, 0)); + mul(product, x_xstart, y_idx); + add(product, product, carry); + srli(carry, product, 32); + subw(kdx, kdx, 1); + shadd(t0, kdx, z, t0, LogBytesPerInt); + sw(product, Address(t0, 0)); + bgtz(idx, L_first_loop); + + bind(L_first_loop_exit); +} + +/** + * Multiply 64 bit by 64 bit first loop. + */ +void MacroAssembler::multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx) +{ + // + // jlong carry, x[], y[], z[]; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx--, kdx--) { + // huge_128 product = y[idx] * x[xstart] + carry; + // z[kdx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // z[xstart] = carry; + // + + Label L_first_loop, L_first_loop_exit; + Label L_one_x, L_one_y, L_multiply; + + subw(xstart, xstart, 1); + bltz(xstart, L_one_x); + + shadd(t0, xstart, x, t0, LogBytesPerInt); + ld(x_xstart, Address(t0, 0)); + ror_imm(x_xstart, x_xstart, 32); // convert big-endian to little-endian + + bind(L_first_loop); + subw(idx, idx, 1); + bltz(idx, L_first_loop_exit); + subw(idx, idx, 1); + bltz(idx, L_one_y); + + shadd(t0, idx, y, t0, LogBytesPerInt); + ld(y_idx, Address(t0, 0)); + ror_imm(y_idx, y_idx, 32); // convert big-endian to little-endian + bind(L_multiply); + + mulhu(t0, x_xstart, y_idx); + mul(product, x_xstart, y_idx); + cad(product, product, carry, t1); + adc(carry, t0, zr, t1); + + subw(kdx, kdx, 2); + ror_imm(product, product, 32); // back to big-endian + shadd(t0, kdx, z, t0, LogBytesPerInt); + sd(product, Address(t0, 0)); + + j(L_first_loop); + + bind(L_one_y); + lwu(y_idx, Address(y, 0)); + j(L_multiply); + + bind(L_one_x); + lwu(x_xstart, Address(x, 0)); + j(L_first_loop); + + bind(L_first_loop_exit); +} + +/** + * Multiply 128 bit by 128 bit. Unrolled inner loop. + * + */ +void MacroAssembler::multiply_128_x_128_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4, + Register tmp6, Register product_hi) +{ + // jlong carry, x[], y[], z[]; + // int kdx = xstart+1; + // for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop + // huge_128 tmp3 = (y[idx+1] * product_hi) + z[kdx+idx+1] + carry; + // jlong carry2 = (jlong)(tmp3 >>> 64); + // huge_128 tmp4 = (y[idx] * product_hi) + z[kdx+idx] + carry2; + // carry = (jlong)(tmp4 >>> 64); + // z[kdx+idx+1] = (jlong)tmp3; + // z[kdx+idx] = (jlong)tmp4; + // } + // idx += 2; + // if (idx > 0) { + // yz_idx1 = (y[idx] * product_hi) + z[kdx+idx] + carry; + // z[kdx+idx] = (jlong)yz_idx1; + // carry = (jlong)(yz_idx1 >>> 64); + // } + // + + Label L_third_loop, L_third_loop_exit, L_post_third_loop_done; + + srliw(jdx, idx, 2); + + bind(L_third_loop); + + subw(jdx, jdx, 1); + bltz(jdx, L_third_loop_exit); + subw(idx, idx, 4); + + shadd(t0, idx, y, t0, LogBytesPerInt); + ld(yz_idx2, Address(t0, 0)); + ld(yz_idx1, Address(t0, wordSize)); + + shadd(tmp6, idx, z, t0, LogBytesPerInt); + + ror_imm(yz_idx1, yz_idx1, 32); // convert big-endian to little-endian + ror_imm(yz_idx2, yz_idx2, 32); + + ld(t1, Address(tmp6, 0)); + ld(t0, Address(tmp6, wordSize)); + + mul(tmp3, product_hi, yz_idx1); // yz_idx1 * product_hi -> tmp4:tmp3 + mulhu(tmp4, product_hi, yz_idx1); + + ror_imm(t0, t0, 32, tmp); // convert big-endian to little-endian + ror_imm(t1, t1, 32, tmp); + + mul(tmp, product_hi, yz_idx2); // yz_idx2 * product_hi -> carry2:tmp + mulhu(carry2, product_hi, yz_idx2); + + cad(tmp3, tmp3, carry, carry); + adc(tmp4, tmp4, zr, carry); + cad(tmp3, tmp3, t0, t0); + cadc(tmp4, tmp4, tmp, t0); + adc(carry, carry2, zr, t0); + cad(tmp4, tmp4, t1, carry2); + adc(carry, carry, zr, carry2); + + ror_imm(tmp3, tmp3, 32); // convert little-endian to big-endian + ror_imm(tmp4, tmp4, 32); + sd(tmp4, Address(tmp6, 0)); + sd(tmp3, Address(tmp6, wordSize)); + + j(L_third_loop); + + bind(L_third_loop_exit); + + andi(idx, idx, 0x3); + beqz(idx, L_post_third_loop_done); + + Label L_check_1; + subw(idx, idx, 2); + bltz(idx, L_check_1); + + shadd(t0, idx, y, t0, LogBytesPerInt); + ld(yz_idx1, Address(t0, 0)); + ror_imm(yz_idx1, yz_idx1, 32); + + mul(tmp3, product_hi, yz_idx1); // yz_idx1 * product_hi -> tmp4:tmp3 + mulhu(tmp4, product_hi, yz_idx1); + + shadd(t0, idx, z, t0, LogBytesPerInt); + ld(yz_idx2, Address(t0, 0)); + ror_imm(yz_idx2, yz_idx2, 32, tmp); + + add2_with_carry(carry, tmp4, tmp3, carry, yz_idx2, tmp); + + ror_imm(tmp3, tmp3, 32, tmp); + sd(tmp3, Address(t0, 0)); + + bind(L_check_1); + + andi(idx, idx, 0x1); + subw(idx, idx, 1); + bltz(idx, L_post_third_loop_done); + shadd(t0, idx, y, t0, LogBytesPerInt); + lwu(tmp4, Address(t0, 0)); + mul(tmp3, tmp4, product_hi); // tmp4 * product_hi -> carry2:tmp3 + mulhu(carry2, tmp4, product_hi); + + shadd(t0, idx, z, t0, LogBytesPerInt); + lwu(tmp4, Address(t0, 0)); + + add2_with_carry(carry2, carry2, tmp3, tmp4, carry, t0); + + shadd(t0, idx, z, t0, LogBytesPerInt); + sw(tmp3, Address(t0, 0)); + + slli(t0, carry2, 32); + srli(carry, tmp3, 32); + orr(carry, carry, t0); + + bind(L_post_third_loop_done); +} + +/** + * Code for BigInteger::multiplyToLen() intrinsic. + * + * x10: x + * x11: xlen + * x12: y + * x13: ylen + * x14: z + * x15: zlen + * x16: tmp1 + * x17: tmp2 + * x7: tmp3 + * x28: tmp4 + * x29: tmp5 + * x30: tmp6 + * x31: tmp7 + */ +void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, + Register z, Register zlen, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, + Register tmp5, Register tmp6, Register product_hi) +{ + assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6); + + const Register idx = tmp1; + const Register kdx = tmp2; + const Register xstart = tmp3; + + const Register y_idx = tmp4; + const Register carry = tmp5; + const Register product = xlen; + const Register x_xstart = zlen; // reuse register + + mv(idx, ylen); // idx = ylen; + mv(kdx, zlen); // kdx = xlen+ylen; + mv(carry, zr); // carry = 0; + + Label L_multiply_64_x_64_loop, L_done; + + subw(xstart, xlen, 1); + bltz(xstart, L_done); + + const Register jdx = tmp1; + + if (AvoidUnalignedAccesses) { + // Check if x and y are both 8-byte aligned. + orr(t0, xlen, ylen); + andi(t0, t0, 0x1); + beqz(t0, L_multiply_64_x_64_loop); + + multiply_32_x_32_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx); + shadd(t0, xstart, z, t0, LogBytesPerInt); + sw(carry, Address(t0, 0)); + + Label L_second_loop_unaligned; + bind(L_second_loop_unaligned); + mv(carry, zr); + mv(jdx, ylen); + subw(xstart, xstart, 1); + bltz(xstart, L_done); + sub(sp, sp, 2 * wordSize); + sd(z, Address(sp, 0)); + sd(zr, Address(sp, wordSize)); + shadd(t0, xstart, z, t0, LogBytesPerInt); + addi(z, t0, 4); + shadd(t0, xstart, x, t0, LogBytesPerInt); + lwu(product, Address(t0, 0)); + Label L_third_loop, L_third_loop_exit; + + blez(jdx, L_third_loop_exit); + + bind(L_third_loop); + subw(jdx, jdx, 1); + shadd(t0, jdx, y, t0, LogBytesPerInt); + lwu(t0, Address(t0, 0)); + mul(t1, t0, product); + add(t0, t1, carry); + shadd(tmp6, jdx, z, t1, LogBytesPerInt); + lwu(t1, Address(tmp6, 0)); + add(t0, t0, t1); + sw(t0, Address(tmp6, 0)); + srli(carry, t0, 32); + bgtz(jdx, L_third_loop); + + bind(L_third_loop_exit); + ld(z, Address(sp, 0)); + addi(sp, sp, 2 * wordSize); + shadd(t0, xstart, z, t0, LogBytesPerInt); + sw(carry, Address(t0, 0)); + + j(L_second_loop_unaligned); + } + + bind(L_multiply_64_x_64_loop); + multiply_64_x_64_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx); + + Label L_second_loop_aligned; + beqz(kdx, L_second_loop_aligned); + + Label L_carry; + subw(kdx, kdx, 1); + beqz(kdx, L_carry); + + shadd(t0, kdx, z, t0, LogBytesPerInt); + sw(carry, Address(t0, 0)); + srli(carry, carry, 32); + subw(kdx, kdx, 1); + + bind(L_carry); + shadd(t0, kdx, z, t0, LogBytesPerInt); + sw(carry, Address(t0, 0)); + + // Second and third (nested) loops. + // + // for (int i = xstart-1; i >= 0; i--) { // Second loop + // carry = 0; + // for (int jdx=ystart, k=ystart+1+i; jdx >= 0; jdx--, k--) { // Third loop + // long product = (y[jdx] & LONG_MASK) * (x[i] & LONG_MASK) + + // (z[k] & LONG_MASK) + carry; + // z[k] = (int)product; + // carry = product >>> 32; + // } + // z[i] = (int)carry; + // } + // + // i = xlen, j = tmp1, k = tmp2, carry = tmp5, x[i] = product_hi + + bind(L_second_loop_aligned); + mv(carry, zr); // carry = 0; + mv(jdx, ylen); // j = ystart+1 + + subw(xstart, xstart, 1); // i = xstart-1; + bltz(xstart, L_done); + + sub(sp, sp, 4 * wordSize); + sd(z, Address(sp, 0)); + + Label L_last_x; + shadd(t0, xstart, z, t0, LogBytesPerInt); + addi(z, t0, 4); + subw(xstart, xstart, 1); // i = xstart-1; + bltz(xstart, L_last_x); + + shadd(t0, xstart, x, t0, LogBytesPerInt); + ld(product_hi, Address(t0, 0)); + ror_imm(product_hi, product_hi, 32); // convert big-endian to little-endian + + Label L_third_loop_prologue; + bind(L_third_loop_prologue); + + sd(ylen, Address(sp, wordSize)); + sd(x, Address(sp, 2 * wordSize)); + sd(xstart, Address(sp, 3 * wordSize)); + multiply_128_x_128_loop(y, z, carry, x, jdx, ylen, product, + tmp2, x_xstart, tmp3, tmp4, tmp6, product_hi); + ld(z, Address(sp, 0)); + ld(ylen, Address(sp, wordSize)); + ld(x, Address(sp, 2 * wordSize)); + ld(xlen, Address(sp, 3 * wordSize)); // copy old xstart -> xlen + addi(sp, sp, 4 * wordSize); + + addiw(tmp3, xlen, 1); + shadd(t0, tmp3, z, t0, LogBytesPerInt); + sw(carry, Address(t0, 0)); + + subw(tmp3, tmp3, 1); + bltz(tmp3, L_done); + + srli(carry, carry, 32); + shadd(t0, tmp3, z, t0, LogBytesPerInt); + sw(carry, Address(t0, 0)); + j(L_second_loop_aligned); + + // Next infrequent code is moved outside loops. + bind(L_last_x); + lwu(product_hi, Address(x, 0)); + j(L_third_loop_prologue); + + bind(L_done); +} +#endif + +// Count bits of trailing zero chars from lsb to msb until first non-zero element. +// For LL case, one byte for one element, so shift 8 bits once, and for other case, +// shift 16 bits once. +void MacroAssembler::ctzc_bit(Register Rd, Register Rs, bool isLL, Register tmp1, Register tmp2) +{ + if (UseRVB) { + assert_different_registers(Rd, Rs, tmp1); + int step = isLL ? 8 : 16; + ctz(Rd, Rs); + andi(tmp1, Rd, step - 1); + sub(Rd, Rd, tmp1); + return; + } + assert_different_registers(Rd, Rs, tmp1, tmp2); + Label Loop; + int step = isLL ? 8 : 16; + li(Rd, -step); + mv(tmp2, Rs); + + bind(Loop); + addi(Rd, Rd, step); + andi(tmp1, tmp2, ((1 << step) - 1)); + srli(tmp2, tmp2, step); + beqz(tmp1, Loop); +} + +// This instruction reads adjacent 4 bytes from the lower half of source register, +// inflate into a register, for example: +// Rs: A7A6A5A4A3A2A1A0 +// Rd: 00A300A200A100A0 +void MacroAssembler::inflate_lo32(Register Rd, Register Rs, Register tmp1, Register tmp2) +{ + assert_different_registers(Rd, Rs, tmp1, tmp2); + li(tmp1, 0xFF); + mv(Rd, zr); + for (int i = 0; i <= 3; i++) + { + andr(tmp2, Rs, tmp1); + if (i) { + slli(tmp2, tmp2, i * 8); + } + orr(Rd, Rd, tmp2); + if (i != 3) { + slli(tmp1, tmp1, 8); + } + } +} + +// This instruction reads adjacent 4 bytes from the upper half of source register, +// inflate into a register, for example: +// Rs: A7A6A5A4A3A2A1A0 +// Rd: 00A700A600A500A4 +void MacroAssembler::inflate_hi32(Register Rd, Register Rs, Register tmp1, Register tmp2) +{ + assert_different_registers(Rd, Rs, tmp1, tmp2); + li(tmp1, 0xFF00000000); + mv(Rd, zr); + for (int i = 0; i <= 3; i++) + { + andr(tmp2, Rs, tmp1); + orr(Rd, Rd, tmp2); + srli(Rd, Rd, 8); + if (i != 3) { + slli(tmp1, tmp1, 8); + } + } +} + +// The size of the blocks erased by the zero_blocks stub. We must +// handle anything smaller than this ourselves in zero_words(). +const int MacroAssembler::zero_words_block_size = 8; + +// zero_words() is used by C2 ClearArray patterns. It is as small as +// possible, handling small word counts locally and delegating +// anything larger to the zero_blocks stub. It is expanded many times +// in compiled code, so it is important to keep it short. + +// ptr: Address of a buffer to be zeroed. +// cnt: Count in HeapWords. +// +// ptr, cnt, and t0 are clobbered. +address MacroAssembler::zero_words(Register ptr, Register cnt) +{ + assert(is_power_of_2(zero_words_block_size), "adjust this"); + assert(ptr == x28 && cnt == x29, "mismatch in register usage"); + assert_different_registers(cnt, t0); + + BLOCK_COMMENT("zero_words {"); + mv(t0, zero_words_block_size); + Label around, done, done16; + bltu(cnt, t0, around); + { + RuntimeAddress zero_blocks = RuntimeAddress(StubRoutines::riscv::zero_blocks()); + assert(zero_blocks.target() != NULL, "zero_blocks stub has not been generated"); + if (StubRoutines::riscv::complete()) { + address tpc = trampoline_call(zero_blocks); + if (tpc == NULL) { + DEBUG_ONLY(reset_labels(around)); + postcond(pc() == badAddress); + return NULL; + } + } else { + jal(zero_blocks); + } + } + bind(around); + for (int i = zero_words_block_size >> 1; i > 1; i >>= 1) { + Label l; + andi(t0, cnt, i); + beqz(t0, l); + for (int j = 0; j < i; j++) { + sd(zr, Address(ptr, 0)); + addi(ptr, ptr, 8); + } + bind(l); + } + { + Label l; + andi(t0, cnt, 1); + beqz(t0, l); + sd(zr, Address(ptr, 0)); + bind(l); + } + BLOCK_COMMENT("} zero_words"); + postcond(pc() != badAddress); + return pc(); +} + +#define SmallArraySize (18 * BytesPerLong) + +// base: Address of a buffer to be zeroed, 8 bytes aligned. +// cnt: Immediate count in HeapWords. +void MacroAssembler::zero_words(Register base, u_int64_t cnt) +{ + assert_different_registers(base, t0, t1); + + BLOCK_COMMENT("zero_words {"); + + if (cnt <= SmallArraySize / BytesPerLong) { + for (int i = 0; i < (int)cnt; i++) { + sd(zr, Address(base, i * wordSize)); + } + } else { + const int unroll = 8; // Number of sd(zr, adr), instructions we'll unroll + int remainder = cnt % unroll; + for (int i = 0; i < remainder; i++) { + sd(zr, Address(base, i * wordSize)); + } + + Label loop; + Register cnt_reg = t0; + Register loop_base = t1; + cnt = cnt - remainder; + li(cnt_reg, cnt); + add(loop_base, base, remainder * wordSize); + bind(loop); + sub(cnt_reg, cnt_reg, unroll); + for (int i = 0; i < unroll; i++) { + sd(zr, Address(loop_base, i * wordSize)); + } + add(loop_base, loop_base, unroll * wordSize); + bnez(cnt_reg, loop); + } + + BLOCK_COMMENT("} zero_words"); +} + +// base: Address of a buffer to be filled, 8 bytes aligned. +// cnt: Count in 8-byte unit. +// value: Value to be filled with. +// base will point to the end of the buffer after filling. +void MacroAssembler::fill_words(Register base, Register cnt, Register value) +{ +// Algorithm: +// +// t0 = cnt & 7 +// cnt -= t0 +// p += t0 +// switch (t0): +// switch start: +// do while cnt +// cnt -= 8 +// p[-8] = value +// case 7: +// p[-7] = value +// case 6: +// p[-6] = value +// // ... +// case 1: +// p[-1] = value +// case 0: +// p += 8 +// do-while end +// switch end + + assert_different_registers(base, cnt, value, t0, t1); + + Label fini, skip, entry, loop; + const int unroll = 8; // Number of sd instructions we'll unroll + + beqz(cnt, fini); + + andi(t0, cnt, unroll - 1); + sub(cnt, cnt, t0); + // align 8, so first sd n % 8 = mod, next loop sd 8 * n. + shadd(base, t0, base, t1, 3); + la(t1, entry); + slli(t0, t0, 2); // sd_inst_nums * 4; t0 is cnt % 8, so t1 = t1 - sd_inst_nums * 4, 4 is sizeof(inst) + sub(t1, t1, t0); + jr(t1); + + bind(loop); + add(base, base, unroll * 8); + for (int i = -unroll; i < 0; i++) { + sd(value, Address(base, i * 8)); + } + bind(entry); + sub(cnt, cnt, unroll); + bgez(cnt, loop); + + bind(fini); +} + +#define FCVT_SAFE(FLOATCVT, FLOATEQ) \ +void MacroAssembler:: FLOATCVT##_safe(Register dst, FloatRegister src, Register tmp) { \ + Label L_Okay; \ + fscsr(zr); \ + FLOATCVT(dst, src); \ + frcsr(tmp); \ + andi(tmp, tmp, 0x1E); \ + beqz(tmp, L_Okay); \ + FLOATEQ(tmp, src, src); \ + bnez(tmp, L_Okay); \ + mv(dst, zr); \ + bind(L_Okay); \ +} + +FCVT_SAFE(fcvt_w_s, feq_s) +FCVT_SAFE(fcvt_l_s, feq_s) +FCVT_SAFE(fcvt_w_d, feq_d) +FCVT_SAFE(fcvt_l_d, feq_d) + +#undef FCVT_SAFE + +#define FCMP(FLOATTYPE, FLOATSIG) \ +void MacroAssembler::FLOATTYPE##_compare(Register result, FloatRegister Rs1, \ + FloatRegister Rs2, int unordered_result) { \ + Label Ldone; \ + if (unordered_result < 0) { \ + /* we want -1 for unordered or less than, 0 for equal and 1 for greater than. */ \ + /* installs 1 if gt else 0 */ \ + flt_##FLOATSIG(result, Rs2, Rs1); \ + /* Rs1 > Rs2, install 1 */ \ + bgtz(result, Ldone); \ + feq_##FLOATSIG(result, Rs1, Rs2); \ + addi(result, result, -1); \ + /* Rs1 = Rs2, install 0 */ \ + /* NaN or Rs1 < Rs2, install -1 */ \ + bind(Ldone); \ + } else { \ + /* we want -1 for less than, 0 for equal and 1 for unordered or greater than. */ \ + /* installs 1 if gt or unordered else 0 */ \ + flt_##FLOATSIG(result, Rs1, Rs2); \ + /* Rs1 < Rs2, install -1 */ \ + bgtz(result, Ldone); \ + feq_##FLOATSIG(result, Rs1, Rs2); \ + addi(result, result, -1); \ + /* Rs1 = Rs2, install 0 */ \ + /* NaN or Rs1 > Rs2, install 1 */ \ + bind(Ldone); \ + neg(result, result); \ + } \ +} + +FCMP(float, s); +FCMP(double, d); + +#undef FCMP + +// Zero words; len is in bytes +// Destroys all registers except addr +// len must be a nonzero multiple of wordSize +void MacroAssembler::zero_memory(Register addr, Register len, Register tmp) { + assert_different_registers(addr, len, tmp, t0, t1); + +#ifdef ASSERT + { + Label L; + andi(t0, len, BytesPerWord - 1); + beqz(t0, L); + stop("len is not a multiple of BytesPerWord"); + bind(L); + } +#endif // ASSERT + +#ifndef PRODUCT + block_comment("zero memory"); +#endif // PRODUCT + + Label loop; + Label entry; + + // Algorithm: + // + // t0 = cnt & 7 + // cnt -= t0 + // p += t0 + // switch (t0) { + // do { + // cnt -= 8 + // p[-8] = 0 + // case 7: + // p[-7] = 0 + // case 6: + // p[-6] = 0 + // ... + // case 1: + // p[-1] = 0 + // case 0: + // p += 8 + // } while (cnt) + // } + + const int unroll = 8; // Number of sd(zr) instructions we'll unroll + + srli(len, len, LogBytesPerWord); + andi(t0, len, unroll - 1); // t0 = cnt % unroll + sub(len, len, t0); // cnt -= unroll + // tmp always points to the end of the region we're about to zero + shadd(tmp, t0, addr, t1, LogBytesPerWord); + la(t1, entry); + slli(t0, t0, 2); + sub(t1, t1, t0); + jr(t1); + bind(loop); + sub(len, len, unroll); + for (int i = -unroll; i < 0; i++) { + Assembler::sd(zr, Address(tmp, i * wordSize)); + } + bind(entry); + add(tmp, tmp, unroll * wordSize); + bnez(len, loop); +} + +// shift left by shamt and add +// Rd = (Rs1 << shamt) + Rs2 +void MacroAssembler::shadd(Register Rd, Register Rs1, Register Rs2, Register tmp, int shamt) { + if (UseRVB) { + if (shamt == 1) { + sh1add(Rd, Rs1, Rs2); + return; + } else if (shamt == 2) { + sh2add(Rd, Rs1, Rs2); + return; + } else if (shamt == 3) { + sh3add(Rd, Rs1, Rs2); + return; + } + } + + if (shamt != 0) { + slli(tmp, Rs1, shamt); + add(Rd, Rs2, tmp); + } else { + add(Rd, Rs1, Rs2); + } +} + +void MacroAssembler::zero_extend(Register dst, Register src, int bits) { + if (UseRVB) { + if (bits == 16) { + zext_h(dst, src); + return; + } else if (bits == 32) { + zext_w(dst, src); + return; + } + } + + if (bits == 8) { + zext_b(dst, src); + } else { + slli(dst, src, XLEN - bits); + srli(dst, dst, XLEN - bits); + } +} + +void MacroAssembler::sign_extend(Register dst, Register src, int bits) { + if (UseRVB) { + if (bits == 8) { + sext_b(dst, src); + return; + } else if (bits == 16) { + sext_h(dst, src); + return; + } + } + + if (bits == 32) { + sext_w(dst, src); + } else { + slli(dst, src, XLEN - bits); + srai(dst, dst, XLEN - bits); + } +} + +void MacroAssembler::cmp_l2i(Register dst, Register src1, Register src2, Register tmp) +{ + if (src1 == src2) { + mv(dst, zr); + return; + } + Label done; + Register left = src1; + Register right = src2; + if (dst == src1) { + assert_different_registers(dst, src2, tmp); + mv(tmp, src1); + left = tmp; + } else if (dst == src2) { + assert_different_registers(dst, src1, tmp); + mv(tmp, src2); + right = tmp; + } + + // installs 1 if gt else 0 + slt(dst, right, left); + bnez(dst, done); + slt(dst, left, right); + // dst = -1 if lt; else if eq , dst = 0 + neg(dst, dst); + bind(done); +} + +void MacroAssembler::safepoint_ifence() { + ifence(); +#ifndef PRODUCT + if (VerifyCrossModifyFence) { + // Clear the thread state. + sb(zr, Address(xthread, in_bytes(JavaThread::requires_cross_modify_fence_offset()))); + } +#endif +} + +#ifndef PRODUCT +void MacroAssembler::verify_cross_modify_fence_not_required() { + if (VerifyCrossModifyFence) { + // Check if thread needs a cross modify fence. + lbu(t0, Address(xthread, in_bytes(JavaThread::requires_cross_modify_fence_offset()))); + Label fence_not_required; + beqz(t0, fence_not_required); + // If it does then fail. + la(t0, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::verify_cross_modify_fence_failure))); + mv(c_rarg0, xthread); + jalr(t0); + bind(fence_not_required); + } +} +#endif diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp new file mode 100644 index 00000000000..23e09475be1 --- /dev/null +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -0,0 +1,858 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_MACROASSEMBLER_RISCV_HPP +#define CPU_RISCV_MACROASSEMBLER_RISCV_HPP + +#include "asm/assembler.hpp" +#include "metaprogramming/enableIf.hpp" +#include "oops/compressedOops.hpp" +#include "utilities/powerOfTwo.hpp" + +// MacroAssembler extends Assembler by frequently used macros. +// +// Instructions for which a 'better' code sequence exists depending +// on arguments should also go in here. + +class MacroAssembler: public Assembler { + + public: + MacroAssembler(CodeBuffer* code) : Assembler(code) { + } + virtual ~MacroAssembler() {} + + void safepoint_poll(Label& slow_path, bool at_return, bool acquire, bool in_nmethod); + + // Place a fence.i after code may have been modified due to a safepoint. + void safepoint_ifence(); + + // Alignment + void align(int modulus, int extra_offset = 0); + + // Stack frame creation/removal + // Note that SP must be updated to the right place before saving/restoring RA and FP + // because signal based thread suspend/resume could happen asynchronously. + void enter() { + addi(sp, sp, - 2 * wordSize); + sd(ra, Address(sp, wordSize)); + sd(fp, Address(sp)); + addi(fp, sp, 2 * wordSize); + } + + void leave() { + addi(sp, fp, - 2 * wordSize); + ld(fp, Address(sp)); + ld(ra, Address(sp, wordSize)); + addi(sp, sp, 2 * wordSize); + } + + + // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information) + // The pointer will be loaded into the thread register. + void get_thread(Register thread); + + // Support for VM calls + // + // It is imperative that all calls into the VM are handled via the call_VM macros. + // They make sure that the stack linkage is setup correctly. call_VM's correspond + // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points. + + void call_VM(Register oop_result, + address entry_point, + bool check_exceptions = true); + void call_VM(Register oop_result, + address entry_point, + Register arg_1, + bool check_exceptions = true); + void call_VM(Register oop_result, + address entry_point, + Register arg_1, Register arg_2, + bool check_exceptions = true); + void call_VM(Register oop_result, + address entry_point, + Register arg_1, Register arg_2, Register arg_3, + bool check_exceptions = true); + + // Overloadings with last_Java_sp + void call_VM(Register oop_result, + Register last_java_sp, + address entry_point, + int number_of_arguments = 0, + bool check_exceptions = true); + void call_VM(Register oop_result, + Register last_java_sp, + address entry_point, + Register arg_1, + bool check_exceptions = true); + void call_VM(Register oop_result, + Register last_java_sp, + address entry_point, + Register arg_1, Register arg_2, + bool check_exceptions = true); + void call_VM(Register oop_result, + Register last_java_sp, + address entry_point, + Register arg_1, Register arg_2, Register arg_3, + bool check_exceptions = true); + + void get_vm_result(Register oop_result, Register java_thread); + void get_vm_result_2(Register metadata_result, Register java_thread); + + // These always tightly bind to MacroAssembler::call_VM_leaf_base + // bypassing the virtual implementation + void call_VM_leaf(address entry_point, + int number_of_arguments = 0); + void call_VM_leaf(address entry_point, + Register arg_0); + void call_VM_leaf(address entry_point, + Register arg_0, Register arg_1); + void call_VM_leaf(address entry_point, + Register arg_0, Register arg_1, Register arg_2); + + // These always tightly bind to MacroAssembler::call_VM_base + // bypassing the virtual implementation + void super_call_VM_leaf(address entry_point, Register arg_0); + void super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1); + void super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2); + void super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3); + + // last Java Frame (fills frame anchor) + void set_last_Java_frame(Register last_java_sp, Register last_java_fp, address last_java_pc, Register tmp); + void set_last_Java_frame(Register last_java_sp, Register last_java_fp, Label &last_java_pc, Register tmp); + void set_last_Java_frame(Register last_java_sp, Register last_java_fp, Register last_java_pc, Register tmp); + + // thread in the default location (xthread) + void reset_last_Java_frame(bool clear_fp); + + void call_native(address entry_point, + Register arg_0); + void call_native_base( + address entry_point, // the entry point + Label* retaddr = NULL + ); + + virtual void call_VM_leaf_base( + address entry_point, // the entry point + int number_of_arguments, // the number of arguments to pop after the call + Label* retaddr = NULL + ); + + virtual void call_VM_leaf_base( + address entry_point, // the entry point + int number_of_arguments, // the number of arguments to pop after the call + Label& retaddr) { + call_VM_leaf_base(entry_point, number_of_arguments, &retaddr); + } + + virtual void call_VM_base( // returns the register containing the thread upon return + Register oop_result, // where an oop-result ends up if any; use noreg otherwise + Register java_thread, // the thread if computed before ; use noreg otherwise + Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise + address entry_point, // the entry point + int number_of_arguments, // the number of arguments (w/o thread) to pop after the call + bool check_exceptions // whether to check for pending exceptions after return + ); + + void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions); + + virtual void check_and_handle_earlyret(Register java_thread); + virtual void check_and_handle_popframe(Register java_thread); + + void resolve_weak_handle(Register result, Register tmp); + void resolve_oop_handle(Register result, Register tmp = x15); + void resolve_jobject(Register value, Register thread, Register tmp); + + void movoop(Register dst, jobject obj, bool immediate = false); + void mov_metadata(Register dst, Metadata* obj); + void bang_stack_size(Register size, Register tmp); + void set_narrow_oop(Register dst, jobject obj); + void set_narrow_klass(Register dst, Klass* k); + + void load_mirror(Register dst, Register method, Register tmp = x15); + void access_load_at(BasicType type, DecoratorSet decorators, Register dst, + Address src, Register tmp1, Register thread_tmp); + void access_store_at(BasicType type, DecoratorSet decorators, Address dst, + Register src, Register tmp1, Register thread_tmp); + void load_klass(Register dst, Register src); + void store_klass(Register dst, Register src); + void cmp_klass(Register oop, Register trial_klass, Register tmp, Label &L); + + void encode_klass_not_null(Register r); + void decode_klass_not_null(Register r); + void encode_klass_not_null(Register dst, Register src, Register tmp = xheapbase); + void decode_klass_not_null(Register dst, Register src, Register tmp = xheapbase); + void decode_heap_oop_not_null(Register r); + void decode_heap_oop_not_null(Register dst, Register src); + void decode_heap_oop(Register d, Register s); + void decode_heap_oop(Register r) { decode_heap_oop(r, r); } + void encode_heap_oop(Register d, Register s); + void encode_heap_oop(Register r) { encode_heap_oop(r, r); }; + void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, + Register thread_tmp = noreg, DecoratorSet decorators = 0); + void load_heap_oop_not_null(Register dst, Address src, Register tmp1 = noreg, + Register thread_tmp = noreg, DecoratorSet decorators = 0); + void store_heap_oop(Address dst, Register src, Register tmp1 = noreg, + Register thread_tmp = noreg, DecoratorSet decorators = 0); + + void store_klass_gap(Register dst, Register src); + + // currently unimplemented + // Used for storing NULL. All other oop constants should be + // stored using routines that take a jobject. + void store_heap_oop_null(Address dst); + + // This dummy is to prevent a call to store_heap_oop from + // converting a zero (linke NULL) into a Register by giving + // the compiler two choices it can't resolve + + void store_heap_oop(Address dst, void* dummy); + + // Support for NULL-checks + // + // Generates code that causes a NULL OS exception if the content of reg is NULL. + // If the accessed location is M[reg + offset] and the offset is known, provide the + // offset. No explicit code generateion is needed if the offset is within a certain + // range (0 <= offset <= page_size). + + virtual void null_check(Register reg, int offset = -1); + static bool needs_explicit_null_check(intptr_t offset); + static bool uses_implicit_null_check(void* address); + + // idiv variant which deals with MINLONG as dividend and -1 as divisor + int corrected_idivl(Register result, Register rs1, Register rs2, + bool want_remainder); + int corrected_idivq(Register result, Register rs1, Register rs2, + bool want_remainder); + + // interface method calling + void lookup_interface_method(Register recv_klass, + Register intf_klass, + RegisterOrConstant itable_index, + Register method_result, + Register scan_tmp, + Label& no_such_interface, + bool return_method = true); + + // virtual method calling + // n.n. x86 allows RegisterOrConstant for vtable_index + void lookup_virtual_method(Register recv_klass, + RegisterOrConstant vtable_index, + Register method_result); + + // Form an addres from base + offset in Rd. Rd my or may not + // actually be used: you must use the Address that is returned. It + // is up to you to ensure that the shift provided mathces the size + // of your data. + Address form_address(Register Rd, Register base, long byte_offset); + + // allocation + void tlab_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register tmp1, // temp register + Register tmp2, // temp register + Label& slow_case, // continuation point of fast allocation fails + bool is_far = false + ); + + void eden_allocate( + Register obj, // result: pointer to object after successful allocation + Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise + int con_size_in_bytes, // object size in bytes if known at compile time + Register tmp, // temp register + Label& slow_case, // continuation point if fast allocation fails + bool is_far = false + ); + + // Test sub_klass against super_klass, with fast and slow paths. + + // The fast path produces a tri-state answer: yes / no / maybe-slow. + // One of the three labels can be NULL, meaning take the fall-through. + // If super_check_offset is -1, the value is loaded up from super_klass. + // No registers are killed, except tmp_reg + void check_klass_subtype_fast_path(Register sub_klass, + Register super_klass, + Register tmp_reg, + Label* L_success, + Label* L_failure, + Label* L_slow_path, + Register super_check_offset = noreg); + + // The reset of the type cehck; must be wired to a corresponding fast path. + // It does not repeat the fast path logic, so don't use it standalone. + // The tmp1_reg and tmp2_reg can be noreg, if no temps are avaliable. + // Updates the sub's secondary super cache as necessary. + void check_klass_subtype_slow_path(Register sub_klass, + Register super_klass, + Register tmp1_reg, + Register tmp2_reg, + Label* L_success, + Label* L_failure); + + void check_klass_subtype(Register sub_klass, + Register super_klass, + Register tmp_reg, + Label& L_success); + + Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0); + + // only if +VerifyOops + void verify_oop(Register reg, const char* s = "broken oop"); + void verify_oop_addr(Address addr, const char* s = "broken oop addr"); + + void _verify_method_ptr(Register reg, const char* msg, const char* file, int line) {} + void _verify_klass_ptr(Register reg, const char* msg, const char* file, int line) {} + +#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__) +#define verify_klass_ptr(reg) _verify_method_ptr(reg, "broken klass " #reg, __FILE__, __LINE__) + + // A more convenient access to fence for our purposes + // We used four bit to indicate the read and write bits in the predecessors and successors, + // and extended i for r, o for w if UseConservativeFence enabled. + enum Membar_mask_bits { + StoreStore = 0b0101, // (pred = ow + succ = ow) + LoadStore = 0b1001, // (pred = ir + succ = ow) + StoreLoad = 0b0110, // (pred = ow + succ = ir) + LoadLoad = 0b1010, // (pred = ir + succ = ir) + AnyAny = LoadStore | StoreLoad // (pred = iorw + succ = iorw) + }; + + void membar(uint32_t order_constraint); + + static void membar_mask_to_pred_succ(uint32_t order_constraint, uint32_t& predecessor, uint32_t& successor) { + predecessor = (order_constraint >> 2) & 0x3; + successor = order_constraint & 0x3; + + // extend rw -> iorw: + // 01(w) -> 0101(ow) + // 10(r) -> 1010(ir) + // 11(rw)-> 1111(iorw) + if (UseConservativeFence) { + predecessor |= predecessor << 2; + successor |= successor << 2; + } + } + + static int pred_succ_to_membar_mask(uint32_t predecessor, uint32_t successor) { + return ((predecessor & 0x3) << 2) | (successor & 0x3); + } + + // prints msg, dumps registers and stops execution + void stop(const char* msg); + + static void debug64(char* msg, int64_t pc, int64_t regs[]); + + void unimplemented(const char* what = ""); + + void should_not_reach_here() { stop("should not reach here"); } + + static address target_addr_for_insn(address insn_addr); + + // Required platform-specific helpers for Label::patch_instructions. + // They _shadow_ the declarations in AbstractAssembler, which are undefined. + static int pd_patch_instruction_size(address branch, address target); + static void pd_patch_instruction(address branch, address target, const char* file = NULL, int line = 0) { + pd_patch_instruction_size(branch, target); + } + static address pd_call_destination(address branch) { + return target_addr_for_insn(branch); + } + + static int patch_oop(address insn_addr, address o); + address emit_trampoline_stub(int insts_call_instruction_offset, address target); + void emit_static_call_stub(); + + // The following 4 methods return the offset of the appropriate move instruction + + // Support for fast byte/short loading with zero extension (depending on particular CPU) + int load_unsigned_byte(Register dst, Address src); + int load_unsigned_short(Register dst, Address src); + + // Support for fast byte/short loading with sign extension (depending on particular CPU) + int load_signed_byte(Register dst, Address src); + int load_signed_short(Register dst, Address src); + + // Load and store values by size and signed-ness + void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2 = noreg); + void store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2 = noreg); + + public: + // Standard pseudoinstruction + void nop(); + void mv(Register Rd, Register Rs); + void notr(Register Rd, Register Rs); + void neg(Register Rd, Register Rs); + void negw(Register Rd, Register Rs); + void sext_w(Register Rd, Register Rs); + void zext_b(Register Rd, Register Rs); + void seqz(Register Rd, Register Rs); // set if = zero + void snez(Register Rd, Register Rs); // set if != zero + void sltz(Register Rd, Register Rs); // set if < zero + void sgtz(Register Rd, Register Rs); // set if > zero + + // Float pseudoinstruction + void fmv_s(FloatRegister Rd, FloatRegister Rs); + void fabs_s(FloatRegister Rd, FloatRegister Rs); // single-precision absolute value + void fneg_s(FloatRegister Rd, FloatRegister Rs); + + // Double pseudoinstruction + void fmv_d(FloatRegister Rd, FloatRegister Rs); + void fabs_d(FloatRegister Rd, FloatRegister Rs); + void fneg_d(FloatRegister Rd, FloatRegister Rs); + + // Pseudoinstruction for control and status register + void rdinstret(Register Rd); // read instruction-retired counter + void rdcycle(Register Rd); // read cycle counter + void rdtime(Register Rd); // read time + void csrr(Register Rd, unsigned csr); // read csr + void csrw(unsigned csr, Register Rs); // write csr + void csrs(unsigned csr, Register Rs); // set bits in csr + void csrc(unsigned csr, Register Rs); // clear bits in csr + void csrwi(unsigned csr, unsigned imm); + void csrsi(unsigned csr, unsigned imm); + void csrci(unsigned csr, unsigned imm); + void frcsr(Register Rd); // read float-point csr + void fscsr(Register Rd, Register Rs); // swap float-point csr + void fscsr(Register Rs); // write float-point csr + void frrm(Register Rd); // read float-point rounding mode + void fsrm(Register Rd, Register Rs); // swap float-point rounding mode + void fsrm(Register Rs); // write float-point rounding mode + void fsrmi(Register Rd, unsigned imm); + void fsrmi(unsigned imm); + void frflags(Register Rd); // read float-point exception flags + void fsflags(Register Rd, Register Rs); // swap float-point exception flags + void fsflags(Register Rs); // write float-point exception flags + void fsflagsi(Register Rd, unsigned imm); + void fsflagsi(unsigned imm); + + void beqz(Register Rs, const address &dest); + void bnez(Register Rs, const address &dest); + void blez(Register Rs, const address &dest); + void bgez(Register Rs, const address &dest); + void bltz(Register Rs, const address &dest); + void bgtz(Register Rs, const address &dest); + void la(Register Rd, Label &label); + void la(Register Rd, const address &dest); + void la(Register Rd, const Address &adr); + //label + void beqz(Register Rs, Label &l, bool is_far = false); + void bnez(Register Rs, Label &l, bool is_far = false); + void blez(Register Rs, Label &l, bool is_far = false); + void bgez(Register Rs, Label &l, bool is_far = false); + void bltz(Register Rs, Label &l, bool is_far = false); + void bgtz(Register Rs, Label &l, bool is_far = false); + void float_beq(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void float_bne(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void float_ble(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void float_bge(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void float_blt(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void float_bgt(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void double_beq(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void double_bne(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void double_ble(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void double_bge(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void double_blt(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + void double_bgt(FloatRegister Rs1, FloatRegister Rs2, Label &l, bool is_far = false, bool is_unordered = false); + + void push_reg(RegSet regs, Register stack) { if (regs.bits()) { push_reg(regs.bits(), stack); } } + void pop_reg(RegSet regs, Register stack) { if (regs.bits()) { pop_reg(regs.bits(), stack); } } + void push_reg(Register Rs); + void pop_reg(Register Rd); + int push_reg(unsigned int bitset, Register stack); + int pop_reg(unsigned int bitset, Register stack); + void push_fp(FloatRegSet regs, Register stack) { if (regs.bits()) push_fp(regs.bits(), stack); } + void pop_fp(FloatRegSet regs, Register stack) { if (regs.bits()) pop_fp(regs.bits(), stack); } +#ifdef COMPILER2 + void push_vp(VectorRegSet regs, Register stack) { if (regs.bits()) push_vp(regs.bits(), stack); } + void pop_vp(VectorRegSet regs, Register stack) { if (regs.bits()) pop_vp(regs.bits(), stack); } +#endif // COMPILER2 + + // Push and pop everything that might be clobbered by a native + // runtime call except t0 and t1. (They are always + // temporary registers, so we don't have to protect them.) + // Additional registers can be excluded in a passed RegSet. + void push_call_clobbered_registers_except(RegSet exclude); + void pop_call_clobbered_registers_except(RegSet exclude); + + void push_call_clobbered_registers() { + push_call_clobbered_registers_except(RegSet()); + } + void pop_call_clobbered_registers() { + pop_call_clobbered_registers_except(RegSet()); + } + + void pusha(); + void popa(); + void push_CPU_state(bool save_vectors = false, int vector_size_in_bytes = 0); + void pop_CPU_state(bool restore_vectors = false, int vector_size_in_bytes = 0); + + // if heap base register is used - reinit it with the correct value + void reinit_heapbase(); + + void bind(Label& L) { + Assembler::bind(L); + // fences across basic blocks should not be merged + code()->clear_last_insn(); + } + + // mv + template::value)> + inline void mv(Register Rd, T o) { + li(Rd, (int64_t)o); + } + + inline void mvw(Register Rd, int32_t imm32) { mv(Rd, imm32); } + + void mv(Register Rd, Address dest); + void mv(Register Rd, address addr); + void mv(Register Rd, RegisterOrConstant src); + + // logic + void andrw(Register Rd, Register Rs1, Register Rs2); + void orrw(Register Rd, Register Rs1, Register Rs2); + void xorrw(Register Rd, Register Rs1, Register Rs2); + + // revb + void revb_h_h(Register Rd, Register Rs, Register tmp = t0); // reverse bytes in halfword in lower 16 bits, sign-extend + void revb_w_w(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); // reverse bytes in lower word, sign-extend + void revb_h_h_u(Register Rd, Register Rs, Register tmp = t0); // reverse bytes in halfword in lower 16 bits, zero-extend + void revb_h_w_u(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); // reverse bytes in halfwords in lower 32 bits, zero-extend + void revb_h_helper(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2= t1); // reverse bytes in upper 16 bits (48:63) and move to lower + void revb_h(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2= t1); // reverse bytes in each halfword + void revb_w(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2= t1); // reverse bytes in each word + void revb(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); // reverse bytes in doubleword + + void ror_imm(Register dst, Register src, uint32_t shift, Register tmp = t0); + void andi(Register Rd, Register Rn, int64_t imm, Register tmp = t0); + void orptr(Address adr, RegisterOrConstant src, Register tmp1 = t0, Register tmp2 = t1); + + void cmpxchg_obj_header(Register oldv, Register newv, Register obj, Register tmp, Label &succeed, Label *fail); + void cmpxchgptr(Register oldv, Register newv, Register addr, Register tmp, Label &succeed, Label *fail); + void cmpxchg(Register addr, Register expected, + Register new_val, + enum operand_size size, + Assembler::Aqrl acquire, Assembler::Aqrl release, + Register result, bool result_as_bool = false); + void cmpxchg_weak(Register addr, Register expected, + Register new_val, + enum operand_size size, + Assembler::Aqrl acquire, Assembler::Aqrl release, + Register result); + void cmpxchg_narrow_value_helper(Register addr, Register expected, + Register new_val, + enum operand_size size, + Register tmp1, Register tmp2, Register tmp3); + void cmpxchg_narrow_value(Register addr, Register expected, + Register new_val, + enum operand_size size, + Assembler::Aqrl acquire, Assembler::Aqrl release, + Register result, bool result_as_bool, + Register tmp1, Register tmp2, Register tmp3); + void weak_cmpxchg_narrow_value(Register addr, Register expected, + Register new_val, + enum operand_size size, + Assembler::Aqrl acquire, Assembler::Aqrl release, + Register result, + Register tmp1, Register tmp2, Register tmp3); + + void atomic_add(Register prev, RegisterOrConstant incr, Register addr); + void atomic_addw(Register prev, RegisterOrConstant incr, Register addr); + void atomic_addal(Register prev, RegisterOrConstant incr, Register addr); + void atomic_addalw(Register prev, RegisterOrConstant incr, Register addr); + + void atomic_xchg(Register prev, Register newv, Register addr); + void atomic_xchgw(Register prev, Register newv, Register addr); + void atomic_xchgal(Register prev, Register newv, Register addr); + void atomic_xchgalw(Register prev, Register newv, Register addr); + void atomic_xchgwu(Register prev, Register newv, Register addr); + void atomic_xchgalwu(Register prev, Register newv, Register addr); + + static bool far_branches() { + return ReservedCodeCacheSize > branch_range; + } + + // Jumps that can reach anywhere in the code cache. + // Trashes tmp. + void far_call(Address entry, CodeBuffer *cbuf = NULL, Register tmp = t0); + void far_jump(Address entry, CodeBuffer *cbuf = NULL, Register tmp = t0); + + static int far_branch_size() { + if (far_branches()) { + return 2 * 4; // auipc + jalr, see far_call() & far_jump() + } else { + return 4; + } + } + + void load_byte_map_base(Register reg); + + void bang_stack_with_offset(int offset) { + // stack grows down, caller passes positive offset + assert(offset > 0, "must bang with negative offset"); + sub(t0, sp, offset); + sd(zr, Address(t0)); + } + + void la_patchable(Register reg1, const Address &dest, int32_t &offset); + + virtual void _call_Unimplemented(address call_site) { + mv(t1, call_site); + } + + #define call_Unimplemented() _call_Unimplemented((address)__PRETTY_FUNCTION__) + + // Frame creation and destruction shared between JITs. + void build_frame(int framesize); + void remove_frame(int framesize); + + void reserved_stack_check(); + + void get_polling_page(Register dest, relocInfo::relocType rtype); + address read_polling_page(Register r, int32_t offset, relocInfo::relocType rtype); + + address trampoline_call(Address entry, CodeBuffer* cbuf = NULL); + address ic_call(address entry, jint method_index = 0); + + void add_memory_int64(const Address dst, int64_t imm); + void add_memory_int32(const Address dst, int32_t imm); + + void cmpptr(Register src1, Address src2, Label& equal); + + void clinit_barrier(Register klass, Register tmp, Label* L_fast_path = NULL, Label* L_slow_path = NULL); + void load_method_holder_cld(Register result, Register method); + void load_method_holder(Register holder, Register method); + + void compute_index(Register str1, Register trailing_zeros, Register match_mask, + Register result, Register char_tmp, Register tmp, + bool haystack_isL); + void compute_match_mask(Register src, Register pattern, Register match_mask, + Register mask1, Register mask2); + +#ifdef COMPILER2 + void mul_add(Register out, Register in, Register offset, + Register len, Register k, Register tmp); + void cad(Register dst, Register src1, Register src2, Register carry); + void cadc(Register dst, Register src1, Register src2, Register carry); + void adc(Register dst, Register src1, Register src2, Register carry); + void add2_with_carry(Register final_dest_hi, Register dest_hi, Register dest_lo, + Register src1, Register src2, Register carry); + void multiply_32_x_32_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx); + void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx); + void multiply_128_x_128_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4, + Register tmp6, Register product_hi); + void multiply_to_len(Register x, Register xlen, Register y, Register ylen, + Register z, Register zlen, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, + Register tmp5, Register tmp6, Register product_hi); +#endif + + void inflate_lo32(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); + void inflate_hi32(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); + + void ctzc_bit(Register Rd, Register Rs, bool isLL = false, Register tmp1 = t0, Register tmp2 = t1); + + void zero_words(Register base, u_int64_t cnt); + address zero_words(Register ptr, Register cnt); + void fill_words(Register base, Register cnt, Register value); + void zero_memory(Register addr, Register len, Register tmp); + + // shift left by shamt and add + void shadd(Register Rd, Register Rs1, Register Rs2, Register tmp, int shamt); + + // Here the float instructions with safe deal with some exceptions. + // e.g. convert from NaN, +Inf, -Inf to int, float, double + // will trigger exception, we need to deal with these situations + // to get correct results. + void fcvt_w_s_safe(Register dst, FloatRegister src, Register tmp = t0); + void fcvt_l_s_safe(Register dst, FloatRegister src, Register tmp = t0); + void fcvt_w_d_safe(Register dst, FloatRegister src, Register tmp = t0); + void fcvt_l_d_safe(Register dst, FloatRegister src, Register tmp = t0); + + // vector load/store unit-stride instructions + void vlex_v(VectorRegister vd, Register base, Assembler::SEW sew, VectorMask vm = unmasked) { + switch (sew) { + case Assembler::e64: + vle64_v(vd, base, vm); + break; + case Assembler::e32: + vle32_v(vd, base, vm); + break; + case Assembler::e16: + vle16_v(vd, base, vm); + break; + case Assembler::e8: // fall through + default: + vle8_v(vd, base, vm); + break; + } + } + + void vsex_v(VectorRegister store_data, Register base, Assembler::SEW sew, VectorMask vm = unmasked) { + switch (sew) { + case Assembler::e64: + vse64_v(store_data, base, vm); + break; + case Assembler::e32: + vse32_v(store_data, base, vm); + break; + case Assembler::e16: + vse16_v(store_data, base, vm); + break; + case Assembler::e8: // fall through + default: + vse8_v(store_data, base, vm); + break; + } + } + + static const int zero_words_block_size; + + void cast_primitive_type(BasicType type, Register Rt) { + switch (type) { + case T_BOOLEAN: + sltu(Rt, zr, Rt); + break; + case T_CHAR : + zero_extend(Rt, Rt, 16); + break; + case T_BYTE : + sign_extend(Rt, Rt, 8); + break; + case T_SHORT : + sign_extend(Rt, Rt, 16); + break; + case T_INT : + addw(Rt, Rt, zr); + break; + case T_LONG : /* nothing to do */ break; + case T_VOID : /* nothing to do */ break; + case T_FLOAT : /* nothing to do */ break; + case T_DOUBLE : /* nothing to do */ break; + default: ShouldNotReachHere(); + } + } + + // float cmp with unordered_result + void float_compare(Register result, FloatRegister Rs1, FloatRegister Rs2, int unordered_result); + void double_compare(Register result, FloatRegister Rs1, FloatRegister Rs2, int unordered_result); + + // Zero/Sign-extend + void zero_extend(Register dst, Register src, int bits); + void sign_extend(Register dst, Register src, int bits); + + // compare src1 and src2 and get -1/0/1 in dst. + // if [src1 > src2], dst = 1; + // if [src1 == src2], dst = 0; + // if [src1 < src2], dst = -1; + void cmp_l2i(Register dst, Register src1, Register src2, Register tmp = t0); + + int push_fp(unsigned int bitset, Register stack); + int pop_fp(unsigned int bitset, Register stack); + + int push_vp(unsigned int bitset, Register stack); + int pop_vp(unsigned int bitset, Register stack); + + // vext + void vmnot_m(VectorRegister vd, VectorRegister vs); + void vncvt_x_x_w(VectorRegister vd, VectorRegister vs, VectorMask vm = unmasked); + void vfneg_v(VectorRegister vd, VectorRegister vs); + +private: + +#ifdef ASSERT + // Template short-hand support to clean-up after a failed call to trampoline + // call generation (see trampoline_call() below), when a set of Labels must + // be reset (before returning). + template + void reset_labels(Label& lbl, More&... more) { + lbl.reset(); reset_labels(more...); + } + template + void reset_labels(Label& lbl) { + lbl.reset(); + } +#endif + void repne_scan(Register addr, Register value, Register count, Register tmp); + + // Return true if an address is within the 48-bit RISCV64 address space. + bool is_valid_riscv64_address(address addr) { + return ((uintptr_t)addr >> 48) == 0; + } + + void ld_constant(Register dest, const Address &const_addr) { + if (NearCpool) { + ld(dest, const_addr); + } else { + int32_t offset = 0; + la_patchable(dest, InternalAddress(const_addr.target()), offset); + ld(dest, Address(dest, offset)); + } + } + + int bitset_to_regs(unsigned int bitset, unsigned char* regs); + Address add_memory_helper(const Address dst); + + void load_reserved(Register addr, enum operand_size size, Assembler::Aqrl acquire); + void store_conditional(Register addr, Register new_val, enum operand_size size, Assembler::Aqrl release); + + // Check the current thread doesn't need a cross modify fence. + void verify_cross_modify_fence_not_required() PRODUCT_RETURN; +}; + +#ifdef ASSERT +inline bool AbstractAssembler::pd_check_instruction_mark() { return false; } +#endif + +/** + * class SkipIfEqual: + * + * Instantiating this class will result in assembly code being output that will + * jump around any code emitted between the creation of the instance and it's + * automatic destruction at the end of a scope block, depending on the value of + * the flag passed to the constructor, which will be checked at run-time. + */ +class SkipIfEqual { + private: + MacroAssembler* _masm; + Label _label; + + public: + SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value); + ~SkipIfEqual(); +}; + +#endif // CPU_RISCV_MACROASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.inline.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.inline.hpp new file mode 100644 index 00000000000..ef968ccd96d --- /dev/null +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.inline.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_MACROASSEMBLER_RISCV_INLINE_HPP +#define CPU_RISCV_MACROASSEMBLER_RISCV_INLINE_HPP + +// Still empty. + +#endif // CPU_RISCV_MACROASSEMBLER_RISCV_INLINE_HPP diff --git a/src/hotspot/cpu/riscv/matcher_riscv.hpp b/src/hotspot/cpu/riscv/matcher_riscv.hpp new file mode 100644 index 00000000000..23a75d20502 --- /dev/null +++ b/src/hotspot/cpu/riscv/matcher_riscv.hpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_MATCHER_RISCV_HPP +#define CPU_RISCV_MATCHER_RISCV_HPP + + // Defined within class Matcher + + // false => size gets scaled to BytesPerLong, ok. + static const bool init_array_count_is_in_bytes = false; + + // Whether this platform implements the scalable vector feature + static const bool implements_scalable_vector = true; + + static const bool supports_scalable_vector() { + return UseRVV; + } + + // riscv supports misaligned vectors store/load. + static constexpr bool misaligned_vectors_ok() { + return true; + } + + // Whether code generation need accurate ConvI2L types. + static const bool convi2l_type_required = false; + + // Does the CPU require late expand (see block.cpp for description of late expand)? + static const bool require_postalloc_expand = false; + + // Do we need to mask the count passed to shift instructions or does + // the cpu only look at the lower 5/6 bits anyway? + static const bool need_masked_shift_count = false; + + // No support for generic vector operands. + static const bool supports_generic_vector_operands = false; + + static constexpr bool isSimpleConstant64(jlong value) { + // Will one (StoreL ConL) be cheaper than two (StoreI ConI)?. + // Probably always true, even if a temp register is required. + return true; + } + + // Use conditional move (CMOVL) + static constexpr int long_cmove_cost() { + // long cmoves are no more expensive than int cmoves + return 0; + } + + static constexpr int float_cmove_cost() { + // float cmoves are no more expensive than int cmoves + return 0; + } + + // This affects two different things: + // - how Decode nodes are matched + // - how ImplicitNullCheck opportunities are recognized + // If true, the matcher will try to remove all Decodes and match them + // (as operands) into nodes. NullChecks are not prepared to deal with + // Decodes by final_graph_reshaping(). + // If false, final_graph_reshaping() forces the decode behind the Cmp + // for a NullCheck. The matcher matches the Decode node into a register. + // Implicit_null_check optimization moves the Decode along with the + // memory operation back up before the NullCheck. + static bool narrow_oop_use_complex_address() { + return CompressedOops::shift() == 0; + } + + static bool narrow_klass_use_complex_address() { + return false; + } + + static bool const_oop_prefer_decode() { + // Prefer ConN+DecodeN over ConP in simple compressed oops mode. + return CompressedOops::base() == NULL; + } + + static bool const_klass_prefer_decode() { + // Prefer ConNKlass+DecodeNKlass over ConP in simple compressed klass mode. + return CompressedKlassPointers::base() == NULL; + } + + // Is it better to copy float constants, or load them directly from + // memory? Intel can load a float constant from a direct address, + // requiring no extra registers. Most RISCs will have to materialize + // an address into a register first, so they would do better to copy + // the constant from stack. + static const bool rematerialize_float_constants = false; + + // If CPU can load and store mis-aligned doubles directly then no + // fixup is needed. Else we split the double into 2 integer pieces + // and move it piece-by-piece. Only happens when passing doubles into + // C code as the Java calling convention forces doubles to be aligned. + static const bool misaligned_doubles_ok = true; + + // Advertise here if the CPU requires explicit rounding operations to implement strictfp mode. + static const bool strict_fp_requires_explicit_rounding = false; + + // Are floats converted to double when stored to stack during + // deoptimization? + static constexpr bool float_in_double() { return false; } + + // Do ints take an entire long register or just half? + // The relevant question is how the int is callee-saved: + // the whole long is written but de-opt'ing will have to extract + // the relevant 32 bits. + static const bool int_in_long = true; + + // Does the CPU supports vector variable shift instructions? + static constexpr bool supports_vector_variable_shifts(void) { + return false; + } + + // Does the CPU supports vector variable rotate instructions? + static constexpr bool supports_vector_variable_rotates(void) { + return false; + } + + // Does the CPU supports vector constant rotate instructions? + static constexpr bool supports_vector_constant_rotates(int shift) { + return false; + } + + // Does the CPU supports vector unsigned comparison instructions? + static const bool supports_vector_comparison_unsigned(int vlen, BasicType bt) { + return false; + } + + // Some microarchitectures have mask registers used on vectors + static const bool has_predicated_vectors(void) { + return false; + } + + // true means we have fast l2f convers + // false means that conversion is done by runtime call + static constexpr bool convL2FSupported(void) { + return true; + } + + // Implements a variant of EncodeISOArrayNode that encode ASCII only + static const bool supports_encode_ascii_array = false; + + // Returns pre-selection estimated size of a vector operation. + static int vector_op_pre_select_sz_estimate(int vopc, BasicType ety, int vlen) { + return 0; + } + +#endif // CPU_RISCV_MATCHER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.cpp b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp new file mode 100644 index 00000000000..1f7c0c87c21 --- /dev/null +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.cpp @@ -0,0 +1,461 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "classfile/javaClasses.inline.hpp" +#include "classfile/vmClasses.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "memory/allocation.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/methodHandles.hpp" +#include "runtime/flags/flagSetting.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/stubRoutines.hpp" + +#define __ _masm-> + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +void MethodHandles::load_klass_from_Class(MacroAssembler* _masm, Register klass_reg) { + assert_cond(_masm != NULL); + if (VerifyMethodHandles) { + verify_klass(_masm, klass_reg, VM_CLASS_ID(java_lang_Class), + "MH argument is a Class"); + } + __ ld(klass_reg, Address(klass_reg, java_lang_Class::klass_offset())); +} + +#ifdef ASSERT +static int check_nonzero(const char* xname, int x) { + assert(x != 0, "%s should be nonzero", xname); + return x; +} +#define NONZERO(x) check_nonzero(#x, x) +#else //ASSERT +#define NONZERO(x) (x) +#endif //PRODUCT + +#ifdef ASSERT +void MethodHandles::verify_klass(MacroAssembler* _masm, + Register obj, vmClassID klass_id, + const char* error_message) { + assert_cond(_masm != NULL); + InstanceKlass** klass_addr = vmClasses::klass_addr_at(klass_id); + Klass* klass = vmClasses::klass_at(klass_id); + Register temp = t1; + Register temp2 = t0; // used by MacroAssembler::cmpptr + Label L_ok, L_bad; + BLOCK_COMMENT("verify_klass {"); + __ verify_oop(obj); + __ beqz(obj, L_bad); + __ push_reg(RegSet::of(temp, temp2), sp); + __ load_klass(temp, obj); + __ cmpptr(temp, ExternalAddress((address) klass_addr), L_ok); + intptr_t super_check_offset = klass->super_check_offset(); + __ ld(temp, Address(temp, super_check_offset)); + __ cmpptr(temp, ExternalAddress((address) klass_addr), L_ok); + __ pop_reg(RegSet::of(temp, temp2), sp); + __ bind(L_bad); + __ stop(error_message); + __ BIND(L_ok); + __ pop_reg(RegSet::of(temp, temp2), sp); + BLOCK_COMMENT("} verify_klass"); +} + +void MethodHandles::verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) {} + +#endif //ASSERT + +void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, + bool for_compiler_entry) { + assert_cond(_masm != NULL); + assert(method == xmethod, "interpreter calling convention"); + Label L_no_such_method; + __ beqz(xmethod, L_no_such_method); + __ verify_method_ptr(method); + + if (!for_compiler_entry && JvmtiExport::can_post_interpreter_events()) { + Label run_compiled_code; + // JVMTI events, such as single-stepping, are implemented partly by avoiding running + // compiled code in threads for which the event is enabled. Check here for + // interp_only_mode if these events CAN be enabled. + + __ lwu(t0, Address(xthread, JavaThread::interp_only_mode_offset())); + __ beqz(t0, run_compiled_code); + __ ld(t0, Address(method, Method::interpreter_entry_offset())); + __ jr(t0); + __ BIND(run_compiled_code); + } + + const ByteSize entry_offset = for_compiler_entry ? Method::from_compiled_offset() : + Method::from_interpreted_offset(); + __ ld(t0,Address(method, entry_offset)); + __ jr(t0); + __ bind(L_no_such_method); + __ far_jump(RuntimeAddress(StubRoutines::throw_AbstractMethodError_entry())); +} + +void MethodHandles::jump_to_lambda_form(MacroAssembler* _masm, + Register recv, Register method_temp, + Register temp2, + bool for_compiler_entry) { + assert_cond(_masm != NULL); + BLOCK_COMMENT("jump_to_lambda_form {"); + // This is the initial entry point of a lazy method handle. + // After type checking, it picks up the invoker from the LambdaForm. + assert_different_registers(recv, method_temp, temp2); + assert(recv != noreg, "required register"); + assert(method_temp == xmethod, "required register for loading method"); + + // Load the invoker, as MH -> MH.form -> LF.vmentry + __ verify_oop(recv); + __ load_heap_oop(method_temp, Address(recv, NONZERO(java_lang_invoke_MethodHandle::form_offset())), temp2); + __ verify_oop(method_temp); + __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_LambdaForm::vmentry_offset())), temp2); + __ verify_oop(method_temp); + __ load_heap_oop(method_temp, Address(method_temp, NONZERO(java_lang_invoke_MemberName::method_offset())), temp2); + __ verify_oop(method_temp); + __ access_load_at(T_ADDRESS, IN_HEAP, method_temp, Address(method_temp, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset())), noreg, noreg); + + if (VerifyMethodHandles && !for_compiler_entry) { + // make sure recv is already on stack + __ ld(temp2, Address(method_temp, Method::const_offset())); + __ load_sized_value(temp2, + Address(temp2, ConstMethod::size_of_parameters_offset()), + sizeof(u2), /*is_signed*/ false); + Label L; + __ ld(t0, __ argument_address(temp2, -1)); + __ beq(recv, t0, L); + __ ld(x10, __ argument_address(temp2, -1)); + __ ebreak(); + __ BIND(L); + } + + jump_from_method_handle(_masm, method_temp, temp2, for_compiler_entry); + BLOCK_COMMENT("} jump_to_lambda_form"); +} + +// Code generation +address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm, + vmIntrinsics::ID iid) { + assert_cond(_masm != NULL); + const bool not_for_compiler_entry = false; // this is the interpreter entry + assert(is_signature_polymorphic(iid), "expected invoke iid"); + if (iid == vmIntrinsics::_invokeGeneric || + iid == vmIntrinsics::_compiledLambdaForm) { + // Perhaps surprisingly, the symbolic references visible to Java are not directly used. + // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod. + // They all allow an appendix argument. + __ ebreak(); // empty stubs make SG sick + return NULL; + } + + // No need in interpreter entry for linkToNative for now. + // Interpreter calls compiled entry through i2c. + if (iid == vmIntrinsics::_linkToNative) { + __ ebreak(); + return NULL; + } + + // x30: sender SP (must preserve; see prepare_to_jump_from_interpreted) + // xmethod: Method* + // x13: argument locator (parameter slot count, added to sp) + // x11: used as temp to hold mh or receiver + // x10, x29: garbage temps, blown away + Register argp = x13; // argument list ptr, live on error paths + Register mh = x11; // MH receiver; dies quickly and is recycled + + // here's where control starts out: + __ align(CodeEntryAlignment); + address entry_point = __ pc(); + + if (VerifyMethodHandles) { + assert(Method::intrinsic_id_size_in_bytes() == 2, "assuming Method::_intrinsic_id is u2"); + + Label L; + BLOCK_COMMENT("verify_intrinsic_id {"); + __ lhu(t0, Address(xmethod, Method::intrinsic_id_offset_in_bytes())); + __ mv(t1, (int) iid); + __ beq(t0, t1, L); + if (iid == vmIntrinsics::_linkToVirtual || + iid == vmIntrinsics::_linkToSpecial) { + // could do this for all kinds, but would explode assembly code size + trace_method_handle(_masm, "bad Method*::intrinsic_id"); + } + __ ebreak(); + __ bind(L); + BLOCK_COMMENT("} verify_intrinsic_id"); + } + + // First task: Find out how big the argument list is. + Address x13_first_arg_addr; + int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid); + assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic"); + if (ref_kind == 0 || MethodHandles::ref_kind_has_receiver(ref_kind)) { + __ ld(argp, Address(xmethod, Method::const_offset())); + __ load_sized_value(argp, + Address(argp, ConstMethod::size_of_parameters_offset()), + sizeof(u2), /*is_signed*/ false); + x13_first_arg_addr = __ argument_address(argp, -1); + } else { + DEBUG_ONLY(argp = noreg); + } + + if (!is_signature_polymorphic_static(iid)) { + __ ld(mh, x13_first_arg_addr); + DEBUG_ONLY(argp = noreg); + } + + // x13_first_arg_addr is live! + + trace_method_handle_interpreter_entry(_masm, iid); + if (iid == vmIntrinsics::_invokeBasic) { + generate_method_handle_dispatch(_masm, iid, mh, noreg, not_for_compiler_entry); + } else { + // Adjust argument list by popping the trailing MemberName argument. + Register recv = noreg; + if (MethodHandles::ref_kind_has_receiver(ref_kind)) { + // Load the receiver (not the MH; the actual MemberName's receiver) up from the interpreter stack. + __ ld(recv = x12, x13_first_arg_addr); + } + DEBUG_ONLY(argp = noreg); + Register xmember = xmethod; // MemberName ptr; incoming method ptr is dead now + __ pop_reg(xmember); // extract last argument + generate_method_handle_dispatch(_masm, iid, recv, xmember, not_for_compiler_entry); + } + + return entry_point; +} + + +void MethodHandles::generate_method_handle_dispatch(MacroAssembler* _masm, + vmIntrinsics::ID iid, + Register receiver_reg, + Register member_reg, + bool for_compiler_entry) { + assert_cond(_masm != NULL); + assert(is_signature_polymorphic(iid), "expected invoke iid"); + // temps used in this code are not used in *either* compiled or interpreted calling sequences + Register temp1 = x7; + Register temp2 = x28; + Register temp3 = x29; // x30 is live by this point: it contains the sender SP + if (for_compiler_entry) { + assert(receiver_reg == (iid == vmIntrinsics::_linkToStatic ? noreg : j_rarg0), "only valid assignment"); + assert_different_registers(temp1, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7); + assert_different_registers(temp2, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7); + assert_different_registers(temp3, j_rarg0, j_rarg1, j_rarg2, j_rarg3, j_rarg4, j_rarg5, j_rarg6, j_rarg7); + } + + assert_different_registers(temp1, temp2, temp3, receiver_reg); + assert_different_registers(temp1, temp2, temp3, member_reg); + + if (iid == vmIntrinsics::_invokeBasic || iid == vmIntrinsics::_linkToNative) { + if (iid == vmIntrinsics::_linkToNative) { + assert(for_compiler_entry, "only compiler entry is supported"); + } + // indirect through MH.form.vmentry.vmtarget + jump_to_lambda_form(_masm, receiver_reg, xmethod, temp1, for_compiler_entry); + } else { + // The method is a member invoker used by direct method handles. + if (VerifyMethodHandles) { + // make sure the trailing argument really is a MemberName (caller responsibility) + verify_klass(_masm, member_reg, VM_CLASS_ID(java_lang_invoke_MemberName), + "MemberName required for invokeVirtual etc."); + } + + Address member_clazz( member_reg, NONZERO(java_lang_invoke_MemberName::clazz_offset())); + Address member_vmindex( member_reg, NONZERO(java_lang_invoke_MemberName::vmindex_offset())); + Address member_vmtarget( member_reg, NONZERO(java_lang_invoke_MemberName::method_offset())); + Address vmtarget_method( xmethod, NONZERO(java_lang_invoke_ResolvedMethodName::vmtarget_offset())); + + Register temp1_recv_klass = temp1; + if (iid != vmIntrinsics::_linkToStatic) { + __ verify_oop(receiver_reg); + if (iid == vmIntrinsics::_linkToSpecial) { + // Don't actually load the klass; just null-check the receiver. + __ null_check(receiver_reg); + } else { + // load receiver klass itself + __ null_check(receiver_reg, oopDesc::klass_offset_in_bytes()); + __ load_klass(temp1_recv_klass, receiver_reg); + __ verify_klass_ptr(temp1_recv_klass); + } + BLOCK_COMMENT("check_receiver {"); + // The receiver for the MemberName must be in receiver_reg. + // Check the receiver against the MemberName.clazz + if (VerifyMethodHandles && iid == vmIntrinsics::_linkToSpecial) { + // Did not load it above... + __ load_klass(temp1_recv_klass, receiver_reg); + __ verify_klass_ptr(temp1_recv_klass); + } + if (VerifyMethodHandles && iid != vmIntrinsics::_linkToInterface) { + Label L_ok; + Register temp2_defc = temp2; + __ load_heap_oop(temp2_defc, member_clazz, temp3); + load_klass_from_Class(_masm, temp2_defc); + __ verify_klass_ptr(temp2_defc); + __ check_klass_subtype(temp1_recv_klass, temp2_defc, temp3, L_ok); + // If we get here, the type check failed! + __ ebreak(); + __ bind(L_ok); + } + BLOCK_COMMENT("} check_receiver"); + } + if (iid == vmIntrinsics::_linkToSpecial || + iid == vmIntrinsics::_linkToStatic) { + DEBUG_ONLY(temp1_recv_klass = noreg); // these guys didn't load the recv_klass + } + + // Live registers at this point: + // member_reg - MemberName that was the trailing argument + // temp1_recv_klass - klass of stacked receiver, if needed + // x30 - interpreter linkage (if interpreted) + // x11 ... x10 - compiler arguments (if compiled) + + Label L_incompatible_class_change_error; + switch (iid) { + case vmIntrinsics::_linkToSpecial: + if (VerifyMethodHandles) { + verify_ref_kind(_masm, JVM_REF_invokeSpecial, member_reg, temp3); + } + __ load_heap_oop(xmethod, member_vmtarget); + __ access_load_at(T_ADDRESS, IN_HEAP, xmethod, vmtarget_method, noreg, noreg); + break; + + case vmIntrinsics::_linkToStatic: + if (VerifyMethodHandles) { + verify_ref_kind(_masm, JVM_REF_invokeStatic, member_reg, temp3); + } + __ load_heap_oop(xmethod, member_vmtarget); + __ access_load_at(T_ADDRESS, IN_HEAP, xmethod, vmtarget_method, noreg, noreg); + break; + + case vmIntrinsics::_linkToVirtual: + { + // same as TemplateTable::invokevirtual, + // minus the CP setup and profiling: + + if (VerifyMethodHandles) { + verify_ref_kind(_masm, JVM_REF_invokeVirtual, member_reg, temp3); + } + + // pick out the vtable index from the MemberName, and then we can discard it: + Register temp2_index = temp2; + __ access_load_at(T_ADDRESS, IN_HEAP, temp2_index, member_vmindex, noreg, noreg); + + if (VerifyMethodHandles) { + Label L_index_ok; + __ bgez(temp2_index, L_index_ok); + __ ebreak(); + __ BIND(L_index_ok); + } + + // Note: The verifier invariants allow us to ignore MemberName.clazz and vmtarget + // at this point. And VerifyMethodHandles has already checked clazz, if needed. + + // get target Method* & entry point + __ lookup_virtual_method(temp1_recv_klass, temp2_index, xmethod); + break; + } + + case vmIntrinsics::_linkToInterface: + { + // same as TemplateTable::invokeinterface + // (minus the CP setup and profiling, with different argument motion) + if (VerifyMethodHandles) { + verify_ref_kind(_masm, JVM_REF_invokeInterface, member_reg, temp3); + } + + Register temp3_intf = temp3; + __ load_heap_oop(temp3_intf, member_clazz); + load_klass_from_Class(_masm, temp3_intf); + __ verify_klass_ptr(temp3_intf); + + Register rindex = xmethod; + __ access_load_at(T_ADDRESS, IN_HEAP, rindex, member_vmindex, noreg, noreg); + if (VerifyMethodHandles) { + Label L; + __ bgez(rindex, L); + __ ebreak(); + __ bind(L); + } + + // given intf, index, and recv klass, dispatch to the implementation method + __ lookup_interface_method(temp1_recv_klass, temp3_intf, + // note: next two args must be the same: + rindex, xmethod, + temp2, + L_incompatible_class_change_error); + break; + } + + default: + fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid)); + break; + } + + // live at this point: xmethod, x30 (if interpreted) + + // After figuring out which concrete method to call, jump into it. + // Note that this works in the interpreter with no data motion. + // But the compiled version will require that r2_recv be shifted out. + __ verify_method_ptr(xmethod); + jump_from_method_handle(_masm, xmethod, temp1, for_compiler_entry); + if (iid == vmIntrinsics::_linkToInterface) { + __ bind(L_incompatible_class_change_error); + __ far_jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); + } + } + +} + +#ifndef PRODUCT +void trace_method_handle_stub(const char* adaptername, + oopDesc* mh, + intptr_t* saved_regs, + intptr_t* entry_sp) { } + +// The stub wraps the arguments in a struct on the stack to avoid +// dealing with the different calling conventions for passing 6 +// arguments. +struct MethodHandleStubArguments { + const char* adaptername; + oopDesc* mh; + intptr_t* saved_regs; + intptr_t* entry_sp; +}; +void trace_method_handle_stub_wrapper(MethodHandleStubArguments* args) { } + +void MethodHandles::trace_method_handle(MacroAssembler* _masm, const char* adaptername) { } +#endif //PRODUCT diff --git a/src/hotspot/cpu/riscv/methodHandles_riscv.hpp b/src/hotspot/cpu/riscv/methodHandles_riscv.hpp new file mode 100644 index 00000000000..f73aba29d67 --- /dev/null +++ b/src/hotspot/cpu/riscv/methodHandles_riscv.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +// Platform-specific definitions for method handles. +// These definitions are inlined into class MethodHandles. + +// Adapters +enum /* platform_dependent_constants */ { + adapter_code_size = 32000 DEBUG_ONLY(+ 120000) +}; + +public: + + static void load_klass_from_Class(MacroAssembler* _masm, Register klass_reg); + + static void verify_klass(MacroAssembler* _masm, + Register obj, vmClassID klass_id, + const char* error_message = "wrong klass") NOT_DEBUG_RETURN; + + static void verify_method_handle(MacroAssembler* _masm, Register mh_reg) { + verify_klass(_masm, mh_reg, VM_CLASS_ID(java_lang_invoke_MethodHandle), + "reference is a MH"); + } + + static void verify_ref_kind(MacroAssembler* _masm, int ref_kind, Register member_reg, Register temp) NOT_DEBUG_RETURN; + + // Similar to InterpreterMacroAssembler::jump_from_interpreted. + // Takes care of special dispatch from single stepping too. + static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, + bool for_compiler_entry); + + static void jump_to_lambda_form(MacroAssembler* _masm, + Register recv, Register method_temp, + Register temp2, + bool for_compiler_entry); diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp new file mode 100644 index 00000000000..0a05c577860 --- /dev/null +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -0,0 +1,429 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "code/compiledIC.hpp" +#include "memory/resourceArea.hpp" +#include "nativeInst_riscv.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/handles.hpp" +#include "runtime/orderAccess.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "utilities/ostream.hpp" +#ifdef COMPILER1 +#include "c1/c1_Runtime1.hpp" +#endif + +Register NativeInstruction::extract_rs1(address instr) { + assert_cond(instr != NULL); + return as_Register(Assembler::extract(((unsigned*)instr)[0], 19, 15)); +} + +Register NativeInstruction::extract_rs2(address instr) { + assert_cond(instr != NULL); + return as_Register(Assembler::extract(((unsigned*)instr)[0], 24, 20)); +} + +Register NativeInstruction::extract_rd(address instr) { + assert_cond(instr != NULL); + return as_Register(Assembler::extract(((unsigned*)instr)[0], 11, 7)); +} + +uint32_t NativeInstruction::extract_opcode(address instr) { + assert_cond(instr != NULL); + return Assembler::extract(((unsigned*)instr)[0], 6, 0); +} + +uint32_t NativeInstruction::extract_funct3(address instr) { + assert_cond(instr != NULL); + return Assembler::extract(((unsigned*)instr)[0], 14, 12); +} + +bool NativeInstruction::is_pc_relative_at(address instr) { + // auipc + jalr + // auipc + addi + // auipc + load + // auipc + fload_load + return (is_auipc_at(instr)) && + (is_addi_at(instr + instruction_size) || + is_jalr_at(instr + instruction_size) || + is_load_at(instr + instruction_size) || + is_float_load_at(instr + instruction_size)) && + check_pc_relative_data_dependency(instr); +} + +// ie:ld(Rd, Label) +bool NativeInstruction::is_load_pc_relative_at(address instr) { + return is_auipc_at(instr) && // auipc + is_ld_at(instr + instruction_size) && // ld + check_load_pc_relative_data_dependency(instr); +} + +bool NativeInstruction::is_movptr_at(address instr) { + return is_lui_at(instr) && // Lui + is_addi_at(instr + instruction_size) && // Addi + is_slli_shift_at(instr + instruction_size * 2, 11) && // Slli Rd, Rs, 11 + is_addi_at(instr + instruction_size * 3) && // Addi + is_slli_shift_at(instr + instruction_size * 4, 5) && // Slli Rd, Rs, 5 + (is_addi_at(instr + instruction_size * 5) || + is_jalr_at(instr + instruction_size * 5) || + is_load_at(instr + instruction_size * 5)) && // Addi/Jalr/Load + check_movptr_data_dependency(instr); +} + +bool NativeInstruction::is_li32_at(address instr) { + return is_lui_at(instr) && // lui + is_addiw_at(instr + instruction_size) && // addiw + check_li32_data_dependency(instr); +} + +bool NativeInstruction::is_li64_at(address instr) { + return is_lui_at(instr) && // lui + is_addi_at(instr + instruction_size) && // addi + is_slli_shift_at(instr + instruction_size * 2, 12) && // Slli Rd, Rs, 12 + is_addi_at(instr + instruction_size * 3) && // addi + is_slli_shift_at(instr + instruction_size * 4, 12) && // Slli Rd, Rs, 12 + is_addi_at(instr + instruction_size * 5) && // addi + is_slli_shift_at(instr + instruction_size * 6, 8) && // Slli Rd, Rs, 8 + is_addi_at(instr + instruction_size * 7) && // addi + check_li64_data_dependency(instr); +} + +void NativeCall::verify() { + assert(NativeCall::is_call_at((address)this), "unexpected code at call site"); +} + +address NativeCall::destination() const { + address addr = (address)this; + assert(NativeInstruction::is_jal_at(instruction_address()), "inst must be jal."); + address destination = MacroAssembler::target_addr_for_insn(instruction_address()); + + // Do we use a trampoline stub for this call? + CodeBlob* cb = CodeCache::find_blob_unsafe(addr); // Else we get assertion if nmethod is zombie. + assert(cb && cb->is_nmethod(), "sanity"); + nmethod *nm = (nmethod *)cb; + if (nm != NULL && nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { + // Yes we do, so get the destination from the trampoline stub. + const address trampoline_stub_addr = destination; + destination = nativeCallTrampolineStub_at(trampoline_stub_addr)->destination(); + } + + return destination; +} + +// Similar to replace_mt_safe, but just changes the destination. The +// important thing is that free-running threads are able to execute this +// call instruction at all times. +// +// Used in the runtime linkage of calls; see class CompiledIC. +// +// Add parameter assert_lock to switch off assertion +// during code generation, where no patching lock is needed. +void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { + assert(!assert_lock || + (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || + CompiledICLocker::is_safe(addr_at(0)), + "concurrent code patching"); + + ResourceMark rm; + address addr_call = addr_at(0); + assert(NativeCall::is_call_at(addr_call), "unexpected code at call site"); + + // Patch the constant in the call's trampoline stub. + address trampoline_stub_addr = get_trampoline(); + if (trampoline_stub_addr != NULL) { + assert (!is_NativeCallTrampolineStub_at(dest), "chained trampolines"); + nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest); + } + + // Patch the call. + if (Assembler::reachable_from_branch_at(addr_call, dest)) { + set_destination(dest); + } else { + assert (trampoline_stub_addr != NULL, "we need a trampoline"); + set_destination(trampoline_stub_addr); + } + + ICache::invalidate_range(addr_call, instruction_size); +} + +address NativeCall::get_trampoline() { + address call_addr = addr_at(0); + + CodeBlob *code = CodeCache::find_blob(call_addr); + assert(code != NULL, "Could not find the containing code blob"); + + address jal_destination = MacroAssembler::pd_call_destination(call_addr); + if (code != NULL && code->contains(jal_destination) && is_NativeCallTrampolineStub_at(jal_destination)) { + return jal_destination; + } + + if (code != NULL && code->is_nmethod()) { + return trampoline_stub_Relocation::get_trampoline_for(call_addr, (nmethod*)code); + } + + return NULL; +} + +// Inserts a native call instruction at a given pc +void NativeCall::insert(address code_pos, address entry) { Unimplemented(); } + +//------------------------------------------------------------------- + +void NativeMovConstReg::verify() { + if (!(nativeInstruction_at(instruction_address())->is_movptr() || + is_auipc_at(instruction_address()))) { + fatal("should be MOVPTR or AUIPC"); + } +} + +intptr_t NativeMovConstReg::data() const { + address addr = MacroAssembler::target_addr_for_insn(instruction_address()); + if (maybe_cpool_ref(instruction_address())) { + return *(intptr_t*)addr; + } else { + return (intptr_t)addr; + } +} + +void NativeMovConstReg::set_data(intptr_t x) { + if (maybe_cpool_ref(instruction_address())) { + address addr = MacroAssembler::target_addr_for_insn(instruction_address()); + *(intptr_t*)addr = x; + } else { + // Store x into the instruction stream. + MacroAssembler::pd_patch_instruction_size(instruction_address(), (address)x); + ICache::invalidate_range(instruction_address(), movptr_instruction_size); + } + + // Find and replace the oop/metadata corresponding to this + // instruction in oops section. + CodeBlob* cb = CodeCache::find_blob(instruction_address()); + nmethod* nm = cb->as_nmethod_or_null(); + if (nm != NULL) { + RelocIterator iter(nm, instruction_address(), next_instruction_address()); + while (iter.next()) { + if (iter.type() == relocInfo::oop_type) { + oop* oop_addr = iter.oop_reloc()->oop_addr(); + *oop_addr = cast_to_oop(x); + break; + } else if (iter.type() == relocInfo::metadata_type) { + Metadata** metadata_addr = iter.metadata_reloc()->metadata_addr(); + *metadata_addr = (Metadata*)x; + break; + } + } + } +} + +void NativeMovConstReg::print() { + tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT, + p2i(instruction_address()), data()); +} + +//------------------------------------------------------------------- + +int NativeMovRegMem::offset() const { + Unimplemented(); + return 0; +} + +void NativeMovRegMem::set_offset(int x) { Unimplemented(); } + +void NativeMovRegMem::verify() { + Unimplemented(); +} + +//-------------------------------------------------------------------------------- + +void NativeJump::verify() { } + + +void NativeJump::check_verified_entry_alignment(address entry, address verified_entry) { +} + + +address NativeJump::jump_destination() const { + address dest = MacroAssembler::target_addr_for_insn(instruction_address()); + + // We use jump to self as the unresolved address which the inline + // cache code (and relocs) know about + // As a special case we also use sequence movptr_with_offset(r,0), jalr(r,0) + // i.e. jump to 0 when we need leave space for a wide immediate + // load + + // return -1 if jump to self or to 0 + if ((dest == (address) this) || dest == 0) { + dest = (address) -1; + } + + return dest; +}; + +void NativeJump::set_jump_destination(address dest) { + // We use jump to self as the unresolved address which the inline + // cache code (and relocs) know about + if (dest == (address) -1) + dest = instruction_address(); + + MacroAssembler::pd_patch_instruction(instruction_address(), dest); + ICache::invalidate_range(instruction_address(), instruction_size); +} + +//------------------------------------------------------------------- + +address NativeGeneralJump::jump_destination() const { + NativeMovConstReg* move = nativeMovConstReg_at(instruction_address()); + address dest = (address) move->data(); + + // We use jump to self as the unresolved address which the inline + // cache code (and relocs) know about + // As a special case we also use jump to 0 when first generating + // a general jump + + // return -1 if jump to self or to 0 + if ((dest == (address) this) || dest == 0) { + dest = (address) -1; + } + + return dest; +} + +//------------------------------------------------------------------- + +bool NativeInstruction::is_safepoint_poll() { + return is_lwu_to_zr(address(this)); +} + +bool NativeInstruction::is_lwu_to_zr(address instr) { + assert_cond(instr != NULL); + return (extract_opcode(instr) == 0b0000011 && + extract_funct3(instr) == 0b110 && + extract_rd(instr) == zr); // zr +} + +// A 16-bit instruction with all bits ones is permanently reserved as an illegal instruction. +bool NativeInstruction::is_sigill_zombie_not_entrant() { + // jvmci + return uint_at(0) == 0xffffffff; +} + +void NativeIllegalInstruction::insert(address code_pos) { + assert_cond(code_pos != NULL); + *(juint*)code_pos = 0xffffffff; // all bits ones is permanently reserved as an illegal instruction +} + +bool NativeInstruction::is_stop() { + return uint_at(0) == 0xffffffff; // an illegal instruction +} + +//------------------------------------------------------------------- + +// MT-safe inserting of a jump over a jump or a nop (used by +// nmethod::make_not_entrant_or_zombie) + +void NativeJump::patch_verified_entry(address entry, address verified_entry, address dest) { + + assert(dest == SharedRuntime::get_handle_wrong_method_stub(), "expected fixed destination of patch"); + + assert(nativeInstruction_at(verified_entry)->is_jump_or_nop() || + nativeInstruction_at(verified_entry)->is_sigill_zombie_not_entrant(), + "riscv cannot replace non-jump with jump"); + + // Patch this nmethod atomically. + if (Assembler::reachable_from_branch_at(verified_entry, dest)) { + ptrdiff_t offset = dest - verified_entry; + guarantee(is_imm_in_range(offset, 20, 1), "offset is too large to be patched in one jal insrusction."); // 1M + + uint32_t insn = 0; + address pInsn = (address)&insn; + Assembler::patch(pInsn, 31, 31, (offset >> 20) & 0x1); + Assembler::patch(pInsn, 30, 21, (offset >> 1) & 0x3ff); + Assembler::patch(pInsn, 20, 20, (offset >> 11) & 0x1); + Assembler::patch(pInsn, 19, 12, (offset >> 12) & 0xff); + Assembler::patch(pInsn, 11, 7, 0); // zero, no link jump + Assembler::patch(pInsn, 6, 0, 0b1101111); // j, (jal x0 offset) + *(unsigned int*)verified_entry = insn; + } else { + // We use an illegal instruction for marking a method as + // not_entrant or zombie. + NativeIllegalInstruction::insert(verified_entry); + } + + ICache::invalidate_range(verified_entry, instruction_size); +} + +void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { + CodeBuffer cb(code_pos, instruction_size); + MacroAssembler a(&cb); + + int32_t offset = 0; + a.movptr_with_offset(t0, entry, offset); // lui, addi, slli, addi, slli + a.jalr(x0, t0, offset); // jalr + + ICache::invalidate_range(code_pos, instruction_size); +} + +// MT-safe patching of a long jump instruction. +void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { + ShouldNotCallThis(); +} + + +address NativeCallTrampolineStub::destination(nmethod *nm) const { + return ptr_at(data_offset); +} + +void NativeCallTrampolineStub::set_destination(address new_destination) { + set_ptr_at(data_offset, new_destination); + OrderAccess::release(); +} + +uint32_t NativeMembar::get_kind() { + uint32_t insn = uint_at(0); + + uint32_t predecessor = Assembler::extract(insn, 27, 24); + uint32_t successor = Assembler::extract(insn, 23, 20); + + return MacroAssembler::pred_succ_to_membar_mask(predecessor, successor); +} + +void NativeMembar::set_kind(uint32_t order_kind) { + uint32_t predecessor = 0; + uint32_t successor = 0; + + MacroAssembler::membar_mask_to_pred_succ(order_kind, predecessor, successor); + + uint32_t insn = uint_at(0); + address pInsn = (address) &insn; + Assembler::patch(pInsn, 27, 24, predecessor); + Assembler::patch(pInsn, 23, 20, successor); + + address membar = addr_at(0); + *(unsigned int*) membar = insn; +} diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp new file mode 100644 index 00000000000..718b2e3de6c --- /dev/null +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -0,0 +1,572 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_NATIVEINST_RISCV_HPP +#define CPU_RISCV_NATIVEINST_RISCV_HPP + +#include "asm/assembler.hpp" +#include "runtime/icache.hpp" +#include "runtime/os.hpp" + +// We have interfaces for the following instructions: +// - NativeInstruction +// - - NativeCall +// - - NativeMovConstReg +// - - NativeMovRegMem +// - - NativeJump +// - - NativeGeneralJump +// - - NativeIllegalInstruction +// - - NativeCallTrampolineStub +// - - NativeMembar +// - - NativeFenceI + +// The base class for different kinds of native instruction abstractions. +// Provides the primitive operations to manipulate code relative to this. + +class NativeCall; + +class NativeInstruction { + friend class Relocation; + friend bool is_NativeCallTrampolineStub_at(address); + public: + enum { + instruction_size = 4, + compressed_instruction_size = 2, + }; + + juint encoding() const { + return uint_at(0); + } + + bool is_jal() const { return is_jal_at(addr_at(0)); } + bool is_movptr() const { return is_movptr_at(addr_at(0)); } + bool is_call() const { return is_call_at(addr_at(0)); } + bool is_jump() const { return is_jump_at(addr_at(0)); } + + static bool is_jal_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b1101111; } + static bool is_jalr_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b1100111 && extract_funct3(instr) == 0b000; } + static bool is_branch_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b1100011; } + static bool is_ld_at(address instr) { assert_cond(instr != NULL); return is_load_at(instr) && extract_funct3(instr) == 0b011; } + static bool is_load_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0000011; } + static bool is_float_load_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0000111; } + static bool is_auipc_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0010111; } + static bool is_jump_at(address instr) { assert_cond(instr != NULL); return is_branch_at(instr) || is_jal_at(instr) || is_jalr_at(instr); } + static bool is_addi_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0010011 && extract_funct3(instr) == 0b000; } + static bool is_addiw_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0011011 && extract_funct3(instr) == 0b000; } + static bool is_lui_at(address instr) { assert_cond(instr != NULL); return extract_opcode(instr) == 0b0110111; } + static bool is_slli_shift_at(address instr, uint32_t shift) { + assert_cond(instr != NULL); + return (extract_opcode(instr) == 0b0010011 && // opcode field + extract_funct3(instr) == 0b001 && // funct3 field, select the type of operation + Assembler::extract(((unsigned*)instr)[0], 25, 20) == shift); // shamt field + } + + static Register extract_rs1(address instr); + static Register extract_rs2(address instr); + static Register extract_rd(address instr); + static uint32_t extract_opcode(address instr); + static uint32_t extract_funct3(address instr); + + // the instruction sequence of movptr is as below: + // lui + // addi + // slli + // addi + // slli + // addi/jalr/load + static bool check_movptr_data_dependency(address instr) { + address lui = instr; + address addi1 = lui + instruction_size; + address slli1 = addi1 + instruction_size; + address addi2 = slli1 + instruction_size; + address slli2 = addi2 + instruction_size; + address last_instr = slli2 + instruction_size; + return extract_rs1(addi1) == extract_rd(lui) && + extract_rs1(addi1) == extract_rd(addi1) && + extract_rs1(slli1) == extract_rd(addi1) && + extract_rs1(slli1) == extract_rd(slli1) && + extract_rs1(addi2) == extract_rd(slli1) && + extract_rs1(addi2) == extract_rd(addi2) && + extract_rs1(slli2) == extract_rd(addi2) && + extract_rs1(slli2) == extract_rd(slli2) && + extract_rs1(last_instr) == extract_rd(slli2); + } + + // the instruction sequence of li64 is as below: + // lui + // addi + // slli + // addi + // slli + // addi + // slli + // addi + static bool check_li64_data_dependency(address instr) { + address lui = instr; + address addi1 = lui + instruction_size; + address slli1 = addi1 + instruction_size; + address addi2 = slli1 + instruction_size; + address slli2 = addi2 + instruction_size; + address addi3 = slli2 + instruction_size; + address slli3 = addi3 + instruction_size; + address addi4 = slli3 + instruction_size; + return extract_rs1(addi1) == extract_rd(lui) && + extract_rs1(addi1) == extract_rd(addi1) && + extract_rs1(slli1) == extract_rd(addi1) && + extract_rs1(slli1) == extract_rd(slli1) && + extract_rs1(addi2) == extract_rd(slli1) && + extract_rs1(addi2) == extract_rd(addi2) && + extract_rs1(slli2) == extract_rd(addi2) && + extract_rs1(slli2) == extract_rd(slli2) && + extract_rs1(addi3) == extract_rd(slli2) && + extract_rs1(addi3) == extract_rd(addi3) && + extract_rs1(slli3) == extract_rd(addi3) && + extract_rs1(slli3) == extract_rd(slli3) && + extract_rs1(addi4) == extract_rd(slli3) && + extract_rs1(addi4) == extract_rd(addi4); + } + + // the instruction sequence of li32 is as below: + // lui + // addiw + static bool check_li32_data_dependency(address instr) { + address lui = instr; + address addiw = lui + instruction_size; + + return extract_rs1(addiw) == extract_rd(lui) && + extract_rs1(addiw) == extract_rd(addiw); + } + + // the instruction sequence of pc-relative is as below: + // auipc + // jalr/addi/load/float_load + static bool check_pc_relative_data_dependency(address instr) { + address auipc = instr; + address last_instr = auipc + instruction_size; + + return extract_rs1(last_instr) == extract_rd(auipc); + } + + // the instruction sequence of load_label is as below: + // auipc + // load + static bool check_load_pc_relative_data_dependency(address instr) { + address auipc = instr; + address load = auipc + instruction_size; + + return extract_rd(load) == extract_rd(auipc) && + extract_rs1(load) == extract_rd(load); + } + + static bool is_movptr_at(address instr); + static bool is_li32_at(address instr); + static bool is_li64_at(address instr); + static bool is_pc_relative_at(address branch); + static bool is_load_pc_relative_at(address branch); + + static bool is_call_at(address instr) { + if (is_jal_at(instr) || is_jalr_at(instr)) { + return true; + } + return false; + } + static bool is_lwu_to_zr(address instr); + + inline bool is_nop(); + inline bool is_jump_or_nop(); + bool is_safepoint_poll(); + bool is_sigill_zombie_not_entrant(); + bool is_stop(); + + protected: + address addr_at(int offset) const { return address(this) + offset; } + + jint int_at(int offset) const { return *(jint*) addr_at(offset); } + juint uint_at(int offset) const { return *(juint*) addr_at(offset); } + + address ptr_at(int offset) const { return *(address*) addr_at(offset); } + + oop oop_at (int offset) const { return *(oop*) addr_at(offset); } + + + void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; } + void set_uint_at(int offset, jint i) { *(juint*)addr_at(offset) = i; } + void set_ptr_at (int offset, address ptr) { *(address*) addr_at(offset) = ptr; } + void set_oop_at (int offset, oop o) { *(oop*) addr_at(offset) = o; } + + public: + + inline friend NativeInstruction* nativeInstruction_at(address addr); + + static bool maybe_cpool_ref(address instr) { + return is_auipc_at(instr); + } + + bool is_membar() { + return (uint_at(0) & 0x7f) == 0b1111 && extract_funct3(addr_at(0)) == 0; + } +}; + +inline NativeInstruction* nativeInstruction_at(address addr) { + return (NativeInstruction*)addr; +} + +// The natural type of an RISCV instruction is uint32_t +inline NativeInstruction* nativeInstruction_at(uint32_t *addr) { + return (NativeInstruction*)addr; +} + +inline NativeCall* nativeCall_at(address addr); +// The NativeCall is an abstraction for accessing/manipulating native +// call instructions (used to manipulate inline caches, primitive & +// DSO calls, etc.). + +class NativeCall: public NativeInstruction { + public: + enum RISCV_specific_constants { + instruction_size = 4, + instruction_offset = 0, + displacement_offset = 0, + return_address_offset = 4 + }; + + address instruction_address() const { return addr_at(instruction_offset); } + address next_instruction_address() const { return addr_at(return_address_offset); } + address return_address() const { return addr_at(return_address_offset); } + address destination() const; + + void set_destination(address dest) { + assert(is_jal(), "Should be jal instruction!"); + intptr_t offset = (intptr_t)(dest - instruction_address()); + assert((offset & 0x1) == 0, "bad alignment"); + assert(is_imm_in_range(offset, 20, 1), "encoding constraint"); + unsigned int insn = 0b1101111; // jal + address pInsn = (address)(&insn); + Assembler::patch(pInsn, 31, 31, (offset >> 20) & 0x1); + Assembler::patch(pInsn, 30, 21, (offset >> 1) & 0x3ff); + Assembler::patch(pInsn, 20, 20, (offset >> 11) & 0x1); + Assembler::patch(pInsn, 19, 12, (offset >> 12) & 0xff); + Assembler::patch(pInsn, 11, 7, ra->encoding()); // Rd must be x1, need ra + set_int_at(displacement_offset, insn); + } + + void verify_alignment() {} // do nothing on riscv + void verify(); + void print(); + + // Creation + inline friend NativeCall* nativeCall_at(address addr); + inline friend NativeCall* nativeCall_before(address return_address); + + static bool is_call_before(address return_address) { + return is_call_at(return_address - NativeCall::return_address_offset); + } + + // MT-safe patching of a call instruction. + static void insert(address code_pos, address entry); + + static void replace_mt_safe(address instr_addr, address code_buffer); + + // Similar to replace_mt_safe, but just changes the destination. The + // important thing is that free-running threads are able to execute + // this call instruction at all times. If the call is an immediate BL + // instruction we can simply rely on atomicity of 32-bit writes to + // make sure other threads will see no intermediate states. + + // We cannot rely on locks here, since the free-running threads must run at + // full speed. + // + // Used in the runtime linkage of calls; see class CompiledIC. + // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) + + // The parameter assert_lock disables the assertion during code generation. + void set_destination_mt_safe(address dest, bool assert_lock = true); + + address get_trampoline(); +}; + +inline NativeCall* nativeCall_at(address addr) { + assert_cond(addr != NULL); + NativeCall* call = (NativeCall*)(addr - NativeCall::instruction_offset); +#ifdef ASSERT + call->verify(); +#endif + return call; +} + +inline NativeCall* nativeCall_before(address return_address) { + assert_cond(return_address != NULL); + NativeCall* call = (NativeCall*)(return_address - NativeCall::return_address_offset); +#ifdef ASSERT + call->verify(); +#endif + return call; +} + +// An interface for accessing/manipulating native mov reg, imm instructions. +// (used to manipulate inlined 64-bit data calls, etc.) +class NativeMovConstReg: public NativeInstruction { + public: + enum RISCV_specific_constants { + movptr_instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, addi. See movptr(). + movptr_with_offset_instruction_size = 5 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli. See movptr_with_offset(). + load_pc_relative_instruction_size = 2 * NativeInstruction::instruction_size, // auipc, ld + instruction_offset = 0, + displacement_offset = 0 + }; + + address instruction_address() const { return addr_at(instruction_offset); } + address next_instruction_address() const { + // if the instruction at 5 * instruction_size is addi, + // it means a lui + addi + slli + addi + slli + addi instruction sequence, + // and the next instruction address should be addr_at(6 * instruction_size). + // However, when the instruction at 5 * instruction_size isn't addi, + // the next instruction address should be addr_at(5 * instruction_size) + if (nativeInstruction_at(instruction_address())->is_movptr()) { + if (is_addi_at(addr_at(movptr_with_offset_instruction_size))) { + // Assume: lui, addi, slli, addi, slli, addi + return addr_at(movptr_instruction_size); + } else { + // Assume: lui, addi, slli, addi, slli + return addr_at(movptr_with_offset_instruction_size); + } + } else if (is_load_pc_relative_at(instruction_address())) { + // Assume: auipc, ld + return addr_at(load_pc_relative_instruction_size); + } + guarantee(false, "Unknown instruction in NativeMovConstReg"); + return NULL; + } + + intptr_t data() const; + void set_data(intptr_t x); + + void flush() { + if (!maybe_cpool_ref(instruction_address())) { + ICache::invalidate_range(instruction_address(), movptr_instruction_size); + } + } + + void verify(); + void print(); + + // Creation + inline friend NativeMovConstReg* nativeMovConstReg_at(address addr); + inline friend NativeMovConstReg* nativeMovConstReg_before(address addr); +}; + +inline NativeMovConstReg* nativeMovConstReg_at(address addr) { + assert_cond(addr != NULL); + NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_offset); +#ifdef ASSERT + test->verify(); +#endif + return test; +} + +inline NativeMovConstReg* nativeMovConstReg_before(address addr) { + assert_cond(addr != NULL); + NativeMovConstReg* test = (NativeMovConstReg*)(addr - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset); +#ifdef ASSERT + test->verify(); +#endif + return test; +} + +// RISCV should not use C1 runtime patching, so just leave NativeMovRegMem Unimplemented. +class NativeMovRegMem: public NativeInstruction { + public: + int instruction_start() const { + Unimplemented(); + return 0; + } + + address instruction_address() const { + Unimplemented(); + return NULL; + } + + int num_bytes_to_end_of_patch() const { + Unimplemented(); + return 0; + } + + int offset() const; + + void set_offset(int x); + + void add_offset_in_bytes(int add_offset) { Unimplemented(); } + + void verify(); + void print(); + + private: + inline friend NativeMovRegMem* nativeMovRegMem_at (address addr); +}; + +inline NativeMovRegMem* nativeMovRegMem_at (address addr) { + Unimplemented(); + return NULL; +} + +class NativeJump: public NativeInstruction { + public: + enum RISCV_specific_constants { + instruction_size = NativeInstruction::instruction_size, + instruction_offset = 0, + data_offset = 0, + next_instruction_offset = NativeInstruction::instruction_size + }; + + address instruction_address() const { return addr_at(instruction_offset); } + address next_instruction_address() const { return addr_at(instruction_size); } + address jump_destination() const; + void set_jump_destination(address dest); + + // Creation + inline friend NativeJump* nativeJump_at(address address); + + void verify(); + + // Insertion of native jump instruction + static void insert(address code_pos, address entry); + // MT-safe insertion of native jump at verified method entry + static void check_verified_entry_alignment(address entry, address verified_entry); + static void patch_verified_entry(address entry, address verified_entry, address dest); +}; + +inline NativeJump* nativeJump_at(address addr) { + NativeJump* jump = (NativeJump*)(addr - NativeJump::instruction_offset); +#ifdef ASSERT + jump->verify(); +#endif + return jump; +} + +class NativeGeneralJump: public NativeJump { +public: + enum RISCV_specific_constants { + instruction_size = 6 * NativeInstruction::instruction_size, // lui, addi, slli, addi, slli, jalr + instruction_offset = 0, + data_offset = 0, + next_instruction_offset = 6 * NativeInstruction::instruction_size // lui, addi, slli, addi, slli, jalr + }; + + address jump_destination() const; + + static void insert_unconditional(address code_pos, address entry); + static void replace_mt_safe(address instr_addr, address code_buffer); +}; + +inline NativeGeneralJump* nativeGeneralJump_at(address addr) { + assert_cond(addr != NULL); + NativeGeneralJump* jump = (NativeGeneralJump*)(addr); + debug_only(jump->verify();) + return jump; +} + +class NativeIllegalInstruction: public NativeInstruction { + public: + // Insert illegal opcode as specific address + static void insert(address code_pos); +}; + +inline bool NativeInstruction::is_nop() { + uint32_t insn = *(uint32_t*)addr_at(0); + return insn == 0x13; +} + +inline bool NativeInstruction::is_jump_or_nop() { + return is_nop() || is_jump(); +} + +// Call trampoline stubs. +class NativeCallTrampolineStub : public NativeInstruction { + public: + + enum RISCV_specific_constants { + // Refer to function emit_trampoline_stub. + instruction_size = 3 * NativeInstruction::instruction_size + wordSize, // auipc + ld + jr + target address + data_offset = 3 * NativeInstruction::instruction_size, // auipc + ld + jr + }; + + address destination(nmethod *nm = NULL) const; + void set_destination(address new_destination); + ptrdiff_t destination_offset() const; +}; + +inline bool is_NativeCallTrampolineStub_at(address addr) { + // Ensure that the stub is exactly + // ld t0, L--->auipc + ld + // jr t0 + // L: + + // judge inst + register + imm + // 1). check the instructions: auipc + ld + jalr + // 2). check if auipc[11:7] == t0 and ld[11:7] == t0 and ld[19:15] == t0 && jr[19:15] == t0 + // 3). check if the offset in ld[31:20] equals the data_offset + assert_cond(addr != NULL); + const int instr_size = NativeInstruction::instruction_size; + if (NativeInstruction::is_auipc_at(addr) && + NativeInstruction::is_ld_at(addr + instr_size) && + NativeInstruction::is_jalr_at(addr + 2 * instr_size) && + (NativeInstruction::extract_rd(addr) == x5) && + (NativeInstruction::extract_rd(addr + instr_size) == x5) && + (NativeInstruction::extract_rs1(addr + instr_size) == x5) && + (NativeInstruction::extract_rs1(addr + 2 * instr_size) == x5) && + (Assembler::extract(((unsigned*)addr)[1], 31, 20) == NativeCallTrampolineStub::data_offset)) { + return true; + } + return false; +} + +inline NativeCallTrampolineStub* nativeCallTrampolineStub_at(address addr) { + assert_cond(addr != NULL); + assert(is_NativeCallTrampolineStub_at(addr), "no call trampoline found"); + return (NativeCallTrampolineStub*)addr; +} + +class NativeMembar : public NativeInstruction { +public: + uint32_t get_kind(); + void set_kind(uint32_t order_kind); +}; + +inline NativeMembar *NativeMembar_at(address addr) { + assert_cond(addr != NULL); + assert(nativeInstruction_at(addr)->is_membar(), "no membar found"); + return (NativeMembar*)addr; +} + +class NativeFenceI : public NativeInstruction { +public: + static inline int instruction_size() { + // 2 for fence.i + fence + return (UseConservativeFence ? 2 : 1) * NativeInstruction::instruction_size; + } +}; + +#endif // CPU_RISCV_NATIVEINST_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/registerMap_riscv.cpp b/src/hotspot/cpu/riscv/registerMap_riscv.cpp new file mode 100644 index 00000000000..26c1edc36ff --- /dev/null +++ b/src/hotspot/cpu/riscv/registerMap_riscv.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "runtime/registerMap.hpp" +#include "vmreg_riscv.inline.hpp" + +address RegisterMap::pd_location(VMReg base_reg, int slot_idx) const { + if (base_reg->is_VectorRegister()) { + assert(base_reg->is_concrete(), "must pass base reg"); + int base_reg_enc = (base_reg->value() - ConcreteRegisterImpl::max_fpr) / + VectorRegisterImpl::max_slots_per_register; + intptr_t offset_in_bytes = slot_idx * VMRegImpl::stack_slot_size; + address base_location = location(base_reg); + if (base_location != NULL) { + return base_location + offset_in_bytes; + } else { + return NULL; + } + } else { + return location(base_reg->next(slot_idx)); + } +} diff --git a/src/hotspot/cpu/riscv/registerMap_riscv.hpp b/src/hotspot/cpu/riscv/registerMap_riscv.hpp new file mode 100644 index 00000000000..f34349811a9 --- /dev/null +++ b/src/hotspot/cpu/riscv/registerMap_riscv.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_REGISTERMAP_RISCV_HPP +#define CPU_RISCV_REGISTERMAP_RISCV_HPP + +// machine-dependent implemention for register maps + friend class frame; + + private: + // This is the hook for finding a register in an "well-known" location, + // such as a register block of a predetermined format. + address pd_location(VMReg reg) const { return NULL; } + address pd_location(VMReg base_reg, int slot_idx) const; + + // no PD state to clear or copy: + void pd_clear() {} + void pd_initialize() {} + void pd_initialize_from(const RegisterMap* map) {} + +#endif // CPU_RISCV_REGISTERMAP_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/register_riscv.cpp b/src/hotspot/cpu/riscv/register_riscv.cpp new file mode 100644 index 00000000000..f8116e9df8c --- /dev/null +++ b/src/hotspot/cpu/riscv/register_riscv.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "register_riscv.hpp" + +REGISTER_IMPL_DEFINITION(Register, RegisterImpl, RegisterImpl::number_of_registers); +REGISTER_IMPL_DEFINITION(FloatRegister, FloatRegisterImpl, FloatRegisterImpl::number_of_registers); +REGISTER_IMPL_DEFINITION(VectorRegister, VectorRegisterImpl, VectorRegisterImpl::number_of_registers); + +const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers * + RegisterImpl::max_slots_per_register; + +const int ConcreteRegisterImpl::max_fpr = + ConcreteRegisterImpl::max_gpr + + FloatRegisterImpl::number_of_registers * FloatRegisterImpl::max_slots_per_register; + +const int ConcreteRegisterImpl::max_vpr = + ConcreteRegisterImpl::max_fpr + + VectorRegisterImpl::number_of_registers * VectorRegisterImpl::max_slots_per_register; + + +const char* RegisterImpl::name() const { + static const char *const names[number_of_registers] = { + "zr", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "x9", + "c_rarg0", "c_rarg1", "c_rarg2", "c_rarg3", "c_rarg4", "c_rarg5", "c_rarg6", "c_rarg7", + "x18", "x19", "esp", "xdispatch", "xbcp", "xthread", "xlocals", + "xmonitors", "xcpool", "xheapbase", "x28", "x29", "x30", "xmethod" + }; + return is_valid() ? names[encoding()] : "noreg"; +} + +const char* FloatRegisterImpl::name() const { + static const char *const names[number_of_registers] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + }; + return is_valid() ? names[encoding()] : "noreg"; +} + +const char* VectorRegisterImpl::name() const { + static const char *const names[number_of_registers] = { + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" + }; + return is_valid() ? names[encoding()] : "noreg"; +} diff --git a/src/hotspot/cpu/riscv/register_riscv.hpp b/src/hotspot/cpu/riscv/register_riscv.hpp new file mode 100644 index 00000000000..a9200cac647 --- /dev/null +++ b/src/hotspot/cpu/riscv/register_riscv.hpp @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_REGISTER_RISCV_HPP +#define CPU_RISCV_REGISTER_RISCV_HPP + +#include "asm/register.hpp" + +#define CSR_FFLAGS 0x001 // Floating-Point Accrued Exceptions. +#define CSR_FRM 0x002 // Floating-Point Dynamic Rounding Mode. +#define CSR_FCSR 0x003 // Floating-Point Control and Status Register (frm + fflags). +#define CSR_VSTART 0x008 // Vector start position +#define CSR_VXSAT 0x009 // Fixed-Point Saturate Flag +#define CSR_VXRM 0x00A // Fixed-Point Rounding Mode +#define CSR_VCSR 0x00F // Vector control and status register +#define CSR_VL 0xC20 // Vector length +#define CSR_VTYPE 0xC21 // Vector data type register +#define CSR_VLENB 0xC22 // VLEN/8 (vector register length in bytes) +#define CSR_CYCLE 0xc00 // Cycle counter for RDCYCLE instruction. +#define CSR_TIME 0xc01 // Timer for RDTIME instruction. +#define CSR_INSTERT 0xc02 // Instructions-retired counter for RDINSTRET instruction. + +class VMRegImpl; +typedef VMRegImpl* VMReg; + +// Use Register as shortcut +class RegisterImpl; +typedef const RegisterImpl* Register; + +inline constexpr Register as_Register(int encoding); + +class RegisterImpl: public AbstractRegisterImpl { + static constexpr Register first(); + + public: + enum { + number_of_registers = 32, + max_slots_per_register = 2, + + // integer registers x8 - x15 and floating-point registers f8 - f15 are allocatable + // for compressed instructions. See Table 17.2 in spec. + compressed_register_base = 8, + compressed_register_top = 15, + }; + + // derived registers, offsets, and addresses + const Register successor() const { return this + 1; } + + // construction + inline friend constexpr Register as_Register(int encoding); + + VMReg as_VMReg() const; + + // accessors + int encoding() const { assert(is_valid(), "invalid register"); return encoding_nocheck(); } + int encoding_nocheck() const { return this - first(); } + bool is_valid() const { return (unsigned)encoding_nocheck() < number_of_registers; } + const char* name() const; + + // for rvc + int compressed_encoding() const { + assert(is_compressed_valid(), "invalid compressed register"); + return encoding() - compressed_register_base; + } + + int compressed_encoding_nocheck() const { + return encoding_nocheck() - compressed_register_base; + } + + bool is_compressed_valid() const { + return encoding_nocheck() >= compressed_register_base && + encoding_nocheck() <= compressed_register_top; + } +}; + +REGISTER_IMPL_DECLARATION(Register, RegisterImpl, RegisterImpl::number_of_registers); + +// The integer registers of the RISCV architecture + +CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1)); + +CONSTANT_REGISTER_DECLARATION(Register, x0, (0)); +CONSTANT_REGISTER_DECLARATION(Register, x1, (1)); +CONSTANT_REGISTER_DECLARATION(Register, x2, (2)); +CONSTANT_REGISTER_DECLARATION(Register, x3, (3)); +CONSTANT_REGISTER_DECLARATION(Register, x4, (4)); +CONSTANT_REGISTER_DECLARATION(Register, x5, (5)); +CONSTANT_REGISTER_DECLARATION(Register, x6, (6)); +CONSTANT_REGISTER_DECLARATION(Register, x7, (7)); +CONSTANT_REGISTER_DECLARATION(Register, x8, (8)); +CONSTANT_REGISTER_DECLARATION(Register, x9, (9)); +CONSTANT_REGISTER_DECLARATION(Register, x10, (10)); +CONSTANT_REGISTER_DECLARATION(Register, x11, (11)); +CONSTANT_REGISTER_DECLARATION(Register, x12, (12)); +CONSTANT_REGISTER_DECLARATION(Register, x13, (13)); +CONSTANT_REGISTER_DECLARATION(Register, x14, (14)); +CONSTANT_REGISTER_DECLARATION(Register, x15, (15)); +CONSTANT_REGISTER_DECLARATION(Register, x16, (16)); +CONSTANT_REGISTER_DECLARATION(Register, x17, (17)); +CONSTANT_REGISTER_DECLARATION(Register, x18, (18)); +CONSTANT_REGISTER_DECLARATION(Register, x19, (19)); +CONSTANT_REGISTER_DECLARATION(Register, x20, (20)); +CONSTANT_REGISTER_DECLARATION(Register, x21, (21)); +CONSTANT_REGISTER_DECLARATION(Register, x22, (22)); +CONSTANT_REGISTER_DECLARATION(Register, x23, (23)); +CONSTANT_REGISTER_DECLARATION(Register, x24, (24)); +CONSTANT_REGISTER_DECLARATION(Register, x25, (25)); +CONSTANT_REGISTER_DECLARATION(Register, x26, (26)); +CONSTANT_REGISTER_DECLARATION(Register, x27, (27)); +CONSTANT_REGISTER_DECLARATION(Register, x28, (28)); +CONSTANT_REGISTER_DECLARATION(Register, x29, (29)); +CONSTANT_REGISTER_DECLARATION(Register, x30, (30)); +CONSTANT_REGISTER_DECLARATION(Register, x31, (31)); + +// Use FloatRegister as shortcut +class FloatRegisterImpl; +typedef const FloatRegisterImpl* FloatRegister; + +inline constexpr FloatRegister as_FloatRegister(int encoding); + +// The implementation of floating point registers for the architecture +class FloatRegisterImpl: public AbstractRegisterImpl { + static constexpr FloatRegister first(); + + public: + enum { + number_of_registers = 32, + max_slots_per_register = 2, + + // float registers in the range of [f8~f15] correspond to RVC. Please see Table 16.2 in spec. + compressed_register_base = 8, + compressed_register_top = 15, + }; + + // construction + inline friend constexpr FloatRegister as_FloatRegister(int encoding); + + VMReg as_VMReg() const; + + // derived registers, offsets, and addresses + FloatRegister successor() const { + return as_FloatRegister((encoding() + 1) % (unsigned)number_of_registers); + } + + // accessors + int encoding() const { assert(is_valid(), "invalid register"); return encoding_nocheck(); } + int encoding_nocheck() const { return this - first(); } + int is_valid() const { return (unsigned)encoding_nocheck() < number_of_registers; } + const char* name() const; + + // for rvc + int compressed_encoding() const { + assert(is_compressed_valid(), "invalid compressed register"); + return encoding() - compressed_register_base; + } + + int compressed_encoding_nocheck() const { + return encoding_nocheck() - compressed_register_base; + } + + bool is_compressed_valid() const { + return encoding_nocheck() >= compressed_register_base && + encoding_nocheck() <= compressed_register_top; + } +}; + +REGISTER_IMPL_DECLARATION(FloatRegister, FloatRegisterImpl, FloatRegisterImpl::number_of_registers); + +// The float registers of the RISCV architecture + +CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg , (-1)); + +CONSTANT_REGISTER_DECLARATION(FloatRegister, f0 , ( 0)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f1 , ( 1)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f2 , ( 2)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f3 , ( 3)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f4 , ( 4)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f5 , ( 5)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f6 , ( 6)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f7 , ( 7)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f8 , ( 8)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f9 , ( 9)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f10 , (10)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f11 , (11)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f12 , (12)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f13 , (13)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f14 , (14)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f15 , (15)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f16 , (16)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f17 , (17)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f18 , (18)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f19 , (19)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f20 , (20)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f21 , (21)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f22 , (22)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f23 , (23)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f24 , (24)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f25 , (25)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f26 , (26)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f27 , (27)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f28 , (28)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f29 , (29)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f30 , (30)); +CONSTANT_REGISTER_DECLARATION(FloatRegister, f31 , (31)); + +// Use VectorRegister as shortcut +class VectorRegisterImpl; +typedef const VectorRegisterImpl* VectorRegister; + +inline constexpr VectorRegister as_VectorRegister(int encoding); + +// The implementation of vector registers for RVV +class VectorRegisterImpl: public AbstractRegisterImpl { + static constexpr VectorRegister first(); + + public: + enum { + number_of_registers = 32, + max_slots_per_register = 4 + }; + + // construction + inline friend constexpr VectorRegister as_VectorRegister(int encoding); + + VMReg as_VMReg() const; + + // derived registers, offsets, and addresses + VectorRegister successor() const { return this + 1; } + + // accessors + int encoding() const { assert(is_valid(), "invalid register"); return encoding_nocheck(); } + int encoding_nocheck() const { return this - first(); } + bool is_valid() const { return (unsigned)encoding_nocheck() < number_of_registers; } + const char* name() const; + +}; + +REGISTER_IMPL_DECLARATION(VectorRegister, VectorRegisterImpl, VectorRegisterImpl::number_of_registers); + +// The vector registers of RVV +CONSTANT_REGISTER_DECLARATION(VectorRegister, vnoreg , (-1)); + +CONSTANT_REGISTER_DECLARATION(VectorRegister, v0 , ( 0)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v1 , ( 1)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v2 , ( 2)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v3 , ( 3)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v4 , ( 4)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v5 , ( 5)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v6 , ( 6)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v7 , ( 7)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v8 , ( 8)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v9 , ( 9)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v10 , (10)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v11 , (11)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v12 , (12)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v13 , (13)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v14 , (14)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v15 , (15)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v16 , (16)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v17 , (17)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v18 , (18)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v19 , (19)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v20 , (20)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v21 , (21)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v22 , (22)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v23 , (23)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v24 , (24)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v25 , (25)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v26 , (26)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v27 , (27)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v28 , (28)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v29 , (29)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v30 , (30)); +CONSTANT_REGISTER_DECLARATION(VectorRegister, v31 , (31)); + + +// Need to know the total number of registers of all sorts for SharedInfo. +// Define a class that exports it. +class ConcreteRegisterImpl : public AbstractRegisterImpl { + public: + enum { + // A big enough number for C2: all the registers plus flags + // This number must be large enough to cover REG_COUNT (defined by c2) registers. + // There is no requirement that any ordering here matches any ordering c2 gives + // it's optoregs. + + number_of_registers = (RegisterImpl::max_slots_per_register * RegisterImpl::number_of_registers + + FloatRegisterImpl::max_slots_per_register * FloatRegisterImpl::number_of_registers + + VectorRegisterImpl::max_slots_per_register * VectorRegisterImpl::number_of_registers) + }; + + // added to make it compile + static const int max_gpr; + static const int max_fpr; + static const int max_vpr; +}; + +typedef AbstractRegSet RegSet; +typedef AbstractRegSet FloatRegSet; +typedef AbstractRegSet VectorRegSet; + +#endif // CPU_RISCV_REGISTER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp new file mode 100644 index 00000000000..228a64eae2c --- /dev/null +++ b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "code/relocInfo.hpp" +#include "nativeInst_riscv.hpp" +#include "oops/oop.inline.hpp" +#include "runtime/safepoint.hpp" + +void Relocation::pd_set_data_value(address x, intptr_t o, bool verify_only) { + if (verify_only) { + return; + } + + int bytes; + + switch (type()) { + case relocInfo::oop_type: { + oop_Relocation *reloc = (oop_Relocation *)this; + // in movoop when BarrierSet::barrier_set()->barrier_set_nmethod() != NULL || !immediate + if (NativeInstruction::is_load_pc_relative_at(addr())) { + address constptr = (address)code()->oop_addr_at(reloc->oop_index()); + bytes = MacroAssembler::pd_patch_instruction_size(addr(), constptr); + assert(*(address*)constptr == x, "error in oop relocation"); + } else { + bytes = MacroAssembler::patch_oop(addr(), x); + } + break; + } + default: + bytes = MacroAssembler::pd_patch_instruction_size(addr(), x); + break; + } + ICache::invalidate_range(addr(), bytes); +} + +address Relocation::pd_call_destination(address orig_addr) { + assert(is_call(), "should be an address instruction here"); + if (NativeCall::is_call_at(addr())) { + address trampoline = nativeCall_at(addr())->get_trampoline(); + if (trampoline != NULL) { + return nativeCallTrampolineStub_at(trampoline)->destination(); + } + } + if (orig_addr != NULL) { + // the extracted address from the instructions in address orig_addr + address new_addr = MacroAssembler::pd_call_destination(orig_addr); + // If call is branch to self, don't try to relocate it, just leave it + // as branch to self. This happens during code generation if the code + // buffer expands. It will be relocated to the trampoline above once + // code generation is complete. + new_addr = (new_addr == orig_addr) ? addr() : new_addr; + return new_addr; + } + return MacroAssembler::pd_call_destination(addr()); +} + +void Relocation::pd_set_call_destination(address x) { + assert(is_call(), "should be an address instruction here"); + if (NativeCall::is_call_at(addr())) { + address trampoline = nativeCall_at(addr())->get_trampoline(); + if (trampoline != NULL) { + nativeCall_at(addr())->set_destination_mt_safe(x, /* assert_lock */false); + return; + } + } + MacroAssembler::pd_patch_instruction_size(addr(), x); + address pd_call = pd_call_destination(addr()); + assert(pd_call == x, "fail in reloc"); +} + +address* Relocation::pd_address_in_code() { + assert(NativeCall::is_load_pc_relative_at(addr()), "Not the expected instruction sequence!"); + return (address*)(MacroAssembler::target_addr_for_insn(addr())); +} + +address Relocation::pd_get_address_from_code() { + return MacroAssembler::pd_call_destination(addr()); +} + +void poll_Relocation::fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest) { + if (NativeInstruction::maybe_cpool_ref(addr())) { + address old_addr = old_addr_for(addr(), src, dest); + MacroAssembler::pd_patch_instruction_size(addr(), MacroAssembler::target_addr_for_insn(old_addr)); + } +} + +void metadata_Relocation::pd_fix_value(address x) { +} diff --git a/src/hotspot/cpu/riscv/relocInfo_riscv.hpp b/src/hotspot/cpu/riscv/relocInfo_riscv.hpp new file mode 100644 index 00000000000..840ed935d88 --- /dev/null +++ b/src/hotspot/cpu/riscv/relocInfo_riscv.hpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_RELOCINFO_RISCV_HPP +#define CPU_RISCV_RELOCINFO_RISCV_HPP + + // machine-dependent parts of class relocInfo + private: + enum { + // Relocations are byte-aligned. + offset_unit = 1, + // Must be at least 1 for RelocInfo::narrow_oop_in_const. + format_width = 1 + }; + + public: + + // This platform has no oops in the code that are not also + // listed in the oop section. + static bool mustIterateImmediateOopsInCode() { return false; } + +#endif // CPU_RISCV_RELOCINFO_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad new file mode 100644 index 00000000000..588887e1d96 --- /dev/null +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -0,0 +1,10611 @@ +// +// Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. +// Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. +// +// + +// RISCV Architecture Description File + +//----------REGISTER DEFINITION BLOCK------------------------------------------ +// This information is used by the matcher and the register allocator to +// describe individual registers and classes of registers within the target +// archtecture. + +register %{ +//----------Architecture Description Register Definitions---------------------- +// General Registers +// "reg_def" name ( register save type, C convention save type, +// ideal register type, encoding ); +// Register Save Types: +// +// NS = No-Save: The register allocator assumes that these registers +// can be used without saving upon entry to the method, & +// that they do not need to be saved at call sites. +// +// SOC = Save-On-Call: The register allocator assumes that these registers +// can be used without saving upon entry to the method, +// but that they must be saved at call sites. +// +// SOE = Save-On-Entry: The register allocator assumes that these registers +// must be saved before using them upon entry to the +// method, but they do not need to be saved at call +// sites. +// +// AS = Always-Save: The register allocator assumes that these registers +// must be saved before using them upon entry to the +// method, & that they must be saved at call sites. +// +// Ideal Register Type is used to determine how to save & restore a +// register. Op_RegI will get spilled with LoadI/StoreI, Op_RegP will get +// spilled with LoadP/StoreP. If the register supports both, use Op_RegI. +// +// The encoding number is the actual bit-pattern placed into the opcodes. + +// We must define the 64 bit int registers in two 32 bit halves, the +// real lower register and a virtual upper half register. upper halves +// are used by the register allocator but are not actually supplied as +// operands to memory ops. +// +// follow the C1 compiler in making registers +// +// x7, x9-x17, x27-x31 volatile (caller save) +// x0-x4, x8, x23 system (no save, no allocate) +// x5-x6 non-allocatable (so we can use them as temporary regs) + +// +// as regards Java usage. we don't use any callee save registers +// because this makes it difficult to de-optimise a frame (see comment +// in x86 implementation of Deoptimization::unwind_callee_save_values) +// + +// General Registers + +reg_def R0 ( NS, NS, Op_RegI, 0, x0->as_VMReg() ); // zr +reg_def R0_H ( NS, NS, Op_RegI, 0, x0->as_VMReg()->next() ); +reg_def R1 ( NS, SOC, Op_RegI, 1, x1->as_VMReg() ); // ra +reg_def R1_H ( NS, SOC, Op_RegI, 1, x1->as_VMReg()->next() ); +reg_def R2 ( NS, SOE, Op_RegI, 2, x2->as_VMReg() ); // sp +reg_def R2_H ( NS, SOE, Op_RegI, 2, x2->as_VMReg()->next() ); +reg_def R3 ( NS, NS, Op_RegI, 3, x3->as_VMReg() ); // gp +reg_def R3_H ( NS, NS, Op_RegI, 3, x3->as_VMReg()->next() ); +reg_def R4 ( NS, NS, Op_RegI, 4, x4->as_VMReg() ); // tp +reg_def R4_H ( NS, NS, Op_RegI, 4, x4->as_VMReg()->next() ); +reg_def R7 ( SOC, SOC, Op_RegI, 7, x7->as_VMReg() ); +reg_def R7_H ( SOC, SOC, Op_RegI, 7, x7->as_VMReg()->next() ); +reg_def R8 ( NS, SOE, Op_RegI, 8, x8->as_VMReg() ); // fp +reg_def R8_H ( NS, SOE, Op_RegI, 8, x8->as_VMReg()->next() ); +reg_def R9 ( SOC, SOE, Op_RegI, 9, x9->as_VMReg() ); +reg_def R9_H ( SOC, SOE, Op_RegI, 9, x9->as_VMReg()->next() ); +reg_def R10 ( SOC, SOC, Op_RegI, 10, x10->as_VMReg() ); +reg_def R10_H ( SOC, SOC, Op_RegI, 10, x10->as_VMReg()->next()); +reg_def R11 ( SOC, SOC, Op_RegI, 11, x11->as_VMReg() ); +reg_def R11_H ( SOC, SOC, Op_RegI, 11, x11->as_VMReg()->next()); +reg_def R12 ( SOC, SOC, Op_RegI, 12, x12->as_VMReg() ); +reg_def R12_H ( SOC, SOC, Op_RegI, 12, x12->as_VMReg()->next()); +reg_def R13 ( SOC, SOC, Op_RegI, 13, x13->as_VMReg() ); +reg_def R13_H ( SOC, SOC, Op_RegI, 13, x13->as_VMReg()->next()); +reg_def R14 ( SOC, SOC, Op_RegI, 14, x14->as_VMReg() ); +reg_def R14_H ( SOC, SOC, Op_RegI, 14, x14->as_VMReg()->next()); +reg_def R15 ( SOC, SOC, Op_RegI, 15, x15->as_VMReg() ); +reg_def R15_H ( SOC, SOC, Op_RegI, 15, x15->as_VMReg()->next()); +reg_def R16 ( SOC, SOC, Op_RegI, 16, x16->as_VMReg() ); +reg_def R16_H ( SOC, SOC, Op_RegI, 16, x16->as_VMReg()->next()); +reg_def R17 ( SOC, SOC, Op_RegI, 17, x17->as_VMReg() ); +reg_def R17_H ( SOC, SOC, Op_RegI, 17, x17->as_VMReg()->next()); +reg_def R18 ( SOC, SOE, Op_RegI, 18, x18->as_VMReg() ); +reg_def R18_H ( SOC, SOE, Op_RegI, 18, x18->as_VMReg()->next()); +reg_def R19 ( SOC, SOE, Op_RegI, 19, x19->as_VMReg() ); +reg_def R19_H ( SOC, SOE, Op_RegI, 19, x19->as_VMReg()->next()); +reg_def R20 ( SOC, SOE, Op_RegI, 20, x20->as_VMReg() ); // caller esp +reg_def R20_H ( SOC, SOE, Op_RegI, 20, x20->as_VMReg()->next()); +reg_def R21 ( SOC, SOE, Op_RegI, 21, x21->as_VMReg() ); +reg_def R21_H ( SOC, SOE, Op_RegI, 21, x21->as_VMReg()->next()); +reg_def R22 ( SOC, SOE, Op_RegI, 22, x22->as_VMReg() ); +reg_def R22_H ( SOC, SOE, Op_RegI, 22, x22->as_VMReg()->next()); +reg_def R23 ( NS, SOE, Op_RegI, 23, x23->as_VMReg() ); // java thread +reg_def R23_H ( NS, SOE, Op_RegI, 23, x23->as_VMReg()->next()); +reg_def R24 ( SOC, SOE, Op_RegI, 24, x24->as_VMReg() ); +reg_def R24_H ( SOC, SOE, Op_RegI, 24, x24->as_VMReg()->next()); +reg_def R25 ( SOC, SOE, Op_RegI, 25, x25->as_VMReg() ); +reg_def R25_H ( SOC, SOE, Op_RegI, 25, x25->as_VMReg()->next()); +reg_def R26 ( SOC, SOE, Op_RegI, 26, x26->as_VMReg() ); +reg_def R26_H ( SOC, SOE, Op_RegI, 26, x26->as_VMReg()->next()); +reg_def R27 ( SOC, SOE, Op_RegI, 27, x27->as_VMReg() ); // heapbase +reg_def R27_H ( SOC, SOE, Op_RegI, 27, x27->as_VMReg()->next()); +reg_def R28 ( SOC, SOC, Op_RegI, 28, x28->as_VMReg() ); +reg_def R28_H ( SOC, SOC, Op_RegI, 28, x28->as_VMReg()->next()); +reg_def R29 ( SOC, SOC, Op_RegI, 29, x29->as_VMReg() ); +reg_def R29_H ( SOC, SOC, Op_RegI, 29, x29->as_VMReg()->next()); +reg_def R30 ( SOC, SOC, Op_RegI, 30, x30->as_VMReg() ); +reg_def R30_H ( SOC, SOC, Op_RegI, 30, x30->as_VMReg()->next()); +reg_def R31 ( SOC, SOC, Op_RegI, 31, x31->as_VMReg() ); +reg_def R31_H ( SOC, SOC, Op_RegI, 31, x31->as_VMReg()->next()); + +// ---------------------------- +// Float/Double Registers +// ---------------------------- + +// Double Registers + +// The rules of ADL require that double registers be defined in pairs. +// Each pair must be two 32-bit values, but not necessarily a pair of +// single float registers. In each pair, ADLC-assigned register numbers +// must be adjacent, with the lower number even. Finally, when the +// CPU stores such a register pair to memory, the word associated with +// the lower ADLC-assigned number must be stored to the lower address. + +// RISCV has 32 floating-point registers. Each can store a single +// or double precision floating-point value. + +// for Java use float registers f0-f31 are always save on call whereas +// the platform ABI treats f8-f9 and f18-f27 as callee save). Other +// float registers are SOC as per the platform spec + +reg_def F0 ( SOC, SOC, Op_RegF, 0, f0->as_VMReg() ); +reg_def F0_H ( SOC, SOC, Op_RegF, 0, f0->as_VMReg()->next() ); +reg_def F1 ( SOC, SOC, Op_RegF, 1, f1->as_VMReg() ); +reg_def F1_H ( SOC, SOC, Op_RegF, 1, f1->as_VMReg()->next() ); +reg_def F2 ( SOC, SOC, Op_RegF, 2, f2->as_VMReg() ); +reg_def F2_H ( SOC, SOC, Op_RegF, 2, f2->as_VMReg()->next() ); +reg_def F3 ( SOC, SOC, Op_RegF, 3, f3->as_VMReg() ); +reg_def F3_H ( SOC, SOC, Op_RegF, 3, f3->as_VMReg()->next() ); +reg_def F4 ( SOC, SOC, Op_RegF, 4, f4->as_VMReg() ); +reg_def F4_H ( SOC, SOC, Op_RegF, 4, f4->as_VMReg()->next() ); +reg_def F5 ( SOC, SOC, Op_RegF, 5, f5->as_VMReg() ); +reg_def F5_H ( SOC, SOC, Op_RegF, 5, f5->as_VMReg()->next() ); +reg_def F6 ( SOC, SOC, Op_RegF, 6, f6->as_VMReg() ); +reg_def F6_H ( SOC, SOC, Op_RegF, 6, f6->as_VMReg()->next() ); +reg_def F7 ( SOC, SOC, Op_RegF, 7, f7->as_VMReg() ); +reg_def F7_H ( SOC, SOC, Op_RegF, 7, f7->as_VMReg()->next() ); +reg_def F8 ( SOC, SOE, Op_RegF, 8, f8->as_VMReg() ); +reg_def F8_H ( SOC, SOE, Op_RegF, 8, f8->as_VMReg()->next() ); +reg_def F9 ( SOC, SOE, Op_RegF, 9, f9->as_VMReg() ); +reg_def F9_H ( SOC, SOE, Op_RegF, 9, f9->as_VMReg()->next() ); +reg_def F10 ( SOC, SOC, Op_RegF, 10, f10->as_VMReg() ); +reg_def F10_H ( SOC, SOC, Op_RegF, 10, f10->as_VMReg()->next() ); +reg_def F11 ( SOC, SOC, Op_RegF, 11, f11->as_VMReg() ); +reg_def F11_H ( SOC, SOC, Op_RegF, 11, f11->as_VMReg()->next() ); +reg_def F12 ( SOC, SOC, Op_RegF, 12, f12->as_VMReg() ); +reg_def F12_H ( SOC, SOC, Op_RegF, 12, f12->as_VMReg()->next() ); +reg_def F13 ( SOC, SOC, Op_RegF, 13, f13->as_VMReg() ); +reg_def F13_H ( SOC, SOC, Op_RegF, 13, f13->as_VMReg()->next() ); +reg_def F14 ( SOC, SOC, Op_RegF, 14, f14->as_VMReg() ); +reg_def F14_H ( SOC, SOC, Op_RegF, 14, f14->as_VMReg()->next() ); +reg_def F15 ( SOC, SOC, Op_RegF, 15, f15->as_VMReg() ); +reg_def F15_H ( SOC, SOC, Op_RegF, 15, f15->as_VMReg()->next() ); +reg_def F16 ( SOC, SOC, Op_RegF, 16, f16->as_VMReg() ); +reg_def F16_H ( SOC, SOC, Op_RegF, 16, f16->as_VMReg()->next() ); +reg_def F17 ( SOC, SOC, Op_RegF, 17, f17->as_VMReg() ); +reg_def F17_H ( SOC, SOC, Op_RegF, 17, f17->as_VMReg()->next() ); +reg_def F18 ( SOC, SOE, Op_RegF, 18, f18->as_VMReg() ); +reg_def F18_H ( SOC, SOE, Op_RegF, 18, f18->as_VMReg()->next() ); +reg_def F19 ( SOC, SOE, Op_RegF, 19, f19->as_VMReg() ); +reg_def F19_H ( SOC, SOE, Op_RegF, 19, f19->as_VMReg()->next() ); +reg_def F20 ( SOC, SOE, Op_RegF, 20, f20->as_VMReg() ); +reg_def F20_H ( SOC, SOE, Op_RegF, 20, f20->as_VMReg()->next() ); +reg_def F21 ( SOC, SOE, Op_RegF, 21, f21->as_VMReg() ); +reg_def F21_H ( SOC, SOE, Op_RegF, 21, f21->as_VMReg()->next() ); +reg_def F22 ( SOC, SOE, Op_RegF, 22, f22->as_VMReg() ); +reg_def F22_H ( SOC, SOE, Op_RegF, 22, f22->as_VMReg()->next() ); +reg_def F23 ( SOC, SOE, Op_RegF, 23, f23->as_VMReg() ); +reg_def F23_H ( SOC, SOE, Op_RegF, 23, f23->as_VMReg()->next() ); +reg_def F24 ( SOC, SOE, Op_RegF, 24, f24->as_VMReg() ); +reg_def F24_H ( SOC, SOE, Op_RegF, 24, f24->as_VMReg()->next() ); +reg_def F25 ( SOC, SOE, Op_RegF, 25, f25->as_VMReg() ); +reg_def F25_H ( SOC, SOE, Op_RegF, 25, f25->as_VMReg()->next() ); +reg_def F26 ( SOC, SOE, Op_RegF, 26, f26->as_VMReg() ); +reg_def F26_H ( SOC, SOE, Op_RegF, 26, f26->as_VMReg()->next() ); +reg_def F27 ( SOC, SOE, Op_RegF, 27, f27->as_VMReg() ); +reg_def F27_H ( SOC, SOE, Op_RegF, 27, f27->as_VMReg()->next() ); +reg_def F28 ( SOC, SOC, Op_RegF, 28, f28->as_VMReg() ); +reg_def F28_H ( SOC, SOC, Op_RegF, 28, f28->as_VMReg()->next() ); +reg_def F29 ( SOC, SOC, Op_RegF, 29, f29->as_VMReg() ); +reg_def F29_H ( SOC, SOC, Op_RegF, 29, f29->as_VMReg()->next() ); +reg_def F30 ( SOC, SOC, Op_RegF, 30, f30->as_VMReg() ); +reg_def F30_H ( SOC, SOC, Op_RegF, 30, f30->as_VMReg()->next() ); +reg_def F31 ( SOC, SOC, Op_RegF, 31, f31->as_VMReg() ); +reg_def F31_H ( SOC, SOC, Op_RegF, 31, f31->as_VMReg()->next() ); + +// ---------------------------- +// Vector Registers +// ---------------------------- + +// For RVV vector registers, we simply extend vector register size to 4 +// 'logical' slots. This is nominally 128 bits but it actually covers +// all possible 'physical' RVV vector register lengths from 128 ~ 1024 +// bits. The 'physical' RVV vector register length is detected during +// startup, so the register allocator is able to identify the correct +// number of bytes needed for an RVV spill/unspill. + +reg_def V0 ( SOC, SOC, Op_VecA, 0, v0->as_VMReg() ); +reg_def V0_H ( SOC, SOC, Op_VecA, 0, v0->as_VMReg()->next() ); +reg_def V0_J ( SOC, SOC, Op_VecA, 0, v0->as_VMReg()->next(2) ); +reg_def V0_K ( SOC, SOC, Op_VecA, 0, v0->as_VMReg()->next(3) ); + +reg_def V1 ( SOC, SOC, Op_VecA, 1, v1->as_VMReg() ); +reg_def V1_H ( SOC, SOC, Op_VecA, 1, v1->as_VMReg()->next() ); +reg_def V1_J ( SOC, SOC, Op_VecA, 1, v1->as_VMReg()->next(2) ); +reg_def V1_K ( SOC, SOC, Op_VecA, 1, v1->as_VMReg()->next(3) ); + +reg_def V2 ( SOC, SOC, Op_VecA, 2, v2->as_VMReg() ); +reg_def V2_H ( SOC, SOC, Op_VecA, 2, v2->as_VMReg()->next() ); +reg_def V2_J ( SOC, SOC, Op_VecA, 2, v2->as_VMReg()->next(2) ); +reg_def V2_K ( SOC, SOC, Op_VecA, 2, v2->as_VMReg()->next(3) ); + +reg_def V3 ( SOC, SOC, Op_VecA, 3, v3->as_VMReg() ); +reg_def V3_H ( SOC, SOC, Op_VecA, 3, v3->as_VMReg()->next() ); +reg_def V3_J ( SOC, SOC, Op_VecA, 3, v3->as_VMReg()->next(2) ); +reg_def V3_K ( SOC, SOC, Op_VecA, 3, v3->as_VMReg()->next(3) ); + +reg_def V4 ( SOC, SOC, Op_VecA, 4, v4->as_VMReg() ); +reg_def V4_H ( SOC, SOC, Op_VecA, 4, v4->as_VMReg()->next() ); +reg_def V4_J ( SOC, SOC, Op_VecA, 4, v4->as_VMReg()->next(2) ); +reg_def V4_K ( SOC, SOC, Op_VecA, 4, v4->as_VMReg()->next(3) ); + +reg_def V5 ( SOC, SOC, Op_VecA, 5, v5->as_VMReg() ); +reg_def V5_H ( SOC, SOC, Op_VecA, 5, v5->as_VMReg()->next() ); +reg_def V5_J ( SOC, SOC, Op_VecA, 5, v5->as_VMReg()->next(2) ); +reg_def V5_K ( SOC, SOC, Op_VecA, 5, v5->as_VMReg()->next(3) ); + +reg_def V6 ( SOC, SOC, Op_VecA, 6, v6->as_VMReg() ); +reg_def V6_H ( SOC, SOC, Op_VecA, 6, v6->as_VMReg()->next() ); +reg_def V6_J ( SOC, SOC, Op_VecA, 6, v6->as_VMReg()->next(2) ); +reg_def V6_K ( SOC, SOC, Op_VecA, 6, v6->as_VMReg()->next(3) ); + +reg_def V7 ( SOC, SOC, Op_VecA, 7, v7->as_VMReg() ); +reg_def V7_H ( SOC, SOC, Op_VecA, 7, v7->as_VMReg()->next() ); +reg_def V7_J ( SOC, SOC, Op_VecA, 7, v7->as_VMReg()->next(2) ); +reg_def V7_K ( SOC, SOC, Op_VecA, 7, v7->as_VMReg()->next(3) ); + +reg_def V8 ( SOC, SOC, Op_VecA, 8, v8->as_VMReg() ); +reg_def V8_H ( SOC, SOC, Op_VecA, 8, v8->as_VMReg()->next() ); +reg_def V8_J ( SOC, SOC, Op_VecA, 8, v8->as_VMReg()->next(2) ); +reg_def V8_K ( SOC, SOC, Op_VecA, 8, v8->as_VMReg()->next(3) ); + +reg_def V9 ( SOC, SOC, Op_VecA, 9, v9->as_VMReg() ); +reg_def V9_H ( SOC, SOC, Op_VecA, 9, v9->as_VMReg()->next() ); +reg_def V9_J ( SOC, SOC, Op_VecA, 9, v9->as_VMReg()->next(2) ); +reg_def V9_K ( SOC, SOC, Op_VecA, 9, v9->as_VMReg()->next(3) ); + +reg_def V10 ( SOC, SOC, Op_VecA, 10, v10->as_VMReg() ); +reg_def V10_H ( SOC, SOC, Op_VecA, 10, v10->as_VMReg()->next() ); +reg_def V10_J ( SOC, SOC, Op_VecA, 10, v10->as_VMReg()->next(2) ); +reg_def V10_K ( SOC, SOC, Op_VecA, 10, v10->as_VMReg()->next(3) ); + +reg_def V11 ( SOC, SOC, Op_VecA, 11, v11->as_VMReg() ); +reg_def V11_H ( SOC, SOC, Op_VecA, 11, v11->as_VMReg()->next() ); +reg_def V11_J ( SOC, SOC, Op_VecA, 11, v11->as_VMReg()->next(2) ); +reg_def V11_K ( SOC, SOC, Op_VecA, 11, v11->as_VMReg()->next(3) ); + +reg_def V12 ( SOC, SOC, Op_VecA, 12, v12->as_VMReg() ); +reg_def V12_H ( SOC, SOC, Op_VecA, 12, v12->as_VMReg()->next() ); +reg_def V12_J ( SOC, SOC, Op_VecA, 12, v12->as_VMReg()->next(2) ); +reg_def V12_K ( SOC, SOC, Op_VecA, 12, v12->as_VMReg()->next(3) ); + +reg_def V13 ( SOC, SOC, Op_VecA, 13, v13->as_VMReg() ); +reg_def V13_H ( SOC, SOC, Op_VecA, 13, v13->as_VMReg()->next() ); +reg_def V13_J ( SOC, SOC, Op_VecA, 13, v13->as_VMReg()->next(2) ); +reg_def V13_K ( SOC, SOC, Op_VecA, 13, v13->as_VMReg()->next(3) ); + +reg_def V14 ( SOC, SOC, Op_VecA, 14, v14->as_VMReg() ); +reg_def V14_H ( SOC, SOC, Op_VecA, 14, v14->as_VMReg()->next() ); +reg_def V14_J ( SOC, SOC, Op_VecA, 14, v14->as_VMReg()->next(2) ); +reg_def V14_K ( SOC, SOC, Op_VecA, 14, v14->as_VMReg()->next(3) ); + +reg_def V15 ( SOC, SOC, Op_VecA, 15, v15->as_VMReg() ); +reg_def V15_H ( SOC, SOC, Op_VecA, 15, v15->as_VMReg()->next() ); +reg_def V15_J ( SOC, SOC, Op_VecA, 15, v15->as_VMReg()->next(2) ); +reg_def V15_K ( SOC, SOC, Op_VecA, 15, v15->as_VMReg()->next(3) ); + +reg_def V16 ( SOC, SOC, Op_VecA, 16, v16->as_VMReg() ); +reg_def V16_H ( SOC, SOC, Op_VecA, 16, v16->as_VMReg()->next() ); +reg_def V16_J ( SOC, SOC, Op_VecA, 16, v16->as_VMReg()->next(2) ); +reg_def V16_K ( SOC, SOC, Op_VecA, 16, v16->as_VMReg()->next(3) ); + +reg_def V17 ( SOC, SOC, Op_VecA, 17, v17->as_VMReg() ); +reg_def V17_H ( SOC, SOC, Op_VecA, 17, v17->as_VMReg()->next() ); +reg_def V17_J ( SOC, SOC, Op_VecA, 17, v17->as_VMReg()->next(2) ); +reg_def V17_K ( SOC, SOC, Op_VecA, 17, v17->as_VMReg()->next(3) ); + +reg_def V18 ( SOC, SOC, Op_VecA, 18, v18->as_VMReg() ); +reg_def V18_H ( SOC, SOC, Op_VecA, 18, v18->as_VMReg()->next() ); +reg_def V18_J ( SOC, SOC, Op_VecA, 18, v18->as_VMReg()->next(2) ); +reg_def V18_K ( SOC, SOC, Op_VecA, 18, v18->as_VMReg()->next(3) ); + +reg_def V19 ( SOC, SOC, Op_VecA, 19, v19->as_VMReg() ); +reg_def V19_H ( SOC, SOC, Op_VecA, 19, v19->as_VMReg()->next() ); +reg_def V19_J ( SOC, SOC, Op_VecA, 19, v19->as_VMReg()->next(2) ); +reg_def V19_K ( SOC, SOC, Op_VecA, 19, v19->as_VMReg()->next(3) ); + +reg_def V20 ( SOC, SOC, Op_VecA, 20, v20->as_VMReg() ); +reg_def V20_H ( SOC, SOC, Op_VecA, 20, v20->as_VMReg()->next() ); +reg_def V20_J ( SOC, SOC, Op_VecA, 20, v20->as_VMReg()->next(2) ); +reg_def V20_K ( SOC, SOC, Op_VecA, 20, v20->as_VMReg()->next(3) ); + +reg_def V21 ( SOC, SOC, Op_VecA, 21, v21->as_VMReg() ); +reg_def V21_H ( SOC, SOC, Op_VecA, 21, v21->as_VMReg()->next() ); +reg_def V21_J ( SOC, SOC, Op_VecA, 21, v21->as_VMReg()->next(2) ); +reg_def V21_K ( SOC, SOC, Op_VecA, 21, v21->as_VMReg()->next(3) ); + +reg_def V22 ( SOC, SOC, Op_VecA, 22, v22->as_VMReg() ); +reg_def V22_H ( SOC, SOC, Op_VecA, 22, v22->as_VMReg()->next() ); +reg_def V22_J ( SOC, SOC, Op_VecA, 22, v22->as_VMReg()->next(2) ); +reg_def V22_K ( SOC, SOC, Op_VecA, 22, v22->as_VMReg()->next(3) ); + +reg_def V23 ( SOC, SOC, Op_VecA, 23, v23->as_VMReg() ); +reg_def V23_H ( SOC, SOC, Op_VecA, 23, v23->as_VMReg()->next() ); +reg_def V23_J ( SOC, SOC, Op_VecA, 23, v23->as_VMReg()->next(2) ); +reg_def V23_K ( SOC, SOC, Op_VecA, 23, v23->as_VMReg()->next(3) ); + +reg_def V24 ( SOC, SOC, Op_VecA, 24, v24->as_VMReg() ); +reg_def V24_H ( SOC, SOC, Op_VecA, 24, v24->as_VMReg()->next() ); +reg_def V24_J ( SOC, SOC, Op_VecA, 24, v24->as_VMReg()->next(2) ); +reg_def V24_K ( SOC, SOC, Op_VecA, 24, v24->as_VMReg()->next(3) ); + +reg_def V25 ( SOC, SOC, Op_VecA, 25, v25->as_VMReg() ); +reg_def V25_H ( SOC, SOC, Op_VecA, 25, v25->as_VMReg()->next() ); +reg_def V25_J ( SOC, SOC, Op_VecA, 25, v25->as_VMReg()->next(2) ); +reg_def V25_K ( SOC, SOC, Op_VecA, 25, v25->as_VMReg()->next(3) ); + +reg_def V26 ( SOC, SOC, Op_VecA, 26, v26->as_VMReg() ); +reg_def V26_H ( SOC, SOC, Op_VecA, 26, v26->as_VMReg()->next() ); +reg_def V26_J ( SOC, SOC, Op_VecA, 26, v26->as_VMReg()->next(2) ); +reg_def V26_K ( SOC, SOC, Op_VecA, 26, v26->as_VMReg()->next(3) ); + +reg_def V27 ( SOC, SOC, Op_VecA, 27, v27->as_VMReg() ); +reg_def V27_H ( SOC, SOC, Op_VecA, 27, v27->as_VMReg()->next() ); +reg_def V27_J ( SOC, SOC, Op_VecA, 27, v27->as_VMReg()->next(2) ); +reg_def V27_K ( SOC, SOC, Op_VecA, 27, v27->as_VMReg()->next(3) ); + +reg_def V28 ( SOC, SOC, Op_VecA, 28, v28->as_VMReg() ); +reg_def V28_H ( SOC, SOC, Op_VecA, 28, v28->as_VMReg()->next() ); +reg_def V28_J ( SOC, SOC, Op_VecA, 28, v28->as_VMReg()->next(2) ); +reg_def V28_K ( SOC, SOC, Op_VecA, 28, v28->as_VMReg()->next(3) ); + +reg_def V29 ( SOC, SOC, Op_VecA, 29, v29->as_VMReg() ); +reg_def V29_H ( SOC, SOC, Op_VecA, 29, v29->as_VMReg()->next() ); +reg_def V29_J ( SOC, SOC, Op_VecA, 29, v29->as_VMReg()->next(2) ); +reg_def V29_K ( SOC, SOC, Op_VecA, 29, v29->as_VMReg()->next(3) ); + +reg_def V30 ( SOC, SOC, Op_VecA, 30, v30->as_VMReg() ); +reg_def V30_H ( SOC, SOC, Op_VecA, 30, v30->as_VMReg()->next() ); +reg_def V30_J ( SOC, SOC, Op_VecA, 30, v30->as_VMReg()->next(2) ); +reg_def V30_K ( SOC, SOC, Op_VecA, 30, v30->as_VMReg()->next(3) ); + +reg_def V31 ( SOC, SOC, Op_VecA, 31, v31->as_VMReg() ); +reg_def V31_H ( SOC, SOC, Op_VecA, 31, v31->as_VMReg()->next() ); +reg_def V31_J ( SOC, SOC, Op_VecA, 31, v31->as_VMReg()->next(2) ); +reg_def V31_K ( SOC, SOC, Op_VecA, 31, v31->as_VMReg()->next(3) ); + +// ---------------------------- +// Special Registers +// ---------------------------- + +// On riscv, the physical flag register is missing, so we use t1 instead, +// to bridge the RegFlag semantics in share/opto + +reg_def RFLAGS (SOC, SOC, Op_RegFlags, 6, x6->as_VMReg() ); + +// Specify priority of register selection within phases of register +// allocation. Highest priority is first. A useful heuristic is to +// give registers a low priority when they are required by machine +// instructions, like EAX and EDX on I486, and choose no-save registers +// before save-on-call, & save-on-call before save-on-entry. Registers +// which participate in fixed calling sequences should come last. +// Registers which are used as pairs must fall on an even boundary. + +alloc_class chunk0( + // volatiles + R7, R7_H, + R28, R28_H, + R29, R29_H, + R30, R30_H, + R31, R31_H, + + // arg registers + R10, R10_H, + R11, R11_H, + R12, R12_H, + R13, R13_H, + R14, R14_H, + R15, R15_H, + R16, R16_H, + R17, R17_H, + + // non-volatiles + R9, R9_H, + R18, R18_H, + R19, R19_H, + R20, R20_H, + R21, R21_H, + R22, R22_H, + R24, R24_H, + R25, R25_H, + R26, R26_H, + + // non-allocatable registers + R23, R23_H, // java thread + R27, R27_H, // heapbase + R4, R4_H, // thread + R8, R8_H, // fp + R0, R0_H, // zero + R1, R1_H, // ra + R2, R2_H, // sp + R3, R3_H, // gp +); + +alloc_class chunk1( + + // no save + F0, F0_H, + F1, F1_H, + F2, F2_H, + F3, F3_H, + F4, F4_H, + F5, F5_H, + F6, F6_H, + F7, F7_H, + F28, F28_H, + F29, F29_H, + F30, F30_H, + F31, F31_H, + + // arg registers + F10, F10_H, + F11, F11_H, + F12, F12_H, + F13, F13_H, + F14, F14_H, + F15, F15_H, + F16, F16_H, + F17, F17_H, + + // non-volatiles + F8, F8_H, + F9, F9_H, + F18, F18_H, + F19, F19_H, + F20, F20_H, + F21, F21_H, + F22, F22_H, + F23, F23_H, + F24, F24_H, + F25, F25_H, + F26, F26_H, + F27, F27_H, +); + +alloc_class chunk2( + V0, V0_H, V0_J, V0_K, + V1, V1_H, V1_J, V1_K, + V2, V2_H, V2_J, V2_K, + V3, V3_H, V3_J, V3_K, + V4, V4_H, V4_J, V4_K, + V5, V5_H, V5_J, V5_K, + V6, V6_H, V6_J, V6_K, + V7, V7_H, V7_J, V7_K, + V8, V8_H, V8_J, V8_K, + V9, V9_H, V9_J, V9_K, + V10, V10_H, V10_J, V10_K, + V11, V11_H, V11_J, V11_K, + V12, V12_H, V12_J, V12_K, + V13, V13_H, V13_J, V13_K, + V14, V14_H, V14_J, V14_K, + V15, V15_H, V15_J, V15_K, + V16, V16_H, V16_J, V16_K, + V17, V17_H, V17_J, V17_K, + V18, V18_H, V18_J, V18_K, + V19, V19_H, V19_J, V19_K, + V20, V20_H, V20_J, V20_K, + V21, V21_H, V21_J, V21_K, + V22, V22_H, V22_J, V22_K, + V23, V23_H, V23_J, V23_K, + V24, V24_H, V24_J, V24_K, + V25, V25_H, V25_J, V25_K, + V26, V26_H, V26_J, V26_K, + V27, V27_H, V27_J, V27_K, + V28, V28_H, V28_J, V28_K, + V29, V29_H, V29_J, V29_K, + V30, V30_H, V30_J, V30_K, + V31, V31_H, V31_J, V31_K, +); + +alloc_class chunk3(RFLAGS); + +//----------Architecture Description Register Classes-------------------------- +// Several register classes are automatically defined based upon information in +// this architecture description. +// 1) reg_class inline_cache_reg ( /* as def'd in frame section */ ) +// 2) reg_class stack_slots( /* one chunk of stack-based "registers" */ ) +// + +// Class for all 32 bit general purpose registers +reg_class all_reg32( + R0, + R1, + R2, + R3, + R4, + R7, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, + R16, + R17, + R18, + R19, + R20, + R21, + R22, + R23, + R24, + R25, + R26, + R27, + R28, + R29, + R30, + R31 +); + +// Class for any 32 bit integer registers (excluding zr) +reg_class any_reg32 %{ + return _ANY_REG32_mask; +%} + +// Singleton class for R10 int register +reg_class int_r10_reg(R10); + +// Singleton class for R12 int register +reg_class int_r12_reg(R12); + +// Singleton class for R13 int register +reg_class int_r13_reg(R13); + +// Singleton class for R14 int register +reg_class int_r14_reg(R14); + +// Class for all long integer registers +reg_class all_reg( + R0, R0_H, + R1, R1_H, + R2, R2_H, + R3, R3_H, + R4, R4_H, + R7, R7_H, + R8, R8_H, + R9, R9_H, + R10, R10_H, + R11, R11_H, + R12, R12_H, + R13, R13_H, + R14, R14_H, + R15, R15_H, + R16, R16_H, + R17, R17_H, + R18, R18_H, + R19, R19_H, + R20, R20_H, + R21, R21_H, + R22, R22_H, + R23, R23_H, + R24, R24_H, + R25, R25_H, + R26, R26_H, + R27, R27_H, + R28, R28_H, + R29, R29_H, + R30, R30_H, + R31, R31_H +); + +// Class for all long integer registers (excluding zr) +reg_class any_reg %{ + return _ANY_REG_mask; +%} + +// Class for non-allocatable 32 bit registers +reg_class non_allocatable_reg32( + R0, // zr + R1, // ra + R2, // sp + R3, // gp + R4, // tp + R23 // java thread +); + +// Class for non-allocatable 64 bit registers +reg_class non_allocatable_reg( + R0, R0_H, // zr + R1, R1_H, // ra + R2, R2_H, // sp + R3, R3_H, // gp + R4, R4_H, // tp + R23, R23_H // java thread +); + +reg_class no_special_reg32 %{ + return _NO_SPECIAL_REG32_mask; +%} + +reg_class no_special_reg %{ + return _NO_SPECIAL_REG_mask; +%} + +reg_class ptr_reg %{ + return _PTR_REG_mask; +%} + +reg_class no_special_ptr_reg %{ + return _NO_SPECIAL_PTR_REG_mask; +%} + +// Class for 64 bit register r10 +reg_class r10_reg( + R10, R10_H +); + +// Class for 64 bit register r11 +reg_class r11_reg( + R11, R11_H +); + +// Class for 64 bit register r12 +reg_class r12_reg( + R12, R12_H +); + +// Class for 64 bit register r13 +reg_class r13_reg( + R13, R13_H +); + +// Class for 64 bit register r14 +reg_class r14_reg( + R14, R14_H +); + +// Class for 64 bit register r15 +reg_class r15_reg( + R15, R15_H +); + +// Class for 64 bit register r16 +reg_class r16_reg( + R16, R16_H +); + +// Class for method register +reg_class method_reg( + R31, R31_H +); + +// Class for heapbase register +reg_class heapbase_reg( + R27, R27_H +); + +// Class for java thread register +reg_class java_thread_reg( + R23, R23_H +); + +reg_class r28_reg( + R28, R28_H +); + +reg_class r29_reg( + R29, R29_H +); + +reg_class r30_reg( + R30, R30_H +); + +// Class for zero registesr +reg_class zr_reg( + R0, R0_H +); + +// Class for thread register +reg_class thread_reg( + R4, R4_H +); + +// Class for frame pointer register +reg_class fp_reg( + R8, R8_H +); + +// Class for link register +reg_class ra_reg( + R1, R1_H +); + +// Class for long sp register +reg_class sp_reg( + R2, R2_H +); + +// Class for all float registers +reg_class float_reg( + F0, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + F13, + F14, + F15, + F16, + F17, + F18, + F19, + F20, + F21, + F22, + F23, + F24, + F25, + F26, + F27, + F28, + F29, + F30, + F31 +); + +// Double precision float registers have virtual `high halves' that +// are needed by the allocator. +// Class for all double registers +reg_class double_reg( + F0, F0_H, + F1, F1_H, + F2, F2_H, + F3, F3_H, + F4, F4_H, + F5, F5_H, + F6, F6_H, + F7, F7_H, + F8, F8_H, + F9, F9_H, + F10, F10_H, + F11, F11_H, + F12, F12_H, + F13, F13_H, + F14, F14_H, + F15, F15_H, + F16, F16_H, + F17, F17_H, + F18, F18_H, + F19, F19_H, + F20, F20_H, + F21, F21_H, + F22, F22_H, + F23, F23_H, + F24, F24_H, + F25, F25_H, + F26, F26_H, + F27, F27_H, + F28, F28_H, + F29, F29_H, + F30, F30_H, + F31, F31_H +); + +// Class for all RVV vector registers +reg_class vectora_reg( + V1, V1_H, V1_J, V1_K, + V2, V2_H, V2_J, V2_K, + V3, V3_H, V3_J, V3_K, + V4, V4_H, V4_J, V4_K, + V5, V5_H, V5_J, V5_K, + V6, V6_H, V6_J, V6_K, + V7, V7_H, V7_J, V7_K, + V8, V8_H, V8_J, V8_K, + V9, V9_H, V9_J, V9_K, + V10, V10_H, V10_J, V10_K, + V11, V11_H, V11_J, V11_K, + V12, V12_H, V12_J, V12_K, + V13, V13_H, V13_J, V13_K, + V14, V14_H, V14_J, V14_K, + V15, V15_H, V15_J, V15_K, + V16, V16_H, V16_J, V16_K, + V17, V17_H, V17_J, V17_K, + V18, V18_H, V18_J, V18_K, + V19, V19_H, V19_J, V19_K, + V20, V20_H, V20_J, V20_K, + V21, V21_H, V21_J, V21_K, + V22, V22_H, V22_J, V22_K, + V23, V23_H, V23_J, V23_K, + V24, V24_H, V24_J, V24_K, + V25, V25_H, V25_J, V25_K, + V26, V26_H, V26_J, V26_K, + V27, V27_H, V27_J, V27_K, + V28, V28_H, V28_J, V28_K, + V29, V29_H, V29_J, V29_K, + V30, V30_H, V30_J, V30_K, + V31, V31_H, V31_J, V31_K +); + +// Class for 64 bit register f0 +reg_class f0_reg( + F0, F0_H +); + +// Class for 64 bit register f1 +reg_class f1_reg( + F1, F1_H +); + +// Class for 64 bit register f2 +reg_class f2_reg( + F2, F2_H +); + +// Class for 64 bit register f3 +reg_class f3_reg( + F3, F3_H +); + +// class for vector register v1 +reg_class v1_reg( + V1, V1_H, V1_J, V1_K +); + +// class for vector register v2 +reg_class v2_reg( + V2, V2_H, V2_J, V2_K +); + +// class for vector register v3 +reg_class v3_reg( + V3, V3_H, V3_J, V3_K +); + +// class for vector register v4 +reg_class v4_reg( + V4, V4_H, V4_J, V4_K +); + +// class for vector register v5 +reg_class v5_reg( + V5, V5_H, V5_J, V5_K +); + +// class for condition codes +reg_class reg_flags(RFLAGS); +%} + +//----------DEFINITION BLOCK--------------------------------------------------- +// Define name --> value mappings to inform the ADLC of an integer valued name +// Current support includes integer values in the range [0, 0x7FFFFFFF] +// Format: +// int_def ( , ); +// Generated Code in ad_.hpp +// #define () +// // value == +// Generated code in ad_.cpp adlc_verification() +// assert( == , "Expect () to equal "); +// + +// we follow the ppc-aix port in using a simple cost model which ranks +// register operations as cheap, memory ops as more expensive and +// branches as most expensive. the first two have a low as well as a +// normal cost. huge cost appears to be a way of saying don't do +// something + +definitions %{ + // The default cost (of a register move instruction). + int_def DEFAULT_COST ( 100, 100); + int_def ALU_COST ( 100, 1 * DEFAULT_COST); // unknown, const, arith, shift, slt, + // multi, auipc, nop, logical, move + int_def LOAD_COST ( 300, 3 * DEFAULT_COST); // load, fpload + int_def STORE_COST ( 100, 1 * DEFAULT_COST); // store, fpstore + int_def XFER_COST ( 300, 3 * DEFAULT_COST); // mfc, mtc, fcvt, fmove, fcmp + int_def BRANCH_COST ( 100, 1 * DEFAULT_COST); // branch, jmp, call + int_def IMUL_COST ( 1000, 10 * DEFAULT_COST); // imul + int_def IDIVSI_COST ( 3400, 34 * DEFAULT_COST); // idivdi + int_def IDIVDI_COST ( 6600, 66 * DEFAULT_COST); // idivsi + int_def FMUL_SINGLE_COST ( 500, 5 * DEFAULT_COST); // fadd, fmul, fmadd + int_def FMUL_DOUBLE_COST ( 700, 7 * DEFAULT_COST); // fadd, fmul, fmadd + int_def FDIV_COST ( 2000, 20 * DEFAULT_COST); // fdiv + int_def FSQRT_COST ( 2500, 25 * DEFAULT_COST); // fsqrt + int_def VOLATILE_REF_COST ( 1000, 10 * DEFAULT_COST); +%} + + + +//----------SOURCE BLOCK------------------------------------------------------- +// This is a block of C++ code which provides values, functions, and +// definitions necessary in the rest of the architecture description + +source_hpp %{ + +#include "asm/macroAssembler.hpp" +#include "gc/shared/cardTable.hpp" +#include "gc/shared/cardTableBarrierSet.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "opto/addnode.hpp" +#include "opto/convertnode.hpp" + +extern RegMask _ANY_REG32_mask; +extern RegMask _ANY_REG_mask; +extern RegMask _PTR_REG_mask; +extern RegMask _NO_SPECIAL_REG32_mask; +extern RegMask _NO_SPECIAL_REG_mask; +extern RegMask _NO_SPECIAL_PTR_REG_mask; + +class CallStubImpl { + + //-------------------------------------------------------------- + //---< Used for optimization in Compile::shorten_branches >--- + //-------------------------------------------------------------- + + public: + // Size of call trampoline stub. + static uint size_call_trampoline() { + return 0; // no call trampolines on this platform + } + + // number of relocations needed by a call trampoline stub + static uint reloc_call_trampoline() { + return 0; // no call trampolines on this platform + } +}; + +class HandlerImpl { + + public: + + static int emit_exception_handler(CodeBuffer &cbuf); + static int emit_deopt_handler(CodeBuffer& cbuf); + + static uint size_exception_handler() { + return MacroAssembler::far_branch_size(); + } + + static uint size_deopt_handler() { + // count auipc + far branch + return NativeInstruction::instruction_size + MacroAssembler::far_branch_size(); + } +}; + +class Node::PD { +public: + enum NodeFlags { + _last_flag = Node::_last_flag + }; +}; + +bool is_CAS(int opcode, bool maybe_volatile); + +// predicate controlling translation of CompareAndSwapX +bool needs_acquiring_load_reserved(const Node *load); + +// predicate controlling addressing modes +bool size_fits_all_mem_uses(AddPNode* addp, int shift); +%} + +source %{ + +// Derived RegMask with conditionally allocatable registers + +RegMask _ANY_REG32_mask; +RegMask _ANY_REG_mask; +RegMask _PTR_REG_mask; +RegMask _NO_SPECIAL_REG32_mask; +RegMask _NO_SPECIAL_REG_mask; +RegMask _NO_SPECIAL_PTR_REG_mask; + +void reg_mask_init() { + + _ANY_REG32_mask = _ALL_REG32_mask; + _ANY_REG32_mask.Remove(OptoReg::as_OptoReg(x0->as_VMReg())); + + _ANY_REG_mask = _ALL_REG_mask; + _ANY_REG_mask.SUBTRACT(_ZR_REG_mask); + + _PTR_REG_mask = _ALL_REG_mask; + _PTR_REG_mask.SUBTRACT(_ZR_REG_mask); + + _NO_SPECIAL_REG32_mask = _ALL_REG32_mask; + _NO_SPECIAL_REG32_mask.SUBTRACT(_NON_ALLOCATABLE_REG32_mask); + + _NO_SPECIAL_REG_mask = _ALL_REG_mask; + _NO_SPECIAL_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask); + + _NO_SPECIAL_PTR_REG_mask = _ALL_REG_mask; + _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_NON_ALLOCATABLE_REG_mask); + + // x27 is not allocatable when compressed oops is on + if (UseCompressedOops) { + _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(x27->as_VMReg())); + _NO_SPECIAL_REG_mask.SUBTRACT(_HEAPBASE_REG_mask); + _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_HEAPBASE_REG_mask); + } + + // x8 is not allocatable when PreserveFramePointer is on + if (PreserveFramePointer) { + _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg())); + _NO_SPECIAL_REG_mask.SUBTRACT(_FP_REG_mask); + _NO_SPECIAL_PTR_REG_mask.SUBTRACT(_FP_REG_mask); + } +} + +void PhaseOutput::pd_perform_mach_node_analysis() { +} + +int MachNode::pd_alignment_required() const { + return 1; +} + +int MachNode::compute_padding(int current_offset) const { + return 0; +} + +// is_CAS(int opcode, bool maybe_volatile) +// +// return true if opcode is one of the possible CompareAndSwapX +// values otherwise false. +bool is_CAS(int opcode, bool maybe_volatile) +{ + switch (opcode) { + // We handle these + case Op_CompareAndSwapI: + case Op_CompareAndSwapL: + case Op_CompareAndSwapP: + case Op_CompareAndSwapN: + case Op_ShenandoahCompareAndSwapP: + case Op_ShenandoahCompareAndSwapN: + case Op_CompareAndSwapB: + case Op_CompareAndSwapS: + case Op_GetAndSetI: + case Op_GetAndSetL: + case Op_GetAndSetP: + case Op_GetAndSetN: + case Op_GetAndAddI: + case Op_GetAndAddL: + return true; + case Op_CompareAndExchangeI: + case Op_CompareAndExchangeN: + case Op_CompareAndExchangeB: + case Op_CompareAndExchangeS: + case Op_CompareAndExchangeL: + case Op_CompareAndExchangeP: + case Op_WeakCompareAndSwapB: + case Op_WeakCompareAndSwapS: + case Op_WeakCompareAndSwapI: + case Op_WeakCompareAndSwapL: + case Op_WeakCompareAndSwapP: + case Op_WeakCompareAndSwapN: + case Op_ShenandoahWeakCompareAndSwapP: + case Op_ShenandoahWeakCompareAndSwapN: + case Op_ShenandoahCompareAndExchangeP: + case Op_ShenandoahCompareAndExchangeN: + return maybe_volatile; + default: + return false; + } +} + +// predicate controlling translation of CAS +// +// returns true if CAS needs to use an acquiring load otherwise false +bool needs_acquiring_load_reserved(const Node *n) +{ + assert(n != NULL && is_CAS(n->Opcode(), true), "expecting a compare and swap"); + + LoadStoreNode* ldst = n->as_LoadStore(); + if (n != NULL && is_CAS(n->Opcode(), false)) { + assert(ldst != NULL && ldst->trailing_membar() != NULL, "expected trailing membar"); + } else { + return ldst != NULL && ldst->trailing_membar() != NULL; + } + // so we can just return true here + return true; +} +#define __ _masm. + +// advance declarations for helper functions to convert register +// indices to register objects + +// the ad file has to provide implementations of certain methods +// expected by the generic code +// +// REQUIRED FUNCTIONALITY + +//============================================================================= + +// !!!!! Special hack to get all types of calls to specify the byte offset +// from the start of the call to the point where the return address +// will point. + +int MachCallStaticJavaNode::ret_addr_offset() +{ + // jal + return 1 * NativeInstruction::instruction_size; +} + +int MachCallDynamicJavaNode::ret_addr_offset() +{ + return 7 * NativeInstruction::instruction_size; // movptr, jal +} + +int MachCallRuntimeNode::ret_addr_offset() { + // for generated stubs the call will be + // jal(addr) + // or with far branches + // jal(trampoline_stub) + // for real runtime callouts it will be 11 instructions + // see riscv_enc_java_to_runtime + // la(t1, retaddr) -> auipc + addi + // la(t0, RuntimeAddress(addr)) -> lui + addi + slli + addi + slli + addi + // addi(sp, sp, -2 * wordSize) -> addi + // sd(t1, Address(sp, wordSize)) -> sd + // jalr(t0) -> jalr + CodeBlob *cb = CodeCache::find_blob(_entry_point); + if (cb != NULL) { + return 1 * NativeInstruction::instruction_size; + } else { + return 11 * NativeInstruction::instruction_size; + } +} + +int MachCallNativeNode::ret_addr_offset() { + Unimplemented(); + return -1; +} + +// +// Compute padding required for nodes which need alignment +// + +// With RVC a call instruction may get 2-byte aligned. +// The address of the call instruction needs to be 4-byte aligned to +// ensure that it does not span a cache line so that it can be patched. +int CallStaticJavaDirectNode::compute_padding(int current_offset) const +{ + // to make sure the address of jal 4-byte aligned. + return align_up(current_offset, alignment_required()) - current_offset; +} + +// With RVC a call instruction may get 2-byte aligned. +// The address of the call instruction needs to be 4-byte aligned to +// ensure that it does not span a cache line so that it can be patched. +int CallDynamicJavaDirectNode::compute_padding(int current_offset) const +{ + // skip the movptr in MacroAssembler::ic_call(): + // lui + addi + slli + addi + slli + addi + // Though movptr() has already 4-byte aligned with or without RVC, + // We need to prevent from further changes by explicitly calculating the size. + const int movptr_size = 6 * NativeInstruction::instruction_size; + current_offset += movptr_size; + // to make sure the address of jal 4-byte aligned. + return align_up(current_offset, alignment_required()) - current_offset; +} + +//============================================================================= + +#ifndef PRODUCT +void MachBreakpointNode::format(PhaseRegAlloc *ra_, outputStream *st) const { + assert_cond(st != NULL); + st->print("BREAKPOINT"); +} +#endif + +void MachBreakpointNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { + C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); + __ ebreak(); +} + +uint MachBreakpointNode::size(PhaseRegAlloc *ra_) const { + return MachNode::size(ra_); +} + +//============================================================================= + +#ifndef PRODUCT + void MachNopNode::format(PhaseRegAlloc*, outputStream* st) const { + st->print("nop \t# %d bytes pad for loops and calls", _count); + } +#endif + + void MachNopNode::emit(CodeBuffer &cbuf, PhaseRegAlloc*) const { + C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); // nops shall be 2-byte under RVC for alignment purposes. + for (int i = 0; i < _count; i++) { + __ nop(); + } + } + + uint MachNopNode::size(PhaseRegAlloc*) const { + return _count * (UseRVC ? NativeInstruction::compressed_instruction_size : NativeInstruction::instruction_size); + } + +//============================================================================= +const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty; + +int ConstantTable::calculate_table_base_offset() const { + return 0; // absolute addressing, no offset +} + +bool MachConstantBaseNode::requires_postalloc_expand() const { return false; } +void MachConstantBaseNode::postalloc_expand(GrowableArray *nodes, PhaseRegAlloc *ra_) { + ShouldNotReachHere(); +} + +void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { + // Empty encoding +} + +uint MachConstantBaseNode::size(PhaseRegAlloc* ra_) const { + return 0; +} + +#ifndef PRODUCT +void MachConstantBaseNode::format(PhaseRegAlloc* ra_, outputStream* st) const { + assert_cond(st != NULL); + st->print("-- \t// MachConstantBaseNode (empty encoding)"); +} +#endif + +#ifndef PRODUCT +void MachPrologNode::format(PhaseRegAlloc *ra_, outputStream *st) const { + assert_cond(st != NULL && ra_ != NULL); + Compile* C = ra_->C; + + int framesize = C->output()->frame_slots() << LogBytesPerInt; + + if (C->output()->need_stack_bang(framesize)) { + st->print("# stack bang size=%d\n\t", framesize); + } + + st->print("sd fp, [sp, #%d]\n\t", - 2 * wordSize); + st->print("sd ra, [sp, #%d]\n\t", - wordSize); + if (PreserveFramePointer) { st->print("sub fp, sp, #%d\n\t", 2 * wordSize); } + st->print("sub sp, sp, #%d\n\t", framesize); + + if (C->stub_function() == NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) { + st->print("ld t0, [guard]\n\t"); + st->print("membar LoadLoad\n\t"); + st->print("ld t1, [xthread, #thread_disarmed_offset]\n\t"); + st->print("beq t0, t1, skip\n\t"); + st->print("jalr #nmethod_entry_barrier_stub\n\t"); + st->print("j skip\n\t"); + st->print("guard: int\n\t"); + st->print("skip:\n\t"); + } +} +#endif + +void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { + assert_cond(ra_ != NULL); + Compile* C = ra_->C; + C2_MacroAssembler _masm(&cbuf); + + // n.b. frame size includes space for return pc and fp + const int framesize = C->output()->frame_size_in_bytes(); + + // insert a nop at the start of the prolog so we can patch in a + // branch if we need to invalidate the method later + __ nop(); + + assert_cond(C != NULL); + + if (C->clinit_barrier_on_entry()) { + assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started"); + + Label L_skip_barrier; + + __ mov_metadata(t1, C->method()->holder()->constant_encoding()); + __ clinit_barrier(t1, t0, &L_skip_barrier); + __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + __ bind(L_skip_barrier); + } + + int bangsize = C->output()->bang_size_in_bytes(); + if (C->output()->need_stack_bang(bangsize)) { + __ generate_stack_overflow_check(bangsize); + } + + __ build_frame(framesize); + + if (C->stub_function() == NULL) { + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->nmethod_entry_barrier(&_masm); + } + + if (VerifyStackAtCalls) { + Unimplemented(); + } + + C->output()->set_frame_complete(cbuf.insts_size()); + + if (C->has_mach_constant_base_node()) { + // NOTE: We set the table base offset here because users might be + // emitted before MachConstantBaseNode. + ConstantTable& constant_table = C->output()->constant_table(); + constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); + } +} + +uint MachPrologNode::size(PhaseRegAlloc* ra_) const +{ + assert_cond(ra_ != NULL); + return MachNode::size(ra_); // too many variables; just compute it + // the hard way +} + +int MachPrologNode::reloc() const +{ + return 0; +} + +//============================================================================= + +#ifndef PRODUCT +void MachEpilogNode::format(PhaseRegAlloc *ra_, outputStream *st) const { + assert_cond(st != NULL && ra_ != NULL); + Compile* C = ra_->C; + assert_cond(C != NULL); + int framesize = C->output()->frame_size_in_bytes(); + + st->print("# pop frame %d\n\t", framesize); + + if (framesize == 0) { + st->print("ld ra, [sp,#%d]\n\t", (2 * wordSize)); + st->print("ld fp, [sp,#%d]\n\t", (3 * wordSize)); + st->print("add sp, sp, #%d\n\t", (2 * wordSize)); + } else { + st->print("add sp, sp, #%d\n\t", framesize); + st->print("ld ra, [sp,#%d]\n\t", - 2 * wordSize); + st->print("ld fp, [sp,#%d]\n\t", - wordSize); + } + + if (do_polling() && C->is_method_compilation()) { + st->print("# test polling word\n\t"); + st->print("ld t0, [xthread,#%d]\n\t", in_bytes(JavaThread::polling_word_offset())); + st->print("bgtu sp, t0, #slow_path"); + } +} +#endif + +void MachEpilogNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { + assert_cond(ra_ != NULL); + Compile* C = ra_->C; + C2_MacroAssembler _masm(&cbuf); + assert_cond(C != NULL); + int framesize = C->output()->frame_size_in_bytes(); + + __ remove_frame(framesize); + + if (StackReservedPages > 0 && C->has_reserved_stack_access()) { + __ reserved_stack_check(); + } + + if (do_polling() && C->is_method_compilation()) { + Label dummy_label; + Label* code_stub = &dummy_label; + if (!C->output()->in_scratch_emit_size()) { + code_stub = &C->output()->safepoint_poll_table()->add_safepoint(__ offset()); + } + __ relocate(relocInfo::poll_return_type); + __ safepoint_poll(*code_stub, true /* at_return */, false /* acquire */, true /* in_nmethod */); + } +} + +uint MachEpilogNode::size(PhaseRegAlloc *ra_) const { + assert_cond(ra_ != NULL); + // Variable size. Determine dynamically. + return MachNode::size(ra_); +} + +int MachEpilogNode::reloc() const { + // Return number of relocatable values contained in this instruction. + return 1; // 1 for polling page. +} +const Pipeline * MachEpilogNode::pipeline() const { + return MachNode::pipeline_class(); +} + +//============================================================================= + +// Figure out which register class each belongs in: rc_int, rc_float or +// rc_stack. +enum RC { rc_bad, rc_int, rc_float, rc_vector, rc_stack }; + +static enum RC rc_class(OptoReg::Name reg) { + + if (reg == OptoReg::Bad) { + return rc_bad; + } + + // we have 30 int registers * 2 halves + // (t0 and t1 are omitted) + int slots_of_int_registers = RegisterImpl::max_slots_per_register * (RegisterImpl::number_of_registers - 2); + if (reg < slots_of_int_registers) { + return rc_int; + } + + // we have 32 float register * 2 halves + int slots_of_float_registers = FloatRegisterImpl::max_slots_per_register * FloatRegisterImpl::number_of_registers; + if (reg < slots_of_int_registers + slots_of_float_registers) { + return rc_float; + } + + // we have 32 vector register * 4 halves + int slots_of_vector_registers = VectorRegisterImpl::max_slots_per_register * VectorRegisterImpl::number_of_registers; + if (reg < slots_of_int_registers + slots_of_float_registers + slots_of_vector_registers) { + return rc_vector; + } + + // Between vector regs & stack is the flags regs. + assert(OptoReg::is_stack(reg), "blow up if spilling flags"); + + return rc_stack; +} + +uint MachSpillCopyNode::implementation(CodeBuffer *cbuf, PhaseRegAlloc *ra_, bool do_size, outputStream *st) const { + assert_cond(ra_ != NULL); + Compile* C = ra_->C; + + // Get registers to move. + OptoReg::Name src_hi = ra_->get_reg_second(in(1)); + OptoReg::Name src_lo = ra_->get_reg_first(in(1)); + OptoReg::Name dst_hi = ra_->get_reg_second(this); + OptoReg::Name dst_lo = ra_->get_reg_first(this); + + enum RC src_hi_rc = rc_class(src_hi); + enum RC src_lo_rc = rc_class(src_lo); + enum RC dst_hi_rc = rc_class(dst_hi); + enum RC dst_lo_rc = rc_class(dst_lo); + + assert(src_lo != OptoReg::Bad && dst_lo != OptoReg::Bad, "must move at least 1 register"); + + if (src_hi != OptoReg::Bad) { + assert((src_lo & 1) == 0 && src_lo + 1 == src_hi && + (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi, + "expected aligned-adjacent pairs"); + } + + if (src_lo == dst_lo && src_hi == dst_hi) { + return 0; // Self copy, no move. + } + + bool is64 = (src_lo & 1) == 0 && src_lo + 1 == src_hi && + (dst_lo & 1) == 0 && dst_lo + 1 == dst_hi; + int src_offset = ra_->reg2offset(src_lo); + int dst_offset = ra_->reg2offset(dst_lo); + + if (bottom_type()->isa_vect() != NULL) { + uint ireg = ideal_reg(); + if (ireg == Op_VecA && cbuf) { + C2_MacroAssembler _masm(cbuf); + Assembler::CompressibleRegion cr(&_masm); + int vector_reg_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE); + if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) { + // stack to stack + __ spill_copy_vector_stack_to_stack(src_offset, dst_offset, + vector_reg_size_in_bytes); + } else if (src_lo_rc == rc_vector && dst_lo_rc == rc_stack) { + // vpr to stack + __ spill(as_VectorRegister(Matcher::_regEncode[src_lo]), ra_->reg2offset(dst_lo)); + } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_vector) { + // stack to vpr + __ unspill(as_VectorRegister(Matcher::_regEncode[dst_lo]), ra_->reg2offset(src_lo)); + } else if (src_lo_rc == rc_vector && dst_lo_rc == rc_vector) { + // vpr to vpr + __ vmv1r_v(as_VectorRegister(Matcher::_regEncode[dst_lo]), as_VectorRegister(Matcher::_regEncode[src_lo])); + } else { + ShouldNotReachHere(); + } + } + } else if (cbuf != NULL) { + C2_MacroAssembler _masm(cbuf); + Assembler::CompressibleRegion cr(&_masm); + switch (src_lo_rc) { + case rc_int: + if (dst_lo_rc == rc_int) { // gpr --> gpr copy + if (!is64 && this->ideal_reg() != Op_RegI) { // zero extended for narrow oop or klass + __ zero_extend(as_Register(Matcher::_regEncode[dst_lo]), as_Register(Matcher::_regEncode[src_lo]), 32); + } else { + __ mv(as_Register(Matcher::_regEncode[dst_lo]), as_Register(Matcher::_regEncode[src_lo])); + } + } else if (dst_lo_rc == rc_float) { // gpr --> fpr copy + if (is64) { + __ fmv_d_x(as_FloatRegister(Matcher::_regEncode[dst_lo]), + as_Register(Matcher::_regEncode[src_lo])); + } else { + __ fmv_w_x(as_FloatRegister(Matcher::_regEncode[dst_lo]), + as_Register(Matcher::_regEncode[src_lo])); + } + } else { // gpr --> stack spill + assert(dst_lo_rc == rc_stack, "spill to bad register class"); + __ spill(as_Register(Matcher::_regEncode[src_lo]), is64, dst_offset); + } + break; + case rc_float: + if (dst_lo_rc == rc_int) { // fpr --> gpr copy + if (is64) { + __ fmv_x_d(as_Register(Matcher::_regEncode[dst_lo]), + as_FloatRegister(Matcher::_regEncode[src_lo])); + } else { + __ fmv_x_w(as_Register(Matcher::_regEncode[dst_lo]), + as_FloatRegister(Matcher::_regEncode[src_lo])); + } + } else if (dst_lo_rc == rc_float) { // fpr --> fpr copy + if (is64) { + __ fmv_d(as_FloatRegister(Matcher::_regEncode[dst_lo]), + as_FloatRegister(Matcher::_regEncode[src_lo])); + } else { + __ fmv_s(as_FloatRegister(Matcher::_regEncode[dst_lo]), + as_FloatRegister(Matcher::_regEncode[src_lo])); + } + } else { // fpr --> stack spill + assert(dst_lo_rc == rc_stack, "spill to bad register class"); + __ spill(as_FloatRegister(Matcher::_regEncode[src_lo]), + is64, dst_offset); + } + break; + case rc_stack: + if (dst_lo_rc == rc_int) { // stack --> gpr load + if (this->ideal_reg() == Op_RegI) { + __ unspill(as_Register(Matcher::_regEncode[dst_lo]), is64, src_offset); + } else { // // zero extended for narrow oop or klass + __ unspillu(as_Register(Matcher::_regEncode[dst_lo]), is64, src_offset); + } + } else if (dst_lo_rc == rc_float) { // stack --> fpr load + __ unspill(as_FloatRegister(Matcher::_regEncode[dst_lo]), + is64, src_offset); + } else { // stack --> stack copy + assert(dst_lo_rc == rc_stack, "spill to bad register class"); + if (this->ideal_reg() == Op_RegI) { + __ unspill(t0, is64, src_offset); + } else { // zero extended for narrow oop or klass + __ unspillu(t0, is64, src_offset); + } + __ spill(t0, is64, dst_offset); + } + break; + default: + ShouldNotReachHere(); + } + } + + if (st != NULL) { + st->print("spill "); + if (src_lo_rc == rc_stack) { + st->print("[sp, #%d] -> ", src_offset); + } else { + st->print("%s -> ", Matcher::regName[src_lo]); + } + if (dst_lo_rc == rc_stack) { + st->print("[sp, #%d]", dst_offset); + } else { + st->print("%s", Matcher::regName[dst_lo]); + } + if (bottom_type()->isa_vect() != NULL) { + int vsize = 0; + if (ideal_reg() == Op_VecA) { + vsize = Matcher::scalable_vector_reg_size(T_BYTE) * 8; + } else { + ShouldNotReachHere(); + } + st->print("\t# vector spill size = %d", vsize); + } else { + st->print("\t# spill size = %d", is64 ? 64 : 32); + } + } + + return 0; +} + +#ifndef PRODUCT +void MachSpillCopyNode::format(PhaseRegAlloc *ra_, outputStream *st) const { + if (ra_ == NULL) { + st->print("N%d = SpillCopy(N%d)", _idx, in(1)->_idx); + } else { + implementation(NULL, ra_, false, st); + } +} +#endif + +void MachSpillCopyNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { + implementation(&cbuf, ra_, false, NULL); +} + +uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { + return MachNode::size(ra_); +} + +//============================================================================= + +#ifndef PRODUCT +void BoxLockNode::format(PhaseRegAlloc *ra_, outputStream *st) const { + assert_cond(ra_ != NULL && st != NULL); + int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); + int reg = ra_->get_reg_first(this); + st->print("add %s, sp, #%d\t# box lock", + Matcher::regName[reg], offset); +} +#endif + +void BoxLockNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const { + C2_MacroAssembler _masm(&cbuf); + + assert_cond(ra_ != NULL); + int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); + int reg = ra_->get_encode(this); + + if (is_imm_in_range(offset, 12, 0)) { + __ addi(as_Register(reg), sp, offset); + } else if (is_imm_in_range(offset, 32, 0)) { + __ li32(t0, offset); + __ add(as_Register(reg), sp, t0); + } else { + ShouldNotReachHere(); + } +} + +uint BoxLockNode::size(PhaseRegAlloc *ra_) const { + // BoxLockNode is not a MachNode, so we can't just call MachNode::size(ra_). + int offset = ra_->reg2offset(in_RegMask(0).find_first_elem()); + + if (is_imm_in_range(offset, 12, 0)) { + return NativeInstruction::instruction_size; + } else { + return 3 * NativeInstruction::instruction_size; // lui + addiw + add; + } +} + +//============================================================================= + +#ifndef PRODUCT +void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const +{ + assert_cond(st != NULL); + st->print_cr("# MachUEPNode"); + if (UseCompressedClassPointers) { + st->print_cr("\tlwu t0, [j_rarg0, oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + if (CompressedKlassPointers::shift() != 0) { + st->print_cr("\tdecode_klass_not_null t0, t0"); + } + } else { + st->print_cr("\tld t0, [j_rarg0, oopDesc::klass_offset_in_bytes()]\t# compressed klass"); + } + st->print_cr("\tbeq t0, t1, ic_hit"); + st->print_cr("\tj, SharedRuntime::_ic_miss_stub\t # Inline cache check"); + st->print_cr("\tic_hit:"); +} +#endif + +void MachUEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const +{ + // This is the unverified entry point. + C2_MacroAssembler _masm(&cbuf); + + Label skip; + __ cmp_klass(j_rarg0, t1, t0, skip); + __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + __ bind(skip); +} + +uint MachUEPNode::size(PhaseRegAlloc* ra_) const +{ + assert_cond(ra_ != NULL); + return MachNode::size(ra_); +} + +// REQUIRED EMIT CODE + +//============================================================================= + +// Emit exception handler code. +int HandlerImpl::emit_exception_handler(CodeBuffer& cbuf) +{ + // la_patchable t0, #exception_blob_entry_point + // jr (offset)t0 + // or + // j #exception_blob_entry_point + // Note that the code buffer's insts_mark is always relative to insts. + // That's why we must use the macroassembler to generate a handler. + C2_MacroAssembler _masm(&cbuf); + address base = __ start_a_stub(size_exception_handler()); + if (base == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return 0; // CodeBuffer::expand failed + } + int offset = __ offset(); + __ far_jump(RuntimeAddress(OptoRuntime::exception_blob()->entry_point())); + assert(__ offset() - offset <= (int) size_exception_handler(), "overflow"); + __ end_a_stub(); + return offset; +} + +// Emit deopt handler code. +int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) +{ + // Note that the code buffer's insts_mark is always relative to insts. + // That's why we must use the macroassembler to generate a handler. + C2_MacroAssembler _masm(&cbuf); + address base = __ start_a_stub(size_deopt_handler()); + if (base == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return 0; // CodeBuffer::expand failed + } + int offset = __ offset(); + + __ auipc(ra, 0); + __ far_jump(RuntimeAddress(SharedRuntime::deopt_blob()->unpack())); + + assert(__ offset() - offset <= (int) size_deopt_handler(), "overflow"); + __ end_a_stub(); + return offset; + +} +// REQUIRED MATCHER CODE + +//============================================================================= + +const bool Matcher::match_rule_supported(int opcode) { + if (!has_match_rule(opcode)) { + return false; + } + + switch (opcode) { + case Op_CacheWB: // fall through + case Op_CacheWBPreSync: // fall through + case Op_CacheWBPostSync: + if (!VM_Version::supports_data_cache_line_flush()) { + return false; + } + break; + + case Op_StrCompressedCopy: // fall through + case Op_StrInflatedCopy: // fall through + case Op_CountPositives: + return UseRVV; + + case Op_EncodeISOArray: + return UseRVV && SpecialEncodeISOArray; + + case Op_PopCountI: + case Op_PopCountL: + return UsePopCountInstruction; + + case Op_RotateRight: + case Op_RotateLeft: + case Op_CountLeadingZerosI: + case Op_CountLeadingZerosL: + case Op_CountTrailingZerosI: + case Op_CountTrailingZerosL: + return UseRVB; + } + + return true; // Per default match rules are supported. +} + +// Identify extra cases that we might want to provide match rules for vector nodes and +// other intrinsics guarded with vector length (vlen) and element type (bt). +const bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { + if (!match_rule_supported(opcode) || !vector_size_supported(bt, vlen)) { + return false; + } + + return op_vec_supported(opcode); +} + +const bool Matcher::match_rule_supported_vector_masked(int opcode, int vlen, BasicType bt) { + return false; +} + +const RegMask* Matcher::predicate_reg_mask(void) { + return NULL; +} + +const TypeVectMask* Matcher::predicate_reg_type(const Type* elemTy, int length) { + return NULL; +} + +// Vector calling convention not yet implemented. +const bool Matcher::supports_vector_calling_convention(void) { + return false; +} + +OptoRegPair Matcher::vector_return_value(uint ideal_reg) { + Unimplemented(); + return OptoRegPair(0, 0); +} + +// Is this branch offset short enough that a short branch can be used? +// +// NOTE: If the platform does not provide any short branch variants, then +// this method should return false for offset 0. +// |---label(L1)-----| +// |-----------------| +// |-----------------|----------eq: float------------------- +// |-----------------| // far_cmpD_branch | cmpD_branch +// |------- ---------| feq; | feq; +// |-far_cmpD_branch-| beqz done; | bnez L; +// |-----------------| j L; | +// |-----------------| bind(done); | +// |-----------------|-------------------------------------- +// |-----------------| // so shortBrSize = br_size - 4; +// |-----------------| // so offs = offset - shortBrSize + 4; +// |---label(L2)-----| +bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) { + // The passed offset is relative to address of the branch. + int shortBrSize = br_size - 4; + int offs = offset - shortBrSize + 4; + return (-4096 <= offs && offs < 4096); +} + +// Vector width in bytes. +const int Matcher::vector_width_in_bytes(BasicType bt) { + if (UseRVV) { + // The MaxVectorSize should have been set by detecting RVV max vector register size when check UseRVV. + // MaxVectorSize == VM_Version::_initial_vector_length + return MaxVectorSize; + } + return 0; +} + +// Limits on vector size (number of elements) loaded into vector. +const int Matcher::max_vector_size(const BasicType bt) { + return vector_width_in_bytes(bt) / type2aelembytes(bt); +} +const int Matcher::min_vector_size(const BasicType bt) { + return max_vector_size(bt); +} + +// Vector ideal reg. +const uint Matcher::vector_ideal_reg(int len) { + assert(MaxVectorSize >= len, ""); + if (UseRVV) { + return Op_VecA; + } + + ShouldNotReachHere(); + return 0; +} + +const int Matcher::scalable_vector_reg_size(const BasicType bt) { + return Matcher::max_vector_size(bt); +} + +MachOper* Matcher::pd_specialize_generic_vector_operand(MachOper* original_opnd, uint ideal_reg, bool is_temp) { + ShouldNotReachHere(); // generic vector operands not supported + return NULL; +} + +bool Matcher::is_reg2reg_move(MachNode* m) { + ShouldNotReachHere(); // generic vector operands not supported + return false; +} + +bool Matcher::is_generic_vector(MachOper* opnd) { + ShouldNotReachHere(); // generic vector operands not supported + return false; +} + +// Return whether or not this register is ever used as an argument. +// This function is used on startup to build the trampoline stubs in +// generateOptoStub. Registers not mentioned will be killed by the VM +// call in the trampoline, and arguments in those registers not be +// available to the callee. +bool Matcher::can_be_java_arg(int reg) +{ + return + reg == R10_num || reg == R10_H_num || + reg == R11_num || reg == R11_H_num || + reg == R12_num || reg == R12_H_num || + reg == R13_num || reg == R13_H_num || + reg == R14_num || reg == R14_H_num || + reg == R15_num || reg == R15_H_num || + reg == R16_num || reg == R16_H_num || + reg == R17_num || reg == R17_H_num || + reg == F10_num || reg == F10_H_num || + reg == F11_num || reg == F11_H_num || + reg == F12_num || reg == F12_H_num || + reg == F13_num || reg == F13_H_num || + reg == F14_num || reg == F14_H_num || + reg == F15_num || reg == F15_H_num || + reg == F16_num || reg == F16_H_num || + reg == F17_num || reg == F17_H_num; +} + +bool Matcher::is_spillable_arg(int reg) +{ + return can_be_java_arg(reg); +} + +uint Matcher::int_pressure_limit() +{ + // A derived pointer is live at CallNode and then is flagged by RA + // as a spilled LRG. Spilling heuristics(Spill-USE) explicitly skip + // derived pointers and lastly fail to spill after reaching maximum + // number of iterations. Lowering the default pressure threshold to + // (_NO_SPECIAL_REG32_mask.Size() minus 1) forces CallNode to become + // a high register pressure area of the code so that split_DEF can + // generate DefinitionSpillCopy for the derived pointer. + uint default_int_pressure_threshold = _NO_SPECIAL_REG32_mask.Size() - 1; + if (!PreserveFramePointer) { + // When PreserveFramePointer is off, frame pointer is allocatable, + // but different from other SOC registers, it is excluded from + // fatproj's mask because its save type is No-Save. Decrease 1 to + // ensure high pressure at fatproj when PreserveFramePointer is off. + // See check_pressure_at_fatproj(). + default_int_pressure_threshold--; + } + return (INTPRESSURE == -1) ? default_int_pressure_threshold : INTPRESSURE; +} + +uint Matcher::float_pressure_limit() +{ + // _FLOAT_REG_mask is generated by adlc from the float_reg register class. + return (FLOATPRESSURE == -1) ? _FLOAT_REG_mask.Size() : FLOATPRESSURE; +} + +bool Matcher::use_asm_for_ldiv_by_con(jlong divisor) { + return false; +} + +RegMask Matcher::divI_proj_mask() { + ShouldNotReachHere(); + return RegMask(); +} + +// Register for MODI projection of divmodI. +RegMask Matcher::modI_proj_mask() { + ShouldNotReachHere(); + return RegMask(); +} + +// Register for DIVL projection of divmodL. +RegMask Matcher::divL_proj_mask() { + ShouldNotReachHere(); + return RegMask(); +} + +// Register for MODL projection of divmodL. +RegMask Matcher::modL_proj_mask() { + ShouldNotReachHere(); + return RegMask(); +} + +const RegMask Matcher::method_handle_invoke_SP_save_mask() { + return FP_REG_mask(); +} + +bool size_fits_all_mem_uses(AddPNode* addp, int shift) { + assert_cond(addp != NULL); + for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { + Node* u = addp->fast_out(i); + if (u != NULL && u->is_Mem()) { + int opsize = u->as_Mem()->memory_size(); + assert(opsize > 0, "unexpected memory operand size"); + if (u->as_Mem()->memory_size() != (1 << shift)) { + return false; + } + } + } + return true; +} + +// Should the Matcher clone input 'm' of node 'n'? +bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { + assert_cond(m != NULL); + if (is_vshift_con_pattern(n, m)) { // ShiftV src (ShiftCntV con) + mstack.push(m, Visit); // m = ShiftCntV + return true; + } + return false; +} + +// Should the Matcher clone shifts on addressing modes, expecting them +// to be subsumed into complex addressing expressions or compute them +// into registers? +bool Matcher::pd_clone_address_expressions(AddPNode* m, Matcher::MStack& mstack, VectorSet& address_visited) { + return clone_base_plus_offset_address(m, mstack, address_visited); +} + +%} + + + +//----------ENCODING BLOCK----------------------------------------------------- +// This block specifies the encoding classes used by the compiler to +// output byte streams. Encoding classes are parameterized macros +// used by Machine Instruction Nodes in order to generate the bit +// encoding of the instruction. Operands specify their base encoding +// interface with the interface keyword. There are currently +// supported four interfaces, REG_INTER, CONST_INTER, MEMORY_INTER, & +// COND_INTER. REG_INTER causes an operand to generate a function +// which returns its register number when queried. CONST_INTER causes +// an operand to generate a function which returns the value of the +// constant when queried. MEMORY_INTER causes an operand to generate +// four functions which return the Base Register, the Index Register, +// the Scale Value, and the Offset Value of the operand when queried. +// COND_INTER causes an operand to generate six functions which return +// the encoding code (ie - encoding bits for the instruction) +// associated with each basic boolean condition for a conditional +// instruction. +// +// Instructions specify two basic values for encoding. Again, a +// function is available to check if the constant displacement is an +// oop. They use the ins_encode keyword to specify their encoding +// classes (which must be a sequence of enc_class names, and their +// parameters, specified in the encoding block), and they use the +// opcode keyword to specify, in order, their primary, secondary, and +// tertiary opcode. Only the opcode sections which a particular +// instruction needs for encoding need to be specified. +encode %{ + // BEGIN Non-volatile memory access + + enc_class riscv_enc_li_imm(iRegIorL dst, immIorL src) %{ + C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); + int64_t con = (int64_t)$src$$constant; + Register dst_reg = as_Register($dst$$reg); + __ li(dst_reg, con); + %} + + enc_class riscv_enc_mov_p(iRegP dst, immP src) %{ + C2_MacroAssembler _masm(&cbuf); + Register dst_reg = as_Register($dst$$reg); + address con = (address)$src$$constant; + if (con == NULL || con == (address)1) { + ShouldNotReachHere(); + } else { + relocInfo::relocType rtype = $src->constant_reloc(); + if (rtype == relocInfo::oop_type) { + __ movoop(dst_reg, (jobject)con, /*immediate*/true); + } else if (rtype == relocInfo::metadata_type) { + __ mov_metadata(dst_reg, (Metadata*)con); + } else { + assert(rtype == relocInfo::none, "unexpected reloc type"); + __ li(dst_reg, $src$$constant); + } + } + %} + + enc_class riscv_enc_mov_p1(iRegP dst) %{ + C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); + Register dst_reg = as_Register($dst$$reg); + __ li(dst_reg, 1); + %} + + enc_class riscv_enc_mov_byte_map_base(iRegP dst) %{ + C2_MacroAssembler _masm(&cbuf); + __ load_byte_map_base($dst$$Register); + %} + + enc_class riscv_enc_mov_n(iRegN dst, immN src) %{ + C2_MacroAssembler _masm(&cbuf); + Register dst_reg = as_Register($dst$$reg); + address con = (address)$src$$constant; + if (con == NULL) { + ShouldNotReachHere(); + } else { + relocInfo::relocType rtype = $src->constant_reloc(); + assert(rtype == relocInfo::oop_type, "unexpected reloc type"); + __ set_narrow_oop(dst_reg, (jobject)con); + } + %} + + enc_class riscv_enc_mov_zero(iRegNorP dst) %{ + C2_MacroAssembler _masm(&cbuf); + Register dst_reg = as_Register($dst$$reg); + __ mv(dst_reg, zr); + %} + + enc_class riscv_enc_mov_nk(iRegN dst, immNKlass src) %{ + C2_MacroAssembler _masm(&cbuf); + Register dst_reg = as_Register($dst$$reg); + address con = (address)$src$$constant; + if (con == NULL) { + ShouldNotReachHere(); + } else { + relocInfo::relocType rtype = $src->constant_reloc(); + assert(rtype == relocInfo::metadata_type, "unexpected reloc type"); + __ set_narrow_klass(dst_reg, (Klass *)con); + } + %} + + enc_class riscv_enc_cmpxchgw(iRegINoSp res, memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + C2_MacroAssembler _masm(&cbuf); + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} + + enc_class riscv_enc_cmpxchgn(iRegINoSp res, memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + C2_MacroAssembler _masm(&cbuf); + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} + + enc_class riscv_enc_cmpxchg(iRegINoSp res, memory mem, iRegLNoSp oldval, iRegLNoSp newval) %{ + C2_MacroAssembler _masm(&cbuf); + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} + + enc_class riscv_enc_cmpxchgw_acq(iRegINoSp res, memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + C2_MacroAssembler _masm(&cbuf); + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} + + enc_class riscv_enc_cmpxchgn_acq(iRegINoSp res, memory mem, iRegINoSp oldval, iRegINoSp newval) %{ + C2_MacroAssembler _masm(&cbuf); + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} + + enc_class riscv_enc_cmpxchg_acq(iRegINoSp res, memory mem, iRegLNoSp oldval, iRegLNoSp newval) %{ + C2_MacroAssembler _masm(&cbuf); + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result as bool*/ true); + %} + + // compare and branch instruction encodings + + enc_class riscv_enc_j(label lbl) %{ + C2_MacroAssembler _masm(&cbuf); + Label* L = $lbl$$label; + __ j(*L); + %} + + enc_class riscv_enc_far_cmpULtGe_imm0_branch(cmpOpULtGe cmp, iRegIorL op1, label lbl) %{ + C2_MacroAssembler _masm(&cbuf); + Label* L = $lbl$$label; + switch ($cmp$$cmpcode) { + case(BoolTest::ge): + __ j(*L); + break; + case(BoolTest::lt): + break; + default: + Unimplemented(); + } + %} + + // call instruction encodings + + enc_class riscv_enc_partial_subtype_check(iRegP sub, iRegP super, iRegP temp, iRegP result) %{ + Register sub_reg = as_Register($sub$$reg); + Register super_reg = as_Register($super$$reg); + Register temp_reg = as_Register($temp$$reg); + Register result_reg = as_Register($result$$reg); + Register cr_reg = t1; + + Label miss; + Label done; + C2_MacroAssembler _masm(&cbuf); + __ check_klass_subtype_slow_path(sub_reg, super_reg, temp_reg, result_reg, + NULL, &miss); + if ($primary) { + __ mv(result_reg, zr); + } else { + __ mv(cr_reg, zr); + __ j(done); + } + + __ bind(miss); + if (!$primary) { + __ li(cr_reg, 1); + } + + __ bind(done); + %} + + enc_class riscv_enc_java_static_call(method meth) %{ + C2_MacroAssembler _masm(&cbuf); + + address addr = (address)$meth$$method; + address call = NULL; + assert_cond(addr != NULL); + if (!_method) { + // A call to a runtime wrapper, e.g. new, new_typeArray_Java, uncommon_trap. + call = __ trampoline_call(Address(addr, relocInfo::runtime_call_type), &cbuf); + if (call == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + } else { + int method_index = resolved_method_index(cbuf); + RelocationHolder rspec = _optimized_virtual ? opt_virtual_call_Relocation::spec(method_index) + : static_call_Relocation::spec(method_index); + call = __ trampoline_call(Address(addr, rspec), &cbuf); + if (call == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + + // Emit stub for static call + address stub = CompiledStaticCall::emit_to_interp_stub(cbuf); + if (stub == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + } + %} + + enc_class riscv_enc_java_dynamic_call(method meth) %{ + C2_MacroAssembler _masm(&cbuf); + int method_index = resolved_method_index(cbuf); + address call = __ ic_call((address)$meth$$method, method_index); + if (call == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + %} + + enc_class riscv_enc_call_epilog() %{ + C2_MacroAssembler _masm(&cbuf); + if (VerifyStackAtCalls) { + // Check that stack depth is unchanged: find majik cookie on stack + __ call_Unimplemented(); + } + %} + + enc_class riscv_enc_java_to_runtime(method meth) %{ + C2_MacroAssembler _masm(&cbuf); + + // some calls to generated routines (arraycopy code) are scheduled + // by C2 as runtime calls. if so we can call them using a jr (they + // will be in a reachable segment) otherwise we have to use a jalr + // which loads the absolute address into a register. + address entry = (address)$meth$$method; + CodeBlob *cb = CodeCache::find_blob(entry); + if (cb != NULL) { + address call = __ trampoline_call(Address(entry, relocInfo::runtime_call_type)); + if (call == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + } else { + Label retaddr; + __ la(t1, retaddr); + __ la(t0, RuntimeAddress(entry)); + // Leave a breadcrumb for JavaFrameAnchor::capture_last_Java_pc() + __ addi(sp, sp, -2 * wordSize); + __ sd(t1, Address(sp, wordSize)); + __ jalr(t0); + __ bind(retaddr); + __ addi(sp, sp, 2 * wordSize); + } + %} + + // using the cr register as the bool result: 0 for success; others failed. + enc_class riscv_enc_fast_lock(iRegP object, iRegP box, iRegP tmp1, iRegP tmp2) %{ + C2_MacroAssembler _masm(&cbuf); + Register flag = t1; + Register oop = as_Register($object$$reg); + Register box = as_Register($box$$reg); + Register disp_hdr = as_Register($tmp1$$reg); + Register tmp = as_Register($tmp2$$reg); + Label cont; + Label object_has_monitor; + + assert_different_registers(oop, box, tmp, disp_hdr, t0); + + // Load markWord from object into displaced_header. + __ ld(disp_hdr, Address(oop, oopDesc::mark_offset_in_bytes())); + + if (DiagnoseSyncOnValueBasedClasses != 0) { + __ load_klass(flag, oop); + __ lwu(flag, Address(flag, Klass::access_flags_offset())); + __ andi(flag, flag, JVM_ACC_IS_VALUE_BASED_CLASS, tmp /* tmp */); + __ bnez(flag, cont, true /* is_far */); + } + + // Check for existing monitor + __ andi(t0, disp_hdr, markWord::monitor_value); + __ bnez(t0, object_has_monitor); + + if (!UseHeavyMonitors) { + // Set tmp to be (markWord of object | UNLOCK_VALUE). + __ ori(tmp, disp_hdr, markWord::unlocked_value); + + // Initialize the box. (Must happen before we update the object mark!) + __ sd(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); + + // Compare object markWord with an unlocked value (tmp) and if + // equal exchange the stack address of our box with object markWord. + // On failure disp_hdr contains the possibly locked markWord. + __ cmpxchg(/*memory address*/oop, /*expected value*/tmp, /*new value*/box, Assembler::int64, Assembler::aq, + Assembler::rl, /*result*/disp_hdr); + __ mv(flag, zr); + __ beq(disp_hdr, tmp, cont); // prepare zero flag and goto cont if we won the cas + + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + + // If the compare-and-exchange succeeded, then we found an unlocked + // object, will have now locked it will continue at label cont + // We did not see an unlocked object so try the fast recursive case. + + // Check if the owner is self by comparing the value in the + // markWord of object (disp_hdr) with the stack pointer. + __ sub(disp_hdr, disp_hdr, sp); + __ li(tmp, (intptr_t) (~(os::vm_page_size()-1) | (uintptr_t)markWord::lock_mask_in_place)); + // If (mark & lock_mask) == 0 and mark - sp < page_size, we are stack-locking and goto cont, + // hence we can store 0 as the displaced header in the box, which indicates that it is a + // recursive lock. + __ andr(tmp/*==0?*/, disp_hdr, tmp); + __ sd(tmp/*==0, perhaps*/, Address(box, BasicLock::displaced_header_offset_in_bytes())); + __ mv(flag, tmp); // we can use the value of tmp as the result here + } else { + __ mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow-path + } + + __ j(cont); + + // Handle existing monitor. + __ bind(object_has_monitor); + // The object's monitor m is unlocked iff m->owner == NULL, + // otherwise m->owner may contain a thread or a stack address. + // + // Try to CAS m->owner from NULL to current thread. + __ add(tmp, disp_hdr, (ObjectMonitor::owner_offset_in_bytes() - markWord::monitor_value)); + __ cmpxchg(/*memory address*/tmp, /*expected value*/zr, /*new value*/xthread, Assembler::int64, Assembler::aq, + Assembler::rl, /*result*/flag); // cas succeeds if flag == zr(expected) + + // Store a non-null value into the box to avoid looking like a re-entrant + // lock. The fast-path monitor unlock code checks for + // markWord::monitor_value so use markWord::unused_mark which has the + // relevant bit set, and also matches ObjectSynchronizer::slow_enter. + __ mv(tmp, (address)markWord::unused_mark().value()); + __ sd(tmp, Address(box, BasicLock::displaced_header_offset_in_bytes())); + + __ beqz(flag, cont); // CAS success means locking succeeded + + __ bne(flag, xthread, cont); // Check for recursive locking + + // Recursive lock case + __ mv(flag, zr); + __ ld(tmp, Address(disp_hdr, ObjectMonitor::recursions_offset_in_bytes() - markWord::monitor_value)); + __ add(tmp, tmp, 1u); + __ sd(tmp, Address(disp_hdr, ObjectMonitor::recursions_offset_in_bytes() - markWord::monitor_value)); + + __ bind(cont); + %} + + // using cr flag to indicate the fast_unlock result: 0 for success; others failed. + enc_class riscv_enc_fast_unlock(iRegP object, iRegP box, iRegP tmp1, iRegP tmp2) %{ + C2_MacroAssembler _masm(&cbuf); + Register flag = t1; + Register oop = as_Register($object$$reg); + Register box = as_Register($box$$reg); + Register disp_hdr = as_Register($tmp1$$reg); + Register tmp = as_Register($tmp2$$reg); + Label cont; + Label object_has_monitor; + + assert_different_registers(oop, box, tmp, disp_hdr, flag); + + if (!UseHeavyMonitors) { + // Find the lock address and load the displaced header from the stack. + __ ld(disp_hdr, Address(box, BasicLock::displaced_header_offset_in_bytes())); + + // If the displaced header is 0, we have a recursive unlock. + __ mv(flag, disp_hdr); + __ beqz(disp_hdr, cont); + } + + // Handle existing monitor. + __ ld(tmp, Address(oop, oopDesc::mark_offset_in_bytes())); + __ andi(t0, disp_hdr, markWord::monitor_value); + __ bnez(t0, object_has_monitor); + + if (!UseHeavyMonitors) { + // Check if it is still a light weight lock, this is true if we + // see the stack address of the basicLock in the markWord of the + // object. + + __ cmpxchg(/*memory address*/oop, /*expected value*/box, /*new value*/disp_hdr, Assembler::int64, Assembler::relaxed, + Assembler::rl, /*result*/tmp); + __ xorr(flag, box, tmp); // box == tmp if cas succeeds + } else { + __ mv(flag, 1); // Set non-zero flag to indicate 'failure' -> take slow path + } + __ j(cont); + + assert(oopDesc::mark_offset_in_bytes() == 0, "offset of _mark is not 0"); + + // Handle existing monitor. + __ bind(object_has_monitor); + STATIC_ASSERT(markWord::monitor_value <= INT_MAX); + __ add(tmp, tmp, -(int)markWord::monitor_value); // monitor + __ ld(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset_in_bytes())); + + Label notRecursive; + __ beqz(disp_hdr, notRecursive); // Will be 0 if not recursive. + + // Recursive lock + __ addi(disp_hdr, disp_hdr, -1); + __ sd(disp_hdr, Address(tmp, ObjectMonitor::recursions_offset_in_bytes())); + __ mv(flag, zr); + __ j(cont); + + __ bind(notRecursive); + __ ld(flag, Address(tmp, ObjectMonitor::EntryList_offset_in_bytes())); + __ ld(disp_hdr, Address(tmp, ObjectMonitor::cxq_offset_in_bytes())); + __ orr(flag, flag, disp_hdr); // Will be 0 if both are 0. + __ bnez(flag, cont); + // need a release store here + __ la(tmp, Address(tmp, ObjectMonitor::owner_offset_in_bytes())); + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + __ sd(zr, Address(tmp)); // set unowned + + __ bind(cont); + %} + + // arithmetic encodings + + enc_class riscv_enc_divw(iRegI dst, iRegI src1, iRegI src2) %{ + C2_MacroAssembler _masm(&cbuf); + Register dst_reg = as_Register($dst$$reg); + Register src1_reg = as_Register($src1$$reg); + Register src2_reg = as_Register($src2$$reg); + __ corrected_idivl(dst_reg, src1_reg, src2_reg, false); + %} + + enc_class riscv_enc_div(iRegI dst, iRegI src1, iRegI src2) %{ + C2_MacroAssembler _masm(&cbuf); + Register dst_reg = as_Register($dst$$reg); + Register src1_reg = as_Register($src1$$reg); + Register src2_reg = as_Register($src2$$reg); + __ corrected_idivq(dst_reg, src1_reg, src2_reg, false); + %} + + enc_class riscv_enc_modw(iRegI dst, iRegI src1, iRegI src2) %{ + C2_MacroAssembler _masm(&cbuf); + Register dst_reg = as_Register($dst$$reg); + Register src1_reg = as_Register($src1$$reg); + Register src2_reg = as_Register($src2$$reg); + __ corrected_idivl(dst_reg, src1_reg, src2_reg, true); + %} + + enc_class riscv_enc_mod(iRegI dst, iRegI src1, iRegI src2) %{ + C2_MacroAssembler _masm(&cbuf); + Register dst_reg = as_Register($dst$$reg); + Register src1_reg = as_Register($src1$$reg); + Register src2_reg = as_Register($src2$$reg); + __ corrected_idivq(dst_reg, src1_reg, src2_reg, true); + %} + + enc_class riscv_enc_tail_call(iRegP jump_target) %{ + C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); + Register target_reg = as_Register($jump_target$$reg); + __ jr(target_reg); + %} + + enc_class riscv_enc_tail_jmp(iRegP jump_target) %{ + C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); + Register target_reg = as_Register($jump_target$$reg); + // exception oop should be in x10 + // ret addr has been popped into ra + // callee expects it in x13 + __ mv(x13, ra); + __ jr(target_reg); + %} + + enc_class riscv_enc_rethrow() %{ + C2_MacroAssembler _masm(&cbuf); + __ far_jump(RuntimeAddress(OptoRuntime::rethrow_stub())); + %} + + enc_class riscv_enc_ret() %{ + C2_MacroAssembler _masm(&cbuf); + Assembler::CompressibleRegion cr(&_masm); + __ ret(); + %} + +%} + +//----------FRAME-------------------------------------------------------------- +// Definition of frame structure and management information. +// +// S T A C K L A Y O U T Allocators stack-slot number +// | (to get allocators register number +// G Owned by | | v add OptoReg::stack0()) +// r CALLER | | +// o | +--------+ pad to even-align allocators stack-slot +// w V | pad0 | numbers; owned by CALLER +// t -----------+--------+----> Matcher::_in_arg_limit, unaligned +// h ^ | in | 5 +// | | args | 4 Holes in incoming args owned by SELF +// | | | | 3 +// | | +--------+ +// V | | old out| Empty on Intel, window on Sparc +// | old |preserve| Must be even aligned. +// | SP-+--------+----> Matcher::_old_SP, even aligned +// | | in | 3 area for Intel ret address +// Owned by |preserve| Empty on Sparc. +// SELF +--------+ +// | | pad2 | 2 pad to align old SP +// | +--------+ 1 +// | | locks | 0 +// | +--------+----> OptoReg::stack0(), even aligned +// | | pad1 | 11 pad to align new SP +// | +--------+ +// | | | 10 +// | | spills | 9 spills +// V | | 8 (pad0 slot for callee) +// -----------+--------+----> Matcher::_out_arg_limit, unaligned +// ^ | out | 7 +// | | args | 6 Holes in outgoing args owned by CALLEE +// Owned by +--------+ +// CALLEE | new out| 6 Empty on Intel, window on Sparc +// | new |preserve| Must be even-aligned. +// | SP-+--------+----> Matcher::_new_SP, even aligned +// | | | +// +// Note 1: Only region 8-11 is determined by the allocator. Region 0-5 is +// known from SELF's arguments and the Java calling convention. +// Region 6-7 is determined per call site. +// Note 2: If the calling convention leaves holes in the incoming argument +// area, those holes are owned by SELF. Holes in the outgoing area +// are owned by the CALLEE. Holes should not be nessecary in the +// incoming area, as the Java calling convention is completely under +// the control of the AD file. Doubles can be sorted and packed to +// avoid holes. Holes in the outgoing arguments may be nessecary for +// varargs C calling conventions. +// Note 3: Region 0-3 is even aligned, with pad2 as needed. Region 3-5 is +// even aligned with pad0 as needed. +// Region 6 is even aligned. Region 6-7 is NOT even aligned; +// (the latter is true on Intel but is it false on RISCV?) +// region 6-11 is even aligned; it may be padded out more so that +// the region from SP to FP meets the minimum stack alignment. +// Note 4: For I2C adapters, the incoming FP may not meet the minimum stack +// alignment. Region 11, pad1, may be dynamically extended so that +// SP meets the minimum alignment. + +frame %{ + // These three registers define part of the calling convention + // between compiled code and the interpreter. + + // Inline Cache Register or methodOop for I2C. + inline_cache_reg(R31); + + // Optional: name the operand used by cisc-spilling to access [stack_pointer + offset] + cisc_spilling_operand_name(indOffset); + + // Number of stack slots consumed by locking an object + // generate Compile::sync_stack_slots + // VMRegImpl::slots_per_word = wordSize / stack_slot_size = 8 / 4 = 2 + sync_stack_slots(1 * VMRegImpl::slots_per_word); + + // Compiled code's Frame Pointer + frame_pointer(R2); + + // Interpreter stores its frame pointer in a register which is + // stored to the stack by I2CAdaptors. + // I2CAdaptors convert from interpreted java to compiled java. + interpreter_frame_pointer(R8); + + // Stack alignment requirement + stack_alignment(StackAlignmentInBytes); // Alignment size in bytes (128-bit -> 16 bytes) + + // Number of outgoing stack slots killed above the out_preserve_stack_slots + // for calls to C. Supports the var-args backing area for register parms. + varargs_C_out_slots_killed(frame::arg_reg_save_area_bytes / BytesPerInt); + + // The after-PROLOG location of the return address. Location of + // return address specifies a type (REG or STACK) and a number + // representing the register number (i.e. - use a register name) or + // stack slot. + // Ret Addr is on stack in slot 0 if no locks or verification or alignment. + // Otherwise, it is above the locks and verification slot and alignment word + // TODO this may well be correct but need to check why that - 2 is there + // ppc port uses 0 but we definitely need to allow for fixed_slots + // which folds in the space used for monitors + return_addr(STACK - 2 + + align_up((Compile::current()->in_preserve_stack_slots() + + Compile::current()->fixed_slots()), + stack_alignment_in_slots())); + + // Location of compiled Java return values. Same as C for now. + return_value + %{ + assert(ideal_reg >= Op_RegI && ideal_reg <= Op_RegL, + "only return normal values"); + + static const int lo[Op_RegL + 1] = { // enum name + 0, // Op_Node + 0, // Op_Set + R10_num, // Op_RegN + R10_num, // Op_RegI + R10_num, // Op_RegP + F10_num, // Op_RegF + F10_num, // Op_RegD + R10_num // Op_RegL + }; + + static const int hi[Op_RegL + 1] = { // enum name + 0, // Op_Node + 0, // Op_Set + OptoReg::Bad, // Op_RegN + OptoReg::Bad, // Op_RegI + R10_H_num, // Op_RegP + OptoReg::Bad, // Op_RegF + F10_H_num, // Op_RegD + R10_H_num // Op_RegL + }; + + return OptoRegPair(hi[ideal_reg], lo[ideal_reg]); + %} +%} + +//----------ATTRIBUTES--------------------------------------------------------- +//----------Operand Attributes------------------------------------------------- +op_attrib op_cost(1); // Required cost attribute + +//----------Instruction Attributes--------------------------------------------- +ins_attrib ins_cost(DEFAULT_COST); // Required cost attribute +ins_attrib ins_size(32); // Required size attribute (in bits) +ins_attrib ins_short_branch(0); // Required flag: is this instruction + // a non-matching short branch variant + // of some long branch? +ins_attrib ins_alignment(4); // Required alignment attribute (must + // be a power of 2) specifies the + // alignment that some part of the + // instruction (not necessarily the + // start) requires. If > 1, a + // compute_padding() function must be + // provided for the instruction + +//----------OPERANDS----------------------------------------------------------- +// Operand definitions must precede instruction definitions for correct parsing +// in the ADLC because operands constitute user defined types which are used in +// instruction definitions. + +//----------Simple Operands---------------------------------------------------- + +// Integer operands 32 bit +// 32 bit immediate +operand immI() +%{ + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 32 bit zero +operand immI0() +%{ + predicate(n->get_int() == 0); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 32 bit unit increment +operand immI_1() +%{ + predicate(n->get_int() == 1); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 32 bit unit decrement +operand immI_M1() +%{ + predicate(n->get_int() == -1); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Unsigned Integer Immediate: 6-bit int, greater than 32 +operand uimmI6_ge32() %{ + predicate(((unsigned int)(n->get_int()) < 64) && (n->get_int() >= 32)); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immI_le_4() +%{ + predicate(n->get_int() <= 4); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immI_16() +%{ + predicate(n->get_int() == 16); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immI_24() +%{ + predicate(n->get_int() == 24); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immI_31() +%{ + predicate(n->get_int() == 31); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immI_63() +%{ + predicate(n->get_int() == 63); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 32 bit integer valid for add immediate +operand immIAdd() +%{ + predicate(Assembler::operand_valid_for_add_immediate((int64_t)n->get_int())); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 32 bit integer valid for sub immediate +operand immISub() +%{ + predicate(Assembler::operand_valid_for_add_immediate(-(int64_t)n->get_int())); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 5 bit signed value. +operand immI5() +%{ + predicate(n->get_int() <= 15 && n->get_int() >= -16); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 5 bit signed value (simm5) +operand immL5() +%{ + predicate(n->get_long() <= 15 && n->get_long() >= -16); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Integer operands 64 bit +// 64 bit immediate +operand immL() +%{ + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 64 bit zero +operand immL0() +%{ + predicate(n->get_long() == 0); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Pointer operands +// Pointer Immediate +operand immP() +%{ + match(ConP); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// NULL Pointer Immediate +operand immP0() +%{ + predicate(n->get_ptr() == 0); + match(ConP); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Pointer Immediate One +// this is used in object initialization (initial object header) +operand immP_1() +%{ + predicate(n->get_ptr() == 1); + match(ConP); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Card Table Byte Map Base +operand immByteMapBase() +%{ + // Get base of card map + predicate(BarrierSet::barrier_set()->is_a(BarrierSet::CardTableBarrierSet) && + (CardTable::CardValue*)n->get_ptr() == + ((CardTableBarrierSet*)(BarrierSet::barrier_set()))->card_table()->byte_map_base()); + match(ConP); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Int Immediate: low 16-bit mask +operand immI_16bits() +%{ + predicate(n->get_int() == 0xFFFF); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Long Immediate: low 32-bit mask +operand immL_32bits() +%{ + predicate(n->get_long() == 0xFFFFFFFFL); + match(ConL); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 64 bit unit decrement +operand immL_M1() +%{ + predicate(n->get_long() == -1); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + + +// 32 bit offset of pc in thread anchor + +operand immL_pc_off() +%{ + predicate(n->get_long() == in_bytes(JavaThread::frame_anchor_offset()) + + in_bytes(JavaFrameAnchor::last_Java_pc_offset())); + match(ConL); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 64 bit integer valid for add immediate +operand immLAdd() +%{ + predicate(Assembler::operand_valid_for_add_immediate(n->get_long())); + match(ConL); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// 64 bit integer valid for sub immediate +operand immLSub() +%{ + predicate(Assembler::operand_valid_for_add_immediate(-(n->get_long()))); + match(ConL); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Narrow pointer operands +// Narrow Pointer Immediate +operand immN() +%{ + match(ConN); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Narrow NULL Pointer Immediate +operand immN0() +%{ + predicate(n->get_narrowcon() == 0); + match(ConN); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immNKlass() +%{ + match(ConNKlass); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Float and Double operands +// Double Immediate +operand immD() +%{ + match(ConD); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Double Immediate: +0.0d +operand immD0() +%{ + predicate(jlong_cast(n->getd()) == 0); + match(ConD); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Float Immediate +operand immF() +%{ + match(ConF); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Float Immediate: +0.0f. +operand immF0() +%{ + predicate(jint_cast(n->getf()) == 0); + match(ConF); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immIOffset() +%{ + predicate(is_imm_in_range(n->get_int(), 12, 0)); + match(ConI); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +operand immLOffset() +%{ + predicate(is_imm_in_range(n->get_long(), 12, 0)); + match(ConL); + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Scale values +operand immIScale() +%{ + predicate(1 <= n->get_int() && (n->get_int() <= 3)); + match(ConI); + + op_cost(0); + format %{ %} + interface(CONST_INTER); +%} + +// Integer 32 bit Register Operands +operand iRegI() +%{ + constraint(ALLOC_IN_RC(any_reg32)); + match(RegI); + match(iRegINoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Integer 32 bit Register not Special +operand iRegINoSp() +%{ + constraint(ALLOC_IN_RC(no_special_reg32)); + match(RegI); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Register R10 only +operand iRegI_R10() +%{ + constraint(ALLOC_IN_RC(int_r10_reg)); + match(RegI); + match(iRegINoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Register R12 only +operand iRegI_R12() +%{ + constraint(ALLOC_IN_RC(int_r12_reg)); + match(RegI); + match(iRegINoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Register R13 only +operand iRegI_R13() +%{ + constraint(ALLOC_IN_RC(int_r13_reg)); + match(RegI); + match(iRegINoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Register R14 only +operand iRegI_R14() +%{ + constraint(ALLOC_IN_RC(int_r14_reg)); + match(RegI); + match(iRegINoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Integer 64 bit Register Operands +operand iRegL() +%{ + constraint(ALLOC_IN_RC(any_reg)); + match(RegL); + match(iRegLNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Integer 64 bit Register not Special +operand iRegLNoSp() +%{ + constraint(ALLOC_IN_RC(no_special_reg)); + match(RegL); + match(iRegL_R10); + format %{ %} + interface(REG_INTER); +%} + +// Long 64 bit Register R28 only +operand iRegL_R28() +%{ + constraint(ALLOC_IN_RC(r28_reg)); + match(RegL); + match(iRegLNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Long 64 bit Register R29 only +operand iRegL_R29() +%{ + constraint(ALLOC_IN_RC(r29_reg)); + match(RegL); + match(iRegLNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Long 64 bit Register R30 only +operand iRegL_R30() +%{ + constraint(ALLOC_IN_RC(r30_reg)); + match(RegL); + match(iRegLNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Pointer Register Operands +// Pointer Register +operand iRegP() +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(RegP); + match(iRegPNoSp); + match(iRegP_R10); + match(javaThread_RegP); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Pointer 64 bit Register not Special +operand iRegPNoSp() +%{ + constraint(ALLOC_IN_RC(no_special_ptr_reg)); + match(RegP); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand iRegP_R10() +%{ + constraint(ALLOC_IN_RC(r10_reg)); + match(RegP); + // match(iRegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Pointer 64 bit Register R11 only +operand iRegP_R11() +%{ + constraint(ALLOC_IN_RC(r11_reg)); + match(RegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand iRegP_R12() +%{ + constraint(ALLOC_IN_RC(r12_reg)); + match(RegP); + // match(iRegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Pointer 64 bit Register R13 only +operand iRegP_R13() +%{ + constraint(ALLOC_IN_RC(r13_reg)); + match(RegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand iRegP_R14() +%{ + constraint(ALLOC_IN_RC(r14_reg)); + match(RegP); + // match(iRegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand iRegP_R15() +%{ + constraint(ALLOC_IN_RC(r15_reg)); + match(RegP); + // match(iRegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand iRegP_R16() +%{ + constraint(ALLOC_IN_RC(r16_reg)); + match(RegP); + // match(iRegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Pointer 64 bit Register R28 only +operand iRegP_R28() +%{ + constraint(ALLOC_IN_RC(r28_reg)); + match(RegP); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Pointer Register Operands +// Narrow Pointer Register +operand iRegN() +%{ + constraint(ALLOC_IN_RC(any_reg32)); + match(RegN); + match(iRegNNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Integer 64 bit Register not Special +operand iRegNNoSp() +%{ + constraint(ALLOC_IN_RC(no_special_reg32)); + match(RegN); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// heap base register -- used for encoding immN0 +operand iRegIHeapbase() +%{ + constraint(ALLOC_IN_RC(heapbase_reg)); + match(RegI); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Long 64 bit Register R10 only +operand iRegL_R10() +%{ + constraint(ALLOC_IN_RC(r10_reg)); + match(RegL); + match(iRegLNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Float Register +// Float register operands +operand fRegF() +%{ + constraint(ALLOC_IN_RC(float_reg)); + match(RegF); + + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Double Register +// Double register operands +operand fRegD() +%{ + constraint(ALLOC_IN_RC(double_reg)); + match(RegD); + + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Generic vector class. This will be used for +// all vector operands. +operand vReg() +%{ + constraint(ALLOC_IN_RC(vectora_reg)); + match(VecA); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vReg_V1() +%{ + constraint(ALLOC_IN_RC(v1_reg)); + match(VecA); + match(vReg); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vReg_V2() +%{ + constraint(ALLOC_IN_RC(v2_reg)); + match(VecA); + match(vReg); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vReg_V3() +%{ + constraint(ALLOC_IN_RC(v3_reg)); + match(VecA); + match(vReg); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vReg_V4() +%{ + constraint(ALLOC_IN_RC(v4_reg)); + match(VecA); + match(vReg); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +operand vReg_V5() +%{ + constraint(ALLOC_IN_RC(v5_reg)); + match(VecA); + match(vReg); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +// Java Thread Register +operand javaThread_RegP(iRegP reg) +%{ + constraint(ALLOC_IN_RC(java_thread_reg)); // java_thread_reg + match(reg); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +//----------Memory Operands---------------------------------------------------- +// RISCV has only base_plus_offset and literal address mode, so no need to use +// index and scale. Here set index as 0xffffffff and scale as 0x0. +operand indirect(iRegP reg) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(reg); + op_cost(0); + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp(0x0); + %} +%} + +operand indOffI(iRegP reg, immIOffset off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffL(iRegP reg, immLOffset off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indirectN(iRegN reg) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(DecodeN reg); + op_cost(0); + format %{ "[$reg]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp(0x0); + %} +%} + +operand indOffIN(iRegN reg, immIOffset off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + op_cost(0); + format %{ "[$reg, $off]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +operand indOffLN(iRegN reg, immLOffset off) +%{ + predicate(CompressedOops::shift() == 0); + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP (DecodeN reg) off); + op_cost(0); + format %{ "[$reg, $off]\t# narrow" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + +// RISCV opto stubs need to write to the pc slot in the thread anchor +operand thread_anchor_pc(javaThread_RegP reg, immL_pc_off off) +%{ + constraint(ALLOC_IN_RC(ptr_reg)); + match(AddP reg off); + op_cost(0); + format %{ "[$reg, $off]" %} + interface(MEMORY_INTER) %{ + base($reg); + index(0xffffffff); + scale(0x0); + disp($off); + %} +%} + + +//----------Special Memory Operands-------------------------------------------- +// Stack Slot Operand - This operand is used for loading and storing temporary +// values on the stack where a match requires a value to +// flow through memory. +operand stackSlotI(sRegI reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + // match(RegI); + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x02); // RSP + index(0xffffffff); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} + +operand stackSlotF(sRegF reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + // match(RegF); + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x02); // RSP + index(0xffffffff); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} + +operand stackSlotD(sRegD reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + // match(RegD); + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x02); // RSP + index(0xffffffff); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} + +operand stackSlotL(sRegL reg) +%{ + constraint(ALLOC_IN_RC(stack_slots)); + // No match rule because this operand is only generated in matching + // match(RegL); + format %{ "[$reg]" %} + interface(MEMORY_INTER) %{ + base(0x02); // RSP + index(0xffffffff); // No Index + scale(0x0); // No Scale + disp($reg); // Stack Offset + %} +%} + +// Special operand allowing long args to int ops to be truncated for free + +operand iRegL2I(iRegL reg) %{ + + op_cost(0); + + match(ConvL2I reg); + + format %{ "l2i($reg)" %} + + interface(REG_INTER) +%} + + +// Comparison Operands +// NOTE: Label is a predefined operand which should not be redefined in +// the AD file. It is generically handled within the ADLC. + +//----------Conditional Branch Operands---------------------------------------- +// Comparison Op - This is the operation of the comparison, and is limited to +// the following set of codes: +// L (<), LE (<=), G (>), GE (>=), E (==), NE (!=) +// +// Other attributes of the comparison, such as unsignedness, are specified +// by the comparison instruction that sets a condition code flags register. +// That result is represented by a flags operand whose subtype is appropriate +// to the unsignedness (etc.) of the comparison. +// +// Later, the instruction which matches both the Comparison Op (a Bool) and +// the flags (produced by the Cmp) specifies the coding of the comparison op +// by matching a specific subtype of Bool operand below, such as cmpOpU. + + +// used for signed integral comparisons and fp comparisons +operand cmpOp() +%{ + match(Bool); + + format %{ "" %} + + // the values in interface derives from struct BoolTest::mask + interface(COND_INTER) %{ + equal(0x0, "eq"); + greater(0x1, "gt"); + overflow(0x2, "overflow"); + less(0x3, "lt"); + not_equal(0x4, "ne"); + less_equal(0x5, "le"); + no_overflow(0x6, "no_overflow"); + greater_equal(0x7, "ge"); + %} +%} + +// used for unsigned integral comparisons +operand cmpOpU() +%{ + match(Bool); + + format %{ "" %} + // the values in interface derives from struct BoolTest::mask + interface(COND_INTER) %{ + equal(0x0, "eq"); + greater(0x1, "gtu"); + overflow(0x2, "overflow"); + less(0x3, "ltu"); + not_equal(0x4, "ne"); + less_equal(0x5, "leu"); + no_overflow(0x6, "no_overflow"); + greater_equal(0x7, "geu"); + %} +%} + +// used for certain integral comparisons which can be +// converted to bxx instructions +operand cmpOpEqNe() +%{ + match(Bool); + op_cost(0); + predicate(n->as_Bool()->_test._test == BoolTest::ne || + n->as_Bool()->_test._test == BoolTest::eq); + + format %{ "" %} + interface(COND_INTER) %{ + equal(0x0, "eq"); + greater(0x1, "gt"); + overflow(0x2, "overflow"); + less(0x3, "lt"); + not_equal(0x4, "ne"); + less_equal(0x5, "le"); + no_overflow(0x6, "no_overflow"); + greater_equal(0x7, "ge"); + %} +%} + +operand cmpOpULtGe() +%{ + match(Bool); + op_cost(0); + predicate(n->as_Bool()->_test._test == BoolTest::lt || + n->as_Bool()->_test._test == BoolTest::ge); + + format %{ "" %} + interface(COND_INTER) %{ + equal(0x0, "eq"); + greater(0x1, "gt"); + overflow(0x2, "overflow"); + less(0x3, "lt"); + not_equal(0x4, "ne"); + less_equal(0x5, "le"); + no_overflow(0x6, "no_overflow"); + greater_equal(0x7, "ge"); + %} +%} + +operand cmpOpUEqNeLeGt() +%{ + match(Bool); + op_cost(0); + predicate(n->as_Bool()->_test._test == BoolTest::ne || + n->as_Bool()->_test._test == BoolTest::eq || + n->as_Bool()->_test._test == BoolTest::le || + n->as_Bool()->_test._test == BoolTest::gt); + + format %{ "" %} + interface(COND_INTER) %{ + equal(0x0, "eq"); + greater(0x1, "gt"); + overflow(0x2, "overflow"); + less(0x3, "lt"); + not_equal(0x4, "ne"); + less_equal(0x5, "le"); + no_overflow(0x6, "no_overflow"); + greater_equal(0x7, "ge"); + %} +%} + + +// Flags register, used as output of compare logic +operand rFlagsReg() +%{ + constraint(ALLOC_IN_RC(reg_flags)); + match(RegFlags); + + op_cost(0); + format %{ "RFLAGS" %} + interface(REG_INTER); +%} + +// Special Registers + +// Method Register +operand inline_cache_RegP(iRegP reg) +%{ + constraint(ALLOC_IN_RC(method_reg)); // inline_cache_reg + match(reg); + match(iRegPNoSp); + op_cost(0); + format %{ %} + interface(REG_INTER); +%} + +//----------OPERAND CLASSES---------------------------------------------------- +// Operand Classes are groups of operands that are used as to simplify +// instruction definitions by not requiring the AD writer to specify +// separate instructions for every form of operand when the +// instruction accepts multiple operand types with the same basic +// encoding and format. The classic case of this is memory operands. + +// memory is used to define read/write location for load/store +// instruction defs. we can turn a memory op into an Address + +opclass memory(indirect, indOffI, indOffL, indirectN, indOffIN, indOffLN); + +// iRegIorL2I is used for src inputs in rules for 32 bit int (I) +// operations. it allows the src to be either an iRegI or a (ConvL2I +// iRegL). in the latter case the l2i normally planted for a ConvL2I +// can be elided because the 32-bit instruction will just employ the +// lower 32 bits anyway. +// +// n.b. this does not elide all L2I conversions. if the truncated +// value is consumed by more than one operation then the ConvL2I +// cannot be bundled into the consuming nodes so an l2i gets planted +// (actually a mvw $dst $src) and the downstream instructions consume +// the result of the l2i as an iRegI input. That's a shame since the +// mvw is actually redundant but its not too costly. + +opclass iRegIorL2I(iRegI, iRegL2I); +opclass iRegIorL(iRegI, iRegL); +opclass iRegNorP(iRegN, iRegP); +opclass iRegILNP(iRegI, iRegL, iRegN, iRegP); +opclass iRegILNPNoSp(iRegINoSp, iRegLNoSp, iRegNNoSp, iRegPNoSp); +opclass immIorL(immI, immL); + +//----------PIPELINE----------------------------------------------------------- +// Rules which define the behavior of the target architectures pipeline. + +// For specific pipelines, e.g. generic RISC-V, define the stages of that pipeline +//pipe_desc(ID, EX, MEM, WR); +#define ID S0 +#define EX S1 +#define MEM S2 +#define WR S3 + +// Integer ALU reg operation +pipeline %{ + +attributes %{ + // RISC-V instructions are of fixed length + fixed_size_instructions; // Fixed size instructions TODO does + max_instructions_per_bundle = 2; // Generic RISC-V 1, Sifive Series 7 2 + // RISC-V instructions come in 32-bit word units + instruction_unit_size = 4; // An instruction is 4 bytes long + instruction_fetch_unit_size = 64; // The processor fetches one line + instruction_fetch_units = 1; // of 64 bytes + + // List of nop instructions + nops( MachNop ); +%} + +// We don't use an actual pipeline model so don't care about resources +// or description. we do use pipeline classes to introduce fixed +// latencies + +//----------RESOURCES---------------------------------------------------------- +// Resources are the functional units available to the machine + +// Generic RISC-V pipeline +// 1 decoder +// 1 instruction decoded per cycle +// 1 load/store ops per cycle, 1 branch, 1 FPU +// 1 mul, 1 div + +resources ( DECODE, + ALU, + MUL, + DIV, + BRANCH, + LDST, + FPU); + +//----------PIPELINE DESCRIPTION----------------------------------------------- +// Pipeline Description specifies the stages in the machine's pipeline + +// Define the pipeline as a generic 6 stage pipeline +pipe_desc(S0, S1, S2, S3, S4, S5); + +//----------PIPELINE CLASSES--------------------------------------------------- +// Pipeline Classes describe the stages in which input and output are +// referenced by the hardware pipeline. + +pipe_class fp_dop_reg_reg_s(fRegF dst, fRegF src1, fRegF src2) +%{ + single_instruction; + src1 : S1(read); + src2 : S2(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_dop_reg_reg_d(fRegD dst, fRegD src1, fRegD src2) +%{ + src1 : S1(read); + src2 : S2(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_uop_s(fRegF dst, fRegF src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_uop_d(fRegD dst, fRegD src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_d2f(fRegF dst, fRegD src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_f2d(fRegD dst, fRegF src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_f2i(iRegINoSp dst, fRegF src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_f2l(iRegLNoSp dst, fRegF src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_i2f(fRegF dst, iRegIorL2I src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_l2f(fRegF dst, iRegL src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_d2i(iRegINoSp dst, fRegD src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_d2l(iRegLNoSp dst, fRegD src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_i2d(fRegD dst, iRegIorL2I src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_l2d(fRegD dst, iRegIorL2I src) +%{ + single_instruction; + src : S1(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_div_s(fRegF dst, fRegF src1, fRegF src2) +%{ + single_instruction; + src1 : S1(read); + src2 : S2(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_div_d(fRegD dst, fRegD src1, fRegD src2) +%{ + single_instruction; + src1 : S1(read); + src2 : S2(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_sqrt_s(fRegF dst, fRegF src1, fRegF src2) +%{ + single_instruction; + src1 : S1(read); + src2 : S2(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_sqrt_d(fRegD dst, fRegD src1, fRegD src2) +%{ + single_instruction; + src1 : S1(read); + src2 : S2(read); + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_load_constant_s(fRegF dst) +%{ + single_instruction; + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_load_constant_d(fRegD dst) +%{ + single_instruction; + dst : S5(write); + DECODE : ID; + FPU : S5; +%} + +pipe_class fp_load_mem_s(fRegF dst, memory mem) +%{ + single_instruction; + mem : S1(read); + dst : S5(write); + DECODE : ID; + LDST : MEM; +%} + +pipe_class fp_load_mem_d(fRegD dst, memory mem) +%{ + single_instruction; + mem : S1(read); + dst : S5(write); + DECODE : ID; + LDST : MEM; +%} + +pipe_class fp_store_reg_s(fRegF src, memory mem) +%{ + single_instruction; + src : S1(read); + mem : S5(write); + DECODE : ID; + LDST : MEM; +%} + +pipe_class fp_store_reg_d(fRegD src, memory mem) +%{ + single_instruction; + src : S1(read); + mem : S5(write); + DECODE : ID; + LDST : MEM; +%} + +//------- Integer ALU operations -------------------------- + +// Integer ALU reg-reg operation +// Operands needs in ID, result generated in EX +// E.g. ADD Rd, Rs1, Rs2 +pipe_class ialu_reg_reg(iRegI dst, iRegI src1, iRegI src2) +%{ + single_instruction; + dst : EX(write); + src1 : ID(read); + src2 : ID(read); + DECODE : ID; + ALU : EX; +%} + +// Integer ALU reg operation with constant shift +// E.g. SLLI Rd, Rs1, #shift +pipe_class ialu_reg_shift(iRegI dst, iRegI src1) +%{ + single_instruction; + dst : EX(write); + src1 : ID(read); + DECODE : ID; + ALU : EX; +%} + +// Integer ALU reg-reg operation with variable shift +// both operands must be available in ID +// E.g. SLL Rd, Rs1, Rs2 +pipe_class ialu_reg_reg_vshift(iRegI dst, iRegI src1, iRegI src2) +%{ + single_instruction; + dst : EX(write); + src1 : ID(read); + src2 : ID(read); + DECODE : ID; + ALU : EX; +%} + +// Integer ALU reg operation +// E.g. NEG Rd, Rs2 +pipe_class ialu_reg(iRegI dst, iRegI src) +%{ + single_instruction; + dst : EX(write); + src : ID(read); + DECODE : ID; + ALU : EX; +%} + +// Integer ALU reg immediate operation +// E.g. ADDI Rd, Rs1, #imm +pipe_class ialu_reg_imm(iRegI dst, iRegI src1) +%{ + single_instruction; + dst : EX(write); + src1 : ID(read); + DECODE : ID; + ALU : EX; +%} + +// Integer ALU immediate operation (no source operands) +// E.g. LI Rd, #imm +pipe_class ialu_imm(iRegI dst) +%{ + single_instruction; + dst : EX(write); + DECODE : ID; + ALU : EX; +%} + +//------- Multiply pipeline operations -------------------- + +// Multiply reg-reg +// E.g. MULW Rd, Rs1, Rs2 +pipe_class imul_reg_reg(iRegI dst, iRegI src1, iRegI src2) +%{ + single_instruction; + dst : WR(write); + src1 : ID(read); + src2 : ID(read); + DECODE : ID; + MUL : WR; +%} + +// E.g. MUL RD, Rs1, Rs2 +pipe_class lmul_reg_reg(iRegI dst, iRegI src1, iRegI src2) +%{ + single_instruction; + fixed_latency(3); // Maximum latency for 64 bit mul + dst : WR(write); + src1 : ID(read); + src2 : ID(read); + DECODE : ID; + MUL : WR; +%} + +//------- Divide pipeline operations -------------------- + +// E.g. DIVW Rd, Rs1, Rs2 +pipe_class idiv_reg_reg(iRegI dst, iRegI src1, iRegI src2) +%{ + single_instruction; + fixed_latency(8); // Maximum latency for 32 bit divide + dst : WR(write); + src1 : ID(read); + src2 : ID(read); + DECODE : ID; + DIV : WR; +%} + +// E.g. DIV RD, Rs1, Rs2 +pipe_class ldiv_reg_reg(iRegI dst, iRegI src1, iRegI src2) +%{ + single_instruction; + fixed_latency(16); // Maximum latency for 64 bit divide + dst : WR(write); + src1 : ID(read); + src2 : ID(read); + DECODE : ID; + DIV : WR; +%} + +//------- Load pipeline operations ------------------------ + +// Load - reg, mem +// E.g. LA Rd, mem +pipe_class iload_reg_mem(iRegI dst, memory mem) +%{ + single_instruction; + dst : WR(write); + mem : ID(read); + DECODE : ID; + LDST : MEM; +%} + +// Load - reg, reg +// E.g. LD Rd, Rs +pipe_class iload_reg_reg(iRegI dst, iRegI src) +%{ + single_instruction; + dst : WR(write); + src : ID(read); + DECODE : ID; + LDST : MEM; +%} + +//------- Store pipeline operations ----------------------- + +// Store - zr, mem +// E.g. SD zr, mem +pipe_class istore_mem(memory mem) +%{ + single_instruction; + mem : ID(read); + DECODE : ID; + LDST : MEM; +%} + +// Store - reg, mem +// E.g. SD Rs, mem +pipe_class istore_reg_mem(iRegI src, memory mem) +%{ + single_instruction; + mem : ID(read); + src : EX(read); + DECODE : ID; + LDST : MEM; +%} + +// Store - reg, reg +// E.g. SD Rs2, Rs1 +pipe_class istore_reg_reg(iRegI dst, iRegI src) +%{ + single_instruction; + dst : ID(read); + src : EX(read); + DECODE : ID; + LDST : MEM; +%} + +//------- Store pipeline operations ----------------------- + +// Branch +pipe_class pipe_branch() +%{ + single_instruction; + DECODE : ID; + BRANCH : EX; +%} + +// Branch +pipe_class pipe_branch_reg(iRegI src) +%{ + single_instruction; + src : ID(read); + DECODE : ID; + BRANCH : EX; +%} + +// Compare & Branch +// E.g. BEQ Rs1, Rs2, L +pipe_class pipe_cmp_branch(iRegI src1, iRegI src2) +%{ + single_instruction; + src1 : ID(read); + src2 : ID(read); + DECODE : ID; + BRANCH : EX; +%} + +// E.g. BEQZ Rs, L +pipe_class pipe_cmpz_branch(iRegI src) +%{ + single_instruction; + src : ID(read); + DECODE : ID; + BRANCH : EX; +%} + +//------- Synchronisation operations ---------------------- +// Any operation requiring serialization +// E.g. FENCE/Atomic Ops/Load Acquire/Store Release +pipe_class pipe_serial() +%{ + single_instruction; + force_serialization; + fixed_latency(16); + DECODE : ID; + LDST : MEM; +%} + +pipe_class pipe_slow() +%{ + instruction_count(10); + multiple_bundles; + force_serialization; + fixed_latency(16); + DECODE : ID; + LDST : MEM; +%} + +// Empty pipeline class +pipe_class pipe_class_empty() +%{ + single_instruction; + fixed_latency(0); +%} + +// Default pipeline class. +pipe_class pipe_class_default() +%{ + single_instruction; + fixed_latency(2); +%} + +// Pipeline class for compares. +pipe_class pipe_class_compare() +%{ + single_instruction; + fixed_latency(16); +%} + +// Pipeline class for memory operations. +pipe_class pipe_class_memory() +%{ + single_instruction; + fixed_latency(16); +%} + +// Pipeline class for call. +pipe_class pipe_class_call() +%{ + single_instruction; + fixed_latency(100); +%} + +// Define the class for the Nop node. +define %{ + MachNop = pipe_class_empty; +%} +%} +//----------INSTRUCTIONS------------------------------------------------------- +// +// match -- States which machine-independent subtree may be replaced +// by this instruction. +// ins_cost -- The estimated cost of this instruction is used by instruction +// selection to identify a minimum cost tree of machine +// instructions that matches a tree of machine-independent +// instructions. +// format -- A string providing the disassembly for this instruction. +// The value of an instruction's operand may be inserted +// by referring to it with a '$' prefix. +// opcode -- Three instruction opcodes may be provided. These are referred +// to within an encode class as $primary, $secondary, and $tertiary +// rrspectively. The primary opcode is commonly used to +// indicate the type of machine instruction, while secondary +// and tertiary are often used for prefix options or addressing +// modes. +// ins_encode -- A list of encode classes with parameters. The encode class +// name must have been defined in an 'enc_class' specification +// in the encode section of the architecture description. + +// ============================================================================ +// Memory (Load/Store) Instructions + +// Load Instructions + +// Load Byte (8 bit signed) +instruct loadB(iRegINoSp dst, memory mem) +%{ + match(Set dst (LoadB mem)); + + ins_cost(LOAD_COST); + format %{ "lb $dst, $mem\t# byte, #@loadB" %} + + ins_encode %{ + __ lb(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Byte (8 bit signed) into long +instruct loadB2L(iRegLNoSp dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadB mem))); + + ins_cost(LOAD_COST); + format %{ "lb $dst, $mem\t# byte, #@loadB2L" %} + + ins_encode %{ + __ lb(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Byte (8 bit unsigned) +instruct loadUB(iRegINoSp dst, memory mem) +%{ + match(Set dst (LoadUB mem)); + + ins_cost(LOAD_COST); + format %{ "lbu $dst, $mem\t# byte, #@loadUB" %} + + ins_encode %{ + __ lbu(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Byte (8 bit unsigned) into long +instruct loadUB2L(iRegLNoSp dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadUB mem))); + + ins_cost(LOAD_COST); + format %{ "lbu $dst, $mem\t# byte, #@loadUB2L" %} + + ins_encode %{ + __ lbu(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Short (16 bit signed) +instruct loadS(iRegINoSp dst, memory mem) +%{ + match(Set dst (LoadS mem)); + + ins_cost(LOAD_COST); + format %{ "lh $dst, $mem\t# short, #@loadS" %} + + ins_encode %{ + __ lh(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Short (16 bit signed) into long +instruct loadS2L(iRegLNoSp dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadS mem))); + + ins_cost(LOAD_COST); + format %{ "lh $dst, $mem\t# short, #@loadS2L" %} + + ins_encode %{ + __ lh(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Char (16 bit unsigned) +instruct loadUS(iRegINoSp dst, memory mem) +%{ + match(Set dst (LoadUS mem)); + + ins_cost(LOAD_COST); + format %{ "lhu $dst, $mem\t# short, #@loadUS" %} + + ins_encode %{ + __ lhu(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Short/Char (16 bit unsigned) into long +instruct loadUS2L(iRegLNoSp dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadUS mem))); + + ins_cost(LOAD_COST); + format %{ "lhu $dst, $mem\t# short, #@loadUS2L" %} + + ins_encode %{ + __ lhu(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Integer (32 bit signed) +instruct loadI(iRegINoSp dst, memory mem) +%{ + match(Set dst (LoadI mem)); + + ins_cost(LOAD_COST); + format %{ "lw $dst, $mem\t# int, #@loadI" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ lw(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Integer (32 bit signed) into long +instruct loadI2L(iRegLNoSp dst, memory mem) +%{ + match(Set dst (ConvI2L (LoadI mem))); + + ins_cost(LOAD_COST); + format %{ "lw $dst, $mem\t# int, #@loadI2L" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ lw(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Integer (32 bit unsigned) into long +instruct loadUI2L(iRegLNoSp dst, memory mem, immL_32bits mask) +%{ + match(Set dst (AndL (ConvI2L (LoadI mem)) mask)); + + ins_cost(LOAD_COST); + format %{ "lwu $dst, $mem\t# int, #@loadUI2L" %} + + ins_encode %{ + __ lwu(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Long (64 bit signed) +instruct loadL(iRegLNoSp dst, memory mem) +%{ + match(Set dst (LoadL mem)); + + ins_cost(LOAD_COST); + format %{ "ld $dst, $mem\t# int, #@loadL" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ ld(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Range +instruct loadRange(iRegINoSp dst, memory mem) +%{ + match(Set dst (LoadRange mem)); + + ins_cost(LOAD_COST); + format %{ "lwu $dst, $mem\t# range, #@loadRange" %} + + ins_encode %{ + __ lwu(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Pointer +instruct loadP(iRegPNoSp dst, memory mem) +%{ + match(Set dst (LoadP mem)); + predicate(n->as_Load()->barrier_data() == 0); + + ins_cost(LOAD_COST); + format %{ "ld $dst, $mem\t# ptr, #@loadP" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ ld(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Compressed Pointer +instruct loadN(iRegNNoSp dst, memory mem) +%{ + match(Set dst (LoadN mem)); + + ins_cost(LOAD_COST); + format %{ "lwu $dst, $mem\t# loadN, compressed ptr, #@loadN" %} + + ins_encode %{ + __ lwu(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Klass Pointer +instruct loadKlass(iRegPNoSp dst, memory mem) +%{ + match(Set dst (LoadKlass mem)); + + ins_cost(LOAD_COST); + format %{ "ld $dst, $mem\t# class, #@loadKlass" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ ld(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Narrow Klass Pointer +instruct loadNKlass(iRegNNoSp dst, memory mem) +%{ + match(Set dst (LoadNKlass mem)); + + ins_cost(LOAD_COST); + format %{ "lwu $dst, $mem\t# loadNKlass, compressed class ptr, #@loadNKlass" %} + + ins_encode %{ + __ lwu(as_Register($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(iload_reg_mem); +%} + +// Load Float +instruct loadF(fRegF dst, memory mem) +%{ + match(Set dst (LoadF mem)); + + ins_cost(LOAD_COST); + format %{ "flw $dst, $mem\t# float, #@loadF" %} + + ins_encode %{ + __ flw(as_FloatRegister($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(fp_load_mem_s); +%} + +// Load Double +instruct loadD(fRegD dst, memory mem) +%{ + match(Set dst (LoadD mem)); + + ins_cost(LOAD_COST); + format %{ "fld $dst, $mem\t# double, #@loadD" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ fld(as_FloatRegister($dst$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(fp_load_mem_d); +%} + +// Load Int Constant +instruct loadConI(iRegINoSp dst, immI src) +%{ + match(Set dst src); + + ins_cost(ALU_COST); + format %{ "li $dst, $src\t# int, #@loadConI" %} + + ins_encode(riscv_enc_li_imm(dst, src)); + + ins_pipe(ialu_imm); +%} + +// Load Long Constant +instruct loadConL(iRegLNoSp dst, immL src) +%{ + match(Set dst src); + + ins_cost(ALU_COST); + format %{ "li $dst, $src\t# long, #@loadConL" %} + + ins_encode(riscv_enc_li_imm(dst, src)); + + ins_pipe(ialu_imm); +%} + +// Load Pointer Constant +instruct loadConP(iRegPNoSp dst, immP con) +%{ + match(Set dst con); + + ins_cost(ALU_COST); + format %{ "mv $dst, $con\t# ptr, #@loadConP" %} + + ins_encode(riscv_enc_mov_p(dst, con)); + + ins_pipe(ialu_imm); +%} + +// Load Null Pointer Constant +instruct loadConP0(iRegPNoSp dst, immP0 con) +%{ + match(Set dst con); + + ins_cost(ALU_COST); + format %{ "mv $dst, $con\t# NULL ptr, #@loadConP0" %} + + ins_encode(riscv_enc_mov_zero(dst)); + + ins_pipe(ialu_imm); +%} + +// Load Pointer Constant One +instruct loadConP1(iRegPNoSp dst, immP_1 con) +%{ + match(Set dst con); + + ins_cost(ALU_COST); + format %{ "mv $dst, $con\t# load ptr constant one, #@loadConP1" %} + + ins_encode(riscv_enc_mov_p1(dst)); + + ins_pipe(ialu_imm); +%} + +// Load Byte Map Base Constant +instruct loadByteMapBase(iRegPNoSp dst, immByteMapBase con) +%{ + match(Set dst con); + ins_cost(ALU_COST); + format %{ "mv $dst, $con\t# Byte Map Base, #@loadByteMapBase" %} + + ins_encode(riscv_enc_mov_byte_map_base(dst)); + + ins_pipe(ialu_imm); +%} + +// Load Narrow Pointer Constant +instruct loadConN(iRegNNoSp dst, immN con) +%{ + match(Set dst con); + + ins_cost(ALU_COST * 4); + format %{ "mv $dst, $con\t# compressed ptr, #@loadConN" %} + + ins_encode(riscv_enc_mov_n(dst, con)); + + ins_pipe(ialu_imm); +%} + +// Load Narrow Null Pointer Constant +instruct loadConN0(iRegNNoSp dst, immN0 con) +%{ + match(Set dst con); + + ins_cost(ALU_COST); + format %{ "mv $dst, $con\t# compressed NULL ptr, #@loadConN0" %} + + ins_encode(riscv_enc_mov_zero(dst)); + + ins_pipe(ialu_imm); +%} + +// Load Narrow Klass Constant +instruct loadConNKlass(iRegNNoSp dst, immNKlass con) +%{ + match(Set dst con); + + ins_cost(ALU_COST * 6); + format %{ "mv $dst, $con\t# compressed klass ptr, #@loadConNKlass" %} + + ins_encode(riscv_enc_mov_nk(dst, con)); + + ins_pipe(ialu_imm); +%} + +// Load Float Constant +instruct loadConF(fRegF dst, immF con) %{ + match(Set dst con); + + ins_cost(LOAD_COST); + format %{ + "flw $dst, [$constantaddress]\t# load from constant table: float=$con, #@loadConF" + %} + + ins_encode %{ + __ flw(as_FloatRegister($dst$$reg), $constantaddress($con)); + %} + + ins_pipe(fp_load_constant_s); +%} + +instruct loadConF0(fRegF dst, immF0 con) %{ + match(Set dst con); + + ins_cost(XFER_COST); + + format %{ "fmv.w.x $dst, zr\t# float, #@loadConF0" %} + + ins_encode %{ + __ fmv_w_x(as_FloatRegister($dst$$reg), zr); + %} + + ins_pipe(fp_load_constant_s); +%} + +// Load Double Constant +instruct loadConD(fRegD dst, immD con) %{ + match(Set dst con); + + ins_cost(LOAD_COST); + format %{ + "fld $dst, [$constantaddress]\t# load from constant table: double=$con, #@loadConD" + %} + + ins_encode %{ + __ fld(as_FloatRegister($dst$$reg), $constantaddress($con)); + %} + + ins_pipe(fp_load_constant_d); +%} + +instruct loadConD0(fRegD dst, immD0 con) %{ + match(Set dst con); + + ins_cost(XFER_COST); + + format %{ "fmv.d.x $dst, zr\t# double, #@loadConD0" %} + + ins_encode %{ + __ fmv_d_x(as_FloatRegister($dst$$reg), zr); + %} + + ins_pipe(fp_load_constant_d); +%} + +// Store Instructions +// Store CMS card-mark Immediate +instruct storeimmCM0(immI0 zero, memory mem) +%{ + match(Set mem (StoreCM mem zero)); + + ins_cost(STORE_COST); + format %{ "storestore (elided)\n\t" + "sb zr, $mem\t# byte, #@storeimmCM0" %} + + ins_encode %{ + __ sb(zr, Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_mem); +%} + +// Store CMS card-mark Immediate with intervening StoreStore +// needed when using CMS with no conditional card marking +instruct storeimmCM0_ordered(immI0 zero, memory mem) +%{ + match(Set mem (StoreCM mem zero)); + + ins_cost(ALU_COST + STORE_COST); + format %{ "membar(StoreStore)\n\t" + "sb zr, $mem\t# byte, #@storeimmCM0_ordered" %} + + ins_encode %{ + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + __ sb(zr, Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_mem); +%} + +// Store Byte +instruct storeB(iRegIorL2I src, memory mem) +%{ + match(Set mem (StoreB mem src)); + + ins_cost(STORE_COST); + format %{ "sb $src, $mem\t# byte, #@storeB" %} + + ins_encode %{ + __ sb(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_reg_mem); +%} + +instruct storeimmB0(immI0 zero, memory mem) +%{ + match(Set mem (StoreB mem zero)); + + ins_cost(STORE_COST); + format %{ "sb zr, $mem\t# byte, #@storeimmB0" %} + + ins_encode %{ + __ sb(zr, Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_mem); +%} + +// Store Char/Short +instruct storeC(iRegIorL2I src, memory mem) +%{ + match(Set mem (StoreC mem src)); + + ins_cost(STORE_COST); + format %{ "sh $src, $mem\t# short, #@storeC" %} + + ins_encode %{ + __ sh(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_reg_mem); +%} + +instruct storeimmC0(immI0 zero, memory mem) +%{ + match(Set mem (StoreC mem zero)); + + ins_cost(STORE_COST); + format %{ "sh zr, $mem\t# short, #@storeimmC0" %} + + ins_encode %{ + __ sh(zr, Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_mem); +%} + +// Store Integer +instruct storeI(iRegIorL2I src, memory mem) +%{ + match(Set mem(StoreI mem src)); + + ins_cost(STORE_COST); + format %{ "sw $src, $mem\t# int, #@storeI" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ sw(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_reg_mem); +%} + +instruct storeimmI0(immI0 zero, memory mem) +%{ + match(Set mem(StoreI mem zero)); + + ins_cost(STORE_COST); + format %{ "sw zr, $mem\t# int, #@storeimmI0" %} + + ins_encode %{ + __ sw(zr, Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_mem); +%} + +// Store Long (64 bit signed) +instruct storeL(iRegL src, memory mem) +%{ + match(Set mem (StoreL mem src)); + + ins_cost(STORE_COST); + format %{ "sd $src, $mem\t# long, #@storeL" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ sd(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_reg_mem); +%} + +// Store Long (64 bit signed) +instruct storeimmL0(immL0 zero, memory mem) +%{ + match(Set mem (StoreL mem zero)); + + ins_cost(STORE_COST); + format %{ "sd zr, $mem\t# long, #@storeimmL0" %} + + ins_encode %{ + __ sd(zr, Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_mem); +%} + +// Store Pointer +instruct storeP(iRegP src, memory mem) +%{ + match(Set mem (StoreP mem src)); + + ins_cost(STORE_COST); + format %{ "sd $src, $mem\t# ptr, #@storeP" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ sd(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_reg_mem); +%} + +// Store Pointer +instruct storeimmP0(immP0 zero, memory mem) +%{ + match(Set mem (StoreP mem zero)); + + ins_cost(STORE_COST); + format %{ "sd zr, $mem\t# ptr, #@storeimmP0" %} + + ins_encode %{ + __ sd(zr, Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_mem); +%} + +// Store Compressed Pointer +instruct storeN(iRegN src, memory mem) +%{ + match(Set mem (StoreN mem src)); + + ins_cost(STORE_COST); + format %{ "sw $src, $mem\t# compressed ptr, #@storeN" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ sw(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_reg_mem); +%} + +instruct storeImmN0(iRegIHeapbase heapbase, immN0 zero, memory mem) +%{ + match(Set mem (StoreN mem zero)); + + ins_cost(STORE_COST); + format %{ "sw rheapbase, $mem\t# compressed ptr (rheapbase==0), #@storeImmN0" %} + + ins_encode %{ + __ sw(as_Register($heapbase$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_reg_mem); +%} + +// Store Float +instruct storeF(fRegF src, memory mem) +%{ + match(Set mem (StoreF mem src)); + + ins_cost(STORE_COST); + format %{ "fsw $src, $mem\t# float, #@storeF" %} + + ins_encode %{ + __ fsw(as_FloatRegister($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(fp_store_reg_s); +%} + +// Store Double +instruct storeD(fRegD src, memory mem) +%{ + match(Set mem (StoreD mem src)); + + ins_cost(STORE_COST); + format %{ "fsd $src, $mem\t# double, #@storeD" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ fsd(as_FloatRegister($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(fp_store_reg_d); +%} + +// Store Compressed Klass Pointer +instruct storeNKlass(iRegN src, memory mem) +%{ + match(Set mem (StoreNKlass mem src)); + + ins_cost(STORE_COST); + format %{ "sw $src, $mem\t# compressed klass ptr, #@storeNKlass" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ sw(as_Register($src$$reg), Address(as_Register($mem$$base), $mem$$disp)); + %} + + ins_pipe(istore_reg_mem); +%} + +// ============================================================================ +// Atomic operation instructions +// +// Intel and SPARC both implement Ideal Node LoadPLocked and +// Store{PIL}Conditional instructions using a normal load for the +// LoadPLocked and a CAS for the Store{PIL}Conditional. +// +// The ideal code appears only to use LoadPLocked/storePConditional as a +// pair to lock object allocations from Eden space when not using +// TLABs. +// +// There does not appear to be a Load{IL}Locked Ideal Node and the +// Ideal code appears to use Store{IL}Conditional as an alias for CAS +// and to use StoreIConditional only for 32-bit and StoreLConditional +// only for 64-bit. +// +// We implement LoadPLocked and storePConditional instructions using, +// respectively the RISCV hw load-reserve and store-conditional +// instructions. Whereas we must implement each of +// Store{IL}Conditional using a CAS which employs a pair of +// instructions comprising a load-reserve followed by a +// store-conditional. + + +// Locked-load (load reserved) of the current heap-top +// used when updating the eden heap top +// implemented using lr_d on RISCV64 +instruct loadPLocked(iRegPNoSp dst, indirect mem) +%{ + match(Set dst (LoadPLocked mem)); + + ins_cost(ALU_COST * 2 + LOAD_COST); + + format %{ "lr.d $dst, $mem\t# ptr load reserved, #@loadPLocked" %} + + ins_encode %{ + __ la(t0, Address(as_Register($mem$$base), $mem$$disp)); + __ lr_d($dst$$Register, t0, Assembler::aq); + %} + + ins_pipe(pipe_serial); +%} + +// Conditional-store of the updated heap-top. +// Used during allocation of the shared heap. +// implemented using sc_d on RISCV64. +instruct storePConditional(memory heap_top_ptr, iRegP oldval, iRegP newval, rFlagsReg cr) +%{ + match(Set cr (StorePConditional heap_top_ptr (Binary oldval newval))); + + ins_cost(ALU_COST * 2 + STORE_COST); + + format %{ + "sc_d t1, $newval $heap_top_ptr,\t# ptr store conditional, #@storePConditional" + %} + + ins_encode %{ + __ la(t0, Address(as_Register($heap_top_ptr$$base), $heap_top_ptr$$disp)); + __ sc_d($cr$$Register, $newval$$Register, t0, Assembler::rl); + %} + + ins_pipe(pipe_serial); +%} + +instruct storeLConditional(indirect mem, iRegLNoSp oldval, iRegLNoSp newval, rFlagsReg cr) +%{ + match(Set cr (StoreLConditional mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + 2 * BRANCH_COST); + + format %{ + "cmpxchg t1, $mem, $oldval, $newval, $mem\t# if $mem == $oldval then $mem <-- $newval" + "xorr $cr, $cr, $oldval\t# $cr == 0 on successful write, #@storeLConditional" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $cr$$Register); + __ xorr($cr$$Register,$cr$$Register, $oldval$$Register); + %} + + ins_pipe(pipe_slow); +%} + +// storeIConditional also has acquire semantics, for no better reason +// than matching storeLConditional. +instruct storeIConditional(indirect mem, iRegINoSp oldval, iRegINoSp newval, rFlagsReg cr) +%{ + match(Set cr (StoreIConditional mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2); + + format %{ + "cmpxchgw t1, $mem, $oldval, $newval, $mem\t# if $mem == $oldval then $mem <-- $newval" + "xorr $cr, $cr, $oldval\t# $cr == 0 on successful write, #@storeIConditional" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $cr$$Register); + __ xorr($cr$$Register,$cr$$Register, $oldval$$Register); + %} + + ins_pipe(pipe_slow); +%} + +// standard CompareAndSwapX when we are using barriers +// these have higher priority than the rules selected by a predicate +instruct compareAndSwapB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + match(Set res (CompareAndSwapB mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 10 + BRANCH_COST * 4); + + effect(TEMP_DEF res, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapB" + %} + + ins_encode %{ + __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result as bool */, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + match(Set res (CompareAndSwapS mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 11 + BRANCH_COST * 4); + + effect(TEMP_DEF res, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3, KILL cr); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapS" + %} + + ins_encode %{ + __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + Assembler::relaxed /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result as bool */, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapI(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval) +%{ + match(Set res (CompareAndSwapI mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapI" + %} + + ins_encode(riscv_enc_cmpxchgw(res, mem, oldval, newval)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapL(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval) +%{ + match(Set res (CompareAndSwapL mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapL" + %} + + ins_encode(riscv_enc_cmpxchg(res, mem, oldval, newval)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval) +%{ + predicate(n->as_LoadStore()->barrier_data() == 0); + + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapP" + %} + + ins_encode(riscv_enc_cmpxchg(res, mem, oldval, newval)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapN(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval) +%{ + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 8 + BRANCH_COST * 4); + + format %{ + "cmpxchg $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapN" + %} + + ins_encode(riscv_enc_cmpxchgn(res, mem, oldval, newval)); + + ins_pipe(pipe_slow); +%} + +// alternative CompareAndSwapX when we are eliding barriers +instruct compareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndSwapB mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 10 + BRANCH_COST * 4); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (byte) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapBAcq" + %} + + ins_encode %{ + __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result as bool */, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndSwapS mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 11 + BRANCH_COST * 4); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (short) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapSAcq" + %} + + ins_encode %{ + __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + Assembler::aq /* acquire */, Assembler::rl /* release */, $res$$Register, + true /* result as bool */, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapIAcq(iRegINoSp res, indirect mem, iRegINoSp oldval, iRegINoSp newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndSwapI mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (int) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapIAcq" + %} + + ins_encode(riscv_enc_cmpxchgw_acq(res, mem, oldval, newval)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapLAcq(iRegINoSp res, indirect mem, iRegLNoSp oldval, iRegLNoSp newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndSwapL mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (long) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapLAcq" + %} + + ins_encode(riscv_enc_cmpxchg_acq(res, mem, oldval, newval)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval) +%{ + predicate(needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == 0)); + + match(Set res (CompareAndSwapP mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 6 + BRANCH_COST * 4); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (ptr) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapPAcq" + %} + + ins_encode(riscv_enc_cmpxchg_acq(res, mem, oldval, newval)); + + ins_pipe(pipe_slow); +%} + +instruct compareAndSwapNAcq(iRegINoSp res, indirect mem, iRegNNoSp oldval, iRegNNoSp newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndSwapN mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + ALU_COST * 8 + BRANCH_COST * 4); + + format %{ + "cmpxchg_acq $mem, $oldval, $newval\t# (narrow oop) if $mem == $oldval then $mem <-- $newval\n\t" + "mv $res, $res == $oldval\t# $res <-- ($res == $oldval ? 1 : 0), #@compareAndSwapNAcq" + %} + + ins_encode(riscv_enc_cmpxchgn_acq(res, mem, oldval, newval)); + + ins_pipe(pipe_slow); +%} + +// Sundry CAS operations. Note that release is always true, +// regardless of the memory ordering of the CAS. This is because we +// need the volatile case to be sequentially consistent but there is +// no trailing StoreLoad barrier emitted by C2. Unfortunately we +// can't check the type of memory ordering here, so we always emit a +// sc_d(w) with rl bit set. +instruct compareAndExchangeB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + match(Set res (CompareAndExchangeB mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 5); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeB" + %} + + ins_encode %{ + __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result_as_bool*/ false, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + match(Set res (CompareAndExchangeS mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 6); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeS" + %} + + ins_encode %{ + __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + /*result_as_bool*/ false, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + match(Set res (CompareAndExchangeI mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); + + effect(TEMP_DEF res); + + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeI" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeL(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval) +%{ + match(Set res (CompareAndExchangeL mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); + + effect(TEMP_DEF res); + + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeL" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeN(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval) +%{ + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 3); + + effect(TEMP_DEF res); + + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeN" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeP(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval) +%{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); + + effect(TEMP_DEF res); + + format %{ + "cmpxchg $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeP" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndExchangeB mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 5); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeBAcq" + %} + + ins_encode %{ + __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result_as_bool*/ false, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndExchangeS mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST * 6); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeSAcq" + %} + + ins_encode %{ + __ cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + /*result_as_bool*/ false, $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndExchangeI mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); + + effect(TEMP_DEF res); + + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeIAcq" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeLAcq(iRegLNoSp res, indirect mem, iRegL oldval, iRegL newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndExchangeL mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); + + effect(TEMP_DEF res); + + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeLAcq" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangeNAcq(iRegNNoSp res, indirect mem, iRegN oldval, iRegN newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (CompareAndExchangeN mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); + + effect(TEMP_DEF res); + + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangeNAcq" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct compareAndExchangePAcq(iRegPNoSp res, indirect mem, iRegP oldval, iRegP newval) +%{ + predicate(needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == 0)); + + match(Set res (CompareAndExchangeP mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 3 + ALU_COST); + + effect(TEMP_DEF res); + + format %{ + "cmpxchg_acq $res = $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval, #@compareAndExchangePAcq" + %} + + ins_encode %{ + __ cmpxchg(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapB(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 6); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg_weak $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapB" + %} + + ins_encode %{ + __ weak_cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapS(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 7); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg_weak $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapS" + %} + + ins_encode %{ + __ weak_cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapI(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + + format %{ + "cmpxchg_weak $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapI" + %} + + ins_encode %{ + __ cmpxchg_weak(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapL(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval) +%{ + match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + + format %{ + "cmpxchg_weak $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapL" + %} + + ins_encode %{ + __ cmpxchg_weak(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapN(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) +%{ + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 4); + + format %{ + "cmpxchg_weak $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapN" + %} + + ins_encode %{ + __ cmpxchg_weak(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapP(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval) +%{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + + format %{ + "cmpxchg_weak $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapP" + %} + + ins_encode %{ + __ cmpxchg_weak(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::relaxed, /*release*/ Assembler::rl, $res$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapBAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (WeakCompareAndSwapB mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 6); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg_weak_acq $mem, $oldval, $newval\t# (byte, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapBAcq" + %} + + ins_encode %{ + __ weak_cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int8, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapSAcq(iRegINoSp res, indirect mem, iRegI_R12 oldval, iRegI_R13 newval, + iRegI tmp1, iRegI tmp2, iRegI tmp3, rFlagsReg cr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (WeakCompareAndSwapS mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 7); + + effect(TEMP_DEF res, KILL cr, USE_KILL oldval, USE_KILL newval, TEMP tmp1, TEMP tmp2, TEMP tmp3); + + format %{ + "cmpxchg_weak_acq $mem, $oldval, $newval\t# (short, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapSAcq" + %} + + ins_encode %{ + __ weak_cmpxchg_narrow_value(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int16, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapIAcq(iRegINoSp res, indirect mem, iRegI oldval, iRegI newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (WeakCompareAndSwapI mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + + format %{ + "cmpxchg_weak_acq $mem, $oldval, $newval\t# (int, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapIAcq" + %} + + ins_encode %{ + __ cmpxchg_weak(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapLAcq(iRegINoSp res, indirect mem, iRegL oldval, iRegL newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (WeakCompareAndSwapL mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + + format %{ + "cmpxchg_weak_acq $mem, $oldval, $newval\t# (long, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapLAcq" + %} + + ins_encode %{ + __ cmpxchg_weak(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapNAcq(iRegINoSp res, indirect mem, iRegN oldval, iRegN newval) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set res (WeakCompareAndSwapN mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 4); + + format %{ + "cmpxchg_weak_acq $mem, $oldval, $newval\t# (narrow oop, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapNAcq" + %} + + ins_encode %{ + __ cmpxchg_weak(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::uint32, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct weakCompareAndSwapPAcq(iRegINoSp res, indirect mem, iRegP oldval, iRegP newval) +%{ + predicate(needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == 0)); + + match(Set res (WeakCompareAndSwapP mem (Binary oldval newval))); + + ins_cost(LOAD_COST + STORE_COST + BRANCH_COST * 2 + ALU_COST * 2); + + format %{ + "cmpxchg_weak_acq $mem, $oldval, $newval\t# (ptr, weak) if $mem == $oldval then $mem <-- $newval\n\t" + "xori $res, $res, 1\t# $res == 1 when success, #@weakCompareAndSwapPAcq" + %} + + ins_encode %{ + __ cmpxchg_weak(as_Register($mem$$base), $oldval$$Register, $newval$$Register, Assembler::int64, + /*acquire*/ Assembler::aq, /*release*/ Assembler::rl, $res$$Register); + __ xori($res$$Register, $res$$Register, 1); + %} + + ins_pipe(pipe_slow); +%} + +instruct get_and_setI(indirect mem, iRegI newv, iRegINoSp prev) +%{ + match(Set prev (GetAndSetI mem newv)); + + ins_cost(ALU_COST); + + format %{ "atomic_xchgw $prev, $newv, [$mem]\t#@get_and_setI" %} + + ins_encode %{ + __ atomic_xchgw($prev$$Register, $newv$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_setL(indirect mem, iRegL newv, iRegLNoSp prev) +%{ + match(Set prev (GetAndSetL mem newv)); + + ins_cost(ALU_COST); + + format %{ "atomic_xchg $prev, $newv, [$mem]\t#@get_and_setL" %} + + ins_encode %{ + __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_setN(indirect mem, iRegN newv, iRegINoSp prev) +%{ + match(Set prev (GetAndSetN mem newv)); + + ins_cost(ALU_COST); + + format %{ "atomic_xchgwu $prev, $newv, [$mem]\t#@get_and_setN" %} + + ins_encode %{ + __ atomic_xchgwu($prev$$Register, $newv$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_setP(indirect mem, iRegP newv, iRegPNoSp prev) +%{ + predicate(n->as_LoadStore()->barrier_data() == 0); + match(Set prev (GetAndSetP mem newv)); + + ins_cost(ALU_COST); + + format %{ "atomic_xchg $prev, $newv, [$mem]\t#@get_and_setP" %} + + ins_encode %{ + __ atomic_xchg($prev$$Register, $newv$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_setIAcq(indirect mem, iRegI newv, iRegINoSp prev) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set prev (GetAndSetI mem newv)); + + ins_cost(ALU_COST); + + format %{ "atomic_xchgw_acq $prev, $newv, [$mem]\t#@get_and_setIAcq" %} + + ins_encode %{ + __ atomic_xchgalw($prev$$Register, $newv$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_setLAcq(indirect mem, iRegL newv, iRegLNoSp prev) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set prev (GetAndSetL mem newv)); + + ins_cost(ALU_COST); + + format %{ "atomic_xchg_acq $prev, $newv, [$mem]\t#@get_and_setLAcq" %} + + ins_encode %{ + __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_setNAcq(indirect mem, iRegN newv, iRegINoSp prev) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set prev (GetAndSetN mem newv)); + + ins_cost(ALU_COST); + + format %{ "atomic_xchgwu_acq $prev, $newv, [$mem]\t#@get_and_setNAcq" %} + + ins_encode %{ + __ atomic_xchgalwu($prev$$Register, $newv$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_setPAcq(indirect mem, iRegP newv, iRegPNoSp prev) +%{ + predicate(needs_acquiring_load_reserved(n) && (n->as_LoadStore()->barrier_data() == 0)); + + match(Set prev (GetAndSetP mem newv)); + + ins_cost(ALU_COST); + + format %{ "atomic_xchg_acq $prev, $newv, [$mem]\t#@get_and_setPAcq" %} + + ins_encode %{ + __ atomic_xchgal($prev$$Register, $newv$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addL(indirect mem, iRegLNoSp newval, iRegL incr) +%{ + match(Set newval (GetAndAddL mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addL $newval, [$mem], $incr\t#@get_and_addL" %} + + ins_encode %{ + __ atomic_add($newval$$Register, $incr$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addL_no_res(indirect mem, Universe dummy, iRegL incr) +%{ + predicate(n->as_LoadStore()->result_not_used()); + + match(Set dummy (GetAndAddL mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addL [$mem], $incr\t#@get_and_addL_no_res" %} + + ins_encode %{ + __ atomic_add(noreg, $incr$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addLi(indirect mem, iRegLNoSp newval, immLAdd incr) +%{ + match(Set newval (GetAndAddL mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addL $newval, [$mem], $incr\t#@get_and_addLi" %} + + ins_encode %{ + __ atomic_add($newval$$Register, $incr$$constant, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addLi_no_res(indirect mem, Universe dummy, immLAdd incr) +%{ + predicate(n->as_LoadStore()->result_not_used()); + + match(Set dummy (GetAndAddL mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addL [$mem], $incr\t#@get_and_addLi_no_res" %} + + ins_encode %{ + __ atomic_add(noreg, $incr$$constant, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addI(indirect mem, iRegINoSp newval, iRegIorL2I incr) +%{ + match(Set newval (GetAndAddI mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addI $newval, [$mem], $incr\t#@get_and_addI" %} + + ins_encode %{ + __ atomic_addw($newval$$Register, $incr$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addI_no_res(indirect mem, Universe dummy, iRegIorL2I incr) +%{ + predicate(n->as_LoadStore()->result_not_used()); + + match(Set dummy (GetAndAddI mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addI [$mem], $incr\t#@get_and_addI_no_res" %} + + ins_encode %{ + __ atomic_addw(noreg, $incr$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addIi(indirect mem, iRegINoSp newval, immIAdd incr) +%{ + match(Set newval (GetAndAddI mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addI $newval, [$mem], $incr\t#@get_and_addIi" %} + + ins_encode %{ + __ atomic_addw($newval$$Register, $incr$$constant, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addIi_no_res(indirect mem, Universe dummy, immIAdd incr) +%{ + predicate(n->as_LoadStore()->result_not_used()); + + match(Set dummy (GetAndAddI mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addI [$mem], $incr\t#@get_and_addIi_no_res" %} + + ins_encode %{ + __ atomic_addw(noreg, $incr$$constant, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addLAcq(indirect mem, iRegLNoSp newval, iRegL incr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set newval (GetAndAddL mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addL_acq $newval, [$mem], $incr\t#@get_and_addLAcq" %} + + ins_encode %{ + __ atomic_addal($newval$$Register, $incr$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addL_no_resAcq(indirect mem, Universe dummy, iRegL incr) %{ + predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_reserved(n)); + + match(Set dummy (GetAndAddL mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addL_acq [$mem], $incr\t#@get_and_addL_no_resAcq" %} + + ins_encode %{ + __ atomic_addal(noreg, $incr$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addLiAcq(indirect mem, iRegLNoSp newval, immLAdd incr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set newval (GetAndAddL mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addL_acq $newval, [$mem], $incr\t#@get_and_addLiAcq" %} + + ins_encode %{ + __ atomic_addal($newval$$Register, $incr$$constant, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addLi_no_resAcq(indirect mem, Universe dummy, immLAdd incr) +%{ + predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_reserved(n)); + + match(Set dummy (GetAndAddL mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addL_acq [$mem], $incr\t#@get_and_addLi_no_resAcq" %} + + ins_encode %{ + __ atomic_addal(noreg, $incr$$constant, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addIAcq(indirect mem, iRegINoSp newval, iRegIorL2I incr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set newval (GetAndAddI mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addI_acq $newval, [$mem], $incr\t#@get_and_addIAcq" %} + + ins_encode %{ + __ atomic_addalw($newval$$Register, $incr$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addI_no_resAcq(indirect mem, Universe dummy, iRegIorL2I incr) +%{ + predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_reserved(n)); + + match(Set dummy (GetAndAddI mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addI_acq [$mem], $incr\t#@get_and_addI_no_resAcq" %} + + ins_encode %{ + __ atomic_addalw(noreg, $incr$$Register, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addIiAcq(indirect mem, iRegINoSp newval, immIAdd incr) +%{ + predicate(needs_acquiring_load_reserved(n)); + + match(Set newval (GetAndAddI mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addI_acq $newval, [$mem], $incr\t#@get_and_addIiAcq" %} + + ins_encode %{ + __ atomic_addalw($newval$$Register, $incr$$constant, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +instruct get_and_addIi_no_resAcq(indirect mem, Universe dummy, immIAdd incr) +%{ + predicate(n->as_LoadStore()->result_not_used() && needs_acquiring_load_reserved(n)); + + match(Set dummy (GetAndAddI mem incr)); + + ins_cost(ALU_COST); + + format %{ "get_and_addI_acq [$mem], $incr\t#@get_and_addIi_no_resAcq" %} + + ins_encode %{ + __ atomic_addalw(noreg, $incr$$constant, as_Register($mem$$base)); + %} + + ins_pipe(pipe_serial); +%} + +// ============================================================================ +// Arithmetic Instructions +// + +// Integer Addition + +// TODO +// these currently employ operations which do not set CR and hence are +// not flagged as killing CR but we would like to isolate the cases +// where we want to set flags from those where we don't. need to work +// out how to do that. +instruct addI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ + match(Set dst (AddI src1 src2)); + + ins_cost(ALU_COST); + format %{ "addw $dst, $src1, $src2\t#@addI_reg_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ addw(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct addI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immIAdd src2) %{ + match(Set dst (AddI src1 src2)); + + ins_cost(ALU_COST); + format %{ "addiw $dst, $src1, $src2\t#@addI_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + int32_t con = (int32_t)$src2$$constant; + __ addiw(as_Register($dst$$reg), + as_Register($src1$$reg), + $src2$$constant); + %} + + ins_pipe(ialu_reg_imm); +%} + +instruct addI_reg_imm_l2i(iRegINoSp dst, iRegL src1, immIAdd src2) %{ + match(Set dst (AddI (ConvL2I src1) src2)); + + ins_cost(ALU_COST); + format %{ "addiw $dst, $src1, $src2\t#@addI_reg_imm_l2i" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ addiw(as_Register($dst$$reg), + as_Register($src1$$reg), + $src2$$constant); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Pointer Addition +instruct addP_reg_reg(iRegPNoSp dst, iRegP src1, iRegL src2) %{ + match(Set dst (AddP src1 src2)); + + ins_cost(ALU_COST); + format %{ "add $dst, $src1, $src2\t# ptr, #@addP_reg_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ add(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// If we shift more than 32 bits, we need not convert I2L. +instruct lShiftL_regI_immGE32(iRegLNoSp dst, iRegI src, uimmI6_ge32 scale) %{ + match(Set dst (LShiftL (ConvI2L src) scale)); + ins_cost(ALU_COST); + format %{ "slli $dst, $src, $scale & 63\t#@lShiftL_regI_immGE32" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ slli(as_Register($dst$$reg), as_Register($src$$reg), $scale$$constant & 63); + %} + + ins_pipe(ialu_reg_shift); +%} + +// Pointer Immediate Addition +// n.b. this needs to be more expensive than using an indirect memory +// operand +instruct addP_reg_imm(iRegPNoSp dst, iRegP src1, immLAdd src2) %{ + match(Set dst (AddP src1 src2)); + ins_cost(ALU_COST); + format %{ "addi $dst, $src1, $src2\t# ptr, #@addP_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + // src2 is imm, so actually call the addi + __ add(as_Register($dst$$reg), + as_Register($src1$$reg), + $src2$$constant); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Long Addition +instruct addL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ + match(Set dst (AddL src1 src2)); + ins_cost(ALU_COST); + format %{ "add $dst, $src1, $src2\t#@addL_reg_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ add(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// No constant pool entries requiredLong Immediate Addition. +instruct addL_reg_imm(iRegLNoSp dst, iRegL src1, immLAdd src2) %{ + match(Set dst (AddL src1 src2)); + ins_cost(ALU_COST); + format %{ "addi $dst, $src1, $src2\t#@addL_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + // src2 is imm, so actually call the addi + __ add(as_Register($dst$$reg), + as_Register($src1$$reg), + $src2$$constant); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Integer Subtraction +instruct subI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ + match(Set dst (SubI src1 src2)); + + ins_cost(ALU_COST); + format %{ "subw $dst, $src1, $src2\t#@subI_reg_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ subw(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Immediate Subtraction +instruct subI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immISub src2) %{ + match(Set dst (SubI src1 src2)); + + ins_cost(ALU_COST); + format %{ "addiw $dst, $src1, -$src2\t#@subI_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + // src2 is imm, so actually call the addiw + __ subw(as_Register($dst$$reg), + as_Register($src1$$reg), + $src2$$constant); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Long Subtraction +instruct subL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ + match(Set dst (SubL src1 src2)); + ins_cost(ALU_COST); + format %{ "sub $dst, $src1, $src2\t#@subL_reg_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ sub(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// No constant pool entries requiredLong Immediate Subtraction. +instruct subL_reg_imm(iRegLNoSp dst, iRegL src1, immLSub src2) %{ + match(Set dst (SubL src1 src2)); + ins_cost(ALU_COST); + format %{ "addi $dst, $src1, -$src2\t#@subL_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + // src2 is imm, so actually call the addi + __ sub(as_Register($dst$$reg), + as_Register($src1$$reg), + $src2$$constant); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Integer Negation (special case for sub) + +instruct negI_reg(iRegINoSp dst, iRegIorL2I src, immI0 zero) %{ + match(Set dst (SubI zero src)); + ins_cost(ALU_COST); + format %{ "subw $dst, x0, $src\t# int, #@negI_reg" %} + + ins_encode %{ + // actually call the subw + __ negw(as_Register($dst$$reg), + as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// Long Negation + +instruct negL_reg(iRegLNoSp dst, iRegL src, immL0 zero) %{ + match(Set dst (SubL zero src)); + ins_cost(ALU_COST); + format %{ "sub $dst, x0, $src\t# long, #@negL_reg" %} + + ins_encode %{ + // actually call the sub + __ neg(as_Register($dst$$reg), + as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// Integer Multiply + +instruct mulI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ + match(Set dst (MulI src1 src2)); + ins_cost(IMUL_COST); + format %{ "mulw $dst, $src1, $src2\t#@mulI" %} + + //this means 2 word multi, and no sign extend to 64 bits + ins_encode %{ + // riscv64 mulw will sign-extension to high 32 bits in dst reg + __ mulw(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(imul_reg_reg); +%} + +// Long Multiply + +instruct mulL(iRegLNoSp dst, iRegL src1, iRegL src2) %{ + match(Set dst (MulL src1 src2)); + ins_cost(IMUL_COST); + format %{ "mul $dst, $src1, $src2\t#@mulL" %} + + ins_encode %{ + __ mul(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(lmul_reg_reg); +%} + +instruct mulHiL_rReg(iRegLNoSp dst, iRegL src1, iRegL src2) +%{ + match(Set dst (MulHiL src1 src2)); + ins_cost(IMUL_COST); + format %{ "mulh $dst, $src1, $src2\t# mulhi, #@mulHiL_rReg" %} + + ins_encode %{ + __ mulh(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(lmul_reg_reg); +%} + +// Integer Divide + +instruct divI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ + match(Set dst (DivI src1 src2)); + ins_cost(IDIVSI_COST); + format %{ "divw $dst, $src1, $src2\t#@divI"%} + + ins_encode(riscv_enc_divw(dst, src1, src2)); + ins_pipe(idiv_reg_reg); +%} + +instruct signExtract(iRegINoSp dst, iRegIorL2I src1, immI_31 div1, immI_31 div2) %{ + match(Set dst (URShiftI (RShiftI src1 div1) div2)); + ins_cost(ALU_COST); + format %{ "srliw $dst, $src1, $div1\t# int signExtract, #@signExtract" %} + + ins_encode %{ + __ srliw(as_Register($dst$$reg), as_Register($src1$$reg), 31); + %} + ins_pipe(ialu_reg_shift); +%} + +// Long Divide + +instruct divL(iRegLNoSp dst, iRegL src1, iRegL src2) %{ + match(Set dst (DivL src1 src2)); + ins_cost(IDIVDI_COST); + format %{ "div $dst, $src1, $src2\t#@divL" %} + + ins_encode(riscv_enc_div(dst, src1, src2)); + ins_pipe(ldiv_reg_reg); +%} + +instruct signExtractL(iRegLNoSp dst, iRegL src1, immI_63 div1, immI_63 div2) %{ + match(Set dst (URShiftL (RShiftL src1 div1) div2)); + ins_cost(ALU_COST); + format %{ "srli $dst, $src1, $div1\t# long signExtract, #@signExtractL" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ srli(as_Register($dst$$reg), as_Register($src1$$reg), 63); + %} + ins_pipe(ialu_reg_shift); +%} + +// Integer Remainder + +instruct modI(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ + match(Set dst (ModI src1 src2)); + ins_cost(IDIVSI_COST); + format %{ "remw $dst, $src1, $src2\t#@modI" %} + + ins_encode(riscv_enc_modw(dst, src1, src2)); + ins_pipe(ialu_reg_reg); +%} + +// Long Remainder + +instruct modL(iRegLNoSp dst, iRegL src1, iRegL src2) %{ + match(Set dst (ModL src1 src2)); + ins_cost(IDIVDI_COST); + format %{ "rem $dst, $src1, $src2\t#@modL" %} + + ins_encode(riscv_enc_mod(dst, src1, src2)); + ins_pipe(ialu_reg_reg); +%} + +// Integer Shifts + +// Shift Left Register +// In RV64I, only the low 5 bits of src2 are considered for the shift amount +instruct lShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ + match(Set dst (LShiftI src1 src2)); + ins_cost(ALU_COST); + format %{ "sllw $dst, $src1, $src2\t#@lShiftI_reg_reg" %} + + ins_encode %{ + __ sllw(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg_vshift); +%} + +// Shift Left Immediate +instruct lShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ + match(Set dst (LShiftI src1 src2)); + ins_cost(ALU_COST); + format %{ "slliw $dst, $src1, ($src2 & 0x1f)\t#@lShiftI_reg_imm" %} + + ins_encode %{ + // the shift amount is encoded in the lower + // 5 bits of the I-immediate field for RV32I + __ slliw(as_Register($dst$$reg), + as_Register($src1$$reg), + (unsigned) $src2$$constant & 0x1f); + %} + + ins_pipe(ialu_reg_shift); +%} + +// Shift Right Logical Register +// In RV64I, only the low 5 bits of src2 are considered for the shift amount +instruct urShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ + match(Set dst (URShiftI src1 src2)); + ins_cost(ALU_COST); + format %{ "srlw $dst, $src1, $src2\t#@urShiftI_reg_reg" %} + + ins_encode %{ + __ srlw(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg_vshift); +%} + +// Shift Right Logical Immediate +instruct urShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ + match(Set dst (URShiftI src1 src2)); + ins_cost(ALU_COST); + format %{ "srliw $dst, $src1, ($src2 & 0x1f)\t#@urShiftI_reg_imm" %} + + ins_encode %{ + // the shift amount is encoded in the lower + // 6 bits of the I-immediate field for RV64I + __ srliw(as_Register($dst$$reg), + as_Register($src1$$reg), + (unsigned) $src2$$constant & 0x1f); + %} + + ins_pipe(ialu_reg_shift); +%} + +// Shift Right Arithmetic Register +// In RV64I, only the low 5 bits of src2 are considered for the shift amount +instruct rShiftI_reg_reg(iRegINoSp dst, iRegIorL2I src1, iRegIorL2I src2) %{ + match(Set dst (RShiftI src1 src2)); + ins_cost(ALU_COST); + format %{ "sraw $dst, $src1, $src2\t#@rShiftI_reg_reg" %} + + ins_encode %{ + // riscv will sign-ext dst high 32 bits + __ sraw(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg_vshift); +%} + +// Shift Right Arithmetic Immediate +instruct rShiftI_reg_imm(iRegINoSp dst, iRegIorL2I src1, immI src2) %{ + match(Set dst (RShiftI src1 src2)); + ins_cost(ALU_COST); + format %{ "sraiw $dst, $src1, ($src2 & 0x1f)\t#@rShiftI_reg_imm" %} + + ins_encode %{ + // riscv will sign-ext dst high 32 bits + __ sraiw(as_Register($dst$$reg), + as_Register($src1$$reg), + (unsigned) $src2$$constant & 0x1f); + %} + + ins_pipe(ialu_reg_shift); +%} + +// Long Shifts + +// Shift Left Register +// In RV64I, only the low 6 bits of src2 are considered for the shift amount +instruct lShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ + match(Set dst (LShiftL src1 src2)); + + ins_cost(ALU_COST); + format %{ "sll $dst, $src1, $src2\t#@lShiftL_reg_reg" %} + + ins_encode %{ + __ sll(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg_vshift); +%} + +// Shift Left Immediate +instruct lShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ + match(Set dst (LShiftL src1 src2)); + + ins_cost(ALU_COST); + format %{ "slli $dst, $src1, ($src2 & 0x3f)\t#@lShiftL_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + // the shift amount is encoded in the lower + // 6 bits of the I-immediate field for RV64I + __ slli(as_Register($dst$$reg), + as_Register($src1$$reg), + (unsigned) $src2$$constant & 0x3f); + %} + + ins_pipe(ialu_reg_shift); +%} + +// Shift Right Logical Register +// In RV64I, only the low 6 bits of src2 are considered for the shift amount +instruct urShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ + match(Set dst (URShiftL src1 src2)); + + ins_cost(ALU_COST); + format %{ "srl $dst, $src1, $src2\t#@urShiftL_reg_reg" %} + + ins_encode %{ + __ srl(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg_vshift); +%} + +// Shift Right Logical Immediate +instruct urShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ + match(Set dst (URShiftL src1 src2)); + + ins_cost(ALU_COST); + format %{ "srli $dst, $src1, ($src2 & 0x3f)\t#@urShiftL_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + // the shift amount is encoded in the lower + // 6 bits of the I-immediate field for RV64I + __ srli(as_Register($dst$$reg), + as_Register($src1$$reg), + (unsigned) $src2$$constant & 0x3f); + %} + + ins_pipe(ialu_reg_shift); +%} + +// A special-case pattern for card table stores. +instruct urShiftP_reg_imm(iRegLNoSp dst, iRegP src1, immI src2) %{ + match(Set dst (URShiftL (CastP2X src1) src2)); + + ins_cost(ALU_COST); + format %{ "srli $dst, p2x($src1), ($src2 & 0x3f)\t#@urShiftP_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + // the shift amount is encoded in the lower + // 6 bits of the I-immediate field for RV64I + __ srli(as_Register($dst$$reg), + as_Register($src1$$reg), + (unsigned) $src2$$constant & 0x3f); + %} + + ins_pipe(ialu_reg_shift); +%} + +// Shift Right Arithmetic Register +// In RV64I, only the low 6 bits of src2 are considered for the shift amount +instruct rShiftL_reg_reg(iRegLNoSp dst, iRegL src1, iRegIorL2I src2) %{ + match(Set dst (RShiftL src1 src2)); + + ins_cost(ALU_COST); + format %{ "sra $dst, $src1, $src2\t#@rShiftL_reg_reg" %} + + ins_encode %{ + __ sra(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg_vshift); +%} + +// Shift Right Arithmetic Immediate +instruct rShiftL_reg_imm(iRegLNoSp dst, iRegL src1, immI src2) %{ + match(Set dst (RShiftL src1 src2)); + + ins_cost(ALU_COST); + format %{ "srai $dst, $src1, ($src2 & 0x3f)\t#@rShiftL_reg_imm" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + // the shift amount is encoded in the lower + // 6 bits of the I-immediate field for RV64I + __ srai(as_Register($dst$$reg), + as_Register($src1$$reg), + (unsigned) $src2$$constant & 0x3f); + %} + + ins_pipe(ialu_reg_shift); +%} + +instruct regI_not_reg(iRegINoSp dst, iRegI src1, immI_M1 m1) %{ + match(Set dst (XorI src1 m1)); + ins_cost(ALU_COST); + format %{ "xori $dst, $src1, -1\t#@regI_not_reg" %} + + ins_encode %{ + __ xori(as_Register($dst$$reg), as_Register($src1$$reg), -1); + %} + + ins_pipe(ialu_reg); +%} + +instruct regL_not_reg(iRegLNoSp dst, iRegL src1, immL_M1 m1) %{ + match(Set dst (XorL src1 m1)); + ins_cost(ALU_COST); + format %{ "xori $dst, $src1, -1\t#@regL_not_reg" %} + + ins_encode %{ + __ xori(as_Register($dst$$reg), as_Register($src1$$reg), -1); + %} + + ins_pipe(ialu_reg); +%} + + +// ============================================================================ +// Floating Point Arithmetic Instructions + +instruct addF_reg_reg(fRegF dst, fRegF src1, fRegF src2) %{ + match(Set dst (AddF src1 src2)); + + ins_cost(FMUL_SINGLE_COST); + format %{ "fadd.s $dst, $src1, $src2\t#@addF_reg_reg" %} + + ins_encode %{ + __ fadd_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + + ins_pipe(fp_dop_reg_reg_s); +%} + +instruct addD_reg_reg(fRegD dst, fRegD src1, fRegD src2) %{ + match(Set dst (AddD src1 src2)); + + ins_cost(FMUL_DOUBLE_COST); + format %{ "fadd.d $dst, $src1, $src2\t#@addD_reg_reg" %} + + ins_encode %{ + __ fadd_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + + ins_pipe(fp_dop_reg_reg_d); +%} + +instruct subF_reg_reg(fRegF dst, fRegF src1, fRegF src2) %{ + match(Set dst (SubF src1 src2)); + + ins_cost(FMUL_SINGLE_COST); + format %{ "fsub.s $dst, $src1, $src2\t#@subF_reg_reg" %} + + ins_encode %{ + __ fsub_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + + ins_pipe(fp_dop_reg_reg_s); +%} + +instruct subD_reg_reg(fRegD dst, fRegD src1, fRegD src2) %{ + match(Set dst (SubD src1 src2)); + + ins_cost(FMUL_DOUBLE_COST); + format %{ "fsub.d $dst, $src1, $src2\t#@subD_reg_reg" %} + + ins_encode %{ + __ fsub_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + + ins_pipe(fp_dop_reg_reg_d); +%} + +instruct mulF_reg_reg(fRegF dst, fRegF src1, fRegF src2) %{ + match(Set dst (MulF src1 src2)); + + ins_cost(FMUL_SINGLE_COST); + format %{ "fmul.s $dst, $src1, $src2\t#@mulF_reg_reg" %} + + ins_encode %{ + __ fmul_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + + ins_pipe(fp_dop_reg_reg_s); +%} + +instruct mulD_reg_reg(fRegD dst, fRegD src1, fRegD src2) %{ + match(Set dst (MulD src1 src2)); + + ins_cost(FMUL_DOUBLE_COST); + format %{ "fmul.d $dst, $src1, $src2\t#@mulD_reg_reg" %} + + ins_encode %{ + __ fmul_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + + ins_pipe(fp_dop_reg_reg_d); +%} + +// src1 * src2 + src3 +instruct maddF_reg_reg(fRegF dst, fRegF src1, fRegF src2, fRegF src3) %{ + predicate(UseFMA); + match(Set dst (FmaF src3 (Binary src1 src2))); + + ins_cost(FMUL_SINGLE_COST); + format %{ "fmadd.s $dst, $src1, $src2, $src3\t#@maddF_reg_reg" %} + + ins_encode %{ + __ fmadd_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg), + as_FloatRegister($src3$$reg)); + %} + + ins_pipe(pipe_class_default); +%} + +// src1 * src2 + src3 +instruct maddD_reg_reg(fRegD dst, fRegD src1, fRegD src2, fRegD src3) %{ + predicate(UseFMA); + match(Set dst (FmaD src3 (Binary src1 src2))); + + ins_cost(FMUL_DOUBLE_COST); + format %{ "fmadd.d $dst, $src1, $src2, $src3\t#@maddD_reg_reg" %} + + ins_encode %{ + __ fmadd_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg), + as_FloatRegister($src3$$reg)); + %} + + ins_pipe(pipe_class_default); +%} + +// src1 * src2 - src3 +instruct msubF_reg_reg(fRegF dst, fRegF src1, fRegF src2, fRegF src3) %{ + predicate(UseFMA); + match(Set dst (FmaF (NegF src3) (Binary src1 src2))); + + ins_cost(FMUL_SINGLE_COST); + format %{ "fmsub.s $dst, $src1, $src2, $src3\t#@msubF_reg_reg" %} + + ins_encode %{ + __ fmsub_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg), + as_FloatRegister($src3$$reg)); + %} + + ins_pipe(pipe_class_default); +%} + +// src1 * src2 - src3 +instruct msubD_reg_reg(fRegD dst, fRegD src1, fRegD src2, fRegD src3) %{ + predicate(UseFMA); + match(Set dst (FmaD (NegD src3) (Binary src1 src2))); + + ins_cost(FMUL_DOUBLE_COST); + format %{ "fmsub.d $dst, $src1, $src2, $src3\t#@msubD_reg_reg" %} + + ins_encode %{ + __ fmsub_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg), + as_FloatRegister($src3$$reg)); + %} + + ins_pipe(pipe_class_default); +%} + +// -src1 * src2 + src3 +instruct nmsubF_reg_reg(fRegF dst, fRegF src1, fRegF src2, fRegF src3) %{ + predicate(UseFMA); + match(Set dst (FmaF src3 (Binary (NegF src1) src2))); + match(Set dst (FmaF src3 (Binary src1 (NegF src2)))); + + ins_cost(FMUL_SINGLE_COST); + format %{ "fnmsub.s $dst, $src1, $src2, $src3\t#@nmsubF_reg_reg" %} + + ins_encode %{ + __ fnmsub_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg), + as_FloatRegister($src3$$reg)); + %} + + ins_pipe(pipe_class_default); +%} + +// -src1 * src2 + src3 +instruct nmsubD_reg_reg(fRegD dst, fRegD src1, fRegD src2, fRegD src3) %{ + predicate(UseFMA); + match(Set dst (FmaD src3 (Binary (NegD src1) src2))); + match(Set dst (FmaD src3 (Binary src1 (NegD src2)))); + + ins_cost(FMUL_DOUBLE_COST); + format %{ "fnmsub.d $dst, $src1, $src2, $src3\t#@nmsubD_reg_reg" %} + + ins_encode %{ + __ fnmsub_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg), + as_FloatRegister($src3$$reg)); + %} + + ins_pipe(pipe_class_default); +%} + +// -src1 * src2 - src3 +instruct nmaddF_reg_reg(fRegF dst, fRegF src1, fRegF src2, fRegF src3) %{ + predicate(UseFMA); + match(Set dst (FmaF (NegF src3) (Binary (NegF src1) src2))); + match(Set dst (FmaF (NegF src3) (Binary src1 (NegF src2)))); + + ins_cost(FMUL_SINGLE_COST); + format %{ "fnmadd.s $dst, $src1, $src2, $src3\t#@nmaddF_reg_reg" %} + + ins_encode %{ + __ fnmadd_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg), + as_FloatRegister($src3$$reg)); + %} + + ins_pipe(pipe_class_default); +%} + +// -src1 * src2 - src3 +instruct nmaddD_reg_reg(fRegD dst, fRegD src1, fRegD src2, fRegD src3) %{ + predicate(UseFMA); + match(Set dst (FmaD (NegD src3) (Binary (NegD src1) src2))); + match(Set dst (FmaD (NegD src3) (Binary src1 (NegD src2)))); + + ins_cost(FMUL_DOUBLE_COST); + format %{ "fnmadd.d $dst, $src1, $src2, $src3\t#@nmaddD_reg_reg" %} + + ins_encode %{ + __ fnmadd_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg), + as_FloatRegister($src3$$reg)); + %} + + ins_pipe(pipe_class_default); +%} + +// Math.max(FF)F +instruct maxF_reg_reg(fRegF dst, fRegF src1, fRegF src2) %{ + match(Set dst (MaxF src1 src2)); + effect(TEMP_DEF dst); + + format %{ "maxF $dst, $src1, $src2" %} + + ins_encode %{ + __ minmax_FD(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), + false /* is_double */, false /* is_min */); + %} + + ins_pipe(fp_dop_reg_reg_s); +%} + +// Math.min(FF)F +instruct minF_reg_reg(fRegF dst, fRegF src1, fRegF src2) %{ + match(Set dst (MinF src1 src2)); + effect(TEMP_DEF dst); + + format %{ "minF $dst, $src1, $src2" %} + + ins_encode %{ + __ minmax_FD(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), + false /* is_double */, true /* is_min */); + %} + + ins_pipe(fp_dop_reg_reg_s); +%} + +// Math.max(DD)D +instruct maxD_reg_reg(fRegD dst, fRegD src1, fRegD src2) %{ + match(Set dst (MaxD src1 src2)); + effect(TEMP_DEF dst); + + format %{ "maxD $dst, $src1, $src2" %} + + ins_encode %{ + __ minmax_FD(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), + true /* is_double */, false /* is_min */); + %} + + ins_pipe(fp_dop_reg_reg_d); +%} + +// Math.min(DD)D +instruct minD_reg_reg(fRegD dst, fRegD src1, fRegD src2) %{ + match(Set dst (MinD src1 src2)); + effect(TEMP_DEF dst); + + format %{ "minD $dst, $src1, $src2" %} + + ins_encode %{ + __ minmax_FD(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg), + true /* is_double */, true /* is_min */); + %} + + ins_pipe(fp_dop_reg_reg_d); +%} + +instruct divF_reg_reg(fRegF dst, fRegF src1, fRegF src2) %{ + match(Set dst (DivF src1 src2)); + + ins_cost(FDIV_COST); + format %{ "fdiv.s $dst, $src1, $src2\t#@divF_reg_reg" %} + + ins_encode %{ + __ fdiv_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + + ins_pipe(fp_div_s); +%} + +instruct divD_reg_reg(fRegD dst, fRegD src1, fRegD src2) %{ + match(Set dst (DivD src1 src2)); + + ins_cost(FDIV_COST); + format %{ "fdiv.d $dst, $src1, $src2\t#@divD_reg_reg" %} + + ins_encode %{ + __ fdiv_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src1$$reg), + as_FloatRegister($src2$$reg)); + %} + + ins_pipe(fp_div_d); +%} + +instruct negF_reg_reg(fRegF dst, fRegF src) %{ + match(Set dst (NegF src)); + + ins_cost(XFER_COST); + format %{ "fsgnjn.s $dst, $src, $src\t#@negF_reg_reg" %} + + ins_encode %{ + __ fneg_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_uop_s); +%} + +instruct negD_reg_reg(fRegD dst, fRegD src) %{ + match(Set dst (NegD src)); + + ins_cost(XFER_COST); + format %{ "fsgnjn.d $dst, $src, $src\t#@negD_reg_reg" %} + + ins_encode %{ + __ fneg_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_uop_d); +%} + +instruct absI_reg(iRegINoSp dst, iRegIorL2I src) %{ + match(Set dst (AbsI src)); + + ins_cost(ALU_COST * 3); + format %{ + "sraiw t0, $src, 0x1f\n\t" + "addw $dst, $src, t0\n\t" + "xorr $dst, $dst, t0\t#@absI_reg" + %} + + ins_encode %{ + __ sraiw(t0, as_Register($src$$reg), 0x1f); + __ addw(as_Register($dst$$reg), as_Register($src$$reg), t0); + __ xorr(as_Register($dst$$reg), as_Register($dst$$reg), t0); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct absL_reg(iRegLNoSp dst, iRegL src) %{ + match(Set dst (AbsL src)); + + ins_cost(ALU_COST * 3); + format %{ + "srai t0, $src, 0x3f\n\t" + "add $dst, $src, t0\n\t" + "xorr $dst, $dst, t0\t#@absL_reg" + %} + + ins_encode %{ + __ srai(t0, as_Register($src$$reg), 0x3f); + __ add(as_Register($dst$$reg), as_Register($src$$reg), t0); + __ xorr(as_Register($dst$$reg), as_Register($dst$$reg), t0); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct absF_reg(fRegF dst, fRegF src) %{ + match(Set dst (AbsF src)); + + ins_cost(XFER_COST); + format %{ "fsgnjx.s $dst, $src, $src\t#@absF_reg" %} + ins_encode %{ + __ fabs_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_uop_s); +%} + +instruct absD_reg(fRegD dst, fRegD src) %{ + match(Set dst (AbsD src)); + + ins_cost(XFER_COST); + format %{ "fsgnjx.d $dst, $src, $src\t#@absD_reg" %} + ins_encode %{ + __ fabs_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_uop_d); +%} + +instruct sqrtF_reg(fRegF dst, fRegF src) %{ + match(Set dst (ConvD2F (SqrtD (ConvF2D src)))); + + ins_cost(FSQRT_COST); + format %{ "fsqrt.s $dst, $src\t#@sqrtF_reg" %} + ins_encode %{ + __ fsqrt_s(as_FloatRegister($dst$$reg), + as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_sqrt_s); +%} + +instruct sqrtD_reg(fRegD dst, fRegD src) %{ + match(Set dst (SqrtD src)); + + ins_cost(FSQRT_COST); + format %{ "fsqrt.d $dst, $src\t#@sqrtD_reg" %} + ins_encode %{ + __ fsqrt_d(as_FloatRegister($dst$$reg), + as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_sqrt_d); +%} + +// Arithmetic Instructions End + +// ============================================================================ +// Logical Instructions + +// Register And +instruct andI_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2) %{ + match(Set dst (AndI src1 src2)); + + format %{ "andr $dst, $src1, $src2\t#@andI_reg_reg" %} + + ins_cost(ALU_COST); + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ andr(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Immediate And +instruct andI_reg_imm(iRegINoSp dst, iRegI src1, immIAdd src2) %{ + match(Set dst (AndI src1 src2)); + + format %{ "andi $dst, $src1, $src2\t#@andI_reg_imm" %} + + ins_cost(ALU_COST); + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ andi(as_Register($dst$$reg), + as_Register($src1$$reg), + (int32_t)($src2$$constant)); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Register Or +instruct orI_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2) %{ + match(Set dst (OrI src1 src2)); + + format %{ "orr $dst, $src1, $src2\t#@orI_reg_reg" %} + + ins_cost(ALU_COST); + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ orr(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Immediate Or +instruct orI_reg_imm(iRegINoSp dst, iRegI src1, immIAdd src2) %{ + match(Set dst (OrI src1 src2)); + + format %{ "ori $dst, $src1, $src2\t#@orI_reg_imm" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ ori(as_Register($dst$$reg), + as_Register($src1$$reg), + (int32_t)($src2$$constant)); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Register Xor +instruct xorI_reg_reg(iRegINoSp dst, iRegI src1, iRegI src2) %{ + match(Set dst (XorI src1 src2)); + + format %{ "xorr $dst, $src1, $src2\t#@xorI_reg_reg" %} + + ins_cost(ALU_COST); + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ xorr(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Immediate Xor +instruct xorI_reg_imm(iRegINoSp dst, iRegI src1, immIAdd src2) %{ + match(Set dst (XorI src1 src2)); + + format %{ "xori $dst, $src1, $src2\t#@xorI_reg_imm" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ xori(as_Register($dst$$reg), + as_Register($src1$$reg), + (int32_t)($src2$$constant)); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Register And Long +instruct andL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ + match(Set dst (AndL src1 src2)); + + format %{ "andr $dst, $src1, $src2\t#@andL_reg_reg" %} + + ins_cost(ALU_COST); + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ andr(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Immediate And Long +instruct andL_reg_imm(iRegLNoSp dst, iRegL src1, immLAdd src2) %{ + match(Set dst (AndL src1 src2)); + + format %{ "andi $dst, $src1, $src2\t#@andL_reg_imm" %} + + ins_cost(ALU_COST); + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ andi(as_Register($dst$$reg), + as_Register($src1$$reg), + (int32_t)($src2$$constant)); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Register Or Long +instruct orL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ + match(Set dst (OrL src1 src2)); + + format %{ "orr $dst, $src1, $src2\t#@orL_reg_reg" %} + + ins_cost(ALU_COST); + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ orr(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Immediate Or Long +instruct orL_reg_imm(iRegLNoSp dst, iRegL src1, immLAdd src2) %{ + match(Set dst (OrL src1 src2)); + + format %{ "ori $dst, $src1, $src2\t#@orL_reg_imm" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ ori(as_Register($dst$$reg), + as_Register($src1$$reg), + (int32_t)($src2$$constant)); + %} + + ins_pipe(ialu_reg_imm); +%} + +// Register Xor Long +instruct xorL_reg_reg(iRegLNoSp dst, iRegL src1, iRegL src2) %{ + match(Set dst (XorL src1 src2)); + + format %{ "xorr $dst, $src1, $src2\t#@xorL_reg_reg" %} + + ins_cost(ALU_COST); + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ xorr(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Immediate Xor Long +instruct xorL_reg_imm(iRegLNoSp dst, iRegL src1, immLAdd src2) %{ + match(Set dst (XorL src1 src2)); + + ins_cost(ALU_COST); + format %{ "xori $dst, $src1, $src2\t#@xorL_reg_imm" %} + + ins_encode %{ + __ xori(as_Register($dst$$reg), + as_Register($src1$$reg), + (int32_t)($src2$$constant)); + %} + + ins_pipe(ialu_reg_imm); +%} + +// ============================================================================ +// BSWAP Instructions + +instruct bytes_reverse_int(iRegINoSp dst, iRegIorL2I src, rFlagsReg cr) %{ + match(Set dst (ReverseBytesI src)); + effect(TEMP cr); + + ins_cost(ALU_COST * 13); + format %{ "revb_w_w $dst, $src\t#@bytes_reverse_int" %} + + ins_encode %{ + __ revb_w_w(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct bytes_reverse_long(iRegLNoSp dst, iRegL src, rFlagsReg cr) %{ + match(Set dst (ReverseBytesL src)); + effect(TEMP cr); + + ins_cost(ALU_COST * 29); + format %{ "revb $dst, $src\t#@bytes_reverse_long" %} + + ins_encode %{ + __ revb(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct bytes_reverse_unsigned_short(iRegINoSp dst, iRegIorL2I src) %{ + match(Set dst (ReverseBytesUS src)); + + ins_cost(ALU_COST * 5); + format %{ "revb_h_h_u $dst, $src\t#@bytes_reverse_unsigned_short" %} + + ins_encode %{ + __ revb_h_h_u(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct bytes_reverse_short(iRegINoSp dst, iRegIorL2I src) %{ + match(Set dst (ReverseBytesS src)); + + ins_cost(ALU_COST * 5); + format %{ "revb_h_h $dst, $src\t#@bytes_reverse_short" %} + + ins_encode %{ + __ revb_h_h(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// ============================================================================ +// MemBar Instruction + +instruct load_fence() %{ + match(LoadFence); + ins_cost(ALU_COST); + + format %{ "#@load_fence" %} + + ins_encode %{ + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + %} + ins_pipe(pipe_serial); +%} + +instruct membar_acquire() %{ + match(MemBarAcquire); + ins_cost(ALU_COST); + + format %{ "#@membar_acquire\n\t" + "fence ir iorw" %} + + ins_encode %{ + __ block_comment("membar_acquire"); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + %} + + ins_pipe(pipe_serial); +%} + +instruct membar_acquire_lock() %{ + match(MemBarAcquireLock); + ins_cost(0); + + format %{ "#@membar_acquire_lock (elided)" %} + + ins_encode %{ + __ block_comment("membar_acquire_lock (elided)"); + %} + + ins_pipe(pipe_serial); +%} + +instruct store_fence() %{ + match(StoreFence); + ins_cost(ALU_COST); + + format %{ "#@store_fence" %} + + ins_encode %{ + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + %} + ins_pipe(pipe_serial); +%} + +instruct membar_release() %{ + match(MemBarRelease); + ins_cost(ALU_COST); + + format %{ "#@membar_release\n\t" + "fence iorw ow" %} + + ins_encode %{ + __ block_comment("membar_release"); + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + %} + ins_pipe(pipe_serial); +%} + +instruct membar_storestore() %{ + match(MemBarStoreStore); + match(StoreStoreFence); + ins_cost(ALU_COST); + + format %{ "MEMBAR-store-store\t#@membar_storestore" %} + + ins_encode %{ + __ membar(MacroAssembler::StoreStore); + %} + ins_pipe(pipe_serial); +%} + +instruct membar_release_lock() %{ + match(MemBarReleaseLock); + ins_cost(0); + + format %{ "#@membar_release_lock (elided)" %} + + ins_encode %{ + __ block_comment("membar_release_lock (elided)"); + %} + + ins_pipe(pipe_serial); +%} + +instruct membar_volatile() %{ + match(MemBarVolatile); + ins_cost(ALU_COST); + + format %{ "#@membar_volatile\n\t" + "fence iorw iorw"%} + + ins_encode %{ + __ block_comment("membar_volatile"); + __ membar(MacroAssembler::StoreLoad); + %} + + ins_pipe(pipe_serial); +%} + +// ============================================================================ +// Cast Instructions (Java-level type cast) + +instruct castX2P(iRegPNoSp dst, iRegL src) %{ + match(Set dst (CastX2P src)); + + ins_cost(ALU_COST); + format %{ "mv $dst, $src\t# long -> ptr, #@castX2P" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + if ($dst$$reg != $src$$reg) { + __ mv(as_Register($dst$$reg), as_Register($src$$reg)); + } + %} + + ins_pipe(ialu_reg); +%} + +instruct castP2X(iRegLNoSp dst, iRegP src) %{ + match(Set dst (CastP2X src)); + + ins_cost(ALU_COST); + format %{ "mv $dst, $src\t# ptr -> long, #@castP2X" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + if ($dst$$reg != $src$$reg) { + __ mv(as_Register($dst$$reg), as_Register($src$$reg)); + } + %} + + ins_pipe(ialu_reg); +%} + +instruct castPP(iRegPNoSp dst) +%{ + match(Set dst (CastPP dst)); + ins_cost(0); + + size(0); + format %{ "# castPP of $dst, #@castPP" %} + ins_encode(/* empty encoding */); + ins_pipe(pipe_class_empty); +%} + +instruct castLL(iRegL dst) +%{ + match(Set dst (CastLL dst)); + + size(0); + format %{ "# castLL of $dst, #@castLL" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(pipe_class_empty); +%} + +instruct castII(iRegI dst) +%{ + match(Set dst (CastII dst)); + + size(0); + format %{ "# castII of $dst, #@castII" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(pipe_class_empty); +%} + +instruct checkCastPP(iRegPNoSp dst) +%{ + match(Set dst (CheckCastPP dst)); + + size(0); + ins_cost(0); + format %{ "# checkcastPP of $dst, #@checkCastPP" %} + ins_encode(/* empty encoding */); + ins_pipe(pipe_class_empty); +%} + +instruct castFF(fRegF dst) +%{ + match(Set dst (CastFF dst)); + + size(0); + format %{ "# castFF of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(pipe_class_empty); +%} + +instruct castDD(fRegD dst) +%{ + match(Set dst (CastDD dst)); + + size(0); + format %{ "# castDD of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(pipe_class_empty); +%} + +instruct castVV(vReg dst) +%{ + match(Set dst (CastVV dst)); + + size(0); + format %{ "# castVV of $dst" %} + ins_encode(/* empty encoding */); + ins_cost(0); + ins_pipe(pipe_class_empty); +%} + +// ============================================================================ +// Convert Instructions + +// int to bool +instruct convI2Bool(iRegINoSp dst, iRegI src) +%{ + match(Set dst (Conv2B src)); + + ins_cost(ALU_COST); + format %{ "snez $dst, $src\t#@convI2Bool" %} + + ins_encode %{ + __ snez(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// pointer to bool +instruct convP2Bool(iRegINoSp dst, iRegP src) +%{ + match(Set dst (Conv2B src)); + + ins_cost(ALU_COST); + format %{ "snez $dst, $src\t#@convP2Bool" %} + + ins_encode %{ + __ snez(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// int <-> long + +instruct convI2L_reg_reg(iRegLNoSp dst, iRegIorL2I src) +%{ + match(Set dst (ConvI2L src)); + + ins_cost(ALU_COST); + format %{ "addw $dst, $src, zr\t#@convI2L_reg_reg" %} + ins_encode %{ + __ addw(as_Register($dst$$reg), as_Register($src$$reg), zr); + %} + ins_pipe(ialu_reg); +%} + +instruct convL2I_reg(iRegINoSp dst, iRegL src) %{ + match(Set dst (ConvL2I src)); + + ins_cost(ALU_COST); + format %{ "addw $dst, $src, zr\t#@convL2I_reg" %} + + ins_encode %{ + __ addw(as_Register($dst$$reg), as_Register($src$$reg), zr); + %} + + ins_pipe(ialu_reg); +%} + +// int to unsigned long (Zero-extend) +instruct convI2UL_reg_reg(iRegLNoSp dst, iRegIorL2I src, immL_32bits mask) +%{ + match(Set dst (AndL (ConvI2L src) mask)); + + ins_cost(ALU_COST * 2); + format %{ "zero_extend $dst, $src, 32\t# i2ul, #@convI2UL_reg_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ zero_extend(as_Register($dst$$reg), as_Register($src$$reg), 32); + %} + + ins_pipe(ialu_reg_shift); +%} + +// float <-> double + +instruct convF2D_reg(fRegD dst, fRegF src) %{ + match(Set dst (ConvF2D src)); + + ins_cost(XFER_COST); + format %{ "fcvt.d.s $dst, $src\t#@convF2D_reg" %} + + ins_encode %{ + __ fcvt_d_s(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_f2d); +%} + +instruct convD2F_reg(fRegF dst, fRegD src) %{ + match(Set dst (ConvD2F src)); + + ins_cost(XFER_COST); + format %{ "fcvt.s.d $dst, $src\t#@convD2F_reg" %} + + ins_encode %{ + __ fcvt_s_d(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_d2f); +%} + +// float <-> int + +instruct convF2I_reg_reg(iRegINoSp dst, fRegF src) %{ + match(Set dst (ConvF2I src)); + + ins_cost(XFER_COST); + format %{ "fcvt.w.s $dst, $src\t#@convF2I_reg_reg" %} + + ins_encode %{ + __ fcvt_w_s_safe($dst$$Register, $src$$FloatRegister); + %} + + ins_pipe(fp_f2i); +%} + +instruct convI2F_reg_reg(fRegF dst, iRegIorL2I src) %{ + match(Set dst (ConvI2F src)); + + ins_cost(XFER_COST); + format %{ "fcvt.s.w $dst, $src\t#@convI2F_reg_reg" %} + + ins_encode %{ + __ fcvt_s_w(as_FloatRegister($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(fp_i2f); +%} + +// float <-> long + +instruct convF2L_reg_reg(iRegLNoSp dst, fRegF src) %{ + match(Set dst (ConvF2L src)); + + ins_cost(XFER_COST); + format %{ "fcvt.l.s $dst, $src\t#@convF2L_reg_reg" %} + + ins_encode %{ + __ fcvt_l_s_safe($dst$$Register, $src$$FloatRegister); + %} + + ins_pipe(fp_f2l); +%} + +instruct convL2F_reg_reg(fRegF dst, iRegL src) %{ + match(Set dst (ConvL2F src)); + + ins_cost(XFER_COST); + format %{ "fcvt.s.l $dst, $src\t#@convL2F_reg_reg" %} + + ins_encode %{ + __ fcvt_s_l(as_FloatRegister($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(fp_l2f); +%} + +// double <-> int + +instruct convD2I_reg_reg(iRegINoSp dst, fRegD src) %{ + match(Set dst (ConvD2I src)); + + ins_cost(XFER_COST); + format %{ "fcvt.w.d $dst, $src\t#@convD2I_reg_reg" %} + + ins_encode %{ + __ fcvt_w_d_safe($dst$$Register, $src$$FloatRegister); + %} + + ins_pipe(fp_d2i); +%} + +instruct convI2D_reg_reg(fRegD dst, iRegIorL2I src) %{ + match(Set dst (ConvI2D src)); + + ins_cost(XFER_COST); + format %{ "fcvt.d.w $dst, $src\t#@convI2D_reg_reg" %} + + ins_encode %{ + __ fcvt_d_w(as_FloatRegister($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(fp_i2d); +%} + +// double <-> long + +instruct convD2L_reg_reg(iRegLNoSp dst, fRegD src) %{ + match(Set dst (ConvD2L src)); + + ins_cost(XFER_COST); + format %{ "fcvt.l.d $dst, $src\t#@convD2L_reg_reg" %} + + ins_encode %{ + __ fcvt_l_d_safe($dst$$Register, $src$$FloatRegister); + %} + + ins_pipe(fp_d2l); +%} + +instruct convL2D_reg_reg(fRegD dst, iRegL src) %{ + match(Set dst (ConvL2D src)); + + ins_cost(XFER_COST); + format %{ "fcvt.d.l $dst, $src\t#@convL2D_reg_reg" %} + + ins_encode %{ + __ fcvt_d_l(as_FloatRegister($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(fp_l2d); +%} + +// Convert oop into int for vectors alignment masking +instruct convP2I(iRegINoSp dst, iRegP src) %{ + match(Set dst (ConvL2I (CastP2X src))); + + ins_cost(ALU_COST * 2); + format %{ "zero_extend $dst, $src, 32\t# ptr -> int, #@convP2I" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ zero_extend($dst$$Register, $src$$Register, 32); + %} + + ins_pipe(ialu_reg); +%} + +// Convert compressed oop into int for vectors alignment masking +// in case of 32bit oops (heap < 4Gb). +instruct convN2I(iRegINoSp dst, iRegN src) +%{ + predicate(CompressedOops::shift() == 0); + match(Set dst (ConvL2I (CastP2X (DecodeN src)))); + + ins_cost(ALU_COST); + format %{ "mv $dst, $src\t# compressed ptr -> int, #@convN2I" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ mv($dst$$Register, $src$$Register); + %} + + ins_pipe(ialu_reg); +%} + +// Convert oop pointer into compressed form +instruct encodeHeapOop(iRegNNoSp dst, iRegP src) %{ + match(Set dst (EncodeP src)); + ins_cost(ALU_COST); + format %{ "encode_heap_oop $dst, $src\t#@encodeHeapOop" %} + ins_encode %{ + Register s = $src$$Register; + Register d = $dst$$Register; + __ encode_heap_oop(d, s); + %} + ins_pipe(ialu_reg); +%} + +instruct decodeHeapOop(iRegPNoSp dst, iRegN src) %{ + predicate(n->bottom_type()->is_ptr()->ptr() != TypePtr::NotNull && + n->bottom_type()->is_ptr()->ptr() != TypePtr::Constant); + match(Set dst (DecodeN src)); + + ins_cost(0); + format %{ "decode_heap_oop $dst, $src\t#@decodeHeapOop" %} + ins_encode %{ + Register s = $src$$Register; + Register d = $dst$$Register; + __ decode_heap_oop(d, s); + %} + ins_pipe(ialu_reg); +%} + +instruct decodeHeapOop_not_null(iRegPNoSp dst, iRegN src) %{ + predicate(n->bottom_type()->is_ptr()->ptr() == TypePtr::NotNull || + n->bottom_type()->is_ptr()->ptr() == TypePtr::Constant); + match(Set dst (DecodeN src)); + + ins_cost(0); + format %{ "decode_heap_oop_not_null $dst, $src\t#@decodeHeapOop_not_null" %} + ins_encode %{ + Register s = $src$$Register; + Register d = $dst$$Register; + __ decode_heap_oop_not_null(d, s); + %} + ins_pipe(ialu_reg); +%} + +// Convert klass pointer into compressed form. +instruct encodeKlass_not_null(iRegNNoSp dst, iRegP src) %{ + match(Set dst (EncodePKlass src)); + + ins_cost(ALU_COST); + format %{ "encode_klass_not_null $dst, $src\t#@encodeKlass_not_null" %} + + ins_encode %{ + Register src_reg = as_Register($src$$reg); + Register dst_reg = as_Register($dst$$reg); + __ encode_klass_not_null(dst_reg, src_reg, t0); + %} + + ins_pipe(ialu_reg); +%} + +instruct decodeKlass_not_null(iRegPNoSp dst, iRegN src, iRegPNoSp tmp) %{ + match(Set dst (DecodeNKlass src)); + + effect(TEMP tmp); + + ins_cost(ALU_COST); + format %{ "decode_klass_not_null $dst, $src\t#@decodeKlass_not_null" %} + + ins_encode %{ + Register src_reg = as_Register($src$$reg); + Register dst_reg = as_Register($dst$$reg); + Register tmp_reg = as_Register($tmp$$reg); + __ decode_klass_not_null(dst_reg, src_reg, tmp_reg); + %} + + ins_pipe(ialu_reg); +%} + +// stack <-> reg and reg <-> reg shuffles with no conversion + +instruct MoveF2I_stack_reg(iRegINoSp dst, stackSlotF src) %{ + + match(Set dst (MoveF2I src)); + + effect(DEF dst, USE src); + + ins_cost(LOAD_COST); + + format %{ "lw $dst, $src\t#@MoveF2I_stack_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ lw(as_Register($dst$$reg), Address(sp, $src$$disp)); + %} + + ins_pipe(iload_reg_reg); + +%} + +instruct MoveI2F_stack_reg(fRegF dst, stackSlotI src) %{ + + match(Set dst (MoveI2F src)); + + effect(DEF dst, USE src); + + ins_cost(LOAD_COST); + + format %{ "flw $dst, $src\t#@MoveI2F_stack_reg" %} + + ins_encode %{ + __ flw(as_FloatRegister($dst$$reg), Address(sp, $src$$disp)); + %} + + ins_pipe(pipe_class_memory); + +%} + +instruct MoveD2L_stack_reg(iRegLNoSp dst, stackSlotD src) %{ + + match(Set dst (MoveD2L src)); + + effect(DEF dst, USE src); + + ins_cost(LOAD_COST); + + format %{ "ld $dst, $src\t#@MoveD2L_stack_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ ld(as_Register($dst$$reg), Address(sp, $src$$disp)); + %} + + ins_pipe(iload_reg_reg); + +%} + +instruct MoveL2D_stack_reg(fRegD dst, stackSlotL src) %{ + + match(Set dst (MoveL2D src)); + + effect(DEF dst, USE src); + + ins_cost(LOAD_COST); + + format %{ "fld $dst, $src\t#@MoveL2D_stack_reg" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ fld(as_FloatRegister($dst$$reg), Address(sp, $src$$disp)); + %} + + ins_pipe(pipe_class_memory); + +%} + +instruct MoveF2I_reg_stack(stackSlotI dst, fRegF src) %{ + + match(Set dst (MoveF2I src)); + + effect(DEF dst, USE src); + + ins_cost(STORE_COST); + + format %{ "fsw $src, $dst\t#@MoveF2I_reg_stack" %} + + ins_encode %{ + __ fsw(as_FloatRegister($src$$reg), Address(sp, $dst$$disp)); + %} + + ins_pipe(pipe_class_memory); + +%} + +instruct MoveI2F_reg_stack(stackSlotF dst, iRegI src) %{ + + match(Set dst (MoveI2F src)); + + effect(DEF dst, USE src); + + ins_cost(STORE_COST); + + format %{ "sw $src, $dst\t#@MoveI2F_reg_stack" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ sw(as_Register($src$$reg), Address(sp, $dst$$disp)); + %} + + ins_pipe(istore_reg_reg); + +%} + +instruct MoveD2L_reg_stack(stackSlotL dst, fRegD src) %{ + + match(Set dst (MoveD2L src)); + + effect(DEF dst, USE src); + + ins_cost(STORE_COST); + + format %{ "fsd $dst, $src\t#@MoveD2L_reg_stack" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ fsd(as_FloatRegister($src$$reg), Address(sp, $dst$$disp)); + %} + + ins_pipe(pipe_class_memory); + +%} + +instruct MoveL2D_reg_stack(stackSlotD dst, iRegL src) %{ + + match(Set dst (MoveL2D src)); + + effect(DEF dst, USE src); + + ins_cost(STORE_COST); + + format %{ "sd $src, $dst\t#@MoveL2D_reg_stack" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + __ sd(as_Register($src$$reg), Address(sp, $dst$$disp)); + %} + + ins_pipe(istore_reg_reg); + +%} + +instruct MoveF2I_reg_reg(iRegINoSp dst, fRegF src) %{ + + match(Set dst (MoveF2I src)); + + effect(DEF dst, USE src); + + ins_cost(XFER_COST); + + format %{ "fmv.x.w $dst, $src\t#@MoveL2D_reg_stack" %} + + ins_encode %{ + __ fmv_x_w(as_Register($dst$$reg), as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_f2i); + +%} + +instruct MoveI2F_reg_reg(fRegF dst, iRegI src) %{ + + match(Set dst (MoveI2F src)); + + effect(DEF dst, USE src); + + ins_cost(XFER_COST); + + format %{ "fmv.w.x $dst, $src\t#@MoveI2F_reg_reg" %} + + ins_encode %{ + __ fmv_w_x(as_FloatRegister($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(fp_i2f); + +%} + +instruct MoveD2L_reg_reg(iRegLNoSp dst, fRegD src) %{ + + match(Set dst (MoveD2L src)); + + effect(DEF dst, USE src); + + ins_cost(XFER_COST); + + format %{ "fmv.x.d $dst, $src\t#@MoveD2L_reg_reg" %} + + ins_encode %{ + __ fmv_x_d(as_Register($dst$$reg), as_FloatRegister($src$$reg)); + %} + + ins_pipe(fp_d2l); + +%} + +instruct MoveL2D_reg_reg(fRegD dst, iRegL src) %{ + + match(Set dst (MoveL2D src)); + + effect(DEF dst, USE src); + + ins_cost(XFER_COST); + + format %{ "fmv.d.x $dst, $src\t#@MoveD2L_reg_reg" %} + + ins_encode %{ + __ fmv_d_x(as_FloatRegister($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(fp_l2d); +%} + +// ============================================================================ +// Compare Instructions which set the result float comparisons in dest register. + +instruct cmpF3_reg_reg(iRegINoSp dst, fRegF op1, fRegF op2) +%{ + match(Set dst (CmpF3 op1 op2)); + + ins_cost(XFER_COST * 2 + BRANCH_COST + ALU_COST); + format %{ "flt.s $dst, $op2, $op1\t#@cmpF3_reg_reg\n\t" + "bgtz $dst, done\n\t" + "feq.s $dst, $op1, $op2\n\t" + "addi $dst, $dst, -1\t#@cmpF3_reg_reg" + %} + + ins_encode %{ + // we want -1 for unordered or less than, 0 for equal and 1 for greater than. + __ float_compare(as_Register($dst$$reg), as_FloatRegister($op1$$reg), + as_FloatRegister($op2$$reg), -1 /*unordered_result < 0*/); + %} + + ins_pipe(pipe_class_default); +%} + +instruct cmpD3_reg_reg(iRegINoSp dst, fRegD op1, fRegD op2) +%{ + match(Set dst (CmpD3 op1 op2)); + + ins_cost(XFER_COST * 2 + BRANCH_COST + ALU_COST); + format %{ "flt.d $dst, $op2, $op1\t#@cmpD3_reg_reg\n\t" + "bgtz $dst, done\n\t" + "feq.d $dst, $op1, $op2\n\t" + "addi $dst, $dst, -1\t#@cmpD3_reg_reg" + %} + + ins_encode %{ + // we want -1 for unordered or less than, 0 for equal and 1 for greater than. + __ double_compare(as_Register($dst$$reg), as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), -1 /*unordered_result < 0*/); + %} + + ins_pipe(pipe_class_default); +%} + +instruct cmpL3_reg_reg(iRegINoSp dst, iRegL op1, iRegL op2) +%{ + match(Set dst (CmpL3 op1 op2)); + + ins_cost(ALU_COST * 3 + BRANCH_COST); + format %{ "slt $dst, $op2, $op1\t#@cmpL3_reg_reg\n\t" + "bnez $dst, done\n\t" + "slt $dst, $op1, $op2\n\t" + "neg $dst, $dst\t#@cmpL3_reg_reg" + %} + ins_encode %{ + __ cmp_l2i(t0, as_Register($op1$$reg), as_Register($op2$$reg)); + __ mv(as_Register($dst$$reg), t0); + %} + + ins_pipe(pipe_class_default); +%} + +instruct cmpLTMask_reg_reg(iRegINoSp dst, iRegI p, iRegI q) +%{ + match(Set dst (CmpLTMask p q)); + + ins_cost(2 * ALU_COST); + + format %{ "slt $dst, $p, $q\t#@cmpLTMask_reg_reg\n\t" + "subw $dst, zr, $dst\t#@cmpLTMask_reg_reg" + %} + + ins_encode %{ + __ slt(as_Register($dst$$reg), as_Register($p$$reg), as_Register($q$$reg)); + __ subw(as_Register($dst$$reg), zr, as_Register($dst$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct cmpLTMask_reg_zero(iRegINoSp dst, iRegIorL2I op, immI0 zero) +%{ + match(Set dst (CmpLTMask op zero)); + + ins_cost(ALU_COST); + + format %{ "sraiw $dst, $dst, 31\t#@cmpLTMask_reg_reg" %} + + ins_encode %{ + __ sraiw(as_Register($dst$$reg), as_Register($op$$reg), 31); + %} + + ins_pipe(ialu_reg_shift); +%} + + +// ============================================================================ +// Max and Min + +instruct minI_rReg(iRegINoSp dst, iRegI src1, iRegI src2) +%{ + match(Set dst (MinI src1 src2)); + + effect(DEF dst, USE src1, USE src2); + + ins_cost(BRANCH_COST + ALU_COST * 2); + format %{ + "ble $src1, $src2, Lsrc1.\t#@minI_rReg\n\t" + "mv $dst, $src2\n\t" + "j Ldone\n\t" + "bind Lsrc1\n\t" + "mv $dst, $src1\n\t" + "bind\t#@minI_rReg" + %} + + ins_encode %{ + Label Lsrc1, Ldone; + __ ble(as_Register($src1$$reg), as_Register($src2$$reg), Lsrc1); + __ mv(as_Register($dst$$reg), as_Register($src2$$reg)); + __ j(Ldone); + __ bind(Lsrc1); + __ mv(as_Register($dst$$reg), as_Register($src1$$reg)); + __ bind(Ldone); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct maxI_rReg(iRegINoSp dst, iRegI src1, iRegI src2) +%{ + match(Set dst (MaxI src1 src2)); + + effect(DEF dst, USE src1, USE src2); + + ins_cost(BRANCH_COST + ALU_COST * 2); + format %{ + "bge $src1, $src2, Lsrc1\t#@maxI_rReg\n\t" + "mv $dst, $src2\n\t" + "j Ldone\n\t" + "bind Lsrc1\n\t" + "mv $dst, $src1\n\t" + "bind\t#@maxI_rReg" + %} + + ins_encode %{ + Label Lsrc1, Ldone; + __ bge(as_Register($src1$$reg), as_Register($src2$$reg), Lsrc1); + __ mv(as_Register($dst$$reg), as_Register($src2$$reg)); + __ j(Ldone); + __ bind(Lsrc1); + __ mv(as_Register($dst$$reg), as_Register($src1$$reg)); + __ bind(Ldone); + + %} + + ins_pipe(ialu_reg_reg); +%} + +// ============================================================================ +// Branch Instructions +// Direct Branch. +instruct branch(label lbl) +%{ + match(Goto); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "j $lbl\t#@branch" %} + + ins_encode(riscv_enc_j(lbl)); + + ins_pipe(pipe_branch); +%} + +// ============================================================================ +// Compare and Branch Instructions + +// Patterns for short (< 12KiB) variants + +// Compare flags and branch near instructions. +instruct cmpFlag_branch(cmpOpEqNe cmp, rFlagsReg cr, label lbl) %{ + match(If cmp cr); + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "b$cmp $cr, zr, $lbl\t#@cmpFlag_branch" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($cr$$reg), *($lbl$$label)); + %} + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +// Compare signed int and branch near instructions +instruct cmpI_branch(cmpOp cmp, iRegI op1, iRegI op2, label lbl) +%{ + // Same match rule as `far_cmpI_branch'. + match(If cmp (CmpI op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpI_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +instruct cmpI_loop(cmpOp cmp, iRegI op1, iRegI op2, label lbl) +%{ + // Same match rule as `far_cmpI_loop'. + match(CountedLoopEnd cmp (CmpI op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpI_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +// Compare unsigned int and branch near instructions +instruct cmpU_branch(cmpOpU cmp, iRegI op1, iRegI op2, label lbl) +%{ + // Same match rule as `far_cmpU_branch'. + match(If cmp (CmpU op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpU_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +instruct cmpU_loop(cmpOpU cmp, iRegI op1, iRegI op2, label lbl) +%{ + // Same match rule as `far_cmpU_loop'. + match(CountedLoopEnd cmp (CmpU op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpU_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +// Compare signed long and branch near instructions +instruct cmpL_branch(cmpOp cmp, iRegL op1, iRegL op2, label lbl) +%{ + // Same match rule as `far_cmpL_branch'. + match(If cmp (CmpL op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpL_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +instruct cmpL_loop(cmpOp cmp, iRegL op1, iRegL op2, label lbl) +%{ + // Same match rule as `far_cmpL_loop'. + match(CountedLoopEnd cmp (CmpL op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpL_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +// Compare unsigned long and branch near instructions +instruct cmpUL_branch(cmpOpU cmp, iRegL op1, iRegL op2, label lbl) +%{ + // Same match rule as `far_cmpUL_branch'. + match(If cmp (CmpUL op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpUL_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +instruct cmpUL_loop(cmpOpU cmp, iRegL op1, iRegL op2, label lbl) +%{ + // Same match rule as `far_cmpUL_loop'. + match(CountedLoopEnd cmp (CmpUL op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpUL_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +// Compare pointer and branch near instructions +instruct cmpP_branch(cmpOpU cmp, iRegP op1, iRegP op2, label lbl) +%{ + // Same match rule as `far_cmpP_branch'. + match(If cmp (CmpP op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpP_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +instruct cmpP_loop(cmpOpU cmp, iRegP op1, iRegP op2, label lbl) +%{ + // Same match rule as `far_cmpP_loop'. + match(CountedLoopEnd cmp (CmpP op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpP_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +// Compare narrow pointer and branch near instructions +instruct cmpN_branch(cmpOpU cmp, iRegN op1, iRegN op2, label lbl) +%{ + // Same match rule as `far_cmpN_branch'. + match(If cmp (CmpN op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpN_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +instruct cmpN_loop(cmpOpU cmp, iRegN op1, iRegN op2, label lbl) +%{ + // Same match rule as `far_cmpN_loop'. + match(CountedLoopEnd cmp (CmpN op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, $op2, $lbl\t#@cmpN_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmp_branch); + ins_short_branch(1); +%} + +// Compare float and branch near instructions +instruct cmpF_branch(cmpOp cmp, fRegF op1, fRegF op2, label lbl) +%{ + // Same match rule as `far_cmpF_branch'. + match(If cmp (CmpF op1 op2)); + + effect(USE lbl); + + ins_cost(XFER_COST + BRANCH_COST); + format %{ "float_b$cmp $op1, $op2 \t#@cmpF_branch"%} + + ins_encode %{ + __ float_cmp_branch($cmp$$cmpcode, as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_class_compare); + ins_short_branch(1); +%} + +instruct cmpF_loop(cmpOp cmp, fRegF op1, fRegF op2, label lbl) +%{ + // Same match rule as `far_cmpF_loop'. + match(CountedLoopEnd cmp (CmpF op1 op2)); + effect(USE lbl); + + ins_cost(XFER_COST + BRANCH_COST); + format %{ "float_b$cmp $op1, $op2\t#@cmpF_loop"%} + + ins_encode %{ + __ float_cmp_branch($cmp$$cmpcode, as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_class_compare); + ins_short_branch(1); +%} + +// Compare double and branch near instructions +instruct cmpD_branch(cmpOp cmp, fRegD op1, fRegD op2, label lbl) +%{ + // Same match rule as `far_cmpD_branch'. + match(If cmp (CmpD op1 op2)); + effect(USE lbl); + + ins_cost(XFER_COST + BRANCH_COST); + format %{ "double_b$cmp $op1, $op2\t#@cmpD_branch"%} + + ins_encode %{ + __ float_cmp_branch($cmp$$cmpcode | C2_MacroAssembler::double_branch_mask, as_FloatRegister($op1$$reg), + as_FloatRegister($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_class_compare); + ins_short_branch(1); +%} + +instruct cmpD_loop(cmpOp cmp, fRegD op1, fRegD op2, label lbl) +%{ + // Same match rule as `far_cmpD_loop'. + match(CountedLoopEnd cmp (CmpD op1 op2)); + effect(USE lbl); + + ins_cost(XFER_COST + BRANCH_COST); + format %{ "double_b$cmp $op1, $op2\t#@cmpD_loop"%} + + ins_encode %{ + __ float_cmp_branch($cmp$$cmpcode | C2_MacroAssembler::double_branch_mask, as_FloatRegister($op1$$reg), + as_FloatRegister($op2$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_class_compare); + ins_short_branch(1); +%} + +// Compare signed int with zero and branch near instructions +instruct cmpI_reg_imm0_branch(cmpOp cmp, iRegI op1, immI0 zero, label lbl) +%{ + // Same match rule as `far_cmpI_reg_imm0_branch'. + match(If cmp (CmpI op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + format %{ "b$cmp $op1, zr, $lbl\t#@cmpI_reg_imm0_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), zr, *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +instruct cmpI_reg_imm0_loop(cmpOp cmp, iRegI op1, immI0 zero, label lbl) +%{ + // Same match rule as `far_cmpI_reg_imm0_loop'. + match(CountedLoopEnd cmp (CmpI op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpI_reg_imm0_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), zr, *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +// Compare unsigned int with zero and branch near instructions +instruct cmpUEqNeLeGt_reg_imm0_branch(cmpOpUEqNeLeGt cmp, iRegI op1, immI0 zero, label lbl) +%{ + // Same match rule as `far_cmpUEqNeLeGt_reg_imm0_branch'. + match(If cmp (CmpU op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpUEqNeLeGt_reg_imm0_branch" %} + + ins_encode %{ + __ enc_cmpUEqNeLeGt_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +instruct cmpUEqNeLeGt_reg_imm0_loop(cmpOpUEqNeLeGt cmp, iRegI op1, immI0 zero, label lbl) +%{ + // Same match rule as `far_cmpUEqNeLeGt_reg_imm0_loop'. + match(CountedLoopEnd cmp (CmpU op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpUEqNeLeGt_reg_imm0_loop" %} + + + ins_encode %{ + __ enc_cmpUEqNeLeGt_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +// Compare signed long with zero and branch near instructions +instruct cmpL_reg_imm0_branch(cmpOp cmp, iRegL op1, immL0 zero, label lbl) +%{ + // Same match rule as `far_cmpL_reg_imm0_branch'. + match(If cmp (CmpL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpL_reg_imm0_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), zr, *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +instruct cmpL_reg_imm0_loop(cmpOp cmp, iRegL op1, immL0 zero, label lbl) +%{ + // Same match rule as `far_cmpL_reg_imm0_loop'. + match(CountedLoopEnd cmp (CmpL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpL_reg_imm0_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), zr, *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +// Compare unsigned long with zero and branch near instructions +instruct cmpULEqNeLeGt_reg_imm0_branch(cmpOpUEqNeLeGt cmp, iRegL op1, immL0 zero, label lbl) +%{ + // Same match rule as `far_cmpULEqNeLeGt_reg_imm0_branch'. + match(If cmp (CmpUL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpULEqNeLeGt_reg_imm0_branch" %} + + ins_encode %{ + __ enc_cmpUEqNeLeGt_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +instruct cmpULEqNeLeGt_reg_imm0_loop(cmpOpUEqNeLeGt cmp, iRegL op1, immL0 zero, label lbl) +%{ + // Same match rule as `far_cmpULEqNeLeGt_reg_imm0_loop'. + match(CountedLoopEnd cmp (CmpUL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpULEqNeLeGt_reg_imm0_loop" %} + + ins_encode %{ + __ enc_cmpUEqNeLeGt_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +// Compare pointer with zero and branch near instructions +instruct cmpP_imm0_branch(cmpOpEqNe cmp, iRegP op1, immP0 zero, label lbl) %{ + // Same match rule as `far_cmpP_reg_imm0_branch'. + match(If cmp (CmpP op1 zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "b$cmp $op1, zr, $lbl\t#@cmpP_imm0_branch" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +instruct cmpP_imm0_loop(cmpOpEqNe cmp, iRegP op1, immP0 zero, label lbl) %{ + // Same match rule as `far_cmpP_reg_imm0_loop'. + match(CountedLoopEnd cmp (CmpP op1 zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "b$cmp $op1, zr, $lbl\t#@cmpP_imm0_loop" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +// Compare narrow pointer with zero and branch near instructions +instruct cmpN_imm0_branch(cmpOpEqNe cmp, iRegN op1, immN0 zero, label lbl) %{ + // Same match rule as `far_cmpN_reg_imm0_branch'. + match(If cmp (CmpN op1 zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpN_imm0_branch" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +instruct cmpN_imm0_loop(cmpOpEqNe cmp, iRegN op1, immN0 zero, label lbl) %{ + // Same match rule as `far_cmpN_reg_imm0_loop'. + match(CountedLoopEnd cmp (CmpN op1 zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "b$cmp $op1, zr, $lbl\t#@cmpN_imm0_loop" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +// Compare narrow pointer with pointer zero and branch near instructions +instruct cmpP_narrowOop_imm0_branch(cmpOpEqNe cmp, iRegN op1, immP0 zero, label lbl) %{ + // Same match rule as `far_cmpP_narrowOop_imm0_branch'. + match(If cmp (CmpP (DecodeN op1) zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "b$cmp $op1, zr, $lbl\t#@cmpP_narrowOop_imm0_branch" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +instruct cmpP_narrowOop_imm0_loop(cmpOpEqNe cmp, iRegN op1, immP0 zero, label lbl) %{ + // Same match rule as `far_cmpP_narrowOop_imm0_loop'. + match(CountedLoopEnd cmp (CmpP (DecodeN op1) zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "b$cmp $op1, zr, $lbl\t#@cmpP_narrowOop_imm0_loop" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label)); + %} + + ins_pipe(pipe_cmpz_branch); + ins_short_branch(1); +%} + +// Patterns for far (20KiB) variants + +instruct far_cmpFlag_branch(cmpOp cmp, rFlagsReg cr, label lbl) %{ + match(If cmp cr); + effect(USE lbl); + + ins_cost(BRANCH_COST); + format %{ "far_b$cmp $cr, zr, L\t#@far_cmpFlag_branch"%} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($cr$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +// Compare signed int and branch far instructions +instruct far_cmpI_branch(cmpOp cmp, iRegI op1, iRegI op2, label lbl) %{ + match(If cmp (CmpI op1 op2)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + + // the format instruction [far_b$cmp] here is be used as two insructions + // in macroassembler: b$not_cmp(op1, op2, done), j($lbl), bind(done) + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpI_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpI_loop(cmpOp cmp, iRegI op1, iRegI op2, label lbl) %{ + match(CountedLoopEnd cmp (CmpI op1 op2)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpI_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpU_branch(cmpOpU cmp, iRegI op1, iRegI op2, label lbl) %{ + match(If cmp (CmpU op1 op2)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpU_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpU_loop(cmpOpU cmp, iRegI op1, iRegI op2, label lbl) %{ + match(CountedLoopEnd cmp (CmpU op1 op2)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpU_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpL_branch(cmpOp cmp, iRegL op1, iRegL op2, label lbl) %{ + match(If cmp (CmpL op1 op2)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpL_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpLloop(cmpOp cmp, iRegL op1, iRegL op2, label lbl) %{ + match(CountedLoopEnd cmp (CmpL op1 op2)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpL_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpUL_branch(cmpOpU cmp, iRegL op1, iRegL op2, label lbl) %{ + match(If cmp (CmpUL op1 op2)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpUL_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpUL_loop(cmpOpU cmp, iRegL op1, iRegL op2, label lbl) %{ + match(CountedLoopEnd cmp (CmpUL op1 op2)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpUL_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpP_branch(cmpOpU cmp, iRegP op1, iRegP op2, label lbl) +%{ + match(If cmp (CmpP op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpP_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpP_loop(cmpOpU cmp, iRegP op1, iRegP op2, label lbl) +%{ + match(CountedLoopEnd cmp (CmpP op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpP_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpN_branch(cmpOpU cmp, iRegN op1, iRegN op2, label lbl) +%{ + match(If cmp (CmpN op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpN_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +instruct far_cmpN_loop(cmpOpU cmp, iRegN op1, iRegN op2, label lbl) +%{ + match(CountedLoopEnd cmp (CmpN op1 op2)); + + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, $op2, $lbl\t#@far_cmpN_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, as_Register($op1$$reg), + as_Register($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmp_branch); +%} + +// Float compare and branch instructions +instruct far_cmpF_branch(cmpOp cmp, fRegF op1, fRegF op2, label lbl) +%{ + match(If cmp (CmpF op1 op2)); + + effect(USE lbl); + + ins_cost(XFER_COST + BRANCH_COST * 2); + format %{ "far_float_b$cmp $op1, $op2\t#@far_cmpF_branch"%} + + ins_encode %{ + __ float_cmp_branch($cmp$$cmpcode, as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct far_cmpF_loop(cmpOp cmp, fRegF op1, fRegF op2, label lbl) +%{ + match(CountedLoopEnd cmp (CmpF op1 op2)); + effect(USE lbl); + + ins_cost(XFER_COST + BRANCH_COST * 2); + format %{ "far_float_b$cmp $op1, $op2\t#@far_cmpF_loop"%} + + ins_encode %{ + __ float_cmp_branch($cmp$$cmpcode, as_FloatRegister($op1$$reg), as_FloatRegister($op2$$reg), + *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_class_compare); +%} + +// Double compare and branch instructions +instruct far_cmpD_branch(cmpOp cmp, fRegD op1, fRegD op2, label lbl) +%{ + match(If cmp (CmpD op1 op2)); + effect(USE lbl); + + ins_cost(XFER_COST + BRANCH_COST * 2); + format %{ "far_double_b$cmp $op1, $op2\t#@far_cmpD_branch"%} + + ins_encode %{ + __ float_cmp_branch($cmp$$cmpcode | C2_MacroAssembler::double_branch_mask, as_FloatRegister($op1$$reg), + as_FloatRegister($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct far_cmpD_loop(cmpOp cmp, fRegD op1, fRegD op2, label lbl) +%{ + match(CountedLoopEnd cmp (CmpD op1 op2)); + effect(USE lbl); + + ins_cost(XFER_COST + BRANCH_COST * 2); + format %{ "far_double_b$cmp $op1, $op2\t#@far_cmpD_loop"%} + + ins_encode %{ + __ float_cmp_branch($cmp$$cmpcode | C2_MacroAssembler::double_branch_mask, as_FloatRegister($op1$$reg), + as_FloatRegister($op2$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_class_compare); +%} + +instruct far_cmpI_reg_imm0_branch(cmpOp cmp, iRegI op1, immI0 zero, label lbl) +%{ + match(If cmp (CmpI op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpI_reg_imm0_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), zr, *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpI_reg_imm0_loop(cmpOp cmp, iRegI op1, immI0 zero, label lbl) +%{ + match(CountedLoopEnd cmp (CmpI op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpI_reg_imm0_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), zr, *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpUEqNeLeGt_imm0_branch(cmpOpUEqNeLeGt cmp, iRegI op1, immI0 zero, label lbl) +%{ + match(If cmp (CmpU op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpUEqNeLeGt_imm0_branch" %} + + ins_encode %{ + __ enc_cmpUEqNeLeGt_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpUEqNeLeGt_reg_imm0_loop(cmpOpUEqNeLeGt cmp, iRegI op1, immI0 zero, label lbl) +%{ + match(CountedLoopEnd cmp (CmpU op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpUEqNeLeGt_reg_imm0_loop" %} + + + ins_encode %{ + __ enc_cmpUEqNeLeGt_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +// compare lt/ge unsigned instructs has no short instruct with same match +instruct far_cmpULtGe_reg_imm0_branch(cmpOpULtGe cmp, iRegI op1, immI0 zero, label lbl) +%{ + match(If cmp (CmpU op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "j $lbl if $cmp == ge\t#@far_cmpULtGe_reg_imm0_branch" %} + + ins_encode(riscv_enc_far_cmpULtGe_imm0_branch(cmp, op1, lbl)); + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpULtGe_reg_imm0_loop(cmpOpULtGe cmp, iRegI op1, immI0 zero, label lbl) +%{ + match(CountedLoopEnd cmp (CmpU op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "j $lbl if $cmp == ge\t#@far_cmpULtGe_reg_imm0_loop" %} + + ins_encode(riscv_enc_far_cmpULtGe_imm0_branch(cmp, op1, lbl)); + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpL_reg_imm0_branch(cmpOp cmp, iRegL op1, immL0 zero, label lbl) +%{ + match(If cmp (CmpL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpL_reg_imm0_branch" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), zr, *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpL_reg_imm0_loop(cmpOp cmp, iRegL op1, immL0 zero, label lbl) +%{ + match(CountedLoopEnd cmp (CmpL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpL_reg_imm0_loop" %} + + ins_encode %{ + __ cmp_branch($cmp$$cmpcode, as_Register($op1$$reg), zr, *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpULEqNeLeGt_reg_imm0_branch(cmpOpUEqNeLeGt cmp, iRegL op1, immL0 zero, label lbl) +%{ + match(If cmp (CmpUL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpULEqNeLeGt_reg_imm0_branch" %} + + ins_encode %{ + __ enc_cmpUEqNeLeGt_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpULEqNeLeGt_reg_imm0_loop(cmpOpUEqNeLeGt cmp, iRegL op1, immL0 zero, label lbl) +%{ + match(CountedLoopEnd cmp (CmpUL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpULEqNeLeGt_reg_imm0_loop" %} + + ins_encode %{ + __ enc_cmpUEqNeLeGt_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +// compare lt/ge unsigned instructs has no short instruct with same match +instruct far_cmpULLtGe_reg_imm0_branch(cmpOpULtGe cmp, iRegL op1, immL0 zero, label lbl) +%{ + match(If cmp (CmpUL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "j $lbl if $cmp == ge\t#@far_cmpULLtGe_reg_imm0_branch" %} + + ins_encode(riscv_enc_far_cmpULtGe_imm0_branch(cmp, op1, lbl)); + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpULLtGe_reg_imm0_loop(cmpOpULtGe cmp, iRegL op1, immL0 zero, label lbl) +%{ + match(CountedLoopEnd cmp (CmpUL op1 zero)); + + effect(USE op1, USE lbl); + + ins_cost(BRANCH_COST); + + format %{ "j $lbl if $cmp == ge\t#@far_cmpULLtGe_reg_imm0_loop" %} + + ins_encode(riscv_enc_far_cmpULtGe_imm0_branch(cmp, op1, lbl)); + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpP_imm0_branch(cmpOpEqNe cmp, iRegP op1, immP0 zero, label lbl) %{ + match(If cmp (CmpP op1 zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpP_imm0_branch" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpP_imm0_loop(cmpOpEqNe cmp, iRegP op1, immP0 zero, label lbl) %{ + match(CountedLoopEnd cmp (CmpP op1 zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpP_imm0_loop" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpN_imm0_branch(cmpOpEqNe cmp, iRegN op1, immN0 zero, label lbl) %{ + match(If cmp (CmpN op1 zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpN_imm0_branch" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpN_imm0_loop(cmpOpEqNe cmp, iRegN op1, immN0 zero, label lbl) %{ + match(CountedLoopEnd cmp (CmpN op1 zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpN_imm0_loop" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpP_narrowOop_imm0_branch(cmpOpEqNe cmp, iRegN op1, immP0 zero, label lbl) %{ + match(If cmp (CmpP (DecodeN op1) zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpP_narrowOop_imm0_branch" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +instruct far_cmpP_narrowOop_imm0_loop(cmpOpEqNe cmp, iRegN op1, immP0 zero, label lbl) %{ + match(CountedLoopEnd cmp (CmpP (DecodeN op1) zero)); + effect(USE lbl); + + ins_cost(BRANCH_COST * 2); + format %{ "far_b$cmp $op1, zr, $lbl\t#@far_cmpP_narrowOop_imm0_loop" %} + + ins_encode %{ + __ enc_cmpEqNe_imm0_branch($cmp$$cmpcode, as_Register($op1$$reg), *($lbl$$label), /* is_far */ true); + %} + + ins_pipe(pipe_cmpz_branch); +%} + +// ============================================================================ +// Conditional Move Instructions +instruct cmovI_cmpI(iRegINoSp dst, iRegI src, iRegI op1, iRegI op2, cmpOp cop) %{ + match(Set dst (CMoveI (Binary cop (CmpI op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "bneg$cop $op1, $op2, skip\t#@cmovI_cmpI\n\t" + "mv $dst, $src\n\t" + "skip:" + %} + + ins_encode %{ + __ enc_cmove($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(pipe_slow); +%} + +instruct cmovI_cmpU(iRegINoSp dst, iRegI src, iRegI op1, iRegI op2, cmpOpU cop) %{ + match(Set dst (CMoveI (Binary cop (CmpU op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "bneg$cop $op1, $op2, skip\t#@cmovI_cmpU\n\t" + "mv $dst, $src\n\t" + "skip:" + %} + + ins_encode %{ + __ enc_cmove($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(pipe_slow); +%} + +instruct cmovI_cmpL(iRegINoSp dst, iRegI src, iRegL op1, iRegL op2, cmpOp cop) %{ + match(Set dst (CMoveI (Binary cop (CmpL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "bneg$cop $op1, $op2, skip\t#@cmovI_cmpL\n\t" + "mv $dst, $src\n\t" + "skip:" + %} + + ins_encode %{ + __ enc_cmove($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(pipe_slow); +%} + +instruct cmovL_cmpL(iRegLNoSp dst, iRegL src, iRegL op1, iRegL op2, cmpOp cop) %{ + match(Set dst (CMoveL (Binary cop (CmpL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "bneg$cop $op1, $op2, skip\t#@cmovL_cmpL\n\t" + "mv $dst, $src\n\t" + "skip:" + %} + + ins_encode %{ + __ enc_cmove($cop$$cmpcode, + as_Register($op1$$reg), as_Register($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(pipe_slow); +%} + +instruct cmovL_cmpUL(iRegLNoSp dst, iRegL src, iRegL op1, iRegL op2, cmpOpU cop) %{ + match(Set dst (CMoveL (Binary cop (CmpUL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + + format %{ + "bneg$cop $op1, $op2, skip\t#@cmovL_cmpUL\n\t" + "mv $dst, $src\n\t" + "skip:" + %} + + ins_encode %{ + __ enc_cmove($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(pipe_slow); +%} + +instruct cmovI_cmpUL(iRegINoSp dst, iRegI src, iRegL op1, iRegL op2, cmpOpU cop) %{ + match(Set dst (CMoveI (Binary cop (CmpUL op1 op2)) (Binary dst src))); + ins_cost(ALU_COST + BRANCH_COST); + format %{ + "bneg$cop $op1, $op2\t#@cmovI_cmpUL\n\t" + "mv $dst, $src\n\t" + "skip:" + %} + + ins_encode %{ + __ enc_cmove($cop$$cmpcode | C2_MacroAssembler::unsigned_branch_mask, + as_Register($op1$$reg), as_Register($op2$$reg), + as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(pipe_slow); +%} + + +// ============================================================================ +// Procedure Call/Return Instructions + +// Call Java Static Instruction +// Note: If this code changes, the corresponding ret_addr_offset() and +// compute_padding() functions will have to be adjusted. +instruct CallStaticJavaDirect(method meth) +%{ + match(CallStaticJava); + + effect(USE meth); + + ins_cost(BRANCH_COST); + + format %{ "CALL,static $meth\t#@CallStaticJavaDirect" %} + + ins_encode(riscv_enc_java_static_call(meth), + riscv_enc_call_epilog); + + ins_pipe(pipe_class_call); + ins_alignment(4); +%} + +// TO HERE + +// Call Java Dynamic Instruction +// Note: If this code changes, the corresponding ret_addr_offset() and +// compute_padding() functions will have to be adjusted. +instruct CallDynamicJavaDirect(method meth, rFlagsReg cr) +%{ + match(CallDynamicJava); + + effect(USE meth, KILL cr); + + ins_cost(BRANCH_COST + ALU_COST * 6); + + format %{ "CALL,dynamic $meth\t#@CallDynamicJavaDirect" %} + + ins_encode(riscv_enc_java_dynamic_call(meth), + riscv_enc_call_epilog); + + ins_pipe(pipe_class_call); + ins_alignment(4); +%} + +// Call Runtime Instruction + +instruct CallRuntimeDirect(method meth, rFlagsReg cr) +%{ + match(CallRuntime); + + effect(USE meth, KILL cr); + + ins_cost(BRANCH_COST); + + format %{ "CALL, runtime $meth\t#@CallRuntimeDirect" %} + + ins_encode(riscv_enc_java_to_runtime(meth)); + + ins_pipe(pipe_class_call); +%} + +// Call Runtime Instruction + +instruct CallLeafDirect(method meth, rFlagsReg cr) +%{ + match(CallLeaf); + + effect(USE meth, KILL cr); + + ins_cost(BRANCH_COST); + + format %{ "CALL, runtime leaf $meth\t#@CallLeafDirect" %} + + ins_encode(riscv_enc_java_to_runtime(meth)); + + ins_pipe(pipe_class_call); +%} + +// Call Runtime Instruction + +instruct CallLeafNoFPDirect(method meth, rFlagsReg cr) +%{ + match(CallLeafNoFP); + + effect(USE meth, KILL cr); + + ins_cost(BRANCH_COST); + + format %{ "CALL, runtime leaf nofp $meth\t#@CallLeafNoFPDirect" %} + + ins_encode(riscv_enc_java_to_runtime(meth)); + + ins_pipe(pipe_class_call); +%} + +// ============================================================================ +// Partial Subtype Check +// +// superklass array for an instance of the superklass. Set a hidden +// internal cache on a hit (cache is checked with exposed code in +// gen_subtype_check()). Return zero for a hit. The encoding +// ALSO sets flags. + +instruct partialSubtypeCheck(iRegP_R15 result, iRegP_R14 sub, iRegP_R10 super, iRegP_R12 tmp, rFlagsReg cr) +%{ + match(Set result (PartialSubtypeCheck sub super)); + effect(KILL tmp, KILL cr); + + ins_cost(2 * STORE_COST + 3 * LOAD_COST + 4 * ALU_COST + BRANCH_COST * 4); + format %{ "partialSubtypeCheck $result, $sub, $super\t#@partialSubtypeCheck" %} + + ins_encode(riscv_enc_partial_subtype_check(sub, super, tmp, result)); + + opcode(0x1); // Force zero of result reg on hit + + ins_pipe(pipe_class_memory); +%} + +instruct partialSubtypeCheckVsZero(iRegP_R15 result, iRegP_R14 sub, iRegP_R10 super, iRegP_R12 tmp, + immP0 zero, rFlagsReg cr) +%{ + match(Set cr (CmpP (PartialSubtypeCheck sub super) zero)); + effect(KILL tmp, KILL result); + + ins_cost(2 * STORE_COST + 3 * LOAD_COST + 4 * ALU_COST + BRANCH_COST * 4); + format %{ "partialSubtypeCheck $result, $sub, $super == 0\t#@partialSubtypeCheckVsZero" %} + + ins_encode(riscv_enc_partial_subtype_check(sub, super, tmp, result)); + + opcode(0x0); // Don't zero result reg on hit + + ins_pipe(pipe_class_memory); +%} + +instruct string_compareU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, iRegP_R28 tmp1, iRegL_R29 tmp2, iRegL_R30 tmp3, rFlagsReg cr) +%{ + predicate(!UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrComp(Binary str1 cnt1)(Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, KILL tmp3, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareU" %} + ins_encode %{ + // Count is in 8-bit bytes; non-Compact chars are 16 bits. + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, + StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_compareL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, iRegP_R28 tmp1, iRegL_R29 tmp2, iRegL_R30 tmp3, rFlagsReg cr) +%{ + predicate(!UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrComp(Binary str1 cnt1)(Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, KILL tmp3, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareL" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, + StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_compareUL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, iRegP_R28 tmp1, iRegL_R29 tmp2, iRegL_R30 tmp3, rFlagsReg cr) +%{ + predicate(!UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrComp(Binary str1 cnt1)(Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, KILL tmp3, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{"String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareUL" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, + StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_compareLU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, iRegP_R28 tmp1, iRegL_R29 tmp2, iRegL_R30 tmp3, + rFlagsReg cr) +%{ + predicate(!UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::LU); + match(Set result (StrComp(Binary str1 cnt1)(Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, KILL tmp3, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, KILL cr); + + format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareLU" %} + ins_encode %{ + __ string_compare($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, + StrIntrinsicNode::LU); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_indexofUU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, + iRegINoSp tmp4, iRegINoSp tmp5, iRegINoSp tmp6, rFlagsReg cr) +%{ + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, KILL cr); + + format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (UU)" %} + ins_encode %{ + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, + $tmp5$$Register, $tmp6$$Register, + $result$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_indexofLL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, + iRegINoSp tmp4, iRegINoSp tmp5, iRegINoSp tmp6, rFlagsReg cr) +%{ + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, KILL cr); + + format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (LL)" %} + ins_encode %{ + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, + $tmp5$$Register, $tmp6$$Register, + $result$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_indexofUL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, iRegINoSp tmp3, + iRegINoSp tmp4, iRegINoSp tmp5, iRegINoSp tmp6, rFlagsReg cr) +%{ + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 cnt2))); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, TEMP tmp5, TEMP tmp6, KILL cr); + format %{ "String IndexOf $str1,$cnt1,$str2,$cnt2 -> $result (UL)" %} + + ins_encode %{ + __ string_indexof($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, + $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, + $tmp5$$Register, $tmp6$$Register, + $result$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_indexof_conUU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, + immI_le_4 int_cnt2, iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) +%{ + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); + + format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (UU)" %} + + ins_encode %{ + int icnt2 = (int)$int_cnt2$$constant; + __ string_indexof_linearscan($str1$$Register, $str2$$Register, + $cnt1$$Register, zr, + $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, + icnt2, $result$$Register, StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_indexof_conLL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, + immI_le_4 int_cnt2, iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) +%{ + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); + + format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (LL)" %} + ins_encode %{ + int icnt2 = (int)$int_cnt2$$constant; + __ string_indexof_linearscan($str1$$Register, $str2$$Register, + $cnt1$$Register, zr, + $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, + icnt2, $result$$Register, StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_indexof_conUL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, + immI_1 int_cnt2, iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) +%{ + predicate(((StrIndexOfNode*)n)->encoding() == StrIntrinsicNode::UL); + match(Set result (StrIndexOf (Binary str1 cnt1) (Binary str2 int_cnt2))); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt1, TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); + + format %{ "String IndexOf $str1,$cnt1,$str2,$int_cnt2 -> $result (UL)" %} + ins_encode %{ + int icnt2 = (int)$int_cnt2$$constant; + __ string_indexof_linearscan($str1$$Register, $str2$$Register, + $cnt1$$Register, zr, + $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, + icnt2, $result$$Register, StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct stringU_indexof_char(iRegP_R11 str1, iRegI_R12 cnt1, iRegI_R13 ch, + iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) +%{ + match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); + predicate(!UseRVV && (((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::U)); + effect(USE_KILL str1, USE_KILL cnt1, USE_KILL ch, TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); + + format %{ "StringUTF16 IndexOf char[] $str1,$cnt1,$ch -> $result" %} + ins_encode %{ + __ string_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, + $result$$Register, $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, false /* isU */); + %} + ins_pipe(pipe_class_memory); +%} + + +instruct stringL_indexof_char(iRegP_R11 str1, iRegI_R12 cnt1, iRegI_R13 ch, + iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, + iRegINoSp tmp3, iRegINoSp tmp4, rFlagsReg cr) +%{ + match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); + predicate(!UseRVV && (((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::L)); + effect(USE_KILL str1, USE_KILL cnt1, USE_KILL ch, TEMP_DEF result, + TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL cr); + + format %{ "StringUTF16 IndexOf char[] $str1,$cnt1,$ch -> $result" %} + ins_encode %{ + __ string_indexof_char($str1$$Register, $cnt1$$Register, $ch$$Register, + $result$$Register, $tmp1$$Register, $tmp2$$Register, + $tmp3$$Register, $tmp4$$Register, true /* isL */); + %} + ins_pipe(pipe_class_memory); +%} + +// clearing of an array +instruct clearArray_reg_reg(iRegL_R29 cnt, iRegP_R28 base, Universe dummy) +%{ + predicate(!UseRVV); + match(Set dummy (ClearArray cnt base)); + effect(USE_KILL cnt, USE_KILL base); + + ins_cost(4 * DEFAULT_COST); + format %{ "ClearArray $cnt, $base\t#@clearArray_reg_reg" %} + + ins_encode %{ + address tpc = __ zero_words($base$$Register, $cnt$$Register); + if (tpc == NULL) { + ciEnv::current()->record_failure("CodeCache is full"); + return; + } + %} + + ins_pipe(pipe_class_memory); +%} + +instruct clearArray_imm_reg(immL cnt, iRegP_R28 base, Universe dummy, rFlagsReg cr) +%{ + predicate(!UseRVV && (uint64_t)n->in(2)->get_long() + < (uint64_t)(BlockZeroingLowLimit >> LogBytesPerWord)); + match(Set dummy (ClearArray cnt base)); + effect(USE_KILL base, KILL cr); + + ins_cost(4 * DEFAULT_COST); + format %{ "ClearArray $cnt, $base\t#@clearArray_imm_reg" %} + + ins_encode %{ + __ zero_words($base$$Register, (uint64_t)$cnt$$constant); + %} + + ins_pipe(pipe_class_memory); +%} + +instruct string_equalsL(iRegP_R11 str1, iRegP_R13 str2, iRegI_R14 cnt, + iRegI_R10 result, rFlagsReg cr) +%{ + predicate(!UseRVV && ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); + + format %{ "String Equals $str1, $str2, $cnt -> $result\t#@string_equalsL" %} + ins_encode %{ + // Count is in 8-bit bytes; non-Compact chars are 16 bits. + __ string_equals($str1$$Register, $str2$$Register, + $result$$Register, $cnt$$Register, 1); + %} + ins_pipe(pipe_class_memory); +%} + +instruct string_equalsU(iRegP_R11 str1, iRegP_R13 str2, iRegI_R14 cnt, + iRegI_R10 result, rFlagsReg cr) +%{ + predicate(!UseRVV && ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, KILL cr); + + format %{ "String Equals $str1, $str2, $cnt -> $result\t#@string_equalsU" %} + ins_encode %{ + // Count is in 8-bit bytes; non-Compact chars are 16 bits. + __ string_equals($str1$$Register, $str2$$Register, + $result$$Register, $cnt$$Register, 2); + %} + ins_pipe(pipe_class_memory); +%} + +instruct array_equalsB(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result, + iRegP_R13 tmp1, iRegP_R14 tmp2, iRegP_R15 tmp3, + iRegP_R16 tmp4, iRegP_R28 tmp5, rFlagsReg cr) +%{ + predicate(!UseRVV && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (AryEq ary1 ary2)); + effect(USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL tmp5, KILL cr); + + format %{ "Array Equals $ary1, ary2 -> $result\t#@array_equalsB // KILL $tmp5" %} + ins_encode %{ + __ arrays_equals($ary1$$Register, $ary2$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, + $result$$Register, $tmp5$$Register, 1); + %} + ins_pipe(pipe_class_memory); +%} + +instruct array_equalsC(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result, + iRegP_R13 tmp1, iRegP_R14 tmp2, iRegP_R15 tmp3, + iRegP_R16 tmp4, iRegP_R28 tmp5, rFlagsReg cr) +%{ + predicate(!UseRVV && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (AryEq ary1 ary2)); + effect(USE_KILL ary1, USE_KILL ary2, TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, KILL tmp5, KILL cr); + + format %{ "Array Equals $ary1, ary2 -> $result\t#@array_equalsC // KILL $tmp5" %} + ins_encode %{ + __ arrays_equals($ary1$$Register, $ary2$$Register, + $tmp1$$Register, $tmp2$$Register, $tmp3$$Register, $tmp4$$Register, + $result$$Register, $tmp5$$Register, 2); + %} + ins_pipe(pipe_class_memory); +%} + +// ============================================================================ +// Safepoint Instructions + +instruct safePoint(iRegP poll) +%{ + match(SafePoint poll); + + ins_cost(2 * LOAD_COST); + format %{ + "lwu zr, [$poll]\t# Safepoint: poll for GC, #@safePoint" + %} + ins_encode %{ + __ read_polling_page(as_Register($poll$$reg), 0, relocInfo::poll_type); + %} + ins_pipe(pipe_serial); // ins_pipe(iload_reg_mem); +%} + +// ============================================================================ +// This name is KNOWN by the ADLC and cannot be changed. +// The ADLC forces a 'TypeRawPtr::BOTTOM' output type +// for this guy. +instruct tlsLoadP(javaThread_RegP dst) +%{ + match(Set dst (ThreadLocal)); + + ins_cost(0); + + format %{ " -- \t// $dst=Thread::current(), empty, #@tlsLoadP" %} + + size(0); + + ins_encode( /*empty*/ ); + + ins_pipe(pipe_class_empty); +%} + +// inlined locking and unlocking +// using t1 as the 'flag' register to bridge the BoolNode producers and consumers +instruct cmpFastLock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2) +%{ + match(Set cr (FastLock object box)); + effect(TEMP tmp1, TEMP tmp2); + + ins_cost(LOAD_COST * 2 + STORE_COST * 3 + ALU_COST * 6 + BRANCH_COST * 3); + format %{ "fastlock $object,$box\t! kills $tmp1,$tmp2, #@cmpFastLock" %} + + ins_encode(riscv_enc_fast_lock(object, box, tmp1, tmp2)); + + ins_pipe(pipe_serial); +%} + +// using t1 as the 'flag' register to bridge the BoolNode producers and consumers +instruct cmpFastUnlock(rFlagsReg cr, iRegP object, iRegP box, iRegPNoSp tmp1, iRegPNoSp tmp2) +%{ + match(Set cr (FastUnlock object box)); + effect(TEMP tmp1, TEMP tmp2); + + ins_cost(LOAD_COST * 2 + STORE_COST + ALU_COST * 2 + BRANCH_COST * 4); + format %{ "fastunlock $object,$box\t! kills $tmp1, $tmp2, #@cmpFastUnlock" %} + + ins_encode(riscv_enc_fast_unlock(object, box, tmp1, tmp2)); + + ins_pipe(pipe_serial); +%} + +// Tail Call; Jump from runtime stub to Java code. +// Also known as an 'interprocedural jump'. +// Target of jump will eventually return to caller. +// TailJump below removes the return address. +instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_oop) +%{ + match(TailCall jump_target method_oop); + + ins_cost(BRANCH_COST); + + format %{ "jalr $jump_target\t# $method_oop holds method oop, #@TailCalljmpInd." %} + + ins_encode(riscv_enc_tail_call(jump_target)); + + ins_pipe(pipe_class_call); +%} + +instruct TailjmpInd(iRegPNoSp jump_target, iRegP_R10 ex_oop) +%{ + match(TailJump jump_target ex_oop); + + ins_cost(ALU_COST + BRANCH_COST); + + format %{ "jalr $jump_target\t# $ex_oop holds exception oop, #@TailjmpInd." %} + + ins_encode(riscv_enc_tail_jmp(jump_target)); + + ins_pipe(pipe_class_call); +%} + +// Create exception oop: created by stack-crawling runtime code. +// Created exception is now available to this handler, and is setup +// just prior to jumping to this handler. No code emitted. +instruct CreateException(iRegP_R10 ex_oop) +%{ + match(Set ex_oop (CreateEx)); + + ins_cost(0); + format %{ " -- \t// exception oop; no code emitted, #@CreateException" %} + + size(0); + + ins_encode( /*empty*/ ); + + ins_pipe(pipe_class_empty); +%} + +// Rethrow exception: The exception oop will come in the first +// argument position. Then JUMP (not call) to the rethrow stub code. +instruct RethrowException() +%{ + match(Rethrow); + + ins_cost(BRANCH_COST); + + format %{ "j rethrow_stub\t#@RethrowException" %} + + ins_encode(riscv_enc_rethrow()); + + ins_pipe(pipe_class_call); +%} + +// Return Instruction +// epilog node loads ret address into ra as part of frame pop +instruct Ret() +%{ + match(Return); + + ins_cost(BRANCH_COST); + format %{ "ret\t// return register, #@Ret" %} + + ins_encode(riscv_enc_ret()); + + ins_pipe(pipe_branch); +%} + +// Die now. +instruct ShouldNotReachHere() %{ + match(Halt); + + ins_cost(BRANCH_COST); + + format %{ "#@ShouldNotReachHere" %} + + ins_encode %{ + Assembler::CompressibleRegion cr(&_masm); + if (is_reachable()) { + __ halt(); + } + %} + + ins_pipe(pipe_class_default); +%} + + +//----------PEEPHOLE RULES----------------------------------------------------- +// These must follow all instruction definitions as they use the names +// defined in the instructions definitions. +// +// peepmatch ( root_instr_name [preceding_instruction]* ); +// +// peepconstraint %{ +// (instruction_number.operand_name relational_op instruction_number.operand_name +// [, ...] ); +// // instruction numbers are zero-based using left to right order in peepmatch +// +// peepreplace ( instr_name ( [instruction_number.operand_name]* ) ); +// // provide an instruction_number.operand_name for each operand that appears +// // in the replacement instruction's match rule +// +// ---------VM FLAGS--------------------------------------------------------- +// +// All peephole optimizations can be turned off using -XX:-OptoPeephole +// +// Each peephole rule is given an identifying number starting with zero and +// increasing by one in the order seen by the parser. An individual peephole +// can be enabled, and all others disabled, by using -XX:OptoPeepholeAt=# +// on the command-line. +// +// ---------CURRENT LIMITATIONS---------------------------------------------- +// +// Only match adjacent instructions in same basic block +// Only equality constraints +// Only constraints between operands, not (0.dest_reg == RAX_enc) +// Only one replacement instruction +// +//----------SMARTSPILL RULES--------------------------------------------------- +// These must follow all instruction definitions as they use the names +// defined in the instructions definitions. + +// Local Variables: +// mode: c++ +// End: diff --git a/src/hotspot/cpu/riscv/riscv_b.ad b/src/hotspot/cpu/riscv/riscv_b.ad new file mode 100644 index 00000000000..4488c1c4031 --- /dev/null +++ b/src/hotspot/cpu/riscv/riscv_b.ad @@ -0,0 +1,527 @@ +// +// Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2022, Huawei Technologies Co., Ltd. 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. +// +// + +// RISCV Bit-Manipulation Extension Architecture Description File + +instruct rorI_imm_rvb(iRegINoSp dst, iRegI src, immI shift) %{ + predicate(UseRVB); + match(Set dst (RotateRight src shift)); + + format %{ "roriw $dst, $src, ($shift & 0x1f)\t#@rorI_imm_rvb" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ roriw(as_Register($dst$$reg), as_Register($src$$reg), $shift$$constant & 0x1f); + %} + + ins_pipe(ialu_reg_shift); +%} + +instruct rorL_imm_rvb(iRegLNoSp dst, iRegL src, immI shift) %{ + predicate(UseRVB); + match(Set dst (RotateRight src shift)); + + format %{ "rori $dst, $src, ($shift & 0x3f)\t#@rorL_imm_rvb" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ rori(as_Register($dst$$reg), as_Register($src$$reg), $shift$$constant & 0x3f); + %} + + ins_pipe(ialu_reg_shift); +%} + +instruct rorI_reg_rvb(iRegINoSp dst, iRegI src, iRegI shift) %{ + predicate(UseRVB); + match(Set dst (RotateRight src shift)); + + format %{ "rorw $dst, $src, $shift\t#@rorI_reg_rvb" %} + ins_cost(ALU_COST); + ins_encode %{ + __ rorw(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct rorL_reg_rvb(iRegLNoSp dst, iRegL src, iRegI shift) %{ + predicate(UseRVB); + match(Set dst (RotateRight src shift)); + + format %{ "ror $dst, $src, $shift\t#@rorL_reg_rvb" %} + ins_cost(ALU_COST); + ins_encode %{ + __ ror(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct rolI_reg_rvb(iRegINoSp dst, iRegI src, iRegI shift) %{ + predicate(UseRVB); + match(Set dst (RotateLeft src shift)); + + format %{ "rolw $dst, $src, $shift\t#@rolI_reg_rvb" %} + ins_cost(ALU_COST); + ins_encode %{ + __ rolw(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct rolL_reg_rvb(iRegLNoSp dst, iRegL src, iRegI shift) %{ + predicate(UseRVB); + match(Set dst (RotateLeft src shift)); + + format %{ "rol $dst, $src, $shift\t#@rolL_reg_rvb" %} + ins_cost(ALU_COST); + ins_encode %{ + __ rol(as_Register($dst$$reg), as_Register($src$$reg), as_Register($shift$$reg)); + %} + ins_pipe(ialu_reg_reg); +%} + +// Convert oop into int for vectors alignment masking +instruct convP2I_rvb(iRegINoSp dst, iRegP src) %{ + predicate(UseRVB); + match(Set dst (ConvL2I (CastP2X src))); + + format %{ "zext.w $dst, $src\t# ptr -> int @convP2I_rvb" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ zext_w(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// byte to int +instruct convB2I_reg_reg_rvb(iRegINoSp dst, iRegIorL2I src, immI_24 lshift, immI_24 rshift) %{ + predicate(UseRVB); + match(Set dst (RShiftI (LShiftI src lshift) rshift)); + + format %{ "sext.b $dst, $src\t# b2i, #@convB2I_reg_reg_rvb" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ sext_b(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// int to short +instruct convI2S_reg_reg_rvb(iRegINoSp dst, iRegIorL2I src, immI_16 lshift, immI_16 rshift) %{ + predicate(UseRVB); + match(Set dst (RShiftI (LShiftI src lshift) rshift)); + + format %{ "sext.h $dst, $src\t# i2s, #@convI2S_reg_reg_rvb" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ sext_h(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// short to unsigned int +instruct convS2UI_reg_reg_rvb(iRegINoSp dst, iRegIorL2I src, immI_16bits mask) %{ + predicate(UseRVB); + match(Set dst (AndI src mask)); + + format %{ "zext.h $dst, $src\t# s2ui, #@convS2UI_reg_reg_rvb" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ zext_h(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// int to unsigned long (zero extend) +instruct convI2UL_reg_reg_rvb(iRegLNoSp dst, iRegIorL2I src, immL_32bits mask) %{ + predicate(UseRVB); + match(Set dst (AndL (ConvI2L src) mask)); + + format %{ "zext.w $dst, $src\t# i2ul, #@convI2UL_reg_reg_rvb" %} + + ins_cost(ALU_COST); + ins_encode %{ + __ zext_w(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg_shift); +%} + +// BSWAP instructions +instruct bytes_reverse_int_rvb(iRegINoSp dst, iRegIorL2I src) %{ + predicate(UseRVB); + match(Set dst (ReverseBytesI src)); + + ins_cost(ALU_COST * 2); + format %{ "revb_w_w $dst, $src\t#@bytes_reverse_int_rvb" %} + + ins_encode %{ + __ revb_w_w(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct bytes_reverse_long_rvb(iRegLNoSp dst, iRegL src) %{ + predicate(UseRVB); + match(Set dst (ReverseBytesL src)); + + ins_cost(ALU_COST); + format %{ "rev8 $dst, $src\t#@bytes_reverse_long_rvb" %} + + ins_encode %{ + __ rev8(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct bytes_reverse_unsigned_short_rvb(iRegINoSp dst, iRegIorL2I src) %{ + predicate(UseRVB); + match(Set dst (ReverseBytesUS src)); + + ins_cost(ALU_COST * 2); + format %{ "revb_h_h_u $dst, $src\t#@bytes_reverse_unsigned_short_rvb" %} + + ins_encode %{ + __ revb_h_h_u(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct bytes_reverse_short_rvb(iRegINoSp dst, iRegIorL2I src) %{ + predicate(UseRVB); + match(Set dst (ReverseBytesS src)); + + ins_cost(ALU_COST * 2); + format %{ "revb_h_h $dst, $src\t#@bytes_reverse_short_rvb" %} + + ins_encode %{ + __ revb_h_h(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// Shift Add Pointer +instruct shaddP_reg_reg_rvb(iRegPNoSp dst, iRegP src1, iRegL src2, immIScale imm) %{ + predicate(UseRVB); + match(Set dst (AddP src1 (LShiftL src2 imm))); + + ins_cost(ALU_COST); + format %{ "shadd $dst, $src2, $src1, $imm\t# ptr, #@shaddP_reg_reg_rvb" %} + + ins_encode %{ + __ shadd(as_Register($dst$$reg), + as_Register($src2$$reg), + as_Register($src1$$reg), + t0, + $imm$$constant); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct shaddP_reg_reg_ext_rvb(iRegPNoSp dst, iRegP src1, iRegI src2, immIScale imm) %{ + predicate(UseRVB); + match(Set dst (AddP src1 (LShiftL (ConvI2L src2) imm))); + + ins_cost(ALU_COST); + format %{ "shadd $dst, $src2, $src1, $imm\t# ptr, #@shaddP_reg_reg_ext_rvb" %} + + ins_encode %{ + __ shadd(as_Register($dst$$reg), + as_Register($src2$$reg), + as_Register($src1$$reg), + t0, + $imm$$constant); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Shift Add Long +instruct shaddL_reg_reg_rvb(iRegLNoSp dst, iRegL src1, iRegL src2, immIScale imm) %{ + predicate(UseRVB); + match(Set dst (AddL src1 (LShiftL src2 imm))); + + ins_cost(ALU_COST); + format %{ "shadd $dst, $src2, $src1, $imm\t#@shaddL_reg_reg_rvb" %} + + ins_encode %{ + __ shadd(as_Register($dst$$reg), + as_Register($src2$$reg), + as_Register($src1$$reg), + t0, + $imm$$constant); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct shaddL_reg_reg_ext_rvb(iRegLNoSp dst, iRegL src1, iRegI src2, immIScale imm) %{ + predicate(UseRVB); + match(Set dst (AddL src1 (LShiftL (ConvI2L src2) imm))); + + ins_cost(ALU_COST); + format %{ "shadd $dst, $src2, $src1, $imm\t#@shaddL_reg_reg_ext_rvb" %} + + ins_encode %{ + __ shadd(as_Register($dst$$reg), + as_Register($src2$$reg), + as_Register($src1$$reg), + t0, + $imm$$constant); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Zeros Count instructions +instruct countLeadingZerosI_rvb(iRegINoSp dst, iRegIorL2I src) %{ + predicate(UseRVB); + match(Set dst (CountLeadingZerosI src)); + + ins_cost(ALU_COST); + format %{ "clzw $dst, $src\t#@countLeadingZerosI_rvb" %} + + ins_encode %{ + __ clzw(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct countLeadingZerosL_rvb(iRegINoSp dst, iRegL src) %{ + predicate(UseRVB); + match(Set dst (CountLeadingZerosL src)); + + ins_cost(ALU_COST); + format %{ "clz $dst, $src\t#@countLeadingZerosL_rvb" %} + + ins_encode %{ + __ clz(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosI_rvb(iRegINoSp dst, iRegIorL2I src) %{ + predicate(UseRVB); + match(Set dst (CountTrailingZerosI src)); + + ins_cost(ALU_COST); + format %{ "ctzw $dst, $src\t#@countTrailingZerosI_rvb" %} + + ins_encode %{ + __ ctzw(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +instruct countTrailingZerosL_rvb(iRegINoSp dst, iRegL src) %{ + predicate(UseRVB); + match(Set dst (CountTrailingZerosL src)); + + ins_cost(ALU_COST); + format %{ "ctz $dst, $src\t#@countTrailingZerosL_rvb" %} + + ins_encode %{ + __ ctz(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// Population Count instructions +instruct popCountI_rvb(iRegINoSp dst, iRegIorL2I src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountI src)); + + ins_cost(ALU_COST); + format %{ "cpopw $dst, $src\t#@popCountI_rvb" %} + + ins_encode %{ + __ cpopw(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// Note: Long/bitCount(long) returns an int. +instruct popCountL_rvb(iRegINoSp dst, iRegL src) %{ + predicate(UsePopCountInstruction); + match(Set dst (PopCountL src)); + + ins_cost(ALU_COST); + format %{ "cpop $dst, $src\t#@popCountL_rvb" %} + + ins_encode %{ + __ cpop(as_Register($dst$$reg), as_Register($src$$reg)); + %} + + ins_pipe(ialu_reg); +%} + +// Max and Min +instruct minI_reg_rvb(iRegINoSp dst, iRegI src1, iRegI src2) %{ + predicate(UseRVB); + match(Set dst (MinI src1 src2)); + + ins_cost(ALU_COST); + format %{ "min $dst, $src1, $src2\t#@minI_reg_rvb" %} + + ins_encode %{ + __ min(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct maxI_reg_rvb(iRegINoSp dst, iRegI src1, iRegI src2) %{ + predicate(UseRVB); + match(Set dst (MaxI src1 src2)); + + ins_cost(ALU_COST); + format %{ "max $dst, $src1, $src2\t#@maxI_reg_rvb" %} + + ins_encode %{ + __ max(as_Register($dst$$reg), as_Register($src1$$reg), as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Abs +instruct absI_reg_rvb(iRegINoSp dst, iRegI src) %{ + predicate(UseRVB); + match(Set dst (AbsI src)); + + ins_cost(ALU_COST * 2); + format %{ + "negw t0, $src\n\t" + "max $dst, $src, t0\t#@absI_reg_rvb" + %} + + ins_encode %{ + __ negw(t0, as_Register($src$$reg)); + __ max(as_Register($dst$$reg), as_Register($src$$reg), t0); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct absL_reg_rvb(iRegLNoSp dst, iRegL src) %{ + predicate(UseRVB); + match(Set dst (AbsL src)); + + ins_cost(ALU_COST * 2); + format %{ + "neg t0, $src\n\t" + "max $dst, $src, t0\t#@absL_reg_rvb" + %} + + ins_encode %{ + __ neg(t0, as_Register($src$$reg)); + __ max(as_Register($dst$$reg), as_Register($src$$reg), t0); + %} + + ins_pipe(ialu_reg); +%} + +// And Not +instruct andnI_reg_reg_rvb(iRegINoSp dst, iRegI src1, iRegI src2, immI_M1 m1) %{ + predicate(UseRVB); + match(Set dst (AndI src1 (XorI src2 m1))); + + ins_cost(ALU_COST); + format %{ "andn $dst, $src1, $src2\t#@andnI_reg_reg_rvb" %} + + ins_encode %{ + __ andn(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct andnL_reg_reg_rvb(iRegLNoSp dst, iRegL src1, iRegL src2, immL_M1 m1) %{ + predicate(UseRVB); + match(Set dst (AndL src1 (XorL src2 m1))); + + ins_cost(ALU_COST); + format %{ "andn $dst, $src1, $src2\t#@andnL_reg_reg_rvb" %} + + ins_encode %{ + __ andn(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +// Or Not +instruct ornI_reg_reg_rvb(iRegINoSp dst, iRegI src1, iRegI src2, immI_M1 m1) %{ + predicate(UseRVB); + match(Set dst (OrI src1 (XorI src2 m1))); + + ins_cost(ALU_COST); + format %{ "orn $dst, $src1, $src2\t#@ornI_reg_reg_rvb" %} + + ins_encode %{ + __ orn(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} + +instruct ornL_reg_reg_rvb(iRegLNoSp dst, iRegL src1, iRegL src2, immL_M1 m1) %{ + predicate(UseRVB); + match(Set dst (OrL src1 (XorL src2 m1))); + + ins_cost(ALU_COST); + format %{ "orn $dst, $src1, $src2\t#@ornL_reg_reg_rvb" %} + + ins_encode %{ + __ orn(as_Register($dst$$reg), + as_Register($src1$$reg), + as_Register($src2$$reg)); + %} + + ins_pipe(ialu_reg_reg); +%} \ No newline at end of file diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad new file mode 100644 index 00000000000..3828e096b21 --- /dev/null +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -0,0 +1,2065 @@ +// +// Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2020, Arm Limited. All rights reserved. +// Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. +// +// + +// RISCV Vector Extension Architecture Description File + +opclass vmemA(indirect); + +source_hpp %{ + bool op_vec_supported(int opcode); +%} + +source %{ + + static void loadStore(C2_MacroAssembler masm, bool is_store, + VectorRegister reg, BasicType bt, Register base) { + Assembler::SEW sew = Assembler::elemtype_to_sew(bt); + masm.vsetvli(t0, x0, sew); + if (is_store) { + masm.vsex_v(reg, base, sew); + } else { + masm.vlex_v(reg, base, sew); + } + } + + bool op_vec_supported(int opcode) { + switch (opcode) { + // No multiply reduction instructions + case Op_MulReductionVD: + case Op_MulReductionVF: + case Op_MulReductionVI: + case Op_MulReductionVL: + // Others + case Op_Extract: + case Op_ExtractB: + case Op_ExtractC: + case Op_ExtractD: + case Op_ExtractF: + case Op_ExtractI: + case Op_ExtractL: + case Op_ExtractS: + case Op_ExtractUB: + // Vector API specific + case Op_AndReductionV: + case Op_OrReductionV: + case Op_XorReductionV: + case Op_LoadVectorGather: + case Op_StoreVectorScatter: + case Op_VectorBlend: + case Op_VectorCast: + case Op_VectorCastB2X: + case Op_VectorCastD2X: + case Op_VectorCastF2X: + case Op_VectorCastI2X: + case Op_VectorCastL2X: + case Op_VectorCastS2X: + case Op_VectorInsert: + case Op_VectorLoadConst: + case Op_VectorLoadMask: + case Op_VectorLoadShuffle: + case Op_VectorMaskCmp: + case Op_VectorRearrange: + case Op_VectorReinterpret: + case Op_VectorStoreMask: + case Op_VectorTest: + return false; + default: + return UseRVV; + } + } + +%} + +definitions %{ + int_def VEC_COST (200, 200); +%} + +// All VEC instructions + +// vector load/store +instruct loadV(vReg dst, vmemA mem) %{ + match(Set dst (LoadVector mem)); + ins_cost(VEC_COST); + format %{ "vle $dst, $mem\t#@loadV" %} + ins_encode %{ + VectorRegister dst_reg = as_VectorRegister($dst$$reg); + loadStore(C2_MacroAssembler(&cbuf), false, dst_reg, + Matcher::vector_element_basic_type(this), as_Register($mem$$base)); + %} + ins_pipe(pipe_slow); +%} + +instruct storeV(vReg src, vmemA mem) %{ + match(Set mem (StoreVector mem src)); + ins_cost(VEC_COST); + format %{ "vse $src, $mem\t#@storeV" %} + ins_encode %{ + VectorRegister src_reg = as_VectorRegister($src$$reg); + loadStore(C2_MacroAssembler(&cbuf), true, src_reg, + Matcher::vector_element_basic_type(this, $src), as_Register($mem$$base)); + %} + ins_pipe(pipe_slow); +%} + +// vector abs + +instruct vabsB(vReg dst, vReg src, vReg tmp) %{ + match(Set dst (AbsVB src)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vrsub.vi $tmp, 0, $src\t#@vabsB\n\t" + "vmax.vv $dst, $tmp, $src" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vrsub_vi(as_VectorRegister($tmp$$reg), 0, as_VectorRegister($src$$reg)); + __ vmax_vv(as_VectorRegister($dst$$reg), as_VectorRegister($tmp$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vabsS(vReg dst, vReg src, vReg tmp) %{ + match(Set dst (AbsVS src)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vrsub.vi $tmp, 0, $src\t#@vabsS\n\t" + "vmax.vv $dst, $tmp, $src" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vrsub_vi(as_VectorRegister($tmp$$reg), 0, as_VectorRegister($src$$reg)); + __ vmax_vv(as_VectorRegister($dst$$reg), as_VectorRegister($tmp$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vabsI(vReg dst, vReg src, vReg tmp) %{ + match(Set dst (AbsVI src)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vrsub.vi $tmp, 0, $src\t#@vabsI\n\t" + "vmax.vv $dst, $tmp, $src" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vrsub_vi(as_VectorRegister($tmp$$reg), 0, as_VectorRegister($src$$reg)); + __ vmax_vv(as_VectorRegister($dst$$reg), as_VectorRegister($tmp$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vabsL(vReg dst, vReg src, vReg tmp) %{ + match(Set dst (AbsVL src)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vrsub.vi $tmp, 0, $src\t#@vabsL\n\t" + "vmax.vv $dst, $tmp, $src" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vrsub_vi(as_VectorRegister($tmp$$reg), 0, as_VectorRegister($src$$reg)); + __ vmax_vv(as_VectorRegister($dst$$reg), as_VectorRegister($tmp$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vabsF(vReg dst, vReg src) %{ + match(Set dst (AbsVF src)); + ins_cost(VEC_COST); + format %{ "vfsgnjx.vv $dst, $src, $src, vm\t#@vabsF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfsgnjx_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vabsD(vReg dst, vReg src) %{ + match(Set dst (AbsVD src)); + ins_cost(VEC_COST); + format %{ "vfsgnjx.vv $dst, $src, $src, vm\t#@vabsD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfsgnjx_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector add + +instruct vaddB(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AddVB src1 src2)); + ins_cost(VEC_COST); + format %{ "vadd.vv $dst, $src1, $src2\t#@vaddB" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vadd_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vaddS(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AddVS src1 src2)); + ins_cost(VEC_COST); + format %{ "vadd.vv $dst, $src1, $src2\t#@vaddS" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vadd_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vaddI(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AddVI src1 src2)); + ins_cost(VEC_COST); + format %{ "vadd.vv $dst, $src1, $src2\t#@vaddI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vadd_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vaddL(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AddVL src1 src2)); + ins_cost(VEC_COST); + format %{ "vadd.vv $dst, $src1, $src2\t#@vaddL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vadd_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vaddF(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AddVF src1 src2)); + ins_cost(VEC_COST); + format %{ "vfadd.vv $dst, $src1, $src2\t#@vaddF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfadd_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vaddD(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AddVD src1 src2)); + ins_cost(VEC_COST); + format %{ "vfadd.vv $dst, $src1, $src2\t#@vaddD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfadd_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector and + +instruct vand(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (AndV src1 src2)); + ins_cost(VEC_COST); + format %{ "vand.vv $dst, $src1, $src2\t#@vand" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vand_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector or + +instruct vor(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (OrV src1 src2)); + ins_cost(VEC_COST); + format %{ "vor.vv $dst, $src1, $src2\t#@vor" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vor_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector xor + +instruct vxor(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (XorV src1 src2)); + ins_cost(VEC_COST); + format %{ "vxor.vv $dst, $src1, $src2\t#@vxor" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vxor_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector float div + +instruct vdivF(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (DivVF src1 src2)); + ins_cost(VEC_COST); + format %{ "vfdiv.vv $dst, $src1, $src2\t#@vdivF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfdiv_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vdivD(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (DivVD src1 src2)); + ins_cost(VEC_COST); + format %{ "vfdiv.vv $dst, $src1, $src2\t#@vdivD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfdiv_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector integer max/min + +instruct vmax(vReg dst, vReg src1, vReg src2) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() != T_FLOAT && + n->bottom_type()->is_vect()->element_basic_type() != T_DOUBLE); + match(Set dst (MaxV src1 src2)); + ins_cost(VEC_COST); + format %{ "vmax.vv $dst, $src1, $src2\t#@vmax" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + Assembler::SEW sew = Assembler::elemtype_to_sew(bt); + __ vsetvli(t0, x0, sew); + __ vmax_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmin(vReg dst, vReg src1, vReg src2) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() != T_FLOAT && + n->bottom_type()->is_vect()->element_basic_type() != T_DOUBLE); + match(Set dst (MinV src1 src2)); + ins_cost(VEC_COST); + format %{ "vmin.vv $dst, $src1, $src2\t#@vmin" %} + ins_encode %{ + BasicType bt = Matcher::vector_element_basic_type(this); + Assembler::SEW sew = Assembler::elemtype_to_sew(bt); + __ vsetvli(t0, x0, sew); + __ vmin_vv(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector float-point max/min + +instruct vmaxF(vReg dst, vReg src1, vReg src2) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_FLOAT); + match(Set dst (MaxV src1 src2)); + effect(TEMP_DEF dst); + ins_cost(VEC_COST); + format %{ "vmaxF $dst, $src1, $src2\t#@vmaxF" %} + ins_encode %{ + __ minmax_FD_v(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg), + false /* is_double */, false /* is_min */); + %} + ins_pipe(pipe_slow); +%} + +instruct vmaxD(vReg dst, vReg src1, vReg src2) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_DOUBLE); + match(Set dst (MaxV src1 src2)); + effect(TEMP_DEF dst); + ins_cost(VEC_COST); + format %{ "vmaxD $dst, $src1, $src2\t#@vmaxD" %} + ins_encode %{ + __ minmax_FD_v(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg), + true /* is_double */, false /* is_min */); + %} + ins_pipe(pipe_slow); +%} + +instruct vminF(vReg dst, vReg src1, vReg src2) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_FLOAT); + match(Set dst (MinV src1 src2)); + effect(TEMP_DEF dst); + ins_cost(VEC_COST); + format %{ "vminF $dst, $src1, $src2\t#@vminF" %} + ins_encode %{ + __ minmax_FD_v(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg), + false /* is_double */, true /* is_min */); + %} + ins_pipe(pipe_slow); +%} + +instruct vminD(vReg dst, vReg src1, vReg src2) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_DOUBLE); + match(Set dst (MinV src1 src2)); + effect(TEMP_DEF dst); + ins_cost(VEC_COST); + format %{ "vminD $dst, $src1, $src2\t#@vminD" %} + ins_encode %{ + __ minmax_FD_v(as_VectorRegister($dst$$reg), + as_VectorRegister($src1$$reg), as_VectorRegister($src2$$reg), + true /* is_double */, true /* is_min */); + %} + ins_pipe(pipe_slow); +%} + +// vector fmla + +// dst_src1 = dst_src1 + src2 * src3 +instruct vfmlaF(vReg dst_src1, vReg src2, vReg src3) %{ + predicate(UseFMA); + match(Set dst_src1 (FmaVF dst_src1 (Binary src2 src3))); + ins_cost(VEC_COST); + format %{ "vfmacc.vv $dst_src1, $src2, $src3\t#@vfmlaF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = dst_src1 + src2 * src3 +instruct vfmlaD(vReg dst_src1, vReg src2, vReg src3) %{ + predicate(UseFMA); + match(Set dst_src1 (FmaVD dst_src1 (Binary src2 src3))); + ins_cost(VEC_COST); + format %{ "vfmacc.vv $dst_src1, $src2, $src3\t#@vfmlaD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector fmls + +// dst_src1 = dst_src1 + -src2 * src3 +// dst_src1 = dst_src1 + src2 * -src3 +instruct vfmlsF(vReg dst_src1, vReg src2, vReg src3) %{ + predicate(UseFMA); + match(Set dst_src1 (FmaVF dst_src1 (Binary (NegVF src2) src3))); + match(Set dst_src1 (FmaVF dst_src1 (Binary src2 (NegVF src3)))); + ins_cost(VEC_COST); + format %{ "vfnmsac.vv $dst_src1, $src2, $src3\t#@vfmlsF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfnmsac_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = dst_src1 + -src2 * src3 +// dst_src1 = dst_src1 + src2 * -src3 +instruct vfmlsD(vReg dst_src1, vReg src2, vReg src3) %{ + predicate(UseFMA); + match(Set dst_src1 (FmaVD dst_src1 (Binary (NegVD src2) src3))); + match(Set dst_src1 (FmaVD dst_src1 (Binary src2 (NegVD src3)))); + ins_cost(VEC_COST); + format %{ "vfnmsac.vv $dst_src1, $src2, $src3\t#@vfmlsD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfnmsac_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector fnmla + +// dst_src1 = -dst_src1 + -src2 * src3 +// dst_src1 = -dst_src1 + src2 * -src3 +instruct vfnmlaF(vReg dst_src1, vReg src2, vReg src3) %{ + predicate(UseFMA); + match(Set dst_src1 (FmaVF (NegVF dst_src1) (Binary (NegVF src2) src3))); + match(Set dst_src1 (FmaVF (NegVF dst_src1) (Binary src2 (NegVF src3)))); + ins_cost(VEC_COST); + format %{ "vfnmacc.vv $dst_src1, $src2, $src3\t#@vfnmlaF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfnmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = -dst_src1 + -src2 * src3 +// dst_src1 = -dst_src1 + src2 * -src3 +instruct vfnmlaD(vReg dst_src1, vReg src2, vReg src3) %{ + predicate(UseFMA); + match(Set dst_src1 (FmaVD (NegVD dst_src1) (Binary (NegVD src2) src3))); + match(Set dst_src1 (FmaVD (NegVD dst_src1) (Binary src2 (NegVD src3)))); + ins_cost(VEC_COST); + format %{ "vfnmacc.vv $dst_src1, $src2, $src3\t#@vfnmlaD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfnmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector fnmls + +// dst_src1 = -dst_src1 + src2 * src3 +instruct vfnmlsF(vReg dst_src1, vReg src2, vReg src3) %{ + predicate(UseFMA); + match(Set dst_src1 (FmaVF (NegVF dst_src1) (Binary src2 src3))); + ins_cost(VEC_COST); + format %{ "vfmsac.vv $dst_src1, $src2, $src3\t#@vfnmlsF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfmsac_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = -dst_src1 + src2 * src3 +instruct vfnmlsD(vReg dst_src1, vReg src2, vReg src3) %{ + predicate(UseFMA); + match(Set dst_src1 (FmaVD (NegVD dst_src1) (Binary src2 src3))); + ins_cost(VEC_COST); + format %{ "vfmsac.vv $dst_src1, $src2, $src3\t#@vfnmlsD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfmsac_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector mla + +// dst_src1 = dst_src1 + src2 * src3 +instruct vmlaB(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (AddVB dst_src1 (MulVB src2 src3))); + ins_cost(VEC_COST); + format %{ "vmacc.vv $dst_src1, src2, src3\t#@vmlaB" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = dst_src1 + src2 * src3 +instruct vmlaS(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (AddVS dst_src1 (MulVS src2 src3))); + ins_cost(VEC_COST); + format %{ "vmacc.vv $dst_src1, src2, src3\t#@vmlaS" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = dst_src1 + src2 * src3 +instruct vmlaI(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (AddVI dst_src1 (MulVI src2 src3))); + ins_cost(VEC_COST); + format %{ "vmacc.vv $dst_src1, src2, src3\t#@vmlaI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = dst_src1 + src2 * src3 +instruct vmlaL(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (AddVL dst_src1 (MulVL src2 src3))); + ins_cost(VEC_COST); + format %{ "vmacc.vv $dst_src1, src2, src3\t#@vmlaL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vmacc_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector mls + +// dst_src1 = dst_src1 - src2 * src3 +instruct vmlsB(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (SubVB dst_src1 (MulVB src2 src3))); + ins_cost(VEC_COST); + format %{ "vnmsac.vv $dst_src1, src2, src3\t#@vmlsB" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vnmsac_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = dst_src1 - src2 * src3 +instruct vmlsS(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (SubVS dst_src1 (MulVS src2 src3))); + ins_cost(VEC_COST); + format %{ "vnmsac.vv $dst_src1, src2, src3\t#@vmlsS" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vnmsac_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = dst_src1 - src2 * src3 +instruct vmlsI(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (SubVI dst_src1 (MulVI src2 src3))); + ins_cost(VEC_COST); + format %{ "vnmsac.vv $dst_src1, src2, src3\t#@vmlsI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vnmsac_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// dst_src1 = dst_src1 - src2 * src3 +instruct vmlsL(vReg dst_src1, vReg src2, vReg src3) %{ + match(Set dst_src1 (SubVL dst_src1 (MulVL src2 src3))); + ins_cost(VEC_COST); + format %{ "vnmsac.vv $dst_src1, src2, src3\t#@vmlsL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vnmsac_vv(as_VectorRegister($dst_src1$$reg), + as_VectorRegister($src2$$reg), as_VectorRegister($src3$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector mul + +instruct vmulB(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (MulVB src1 src2)); + ins_cost(VEC_COST); + format %{ "vmul.vv $dst, $src1, $src2\t#@vmulB" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vmul_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmulS(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (MulVS src1 src2)); + ins_cost(VEC_COST); + format %{ "vmul.vv $dst, $src1, $src2\t#@vmulS" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vmul_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmulI(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (MulVI src1 src2)); + ins_cost(VEC_COST); + format %{ "vmul.vv $dst, $src1, $src2\t#@vmulI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vmul_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmulL(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (MulVL src1 src2)); + ins_cost(VEC_COST); + format %{ "vmul.vv $dst, $src1, $src2\t#@vmulL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vmul_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmulF(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (MulVF src1 src2)); + ins_cost(VEC_COST); + format %{ "vfmul.vv $dst, $src1, $src2\t#@vmulF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfmul_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vmulD(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (MulVD src1 src2)); + ins_cost(VEC_COST); + format %{ "vfmul.vv $dst, $src1, $src2\t#@vmulD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfmul_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector fneg + +instruct vnegF(vReg dst, vReg src) %{ + match(Set dst (NegVF src)); + ins_cost(VEC_COST); + format %{ "vfsgnjn.vv $dst, $src, $src\t#@vnegF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfneg_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vnegD(vReg dst, vReg src) %{ + match(Set dst (NegVD src)); + ins_cost(VEC_COST); + format %{ "vfsgnjn.vv $dst, $src, $src\t#@vnegD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfneg_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// popcount vector + +instruct vpopcountI(iRegINoSp dst, vReg src) %{ + match(Set dst (PopCountVI src)); + format %{ "vpopc.m $dst, $src\t#@vpopcountI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vpopc_m(as_Register($dst$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector add reduction + +instruct reduce_addB(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_BYTE); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp); + ins_cost(VEC_COST); + format %{ "vmv.s.x $tmp, $src1\t#@reduce_addB\n\t" + "vredsum.vs $tmp, $src2, $tmp\n\t" + "vmv.x.s $dst, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vmv_s_x(as_VectorRegister($tmp$$reg), $src1$$Register); + __ vredsum_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), + as_VectorRegister($tmp$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct reduce_addS(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_SHORT); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp); + ins_cost(VEC_COST); + format %{ "vmv.s.x $tmp, $src1\t#@reduce_addS\n\t" + "vredsum.vs $tmp, $src2, $tmp\n\t" + "vmv.x.s $dst, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vmv_s_x(as_VectorRegister($tmp$$reg), $src1$$Register); + __ vredsum_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), + as_VectorRegister($tmp$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct reduce_addI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_INT); + match(Set dst (AddReductionVI src1 src2)); + effect(TEMP tmp); + ins_cost(VEC_COST); + format %{ "vmv.s.x $tmp, $src1\t#@reduce_addI\n\t" + "vredsum.vs $tmp, $src2, $tmp\n\t" + "vmv.x.s $dst, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vmv_s_x(as_VectorRegister($tmp$$reg), $src1$$Register); + __ vredsum_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), + as_VectorRegister($tmp$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct reduce_addL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_LONG); + match(Set dst (AddReductionVL src1 src2)); + effect(TEMP tmp); + ins_cost(VEC_COST); + format %{ "vmv.s.x $tmp, $src1\t#@reduce_addL\n\t" + "vredsum.vs $tmp, $src2, $tmp\n\t" + "vmv.x.s $dst, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vmv_s_x(as_VectorRegister($tmp$$reg), $src1$$Register); + __ vredsum_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), + as_VectorRegister($tmp$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct reduce_addF(fRegF src1_dst, vReg src2, vReg tmp) %{ + match(Set src1_dst (AddReductionVF src1_dst src2)); + effect(TEMP tmp); + ins_cost(VEC_COST); + format %{ "vfmv.s.f $tmp, $src1_dst\t#@reduce_addF\n\t" + "vfredosum.vs $tmp, $src2, $tmp\n\t" + "vfmv.f.s $src1_dst, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfmv_s_f(as_VectorRegister($tmp$$reg), $src1_dst$$FloatRegister); + __ vfredosum_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), + as_VectorRegister($tmp$$reg)); + __ vfmv_f_s($src1_dst$$FloatRegister, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct reduce_addD(fRegD src1_dst, vReg src2, vReg tmp) %{ + match(Set src1_dst (AddReductionVD src1_dst src2)); + effect(TEMP tmp); + ins_cost(VEC_COST); + format %{ "vfmv.s.f $tmp, $src1_dst\t#@reduce_addD\n\t" + "vfredosum.vs $tmp, $src2, $tmp\n\t" + "vfmv.f.s $src1_dst, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfmv_s_f(as_VectorRegister($tmp$$reg), $src1_dst$$FloatRegister); + __ vfredosum_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), + as_VectorRegister($tmp$$reg)); + __ vfmv_f_s($src1_dst$$FloatRegister, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector integer max reduction +instruct vreduce_maxB(iRegINoSp dst, iRegI src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_BYTE); + match(Set dst (MaxReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vreduce_maxB $dst, $src1, $src2, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vredmax_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), as_VectorRegister($src2$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + Label Ldone; + __ ble(as_Register($src1$$reg), as_Register($dst$$reg), Ldone); + __ mv(as_Register($dst$$reg), as_Register($src1$$reg)); + __ bind(Ldone); + %} + ins_pipe(pipe_slow); +%} + +instruct vreduce_maxS(iRegINoSp dst, iRegI src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_SHORT); + match(Set dst (MaxReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vreduce_maxS $dst, $src1, $src2, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vredmax_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), as_VectorRegister($src2$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + Label Ldone; + __ ble(as_Register($src1$$reg), as_Register($dst$$reg), Ldone); + __ mv(as_Register($dst$$reg), as_Register($src1$$reg)); + __ bind(Ldone); + %} + ins_pipe(pipe_slow); +%} + +instruct vreduce_maxI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_INT); + match(Set dst (MaxReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vreduce_maxI $dst, $src1, $src2, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vmv_s_x(as_VectorRegister($tmp$$reg), $src1$$Register); + __ vredmax_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), as_VectorRegister($tmp$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vreduce_maxL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_LONG); + match(Set dst (MaxReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vreduce_maxL $dst, $src1, $src2, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vmv_s_x(as_VectorRegister($tmp$$reg), $src1$$Register); + __ vredmax_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), as_VectorRegister($tmp$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector integer min reduction +instruct vreduce_minB(iRegINoSp dst, iRegI src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_BYTE); + match(Set dst (MinReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vreduce_minB $dst, $src1, $src2, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vredmin_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), as_VectorRegister($src2$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + Label Ldone; + __ bge(as_Register($src1$$reg), as_Register($dst$$reg), Ldone); + __ mv(as_Register($dst$$reg), as_Register($src1$$reg)); + __ bind(Ldone); + %} + ins_pipe(pipe_slow); +%} + +instruct vreduce_minS(iRegINoSp dst, iRegI src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_SHORT); + match(Set dst (MinReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vreduce_minS $dst, $src1, $src2, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vredmin_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), as_VectorRegister($src2$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + Label Ldone; + __ bge(as_Register($src1$$reg), as_Register($dst$$reg), Ldone); + __ mv(as_Register($dst$$reg), as_Register($src1$$reg)); + __ bind(Ldone); + %} + ins_pipe(pipe_slow); +%} + +instruct vreduce_minI(iRegINoSp dst, iRegIorL2I src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_INT); + match(Set dst (MinReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vreduce_minI $dst, $src1, $src2, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vmv_s_x(as_VectorRegister($tmp$$reg), $src1$$Register); + __ vredmin_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), as_VectorRegister($tmp$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vreduce_minL(iRegLNoSp dst, iRegL src1, vReg src2, vReg tmp) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_LONG); + match(Set dst (MinReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP tmp); + format %{ "vreduce_minL $dst, $src1, $src2, $tmp" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vmv_s_x(as_VectorRegister($tmp$$reg), $src1$$Register); + __ vredmin_vs(as_VectorRegister($tmp$$reg), as_VectorRegister($src2$$reg), as_VectorRegister($tmp$$reg)); + __ vmv_x_s($dst$$Register, as_VectorRegister($tmp$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector float max reduction + +instruct vreduce_maxF(fRegF dst, fRegF src1, vReg src2, vReg tmp1, vReg tmp2) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_FLOAT); + match(Set dst (MaxReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); + format %{ "reduce_maxF $dst, $src1, $src2, $tmp1, $tmp2" %} + ins_encode %{ + __ reduce_minmax_FD_v($dst$$FloatRegister, + $src1$$FloatRegister, as_VectorRegister($src2$$reg), + as_VectorRegister($tmp1$$reg), as_VectorRegister($tmp2$$reg), + false /* is_double */, false /* is_min */); + %} + ins_pipe(pipe_slow); +%} + +instruct vreduce_maxD(fRegD dst, fRegD src1, vReg src2, vReg tmp1, vReg tmp2) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_DOUBLE); + match(Set dst (MaxReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); + format %{ "reduce_maxD $dst, $src1, $src2, $tmp1, $tmp2" %} + ins_encode %{ + __ reduce_minmax_FD_v($dst$$FloatRegister, + $src1$$FloatRegister, as_VectorRegister($src2$$reg), + as_VectorRegister($tmp1$$reg), as_VectorRegister($tmp2$$reg), + true /* is_double */, false /* is_min */); + %} + ins_pipe(pipe_slow); +%} + +// vector float min reduction + +instruct vreduce_minF(fRegF dst, fRegF src1, vReg src2, vReg tmp1, vReg tmp2) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_FLOAT); + match(Set dst (MinReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); + format %{ "reduce_minF $dst, $src1, $src2, $tmp1, $tmp2" %} + ins_encode %{ + __ reduce_minmax_FD_v($dst$$FloatRegister, + $src1$$FloatRegister, as_VectorRegister($src2$$reg), + as_VectorRegister($tmp1$$reg), as_VectorRegister($tmp2$$reg), + false /* is_double */, true /* is_min */); + %} + ins_pipe(pipe_slow); +%} + +instruct vreduce_minD(fRegD dst, fRegD src1, vReg src2, vReg tmp1, vReg tmp2) %{ + predicate(n->in(2)->bottom_type()->is_vect()->element_basic_type() == T_DOUBLE); + match(Set dst (MinReductionV src1 src2)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst, TEMP tmp1, TEMP tmp2); + format %{ "reduce_minD $dst, $src1, $src2, $tmp1, $tmp2" %} + ins_encode %{ + __ reduce_minmax_FD_v($dst$$FloatRegister, + $src1$$FloatRegister, as_VectorRegister($src2$$reg), + as_VectorRegister($tmp1$$reg), as_VectorRegister($tmp2$$reg), + true /* is_double */, true /* is_min */); + %} + ins_pipe(pipe_slow); +%} + +// vector Math.rint, floor, ceil + +instruct vroundD(vReg dst, vReg src, immI rmode) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_DOUBLE); + match(Set dst (RoundDoubleModeV src rmode)); + format %{ "vroundD $dst, $src, $rmode" %} + ins_encode %{ + switch ($rmode$$constant) { + case RoundDoubleModeNode::rmode_rint: + __ csrwi(CSR_FRM, C2_MacroAssembler::rne); + __ vfcvt_rtz_x_f_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + break; + case RoundDoubleModeNode::rmode_floor: + __ csrwi(CSR_FRM, C2_MacroAssembler::rdn); + __ vfcvt_rtz_x_f_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + break; + case RoundDoubleModeNode::rmode_ceil: + __ csrwi(CSR_FRM, C2_MacroAssembler::rup); + __ vfcvt_rtz_x_f_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + break; + default: + ShouldNotReachHere(); + break; + } + %} + ins_pipe(pipe_slow); +%} + +// vector replicate + +instruct replicateB(vReg dst, iRegIorL2I src) %{ + match(Set dst (ReplicateB src)); + ins_cost(VEC_COST); + format %{ "vmv.v.x $dst, $src\t#@replicateB" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vmv_v_x(as_VectorRegister($dst$$reg), as_Register($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateS(vReg dst, iRegIorL2I src) %{ + match(Set dst (ReplicateS src)); + ins_cost(VEC_COST); + format %{ "vmv.v.x $dst, $src\t#@replicateS" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vmv_v_x(as_VectorRegister($dst$$reg), as_Register($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateI(vReg dst, iRegIorL2I src) %{ + match(Set dst (ReplicateI src)); + ins_cost(VEC_COST); + format %{ "vmv.v.x $dst, $src\t#@replicateI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vmv_v_x(as_VectorRegister($dst$$reg), as_Register($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateL(vReg dst, iRegL src) %{ + match(Set dst (ReplicateL src)); + ins_cost(VEC_COST); + format %{ "vmv.v.x $dst, $src\t#@replicateL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vmv_v_x(as_VectorRegister($dst$$reg), as_Register($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateB_imm5(vReg dst, immI5 con) %{ + match(Set dst (ReplicateB con)); + ins_cost(VEC_COST); + format %{ "vmv.v.i $dst, $con\t#@replicateB_imm5" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vmv_v_i(as_VectorRegister($dst$$reg), $con$$constant); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateS_imm5(vReg dst, immI5 con) %{ + match(Set dst (ReplicateS con)); + ins_cost(VEC_COST); + format %{ "vmv.v.i $dst, $con\t#@replicateS_imm5" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vmv_v_i(as_VectorRegister($dst$$reg), $con$$constant); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateI_imm5(vReg dst, immI5 con) %{ + match(Set dst (ReplicateI con)); + ins_cost(VEC_COST); + format %{ "vmv.v.i $dst, $con\t#@replicateI_imm5" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vmv_v_i(as_VectorRegister($dst$$reg), $con$$constant); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateL_imm5(vReg dst, immL5 con) %{ + match(Set dst (ReplicateL con)); + ins_cost(VEC_COST); + format %{ "vmv.v.i $dst, $con\t#@replicateL_imm5" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vmv_v_i(as_VectorRegister($dst$$reg), $con$$constant); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateF(vReg dst, fRegF src) %{ + match(Set dst (ReplicateF src)); + ins_cost(VEC_COST); + format %{ "vfmv.v.f $dst, $src\t#@replicateF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfmv_v_f(as_VectorRegister($dst$$reg), $src$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + +instruct replicateD(vReg dst, fRegD src) %{ + match(Set dst (ReplicateD src)); + ins_cost(VEC_COST); + format %{ "vfmv.v.f $dst, $src\t#@replicateD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfmv_v_f(as_VectorRegister($dst$$reg), $src$$FloatRegister); + %} + ins_pipe(pipe_slow); +%} + +// vector shift + +instruct vasrB(vReg dst, vReg src, vReg shift) %{ + match(Set dst (RShiftVB src shift)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst); + format %{ "vmsgtu.vi v0, $shift 7\t#@vasrB\n\t" + "vsra.vi $dst, $src, 7, Assembler::v0_t\n\t" + "vmnot.m v0, v0\n\t" + "vsra.vv $dst, $src, $shift, Assembler::v0_t" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + // if shift > BitsPerByte - 1, clear the low BitsPerByte - 1 bits + __ vmsgtu_vi(v0, as_VectorRegister($shift$$reg), BitsPerByte - 1); + __ vsra_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + BitsPerByte - 1, Assembler::v0_t); + // otherwise, shift + __ vmnot_m(v0, v0); + __ vsra_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vasrS(vReg dst, vReg src, vReg shift) %{ + match(Set dst (RShiftVS src shift)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst); + format %{ "vmsgtu.vi v0, $shift, 15\t#@vasrS\n\t" + "vsra.vi $dst, $src, 15, Assembler::v0_t\n\t" + "vmnot.m v0, v0\n\t" + "vsra.vv $dst, $src, $shift, Assembler::v0_t" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + // if shift > BitsPerShort - 1, clear the low BitsPerShort - 1 bits + __ vmsgtu_vi(v0, as_VectorRegister($shift$$reg), BitsPerShort - 1); + __ vsra_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + BitsPerShort - 1, Assembler::v0_t); + // otherwise, shift + __ vmnot_m(v0, v0); + __ vsra_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vasrI(vReg dst, vReg src, vReg shift) %{ + match(Set dst (RShiftVI src shift)); + ins_cost(VEC_COST); + format %{ "vsra.vv $dst, $src, $shift\t#@vasrI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vsra_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vasrL(vReg dst, vReg src, vReg shift) %{ + match(Set dst (RShiftVL src shift)); + ins_cost(VEC_COST); + format %{ "vsra.vv $dst, $src, $shift\t#@vasrL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vsra_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vlslB(vReg dst, vReg src, vReg shift) %{ + match(Set dst (LShiftVB src shift)); + ins_cost(VEC_COST); + effect( TEMP_DEF dst); + format %{ "vmsgtu.vi v0, $shift, 7\t#@vlslB\n\t" + "vxor.vv $dst, $src, $src, Assembler::v0_t\n\t" + "vmnot.m v0, v0\n\t" + "vsll.vv $dst, $src, $shift, Assembler::v0_t" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + // if shift > BitsPerByte - 1, clear the element + __ vmsgtu_vi(v0, as_VectorRegister($shift$$reg), BitsPerByte - 1); + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg), Assembler::v0_t); + // otherwise, shift + __ vmnot_m(v0, v0); + __ vsll_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vlslS(vReg dst, vReg src, vReg shift) %{ + match(Set dst (LShiftVS src shift)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst); + format %{ "vmsgtu.vi v0, $shift, 15\t#@vlslS\n\t" + "vxor.vv $dst, $src, $src, Assembler::v0_t\n\t" + "vmnot.m v0, v0\n\t" + "vsll.vv $dst, $src, $shift, Assembler::v0_t" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + // if shift > BitsPerShort - 1, clear the element + __ vmsgtu_vi(v0, as_VectorRegister($shift$$reg), BitsPerShort - 1); + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg), Assembler::v0_t); + // otherwise, shift + __ vmnot_m(v0, v0); + __ vsll_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vlslI(vReg dst, vReg src, vReg shift) %{ + match(Set dst (LShiftVI src shift)); + ins_cost(VEC_COST); + format %{ "vsll.vv $dst, $src, $shift\t#@vlslI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vsll_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vlslL(vReg dst, vReg src, vReg shift) %{ + match(Set dst (LShiftVL src shift)); + ins_cost(VEC_COST); + format %{ "vsll.vv $dst, $src, $shift\t# vector (D)" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vsll_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vlsrB(vReg dst, vReg src, vReg shift) %{ + match(Set dst (URShiftVB src shift)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst); + format %{ "vmsgtu.vi v0, $shift, 7\t#@vlsrB\n\t" + "vxor.vv $dst, $src, $src, Assembler::v0_t\n\t" + "vmnot.m v0, v0, v0\n\t" + "vsll.vv $dst, $src, $shift, Assembler::v0_t" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + // if shift > BitsPerByte - 1, clear the element + __ vmsgtu_vi(v0, as_VectorRegister($shift$$reg), BitsPerByte - 1); + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg), Assembler::v0_t); + // otherwise, shift + __ vmnot_m(v0, v0); + __ vsrl_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + +instruct vlsrS(vReg dst, vReg src, vReg shift) %{ + match(Set dst (URShiftVS src shift)); + ins_cost(VEC_COST); + effect(TEMP_DEF dst); + format %{ "vmsgtu.vi v0, $shift, 15\t#@vlsrS\n\t" + "vxor.vv $dst, $src, $src, Assembler::v0_t\n\t" + "vmnot.m v0, v0\n\t" + "vsll.vv $dst, $src, $shift, Assembler::v0_t" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + // if shift > BitsPerShort - 1, clear the element + __ vmsgtu_vi(v0, as_VectorRegister($shift$$reg), BitsPerShort - 1); + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg), Assembler::v0_t); + // otherwise, shift + __ vmnot_m(v0, v0); + __ vsrl_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg), Assembler::v0_t); + %} + ins_pipe(pipe_slow); +%} + + +instruct vlsrI(vReg dst, vReg src, vReg shift) %{ + match(Set dst (URShiftVI src shift)); + ins_cost(VEC_COST); + format %{ "vsrl.vv $dst, $src, $shift\t#@vlsrI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vsrl_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + + +instruct vlsrL(vReg dst, vReg src, vReg shift) %{ + match(Set dst (URShiftVL src shift)); + ins_cost(VEC_COST); + format %{ "vsrl.vv $dst, $src, $shift\t#@vlsrL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vsrl_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($shift$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vasrB_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (RShiftVB src (RShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsra.vi $dst, $src, $shift\t#@vasrB_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e8); + if (con == 0) { + __ vor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + if (con >= BitsPerByte) con = BitsPerByte - 1; + __ vsra_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vasrS_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (RShiftVS src (RShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsra.vi $dst, $src, $shift\t#@vasrS_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e16); + if (con == 0) { + __ vor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + if (con >= BitsPerShort) con = BitsPerShort - 1; + __ vsra_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vasrI_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (RShiftVI src (RShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsrl.vi $dst, $src, $shift\t#@vasrI_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e32); + if (con == 0) { + __ vor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + __ vsra_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vasrL_imm(vReg dst, vReg src, immI shift) %{ + predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); + match(Set dst (RShiftVL src (RShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsrl.vi $dst, $src, $shift\t#@vasrL_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e64); + if (con == 0) { + __ vor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + __ vsra_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vlsrB_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (URShiftVB src (RShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsrl.vi $dst, $src, $shift\t#@vlsrB_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e8); + if (con == 0) { + __ vor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + if (con >= BitsPerByte) { + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + __ vsrl_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vlsrS_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (URShiftVS src (RShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsrl.vi $dst, $src, $shift\t#@vlsrS_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e16); + if (con == 0) { + __ vor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + if (con >= BitsPerShort) { + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + __ vsrl_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vlsrI_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (URShiftVI src (RShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsrl.vi $dst, $src, $shift\t#@vlsrI_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e32); + if (con == 0) { + __ vor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + __ vsrl_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vlsrL_imm(vReg dst, vReg src, immI shift) %{ + predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); + match(Set dst (URShiftVL src (RShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsrl.vi $dst, $src, $shift\t#@vlsrL_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e64); + if (con == 0) { + __ vor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + __ vsrl_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vlslB_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (LShiftVB src (LShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsll.vi $dst, $src, $shift\t#@vlslB_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e8); + if (con >= BitsPerByte) { + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vlslS_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (LShiftVS src (LShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsll.vi $dst, $src, $shift\t#@vlslS_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e16); + if (con >= BitsPerShort) { + __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), + as_VectorRegister($src$$reg)); + return; + } + __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vlslI_imm(vReg dst, vReg src, immI shift) %{ + match(Set dst (LShiftVI src (LShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsll.vi $dst, $src, $shift\t#@vlslI_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e32); + __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vlslL_imm(vReg dst, vReg src, immI shift) %{ + predicate((n->in(2)->in(1)->get_int() & 0x3f) < 32); + match(Set dst (LShiftVL src (LShiftCntV shift))); + ins_cost(VEC_COST); + format %{ "vsll.vi $dst, $src, $shift\t#@vlslL_imm" %} + ins_encode %{ + uint32_t con = (unsigned)$shift$$constant & 0x1f; + __ vsetvli(t0, x0, Assembler::e64); + __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg), con); + %} + ins_pipe(pipe_slow); +%} + +instruct vshiftcntB(vReg dst, iRegIorL2I cnt) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_BYTE); + match(Set dst (LShiftCntV cnt)); + match(Set dst (RShiftCntV cnt)); + format %{ "vmv.v.x $dst, $cnt\t#@vshiftcntB" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vmv_v_x(as_VectorRegister($dst$$reg), as_Register($cnt$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vshiftcntS(vReg dst, iRegIorL2I cnt) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_SHORT || + n->bottom_type()->is_vect()->element_basic_type() == T_CHAR); + match(Set dst (LShiftCntV cnt)); + match(Set dst (RShiftCntV cnt)); + format %{ "vmv.v.x $dst, $cnt\t#@vshiftcntS" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vmv_v_x(as_VectorRegister($dst$$reg), as_Register($cnt$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vshiftcntI(vReg dst, iRegIorL2I cnt) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_INT); + match(Set dst (LShiftCntV cnt)); + match(Set dst (RShiftCntV cnt)); + format %{ "vmv.v.x $dst, $cnt\t#@vshiftcntI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vmv_v_x(as_VectorRegister($dst$$reg), as_Register($cnt$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vshiftcntL(vReg dst, iRegIorL2I cnt) %{ + predicate(n->bottom_type()->is_vect()->element_basic_type() == T_LONG); + match(Set dst (LShiftCntV cnt)); + match(Set dst (RShiftCntV cnt)); + format %{ "vmv.v.x $dst, $cnt\t#@vshiftcntL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vmv_v_x(as_VectorRegister($dst$$reg), as_Register($cnt$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector sqrt + +instruct vsqrtF(vReg dst, vReg src) %{ + match(Set dst (SqrtVF src)); + ins_cost(VEC_COST); + format %{ "vfsqrt.v $dst, $src\t#@vsqrtF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfsqrt_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vsqrtD(vReg dst, vReg src) %{ + match(Set dst (SqrtVD src)); + ins_cost(VEC_COST); + format %{ "vfsqrt.v $dst, $src\t#@vsqrtD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfsqrt_v(as_VectorRegister($dst$$reg), as_VectorRegister($src$$reg)); + %} + ins_pipe(pipe_slow); +%} + +// vector sub + +instruct vsubB(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (SubVB src1 src2)); + ins_cost(VEC_COST); + format %{ "vsub.vv $dst, $src1, $src2\t#@vsubB" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e8); + __ vsub_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vsubS(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (SubVS src1 src2)); + ins_cost(VEC_COST); + format %{ "vsub.vv $dst, $src1, $src2\t#@vsubS" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e16); + __ vsub_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vsubI(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (SubVI src1 src2)); + ins_cost(VEC_COST); + format %{ "vsub.vv $dst, $src1, $src2\t#@vsubI" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vsub_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vsubL(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (SubVL src1 src2)); + ins_cost(VEC_COST); + format %{ "vsub.vv $dst, $src1, $src2\t#@vsubL" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vsub_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vsubF(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (SubVF src1 src2)); + ins_cost(VEC_COST); + format %{ "vfsub.vv $dst, $src1, $src2\t@vsubF" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e32); + __ vfsub_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vsubD(vReg dst, vReg src1, vReg src2) %{ + match(Set dst (SubVD src1 src2)); + ins_cost(VEC_COST); + format %{ "vfsub.vv $dst, $src1, $src2\t#@vsubD" %} + ins_encode %{ + __ vsetvli(t0, x0, Assembler::e64); + __ vfsub_vv(as_VectorRegister($dst$$reg), as_VectorRegister($src1$$reg), + as_VectorRegister($src2$$reg)); + %} + ins_pipe(pipe_slow); +%} + +instruct vstring_equalsL(iRegP_R11 str1, iRegP_R13 str2, iRegI_R14 cnt, + iRegI_R10 result, vReg_V1 v1, + vReg_V2 v2, vReg_V3 v3, rFlagsReg cr) +%{ + predicate(UseRVV && ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP v1, TEMP v2, TEMP v3, KILL cr); + + format %{ "String Equals $str1, $str2, $cnt -> $result\t#@string_equalsL" %} + ins_encode %{ + // Count is in 8-bit bytes; non-Compact chars are 16 bits. + __ string_equals_v($str1$$Register, $str2$$Register, + $result$$Register, $cnt$$Register, 1); + %} + ins_pipe(pipe_class_memory); +%} + +instruct vstring_equalsU(iRegP_R11 str1, iRegP_R13 str2, iRegI_R14 cnt, + iRegI_R10 result, vReg_V1 v1, + vReg_V2 v2, vReg_V3 v3, rFlagsReg cr) +%{ + predicate(UseRVV && ((StrEqualsNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (StrEquals (Binary str1 str2) cnt)); + effect(USE_KILL str1, USE_KILL str2, USE_KILL cnt, TEMP v1, TEMP v2, TEMP v3, KILL cr); + + format %{ "String Equals $str1, $str2, $cnt -> $result\t#@string_equalsU" %} + ins_encode %{ + // Count is in 8-bit bytes; non-Compact chars are 16 bits. + __ string_equals_v($str1$$Register, $str2$$Register, + $result$$Register, $cnt$$Register, 2); + %} + ins_pipe(pipe_class_memory); +%} + +instruct varray_equalsB(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result, + vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, iRegP_R28 tmp, rFlagsReg cr) +%{ + predicate(UseRVV && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::LL); + match(Set result (AryEq ary1 ary2)); + effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, TEMP v1, TEMP v2, TEMP v3, KILL cr); + + format %{ "Array Equals $ary1, ary2 -> $result\t#@array_equalsB // KILL $tmp" %} + ins_encode %{ + __ arrays_equals_v($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, 1); + %} + ins_pipe(pipe_class_memory); +%} + +instruct varray_equalsC(iRegP_R11 ary1, iRegP_R12 ary2, iRegI_R10 result, + vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, iRegP_R28 tmp, rFlagsReg cr) +%{ + predicate(UseRVV && ((AryEqNode*)n)->encoding() == StrIntrinsicNode::UU); + match(Set result (AryEq ary1 ary2)); + effect(KILL tmp, USE_KILL ary1, USE_KILL ary2, TEMP v1, TEMP v2, TEMP v3, KILL cr); + + format %{ "Array Equals $ary1, ary2 -> $result\t#@array_equalsC // KILL $tmp" %} + ins_encode %{ + __ arrays_equals_v($ary1$$Register, $ary2$$Register, + $result$$Register, $tmp$$Register, 2); + %} + ins_pipe(pipe_class_memory); +%} + +instruct vstring_compareU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, + iRegP_R28 tmp1, iRegL_R29 tmp2) +%{ + predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UU); + match(Set result(StrComp(Binary str1 cnt1)(Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, + TEMP v1, TEMP v2, TEMP v3, TEMP v4, TEMP v5); + + format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareU" %} + ins_encode %{ + // Count is in 8-bit bytes; non-Compact chars are 16 bits. + __ string_compare_v($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, + StrIntrinsicNode::UU); + %} + ins_pipe(pipe_class_memory); +%} +instruct vstring_compareL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, + iRegP_R28 tmp1, iRegL_R29 tmp2) +%{ + predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::LL); + match(Set result(StrComp(Binary str1 cnt1)(Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, + TEMP v1, TEMP v2, TEMP v3, TEMP v4, TEMP v5); + + format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareL" %} + ins_encode %{ + __ string_compare_v($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, + StrIntrinsicNode::LL); + %} + ins_pipe(pipe_class_memory); +%} + +instruct vstring_compareUL(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, + iRegP_R28 tmp1, iRegL_R29 tmp2) +%{ + predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::UL); + match(Set result(StrComp(Binary str1 cnt1)(Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, + TEMP v1, TEMP v2, TEMP v3, TEMP v4, TEMP v5); + + format %{"String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareUL" %} + ins_encode %{ + __ string_compare_v($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, + StrIntrinsicNode::UL); + %} + ins_pipe(pipe_class_memory); +%} +instruct vstring_compareLU(iRegP_R11 str1, iRegI_R12 cnt1, iRegP_R13 str2, iRegI_R14 cnt2, + iRegI_R10 result, vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, vReg_V4 v4, vReg_V5 v5, + iRegP_R28 tmp1, iRegL_R29 tmp2) +%{ + predicate(UseRVV && ((StrCompNode *)n)->encoding() == StrIntrinsicNode::LU); + match(Set result(StrComp(Binary str1 cnt1)(Binary str2 cnt2))); + effect(KILL tmp1, KILL tmp2, USE_KILL str1, USE_KILL str2, USE_KILL cnt1, USE_KILL cnt2, + TEMP v1, TEMP v2, TEMP v3, TEMP v4, TEMP v5); + + format %{ "String Compare $str1, $cnt1, $str2, $cnt2 -> $result\t#@string_compareLU" %} + ins_encode %{ + __ string_compare_v($str1$$Register, $str2$$Register, + $cnt1$$Register, $cnt2$$Register, $result$$Register, + $tmp1$$Register, $tmp2$$Register, + StrIntrinsicNode::LU); + %} + ins_pipe(pipe_class_memory); +%} + +// fast byte[] to char[] inflation +instruct vstring_inflate(Universe dummy, iRegP_R10 src, iRegP_R11 dst, iRegI_R12 len, + vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, iRegL tmp) +%{ + predicate(UseRVV); + match(Set dummy (StrInflatedCopy src (Binary dst len))); + effect(TEMP v1, TEMP v2, TEMP v3, TEMP tmp, USE_KILL src, USE_KILL dst, USE_KILL len); + + format %{ "String Inflate $src,$dst" %} + ins_encode %{ + __ byte_array_inflate_v($src$$Register, $dst$$Register, $len$$Register, $tmp$$Register); + %} + ins_pipe(pipe_class_memory); +%} + +// encode char[] to byte[] in ISO_8859_1 +instruct vencode_iso_array(iRegP_R12 src, iRegP_R11 dst, iRegI_R13 len, iRegI_R10 result, + vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, iRegL tmp) +%{ + predicate(UseRVV); + match(Set result (EncodeISOArray src (Binary dst len))); + effect(TEMP_DEF result, USE_KILL src, USE_KILL dst, USE_KILL len, + TEMP v1, TEMP v2, TEMP v3, TEMP tmp); + + format %{ "Encode array $src,$dst,$len -> $result" %} + ins_encode %{ + __ encode_iso_array_v($src$$Register, $dst$$Register, $len$$Register, + $result$$Register, $tmp$$Register); + %} + ins_pipe( pipe_class_memory ); +%} + +// fast char[] to byte[] compression +instruct vstring_compress(iRegP_R12 src, iRegP_R11 dst, iRegI_R13 len, iRegI_R10 result, + vReg_V1 v1, vReg_V2 v2, vReg_V3 v3, iRegL tmp) +%{ + predicate(UseRVV); + match(Set result (StrCompressedCopy src (Binary dst len))); + effect(TEMP_DEF result, USE_KILL src, USE_KILL dst, USE_KILL len, + TEMP v1, TEMP v2, TEMP v3, TEMP tmp); + + format %{ "String Compress $src,$dst -> $result // KILL R11, R12, R13" %} + ins_encode %{ + __ char_array_compress_v($src$$Register, $dst$$Register, $len$$Register, + $result$$Register, $tmp$$Register); + %} + ins_pipe( pipe_slow ); +%} + +instruct vcount_positives(iRegP_R11 ary, iRegI_R12 len, iRegI_R10 result, iRegL tmp) +%{ + predicate(UseRVV); + match(Set result (CountPositives ary len)); + effect(USE_KILL ary, USE_KILL len, TEMP tmp); + + format %{ "count positives byte[] $ary, $len -> $result" %} + ins_encode %{ + __ count_positives_v($ary$$Register, $len$$Register, $result$$Register, $tmp$$Register); + %} + + ins_pipe(pipe_slow); +%} + +instruct vstringU_indexof_char(iRegP_R11 str1, iRegI_R12 cnt1, iRegI_R13 ch, + iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, + vReg_V1 v1, vReg_V2 v2, vReg_V3 v3) +%{ + predicate(UseRVV && (((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::U)); + match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL cnt1, USE_KILL ch, + TEMP tmp1, TEMP tmp2, TEMP v1, TEMP v2, TEMP v3); + + format %{ "StringUTF16 IndexOf char[] $str1, $cnt1, $ch -> $result" %} + + ins_encode %{ + __ string_indexof_char_v($str1$$Register, $cnt1$$Register, $ch$$Register, + $result$$Register, $tmp1$$Register, $tmp2$$Register, + false /* isL */); + %} + + ins_pipe(pipe_class_memory); +%} + +instruct vstringL_indexof_char(iRegP_R11 str1, iRegI_R12 cnt1, iRegI_R13 ch, + iRegI_R10 result, iRegINoSp tmp1, iRegINoSp tmp2, + vReg_V1 v1, vReg_V2 v2, vReg_V3 v3) +%{ + predicate(UseRVV && (((StrIndexOfCharNode*)n)->encoding() == StrIntrinsicNode::L)); + match(Set result (StrIndexOfChar (Binary str1 cnt1) ch)); + effect(TEMP_DEF result, USE_KILL str1, USE_KILL cnt1, USE_KILL ch, + TEMP tmp1, TEMP tmp2, TEMP v1, TEMP v2, TEMP v3); + + format %{ "StringLatin1 IndexOf char[] $str1, $cnt1, $ch -> $result" %} + + ins_encode %{ + __ string_indexof_char_v($str1$$Register, $cnt1$$Register, $ch$$Register, + $result$$Register, $tmp1$$Register, $tmp2$$Register, + true /* isL */); + %} + + ins_pipe(pipe_class_memory); +%} + +// clearing of an array +instruct vclearArray_reg_reg(iRegL_R29 cnt, iRegP_R28 base, Universe dummy, + vReg_V1 vReg1, vReg_V2 vReg2, vReg_V3 vReg3) +%{ + predicate(UseRVV); + match(Set dummy (ClearArray cnt base)); + effect(USE_KILL cnt, USE_KILL base, TEMP vReg1, TEMP vReg2, TEMP vReg3); + + format %{ "ClearArray $cnt, $base\t#@clearArray_reg_reg" %} + + ins_encode %{ + __ clear_array_v($base$$Register, $cnt$$Register); + %} + + ins_pipe(pipe_class_memory); +%} diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp new file mode 100644 index 00000000000..f85d4b25a76 --- /dev/null +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -0,0 +1,2761 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "code/debugInfoRec.hpp" +#include "code/icBuffer.hpp" +#include "code/vtableStubs.hpp" +#include "compiler/oopMap.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" +#include "logging/log.hpp" +#include "memory/resourceArea.hpp" +#include "nativeInst_riscv.hpp" +#include "oops/compiledICHolder.hpp" +#include "oops/klass.inline.hpp" +#include "prims/methodHandles.hpp" +#include "runtime/jniHandles.hpp" +#include "runtime/safepointMechanism.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/signature.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/vframeArray.hpp" +#include "utilities/align.hpp" +#include "utilities/formatBuffer.hpp" +#include "vmreg_riscv.inline.hpp" +#ifdef COMPILER1 +#include "c1/c1_Runtime1.hpp" +#endif +#ifdef COMPILER2 +#include "adfiles/ad_riscv.hpp" +#include "opto/runtime.hpp" +#endif + +#define __ masm-> + +const int StackAlignmentInSlots = StackAlignmentInBytes / VMRegImpl::stack_slot_size; + +class SimpleRuntimeFrame { +public: + + // Most of the runtime stubs have this simple frame layout. + // This class exists to make the layout shared in one place. + // Offsets are for compiler stack slots, which are jints. + enum layout { + // The frame sender code expects that fp will be in the "natural" place and + // will override any oopMap setting for it. We must therefore force the layout + // so that it agrees with the frame sender code. + // we don't expect any arg reg save area so riscv asserts that + // frame::arg_reg_save_area_bytes == 0 + fp_off = 0, fp_off2, + return_off, return_off2, + framesize + }; +}; + +class RegisterSaver { + const bool _save_vectors; + public: + RegisterSaver(bool save_vectors) : _save_vectors(UseRVV && save_vectors) {} + ~RegisterSaver() {} + OopMap* save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words); + void restore_live_registers(MacroAssembler* masm); + + // Offsets into the register save area + // Used by deoptimization when it is managing result register + // values on its own + // gregs:28, float_register:32; except: x1(ra) & x2(sp) & gp(x3) & tp(x4) + // |---v0---|<---SP + // |---v1---|save vectors only in generate_handler_blob + // |-- .. --| + // |---v31--|----- + // |---f0---| + // |---f1---| + // | .. | + // |---f31--| + // |---reserved slot for stack alignment---| + // |---x5---| + // | x6 | + // |---.. --| + // |---x31--| + // |---fp---| + // |---ra---| + int v0_offset_in_bytes(void) { return 0; } + int f0_offset_in_bytes(void) { + int f0_offset = 0; +#ifdef COMPILER2 + if (_save_vectors) { + f0_offset += Matcher::scalable_vector_reg_size(T_INT) * VectorRegisterImpl::number_of_registers * + BytesPerInt; + } +#endif + return f0_offset; + } + int reserved_slot_offset_in_bytes(void) { + return f0_offset_in_bytes() + + FloatRegisterImpl::max_slots_per_register * + FloatRegisterImpl::number_of_registers * + BytesPerInt; + } + + int reg_offset_in_bytes(Register r) { + assert (r->encoding() > 4, "ra, sp, gp and tp not saved"); + return reserved_slot_offset_in_bytes() + (r->encoding() - 4 /* x1, x2, x3, x4 */) * wordSize; + } + + int freg_offset_in_bytes(FloatRegister f) { + return f0_offset_in_bytes() + f->encoding() * wordSize; + } + + int ra_offset_in_bytes(void) { + return reserved_slot_offset_in_bytes() + + (RegisterImpl::number_of_registers - 3) * + RegisterImpl::max_slots_per_register * + BytesPerInt; + } +}; + +OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words) { + int vector_size_in_bytes = 0; + int vector_size_in_slots = 0; +#ifdef COMPILER2 + if (_save_vectors) { + vector_size_in_bytes += Matcher::scalable_vector_reg_size(T_BYTE); + vector_size_in_slots += Matcher::scalable_vector_reg_size(T_INT); + } +#endif + + assert_cond(masm != NULL && total_frame_words != NULL); + int frame_size_in_bytes = align_up(additional_frame_words * wordSize + ra_offset_in_bytes() + wordSize, 16); + // OopMap frame size is in compiler stack slots (jint's) not bytes or words + int frame_size_in_slots = frame_size_in_bytes / BytesPerInt; + // The caller will allocate additional_frame_words + int additional_frame_slots = additional_frame_words * wordSize / BytesPerInt; + // CodeBlob frame size is in words. + int frame_size_in_words = frame_size_in_bytes / wordSize; + *total_frame_words = frame_size_in_words; + + // Save Integer, Float and Vector registers. + __ enter(); + __ push_CPU_state(_save_vectors, vector_size_in_bytes); + + // Set an oopmap for the call site. This oopmap will map all + // oop-registers and debug-info registers as callee-saved. This + // will allow deoptimization at this safepoint to find all possible + // debug-info recordings, as well as let GC find all oops. + + OopMapSet *oop_maps = new OopMapSet(); + OopMap* oop_map = new OopMap(frame_size_in_slots, 0); + assert_cond(oop_maps != NULL && oop_map != NULL); + + int sp_offset_in_slots = 0; + int step_in_slots = 0; + if (_save_vectors) { + step_in_slots = vector_size_in_slots; + for (int i = 0; i < VectorRegisterImpl::number_of_registers; i++, sp_offset_in_slots += step_in_slots) { + VectorRegister r = as_VectorRegister(i); + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset_in_slots), r->as_VMReg()); + } + } + + step_in_slots = FloatRegisterImpl::max_slots_per_register; + for (int i = 0; i < FloatRegisterImpl::number_of_registers; i++, sp_offset_in_slots += step_in_slots) { + FloatRegister r = as_FloatRegister(i); + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset_in_slots), r->as_VMReg()); + } + + step_in_slots = RegisterImpl::max_slots_per_register; + // skip the slot reserved for alignment, see MacroAssembler::push_reg; + // also skip x5 ~ x6 on the stack because they are caller-saved registers. + sp_offset_in_slots += RegisterImpl::max_slots_per_register * 3; + // besides, we ignore x0 ~ x4 because push_CPU_state won't push them on the stack. + for (int i = 7; i < RegisterImpl::number_of_registers; i++, sp_offset_in_slots += step_in_slots) { + Register r = as_Register(i); + if (r != xthread) { + oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset_in_slots + additional_frame_slots), r->as_VMReg()); + } + } + + return oop_map; +} + +void RegisterSaver::restore_live_registers(MacroAssembler* masm) { + assert_cond(masm != NULL); +#ifdef COMPILER2 + __ pop_CPU_state(_save_vectors, Matcher::scalable_vector_reg_size(T_BYTE)); +#else + __ pop_CPU_state(_save_vectors); +#endif + __ leave(); +} + +// Is vector's size (in bytes) bigger than a size saved by default? +// riscv does not ovlerlay the floating-point registers on vector registers like aarch64. +bool SharedRuntime::is_wide_vector(int size) { + return UseRVV; +} + +// The java_calling_convention describes stack locations as ideal slots on +// a frame with no abi restrictions. Since we must observe abi restrictions +// (like the placement of the register window) the slots must be biased by +// the following value. +static int reg2offset_in(VMReg r) { + // Account for saved fp and ra + // This should really be in_preserve_stack_slots + return r->reg2stack() * VMRegImpl::stack_slot_size; +} + +static int reg2offset_out(VMReg r) { + return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size; +} + +// --------------------------------------------------------------------------- +// Read the array of BasicTypes from a signature, and compute where the +// arguments should go. Values in the VMRegPair regs array refer to 4-byte +// quantities. Values less than VMRegImpl::stack0 are registers, those above +// refer to 4-byte stack slots. All stack slots are based off of the stack pointer +// as framesizes are fixed. +// VMRegImpl::stack0 refers to the first slot 0(sp). +// and VMRegImpl::stack0+1 refers to the memory word 4-byes higher. Register +// up to RegisterImpl::number_of_registers) are the 64-bit +// integer registers. + +// Note: the INPUTS in sig_bt are in units of Java argument words, +// which are 64-bit. The OUTPUTS are in 32-bit units. + +// The Java calling convention is a "shifted" version of the C ABI. +// By skipping the first C ABI register we can call non-static jni +// methods with small numbers of arguments without having to shuffle +// the arguments at all. Since we control the java ABI we ought to at +// least get some advantage out of it. + +int SharedRuntime::java_calling_convention(const BasicType *sig_bt, + VMRegPair *regs, + int total_args_passed) { + // Create the mapping between argument positions and + // registers. + static const Register INT_ArgReg[Argument::n_int_register_parameters_j] = { + j_rarg0, j_rarg1, j_rarg2, j_rarg3, + j_rarg4, j_rarg5, j_rarg6, j_rarg7 + }; + static const FloatRegister FP_ArgReg[Argument::n_float_register_parameters_j] = { + j_farg0, j_farg1, j_farg2, j_farg3, + j_farg4, j_farg5, j_farg6, j_farg7 + }; + + uint int_args = 0; + uint fp_args = 0; + uint stk_args = 0; // inc by 2 each time + + for (int i = 0; i < total_args_passed; i++) { + switch (sig_bt[i]) { + case T_BOOLEAN: // fall through + case T_CHAR: // fall through + case T_BYTE: // fall through + case T_SHORT: // fall through + case T_INT: + if (int_args < Argument::n_int_register_parameters_j) { + regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); + } else { + regs[i].set1(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } + break; + case T_VOID: + // halves of T_LONG or T_DOUBLE + assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half"); + regs[i].set_bad(); + break; + case T_LONG: // fall through + assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); + case T_OBJECT: // fall through + case T_ARRAY: // fall through + case T_ADDRESS: + if (int_args < Argument::n_int_register_parameters_j) { + regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); + } else { + regs[i].set2(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } + break; + case T_FLOAT: + if (fp_args < Argument::n_float_register_parameters_j) { + regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); + } else { + regs[i].set1(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } + break; + case T_DOUBLE: + assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); + if (fp_args < Argument::n_float_register_parameters_j) { + regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); + } else { + regs[i].set2(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } + break; + default: + ShouldNotReachHere(); + } + } + + return align_up(stk_args, 2); +} + +// Patch the callers callsite with entry to compiled code if it exists. +static void patch_callers_callsite(MacroAssembler *masm) { + assert_cond(masm != NULL); + Label L; + __ ld(t0, Address(xmethod, in_bytes(Method::code_offset()))); + __ beqz(t0, L); + + __ enter(); + __ push_CPU_state(); + + // VM needs caller's callsite + // VM needs target method + // This needs to be a long call since we will relocate this adapter to + // the codeBuffer and it may not reach + +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + + __ mv(c_rarg0, xmethod); + __ mv(c_rarg1, ra); + int32_t offset = 0; + __ la_patchable(t0, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::fixup_callers_callsite)), offset); + __ jalr(x1, t0, offset); + + // Explicit fence.i required because fixup_callers_callsite may change the code + // stream. + __ safepoint_ifence(); + + __ pop_CPU_state(); + // restore sp + __ leave(); + __ bind(L); +} + +static void gen_c2i_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + Label& skip_fixup) { + // Before we get into the guts of the C2I adapter, see if we should be here + // at all. We've come from compiled code and are attempting to jump to the + // interpreter, which means the caller made a static call to get here + // (vcalls always get a compiled target if there is one). Check for a + // compiled target. If there is one, we need to patch the caller's call. + patch_callers_callsite(masm); + + __ bind(skip_fixup); + + int words_pushed = 0; + + // Since all args are passed on the stack, total_args_passed * + // Interpreter::stackElementSize is the space we need. + + int extraspace = total_args_passed * Interpreter::stackElementSize; + + __ mv(x30, sp); + + // stack is aligned, keep it that way + extraspace = align_up(extraspace, 2 * wordSize); + + if (extraspace) { + __ sub(sp, sp, extraspace); + } + + // Now write the args into the outgoing interpreter space + for (int i = 0; i < total_args_passed; i++) { + if (sig_bt[i] == T_VOID) { + assert(i > 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "missing half"); + continue; + } + + // offset to start parameters + int st_off = (total_args_passed - i - 1) * Interpreter::stackElementSize; + int next_off = st_off - Interpreter::stackElementSize; + + // Say 4 args: + // i st_off + // 0 32 T_LONG + // 1 24 T_VOID + // 2 16 T_OBJECT + // 3 8 T_BOOL + // - 0 return address + // + // However to make thing extra confusing. Because we can fit a Java long/double in + // a single slot on a 64 bt vm and it would be silly to break them up, the interpreter + // leaves one slot empty and only stores to a single slot. In this case the + // slot that is occupied is the T_VOID slot. See I said it was confusing. + + VMReg r_1 = regs[i].first(); + VMReg r_2 = regs[i].second(); + if (!r_1->is_valid()) { + assert(!r_2->is_valid(), ""); + continue; + } + if (r_1->is_stack()) { + // memory to memory use t0 + int ld_off = (r_1->reg2stack() * VMRegImpl::stack_slot_size + + extraspace + + words_pushed * wordSize); + if (!r_2->is_valid()) { + __ lwu(t0, Address(sp, ld_off)); + __ sd(t0, Address(sp, st_off), /*temp register*/esp); + } else { + __ ld(t0, Address(sp, ld_off), /*temp register*/esp); + + // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG + // T_DOUBLE and T_LONG use two slots in the interpreter + if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) { + // ld_off == LSW, ld_off+wordSize == MSW + // st_off == MSW, next_off == LSW + __ sd(t0, Address(sp, next_off), /*temp register*/esp); +#ifdef ASSERT + // Overwrite the unused slot with known junk + __ li(t0, 0xdeadffffdeadaaaaul); + __ sd(t0, Address(sp, st_off), /*temp register*/esp); +#endif /* ASSERT */ + } else { + __ sd(t0, Address(sp, st_off), /*temp register*/esp); + } + } + } else if (r_1->is_Register()) { + Register r = r_1->as_Register(); + if (!r_2->is_valid()) { + // must be only an int (or less ) so move only 32bits to slot + __ sd(r, Address(sp, st_off)); + } else { + // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG + // T_DOUBLE and T_LONG use two slots in the interpreter + if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) { + // long/double in gpr +#ifdef ASSERT + // Overwrite the unused slot with known junk + __ li(t0, 0xdeadffffdeadaaabul); + __ sd(t0, Address(sp, st_off), /*temp register*/esp); +#endif /* ASSERT */ + __ sd(r, Address(sp, next_off)); + } else { + __ sd(r, Address(sp, st_off)); + } + } + } else { + assert(r_1->is_FloatRegister(), ""); + if (!r_2->is_valid()) { + // only a float use just part of the slot + __ fsw(r_1->as_FloatRegister(), Address(sp, st_off)); + } else { +#ifdef ASSERT + // Overwrite the unused slot with known junk + __ li(t0, 0xdeadffffdeadaaacul); + __ sd(t0, Address(sp, st_off), /*temp register*/esp); +#endif /* ASSERT */ + __ fsd(r_1->as_FloatRegister(), Address(sp, next_off)); + } + } + } + + __ mv(esp, sp); // Interp expects args on caller's expression stack + + __ ld(t0, Address(xmethod, in_bytes(Method::interpreter_entry_offset()))); + __ jr(t0); +} + +void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs) { + // Cut-out for having no stack args. + int comp_words_on_stack = align_up(comp_args_on_stack * VMRegImpl::stack_slot_size, wordSize) >> LogBytesPerWord; + if (comp_args_on_stack != 0) { + __ sub(t0, sp, comp_words_on_stack * wordSize); + __ andi(sp, t0, -16); + } + + // Will jump to the compiled code just as if compiled code was doing it. + // Pre-load the register-jump target early, to schedule it better. + __ ld(t1, Address(xmethod, in_bytes(Method::from_compiled_offset()))); + + // Now generate the shuffle code. + for (int i = 0; i < total_args_passed; i++) { + if (sig_bt[i] == T_VOID) { + assert(i > 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "missing half"); + continue; + } + + // Pick up 0, 1 or 2 words from SP+offset. + + assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), + "scrambled load targets?"); + // Load in argument order going down. + int ld_off = (total_args_passed - i - 1) * Interpreter::stackElementSize; + // Point to interpreter value (vs. tag) + int next_off = ld_off - Interpreter::stackElementSize; + + VMReg r_1 = regs[i].first(); + VMReg r_2 = regs[i].second(); + if (!r_1->is_valid()) { + assert(!r_2->is_valid(), ""); + continue; + } + if (r_1->is_stack()) { + // Convert stack slot to an SP offset (+ wordSize to account for return address ) + int st_off = regs[i].first()->reg2stack() * VMRegImpl::stack_slot_size; + if (!r_2->is_valid()) { + __ lw(t0, Address(esp, ld_off)); + __ sd(t0, Address(sp, st_off), /*temp register*/t2); + } else { + // + // We are using two optoregs. This can be either T_OBJECT, + // T_ADDRESS, T_LONG, or T_DOUBLE the interpreter allocates + // two slots but only uses one for thr T_LONG or T_DOUBLE case + // So we must adjust where to pick up the data to match the + // interpreter. + // + // Interpreter local[n] == MSW, local[n+1] == LSW however locals + // are accessed as negative so LSW is at LOW address + + // ld_off is MSW so get LSW + const int offset = (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) ? + next_off : ld_off; + __ ld(t0, Address(esp, offset)); + // st_off is LSW (i.e. reg.first()) + __ sd(t0, Address(sp, st_off), /*temp register*/t2); + } + } else if (r_1->is_Register()) { // Register argument + Register r = r_1->as_Register(); + if (r_2->is_valid()) { + // + // We are using two VMRegs. This can be either T_OBJECT, + // T_ADDRESS, T_LONG, or T_DOUBLE the interpreter allocates + // two slots but only uses one for thr T_LONG or T_DOUBLE case + // So we must adjust where to pick up the data to match the + // interpreter. + + const int offset = (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) ? + next_off : ld_off; + + // this can be a misaligned move + __ ld(r, Address(esp, offset)); + } else { + // sign extend and use a full word? + __ lw(r, Address(esp, ld_off)); + } + } else { + if (!r_2->is_valid()) { + __ flw(r_1->as_FloatRegister(), Address(esp, ld_off)); + } else { + __ fld(r_1->as_FloatRegister(), Address(esp, next_off)); + } + } + } + + // 6243940 We might end up in handle_wrong_method if + // the callee is deoptimized as we race thru here. If that + // happens we don't want to take a safepoint because the + // caller frame will look interpreted and arguments are now + // "compiled" so it is much better to make this transition + // invisible to the stack walking code. Unfortunately if + // we try and find the callee by normal means a safepoint + // is possible. So we stash the desired callee in the thread + // and the vm will find there should this case occur. + + __ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); + + __ jr(t1); +} + +// --------------------------------------------------------------- +AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm, + int total_args_passed, + int comp_args_on_stack, + const BasicType *sig_bt, + const VMRegPair *regs, + AdapterFingerPrint* fingerprint) { + address i2c_entry = __ pc(); + gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs); + + address c2i_unverified_entry = __ pc(); + Label skip_fixup; + + Label ok; + + const Register holder = t1; + const Register receiver = j_rarg0; + const Register tmp = t2; // A call-clobbered register not used for arg passing + + // ------------------------------------------------------------------------- + // Generate a C2I adapter. On entry we know xmethod holds the Method* during calls + // to the interpreter. The args start out packed in the compiled layout. They + // need to be unpacked into the interpreter layout. This will almost always + // require some stack space. We grow the current (compiled) stack, then repack + // the args. We finally end in a jump to the generic interpreter entry point. + // On exit from the interpreter, the interpreter will restore our SP (lest the + // compiled code, which relys solely on SP and not FP, get sick). + + { + __ block_comment("c2i_unverified_entry {"); + __ load_klass(t0, receiver); + __ ld(tmp, Address(holder, CompiledICHolder::holder_klass_offset())); + __ ld(xmethod, Address(holder, CompiledICHolder::holder_metadata_offset())); + __ beq(t0, tmp, ok); + __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + + __ bind(ok); + // Method might have been compiled since the call site was patched to + // interpreted; if that is the case treat it as a miss so we can get + // the call site corrected. + __ ld(t0, Address(xmethod, in_bytes(Method::code_offset()))); + __ beqz(t0, skip_fixup); + __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + __ block_comment("} c2i_unverified_entry"); + } + + address c2i_entry = __ pc(); + + // Class initialization barrier for static methods + address c2i_no_clinit_check_entry = NULL; + if (VM_Version::supports_fast_class_init_checks()) { + Label L_skip_barrier; + + { // Bypass the barrier for non-static methods + __ lwu(t0, Address(xmethod, Method::access_flags_offset())); + __ andi(t1, t0, JVM_ACC_STATIC); + __ beqz(t1, L_skip_barrier); // non-static + } + + __ load_method_holder(t1, xmethod); + __ clinit_barrier(t1, t0, &L_skip_barrier); + __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + + __ bind(L_skip_barrier); + c2i_no_clinit_check_entry = __ pc(); + } + + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->c2i_entry_barrier(masm); + + gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup); + + __ flush(); + return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); +} + +int SharedRuntime::vector_calling_convention(VMRegPair *regs, + uint num_bits, + uint total_args_passed) { + Unimplemented(); + return 0; +} + +int SharedRuntime::c_calling_convention(const BasicType *sig_bt, + VMRegPair *regs, + VMRegPair *regs2, + int total_args_passed) { + assert(regs2 == NULL, "not needed on riscv"); + + // We return the amount of VMRegImpl stack slots we need to reserve for all + // the arguments NOT counting out_preserve_stack_slots. + + static const Register INT_ArgReg[Argument::n_int_register_parameters_c] = { + c_rarg0, c_rarg1, c_rarg2, c_rarg3, + c_rarg4, c_rarg5, c_rarg6, c_rarg7 + }; + static const FloatRegister FP_ArgReg[Argument::n_float_register_parameters_c] = { + c_farg0, c_farg1, c_farg2, c_farg3, + c_farg4, c_farg5, c_farg6, c_farg7 + }; + + uint int_args = 0; + uint fp_args = 0; + uint stk_args = 0; // inc by 2 each time + + for (int i = 0; i < total_args_passed; i++) { + switch (sig_bt[i]) { + case T_BOOLEAN: // fall through + case T_CHAR: // fall through + case T_BYTE: // fall through + case T_SHORT: // fall through + case T_INT: + if (int_args < Argument::n_int_register_parameters_c) { + regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); + } else { + regs[i].set1(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } + break; + case T_LONG: // fall through + assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); + case T_OBJECT: // fall through + case T_ARRAY: // fall through + case T_ADDRESS: // fall through + case T_METADATA: + if (int_args < Argument::n_int_register_parameters_c) { + regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); + } else { + regs[i].set2(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } + break; + case T_FLOAT: + if (fp_args < Argument::n_float_register_parameters_c) { + regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); + } else if (int_args < Argument::n_int_register_parameters_c) { + regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); + } else { + regs[i].set1(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } + break; + case T_DOUBLE: + assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half"); + if (fp_args < Argument::n_float_register_parameters_c) { + regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); + } else if (int_args < Argument::n_int_register_parameters_c) { + regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); + } else { + regs[i].set2(VMRegImpl::stack2reg(stk_args)); + stk_args += 2; + } + break; + case T_VOID: // Halves of longs and doubles + assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half"); + regs[i].set_bad(); + break; + default: + ShouldNotReachHere(); + } + } + + return stk_args; +} + +// On 64 bit we will store integer like items to the stack as +// 64 bits items (riscv64 abi) even though java would only store +// 32bits for a parameter. On 32bit it will simply be 32 bits +// So this routine will do 32->32 on 32bit and 32->64 on 64bit +static void move32_64(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { + assert_cond(masm != NULL); + if (src.first()->is_stack()) { + if (dst.first()->is_stack()) { + // stack to stack + __ ld(t0, Address(fp, reg2offset_in(src.first()))); + __ sd(t0, Address(sp, reg2offset_out(dst.first()))); + } else { + // stack to reg + __ lw(dst.first()->as_Register(), Address(fp, reg2offset_in(src.first()))); + } + } else if (dst.first()->is_stack()) { + // reg to stack + __ sd(src.first()->as_Register(), Address(sp, reg2offset_out(dst.first()))); + } else { + if (dst.first() != src.first()) { + // 32bits extend sign + __ addw(dst.first()->as_Register(), src.first()->as_Register(), zr); + } + } +} + +// An oop arg. Must pass a handle not the oop itself +static void object_move(MacroAssembler* masm, + OopMap* map, + int oop_handle_offset, + int framesize_in_slots, + VMRegPair src, + VMRegPair dst, + bool is_receiver, + int* receiver_offset) { + assert_cond(masm != NULL && map != NULL && receiver_offset != NULL); + // must pass a handle. First figure out the location we use as a handle + Register rHandle = dst.first()->is_stack() ? t1 : dst.first()->as_Register(); + + // See if oop is NULL if it is we need no handle + + if (src.first()->is_stack()) { + + // Oop is already on the stack as an argument + int offset_in_older_frame = src.first()->reg2stack() + SharedRuntime::out_preserve_stack_slots(); + map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + framesize_in_slots)); + if (is_receiver) { + *receiver_offset = (offset_in_older_frame + framesize_in_slots) * VMRegImpl::stack_slot_size; + } + + __ ld(t0, Address(fp, reg2offset_in(src.first()))); + __ la(rHandle, Address(fp, reg2offset_in(src.first()))); + // conditionally move a NULL + Label notZero1; + __ bnez(t0, notZero1); + __ mv(rHandle, zr); + __ bind(notZero1); + } else { + + // Oop is in an a register we must store it to the space we reserve + // on the stack for oop_handles and pass a handle if oop is non-NULL + + const Register rOop = src.first()->as_Register(); + int oop_slot = -1; + if (rOop == j_rarg0) { + oop_slot = 0; + } else if (rOop == j_rarg1) { + oop_slot = 1; + } else if (rOop == j_rarg2) { + oop_slot = 2; + } else if (rOop == j_rarg3) { + oop_slot = 3; + } else if (rOop == j_rarg4) { + oop_slot = 4; + } else if (rOop == j_rarg5) { + oop_slot = 5; + } else if (rOop == j_rarg6) { + oop_slot = 6; + } else { + assert(rOop == j_rarg7, "wrong register"); + oop_slot = 7; + } + + oop_slot = oop_slot * VMRegImpl::slots_per_word + oop_handle_offset; + int offset = oop_slot * VMRegImpl::stack_slot_size; + + map->set_oop(VMRegImpl::stack2reg(oop_slot)); + // Store oop in handle area, may be NULL + __ sd(rOop, Address(sp, offset)); + if (is_receiver) { + *receiver_offset = offset; + } + + //rOop maybe the same as rHandle + if (rOop == rHandle) { + Label isZero; + __ beqz(rOop, isZero); + __ la(rHandle, Address(sp, offset)); + __ bind(isZero); + } else { + Label notZero2; + __ la(rHandle, Address(sp, offset)); + __ bnez(rOop, notZero2); + __ mv(rHandle, zr); + __ bind(notZero2); + } + } + + // If arg is on the stack then place it otherwise it is already in correct reg. + if (dst.first()->is_stack()) { + __ sd(rHandle, Address(sp, reg2offset_out(dst.first()))); + } +} + +// A float arg may have to do float reg int reg conversion +static void float_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { + assert(src.first()->is_stack() && dst.first()->is_stack() || + src.first()->is_reg() && dst.first()->is_reg() || src.first()->is_stack() && dst.first()->is_reg(), "Unexpected error"); + assert_cond(masm != NULL); + if (src.first()->is_stack()) { + if (dst.first()->is_stack()) { + __ lwu(t0, Address(fp, reg2offset_in(src.first()))); + __ sw(t0, Address(sp, reg2offset_out(dst.first()))); + } else if (dst.first()->is_Register()) { + __ lwu(dst.first()->as_Register(), Address(fp, reg2offset_in(src.first()))); + } else { + ShouldNotReachHere(); + } + } else if (src.first() != dst.first()) { + if (src.is_single_phys_reg() && dst.is_single_phys_reg()) { + __ fmv_s(dst.first()->as_FloatRegister(), src.first()->as_FloatRegister()); + } else { + ShouldNotReachHere(); + } + } +} + +// A long move +static void long_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { + assert_cond(masm != NULL); + if (src.first()->is_stack()) { + if (dst.first()->is_stack()) { + // stack to stack + __ ld(t0, Address(fp, reg2offset_in(src.first()))); + __ sd(t0, Address(sp, reg2offset_out(dst.first()))); + } else { + // stack to reg + __ ld(dst.first()->as_Register(), Address(fp, reg2offset_in(src.first()))); + } + } else if (dst.first()->is_stack()) { + // reg to stack + __ sd(src.first()->as_Register(), Address(sp, reg2offset_out(dst.first()))); + } else { + if (dst.first() != src.first()) { + __ mv(dst.first()->as_Register(), src.first()->as_Register()); + } + } +} + +// A double move +static void double_move(MacroAssembler* masm, VMRegPair src, VMRegPair dst) { + assert(src.first()->is_stack() && dst.first()->is_stack() || + src.first()->is_reg() && dst.first()->is_reg() || src.first()->is_stack() && dst.first()->is_reg(), "Unexpected error"); + assert_cond(masm != NULL); + if (src.first()->is_stack()) { + if (dst.first()->is_stack()) { + __ ld(t0, Address(fp, reg2offset_in(src.first()))); + __ sd(t0, Address(sp, reg2offset_out(dst.first()))); + } else if (dst.first()-> is_Register()) { + __ ld(dst.first()->as_Register(), Address(fp, reg2offset_in(src.first()))); + } else { + ShouldNotReachHere(); + } + } else if (src.first() != dst.first()) { + if (src.is_single_phys_reg() && dst.is_single_phys_reg()) { + __ fmv_d(dst.first()->as_FloatRegister(), src.first()->as_FloatRegister()); + } else { + ShouldNotReachHere(); + } + } +} + +void SharedRuntime::save_native_result(MacroAssembler *masm, BasicType ret_type, int frame_slots) { + assert_cond(masm != NULL); + // We always ignore the frame_slots arg and just use the space just below frame pointer + // which by this time is free to use + switch (ret_type) { + case T_FLOAT: + __ fsw(f10, Address(fp, -3 * wordSize)); + break; + case T_DOUBLE: + __ fsd(f10, Address(fp, -3 * wordSize)); + break; + case T_VOID: break; + default: { + __ sd(x10, Address(fp, -3 * wordSize)); + } + } +} + +void SharedRuntime::restore_native_result(MacroAssembler *masm, BasicType ret_type, int frame_slots) { + assert_cond(masm != NULL); + // We always ignore the frame_slots arg and just use the space just below frame pointer + // which by this time is free to use + switch (ret_type) { + case T_FLOAT: + __ flw(f10, Address(fp, -3 * wordSize)); + break; + case T_DOUBLE: + __ fld(f10, Address(fp, -3 * wordSize)); + break; + case T_VOID: break; + default: { + __ ld(x10, Address(fp, -3 * wordSize)); + } + } +} + +static void save_args(MacroAssembler *masm, int arg_count, int first_arg, VMRegPair *args) { + assert_cond(masm != NULL && args != NULL); + RegSet x; + for ( int i = first_arg ; i < arg_count ; i++ ) { + if (args[i].first()->is_Register()) { + x = x + args[i].first()->as_Register(); + } else if (args[i].first()->is_FloatRegister()) { + __ addi(sp, sp, -2 * wordSize); + __ fsd(args[i].first()->as_FloatRegister(), Address(sp, 0)); + } + } + __ push_reg(x, sp); +} + +static void restore_args(MacroAssembler *masm, int arg_count, int first_arg, VMRegPair *args) { + assert_cond(masm != NULL && args != NULL); + RegSet x; + for ( int i = first_arg ; i < arg_count ; i++ ) { + if (args[i].first()->is_Register()) { + x = x + args[i].first()->as_Register(); + } else { + ; + } + } + __ pop_reg(x, sp); + for ( int i = arg_count - 1 ; i >= first_arg ; i-- ) { + if (args[i].first()->is_Register()) { + ; + } else if (args[i].first()->is_FloatRegister()) { + __ fld(args[i].first()->as_FloatRegister(), Address(sp, 0)); + __ add(sp, sp, 2 * wordSize); + } + } +} + +static void rt_call(MacroAssembler* masm, address dest) { + assert_cond(masm != NULL); + CodeBlob *cb = CodeCache::find_blob(dest); + if (cb) { + __ far_call(RuntimeAddress(dest)); + } else { + int32_t offset = 0; + __ la_patchable(t0, RuntimeAddress(dest), offset); + __ jalr(x1, t0, offset); + } +} + +static void verify_oop_args(MacroAssembler* masm, + const methodHandle& method, + const BasicType* sig_bt, + const VMRegPair* regs) { + const Register temp_reg = x9; // not part of any compiled calling seq + if (VerifyOops) { + for (int i = 0; i < method->size_of_parameters(); i++) { + if (sig_bt[i] == T_OBJECT || + sig_bt[i] == T_ARRAY) { + VMReg r = regs[i].first(); + assert(r->is_valid(), "bad oop arg"); + if (r->is_stack()) { + __ ld(temp_reg, Address(sp, r->reg2stack() * VMRegImpl::stack_slot_size)); + __ verify_oop(temp_reg); + } else { + __ verify_oop(r->as_Register()); + } + } + } + } +} + +static void gen_special_dispatch(MacroAssembler* masm, + const methodHandle& method, + const BasicType* sig_bt, + const VMRegPair* regs) { + verify_oop_args(masm, method, sig_bt, regs); + vmIntrinsics::ID iid = method->intrinsic_id(); + + // Now write the args into the outgoing interpreter space + bool has_receiver = false; + Register receiver_reg = noreg; + int member_arg_pos = -1; + Register member_reg = noreg; + int ref_kind = MethodHandles::signature_polymorphic_intrinsic_ref_kind(iid); + if (ref_kind != 0) { + member_arg_pos = method->size_of_parameters() - 1; // trailing MemberName argument + member_reg = x9; // known to be free at this point + has_receiver = MethodHandles::ref_kind_has_receiver(ref_kind); + } else if (iid == vmIntrinsics::_invokeBasic || iid == vmIntrinsics::_linkToNative) { + has_receiver = true; + } else { + fatal("unexpected intrinsic id %d", vmIntrinsics::as_int(iid)); + } + + if (member_reg != noreg) { + // Load the member_arg into register, if necessary. + SharedRuntime::check_member_name_argument_is_last_argument(method, sig_bt, regs); + VMReg r = regs[member_arg_pos].first(); + if (r->is_stack()) { + __ ld(member_reg, Address(sp, r->reg2stack() * VMRegImpl::stack_slot_size)); + } else { + // no data motion is needed + member_reg = r->as_Register(); + } + } + + if (has_receiver) { + // Make sure the receiver is loaded into a register. + assert(method->size_of_parameters() > 0, "oob"); + assert(sig_bt[0] == T_OBJECT, "receiver argument must be an object"); + VMReg r = regs[0].first(); + assert(r->is_valid(), "bad receiver arg"); + if (r->is_stack()) { + // Porting note: This assumes that compiled calling conventions always + // pass the receiver oop in a register. If this is not true on some + // platform, pick a temp and load the receiver from stack. + fatal("receiver always in a register"); + receiver_reg = x12; // known to be free at this point + __ ld(receiver_reg, Address(sp, r->reg2stack() * VMRegImpl::stack_slot_size)); + } else { + // no data motion is needed + receiver_reg = r->as_Register(); + } + } + + // Figure out which address we are really jumping to: + MethodHandles::generate_method_handle_dispatch(masm, iid, + receiver_reg, member_reg, /*for_compiler_entry:*/ true); +} + +// --------------------------------------------------------------------------- +// Generate a native wrapper for a given method. The method takes arguments +// in the Java compiled code convention, marshals them to the native +// convention (handlizes oops, etc), transitions to native, makes the call, +// returns to java state (possibly blocking), unhandlizes any result and +// returns. +// +// Critical native functions are a shorthand for the use of +// GetPrimtiveArrayCritical and disallow the use of any other JNI +// functions. The wrapper is expected to unpack the arguments before +// passing them to the callee and perform checks before and after the +// native call to ensure that they GCLocker +// lock_critical/unlock_critical semantics are followed. Some other +// parts of JNI setup are skipped like the tear down of the JNI handle +// block and the check for pending exceptions it's impossible for them +// to be thrown. +// +// They are roughly structured like this: +// if (GCLocker::needs_gc()) SharedRuntime::block_for_jni_critical() +// tranistion to thread_in_native +// unpack arrray arguments and call native entry point +// check for safepoint in progress +// check if any thread suspend flags are set +// call into JVM and possible unlock the JNI critical +// if a GC was suppressed while in the critical native. +// transition back to thread_in_Java +// return to caller +// +nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, + const methodHandle& method, + int compile_id, + BasicType* in_sig_bt, + VMRegPair* in_regs, + BasicType ret_type) { + if (method->is_method_handle_intrinsic()) { + vmIntrinsics::ID iid = method->intrinsic_id(); + intptr_t start = (intptr_t)__ pc(); + int vep_offset = ((intptr_t)__ pc()) - start; + + // First instruction must be a nop as it may need to be patched on deoptimisation + __ nop(); + gen_special_dispatch(masm, + method, + in_sig_bt, + in_regs); + int frame_complete = ((intptr_t)__ pc()) - start; // not complete, period + __ flush(); + int stack_slots = SharedRuntime::out_preserve_stack_slots(); // no out slots at all, actually + return nmethod::new_native_nmethod(method, + compile_id, + masm->code(), + vep_offset, + frame_complete, + stack_slots / VMRegImpl::slots_per_word, + in_ByteSize(-1), + in_ByteSize(-1), + (OopMapSet*)NULL); + } + address native_func = method->native_function(); + assert(native_func != NULL, "must have function"); + + // An OopMap for lock (and class if static) + OopMapSet *oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + intptr_t start = (intptr_t)__ pc(); + + // We have received a description of where all the java arg are located + // on entry to the wrapper. We need to convert these args to where + // the jni function will expect them. To figure out where they go + // we convert the java signature to a C signature by inserting + // the hidden arguments as arg[0] and possibly arg[1] (static method) + + const int total_in_args = method->size_of_parameters(); + int total_c_args = total_in_args + (method->is_static() ? 2 : 1); + + BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_c_args); + VMRegPair* out_regs = NEW_RESOURCE_ARRAY(VMRegPair, total_c_args); + BasicType* in_elem_bt = NULL; + + int argc = 0; + out_sig_bt[argc++] = T_ADDRESS; + if (method->is_static()) { + out_sig_bt[argc++] = T_OBJECT; + } + + for (int i = 0; i < total_in_args ; i++) { + out_sig_bt[argc++] = in_sig_bt[i]; + } + + // Now figure out where the args must be stored and how much stack space + // they require. + int out_arg_slots = c_calling_convention(out_sig_bt, out_regs, NULL, total_c_args); + + // Compute framesize for the wrapper. We need to handlize all oops in + // incoming registers + + // Calculate the total number of stack slots we will need. + + // First count the abi requirement plus all of the outgoing args + int stack_slots = SharedRuntime::out_preserve_stack_slots() + out_arg_slots; + + // Now the space for the inbound oop handle area + int total_save_slots = 8 * VMRegImpl::slots_per_word; // 8 arguments passed in registers + + int oop_handle_offset = stack_slots; + stack_slots += total_save_slots; + + // Now any space we need for handlizing a klass if static method + + int klass_slot_offset = 0; + int klass_offset = -1; + int lock_slot_offset = 0; + bool is_static = false; + + if (method->is_static()) { + klass_slot_offset = stack_slots; + stack_slots += VMRegImpl::slots_per_word; + klass_offset = klass_slot_offset * VMRegImpl::stack_slot_size; + is_static = true; + } + + // Plus a lock if needed + + if (method->is_synchronized()) { + lock_slot_offset = stack_slots; + stack_slots += VMRegImpl::slots_per_word; + } + + // Now a place (+2) to save return values or temp during shuffling + // + 4 for return address (which we own) and saved fp + stack_slots += 6; + + // Ok The space we have allocated will look like: + // + // + // FP-> | | + // | 2 slots (ra) | + // | 2 slots (fp) | + // |---------------------| + // | 2 slots for moves | + // |---------------------| + // | lock box (if sync) | + // |---------------------| <- lock_slot_offset + // | klass (if static) | + // |---------------------| <- klass_slot_offset + // | oopHandle area | + // |---------------------| <- oop_handle_offset (8 java arg registers) + // | outbound memory | + // | based arguments | + // | | + // |---------------------| + // | | + // SP-> | out_preserved_slots | + // + // + + + // Now compute actual number of stack words we need rounding to make + // stack properly aligned. + stack_slots = align_up(stack_slots, StackAlignmentInSlots); + + int stack_size = stack_slots * VMRegImpl::stack_slot_size; + + // First thing make an ic check to see if we should even be here + + // We are free to use all registers as temps without saving them and + // restoring them except fp. fp is the only callee save register + // as far as the interpreter and the compiler(s) are concerned. + + + const Register ic_reg = t1; + const Register receiver = j_rarg0; + + Label hit; + Label exception_pending; + + assert_different_registers(ic_reg, receiver, t0); + __ verify_oop(receiver); + __ cmp_klass(receiver, ic_reg, t0, hit); + + __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub())); + + // Verified entry point must be aligned + __ align(8); + + __ bind(hit); + + int vep_offset = ((intptr_t)__ pc()) - start; + + // If we have to make this method not-entrant we'll overwrite its + // first instruction with a jump. + __ nop(); + + if (VM_Version::supports_fast_class_init_checks() && method->needs_clinit_barrier()) { + Label L_skip_barrier; + __ mov_metadata(t1, method->method_holder()); // InstanceKlass* + __ clinit_barrier(t1, t0, &L_skip_barrier); + __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + + __ bind(L_skip_barrier); + } + + // Generate stack overflow check + __ bang_stack_with_offset(checked_cast(StackOverflow::stack_shadow_zone_size())); + + // Generate a new frame for the wrapper. + __ enter(); + // -2 because return address is already present and so is saved fp + __ sub(sp, sp, stack_size - 2 * wordSize); + + BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler(); + assert_cond(bs != NULL); + bs->nmethod_entry_barrier(masm); + + // Frame is now completed as far as size and linkage. + int frame_complete = ((intptr_t)__ pc()) - start; + + // We use x18 as the oop handle for the receiver/klass + // It is callee save so it survives the call to native + + const Register oop_handle_reg = x18; + + // + // We immediately shuffle the arguments so that any vm call we have to + // make from here on out (sync slow path, jvmti, etc.) we will have + // captured the oops from our caller and have a valid oopMap for + // them. + + // ----------------- + // The Grand Shuffle + + // The Java calling convention is either equal (linux) or denser (win64) than the + // c calling convention. However the because of the jni_env argument the c calling + // convention always has at least one more (and two for static) arguments than Java. + // Therefore if we move the args from java -> c backwards then we will never have + // a register->register conflict and we don't have to build a dependency graph + // and figure out how to break any cycles. + // + + // Record esp-based slot for receiver on stack for non-static methods + int receiver_offset = -1; + + // This is a trick. We double the stack slots so we can claim + // the oops in the caller's frame. Since we are sure to have + // more args than the caller doubling is enough to make + // sure we can capture all the incoming oop args from the + // caller. + // + OopMap* map = new OopMap(stack_slots * 2, 0 /* arg_slots*/); + assert_cond(map != NULL); + + int float_args = 0; + int int_args = 0; + +#ifdef ASSERT + bool reg_destroyed[RegisterImpl::number_of_registers]; + bool freg_destroyed[FloatRegisterImpl::number_of_registers]; + for ( int r = 0 ; r < RegisterImpl::number_of_registers ; r++ ) { + reg_destroyed[r] = false; + } + for ( int f = 0 ; f < FloatRegisterImpl::number_of_registers ; f++ ) { + freg_destroyed[f] = false; + } + +#endif /* ASSERT */ + + // For JNI natives the incoming and outgoing registers are offset upwards. + GrowableArray arg_order(2 * total_in_args); + VMRegPair tmp_vmreg; + tmp_vmreg.set2(x9->as_VMReg()); + + for (int i = total_in_args - 1, c_arg = total_c_args - 1; i >= 0; i--, c_arg--) { + arg_order.push(i); + arg_order.push(c_arg); + } + + int temploc = -1; + for (int ai = 0; ai < arg_order.length(); ai += 2) { + int i = arg_order.at(ai); + int c_arg = arg_order.at(ai + 1); + __ block_comment(err_msg("mv %d -> %d", i, c_arg)); + assert(c_arg != -1 && i != -1, "wrong order"); +#ifdef ASSERT + if (in_regs[i].first()->is_Register()) { + assert(!reg_destroyed[in_regs[i].first()->as_Register()->encoding()], "destroyed reg!"); + } else if (in_regs[i].first()->is_FloatRegister()) { + assert(!freg_destroyed[in_regs[i].first()->as_FloatRegister()->encoding()], "destroyed reg!"); + } + if (out_regs[c_arg].first()->is_Register()) { + reg_destroyed[out_regs[c_arg].first()->as_Register()->encoding()] = true; + } else if (out_regs[c_arg].first()->is_FloatRegister()) { + freg_destroyed[out_regs[c_arg].first()->as_FloatRegister()->encoding()] = true; + } +#endif /* ASSERT */ + switch (in_sig_bt[i]) { + case T_ARRAY: + case T_OBJECT: + object_move(masm, map, oop_handle_offset, stack_slots, in_regs[i], out_regs[c_arg], + ((i == 0) && (!is_static)), + &receiver_offset); + int_args++; + break; + case T_VOID: + break; + + case T_FLOAT: + float_move(masm, in_regs[i], out_regs[c_arg]); + float_args++; + break; + + case T_DOUBLE: + assert( i + 1 < total_in_args && + in_sig_bt[i + 1] == T_VOID && + out_sig_bt[c_arg + 1] == T_VOID, "bad arg list"); + double_move(masm, in_regs[i], out_regs[c_arg]); + float_args++; + break; + + case T_LONG : + long_move(masm, in_regs[i], out_regs[c_arg]); + int_args++; + break; + + case T_ADDRESS: + assert(false, "found T_ADDRESS in java args"); + break; + + default: + move32_64(masm, in_regs[i], out_regs[c_arg]); + int_args++; + } + } + + // point c_arg at the first arg that is already loaded in case we + // need to spill before we call out + int c_arg = total_c_args - total_in_args; + + // Pre-load a static method's oop into c_rarg1. + if (method->is_static()) { + + // load oop into a register + __ movoop(c_rarg1, + JNIHandles::make_local(method->method_holder()->java_mirror()), + /*immediate*/true); + + // Now handlize the static class mirror it's known not-null. + __ sd(c_rarg1, Address(sp, klass_offset)); + map->set_oop(VMRegImpl::stack2reg(klass_slot_offset)); + + // Now get the handle + __ la(c_rarg1, Address(sp, klass_offset)); + // and protect the arg if we must spill + c_arg--; + } + + // Change state to native (we save the return address in the thread, since it might not + // be pushed on the stack when we do a stack traversal). + // We use the same pc/oopMap repeatedly when we call out + + Label native_return; + __ set_last_Java_frame(sp, noreg, native_return, t0); + + Label dtrace_method_entry, dtrace_method_entry_done; + { + int32_t offset = 0; + __ la_patchable(t0, ExternalAddress((address)&DTraceMethodProbes), offset); + __ lbu(t0, Address(t0, offset)); + __ addw(t0, t0, zr); + __ bnez(t0, dtrace_method_entry); + __ bind(dtrace_method_entry_done); + } + + // RedefineClasses() tracing support for obsolete method entry + if (log_is_enabled(Trace, redefine, class, obsolete)) { + // protect the args we've loaded + save_args(masm, total_c_args, c_arg, out_regs); + __ mov_metadata(c_rarg1, method()); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::rc_trace_method_entry), + xthread, c_rarg1); + restore_args(masm, total_c_args, c_arg, out_regs); + } + + // Lock a synchronized method + + // Register definitions used by locking and unlocking + + const Register swap_reg = x10; + const Register obj_reg = x9; // Will contain the oop + const Register lock_reg = x30; // Address of compiler lock object (BasicLock) + const Register old_hdr = x30; // value of old header at unlock time + const Register tmp = ra; + + Label slow_path_lock; + Label lock_done; + + if (method->is_synchronized()) { + + const int mark_word_offset = BasicLock::displaced_header_offset_in_bytes(); + + // Get the handle (the 2nd argument) + __ mv(oop_handle_reg, c_rarg1); + + // Get address of the box + + __ la(lock_reg, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); + + // Load the oop from the handle + __ ld(obj_reg, Address(oop_handle_reg, 0)); + + if (!UseHeavyMonitors) { + // Load (object->mark() | 1) into swap_reg % x10 + __ ld(t0, Address(obj_reg, oopDesc::mark_offset_in_bytes())); + __ ori(swap_reg, t0, 1); + + // Save (object->mark() | 1) into BasicLock's displaced header + __ sd(swap_reg, Address(lock_reg, mark_word_offset)); + + // src -> dest if dest == x10 else x10 <- dest + { + Label here; + __ cmpxchg_obj_header(x10, lock_reg, obj_reg, t0, lock_done, /*fallthrough*/NULL); + } + + // Test if the oopMark is an obvious stack pointer, i.e., + // 1) (mark & 3) == 0, and + // 2) sp <= mark < mark + os::pagesize() + // These 3 tests can be done by evaluating the following + // expression: ((mark - sp) & (3 - os::vm_page_size())), + // assuming both stack pointer and pagesize have their + // least significant 2 bits clear. + // NOTE: the oopMark is in swap_reg % 10 as the result of cmpxchg + + __ sub(swap_reg, swap_reg, sp); + __ andi(swap_reg, swap_reg, 3 - os::vm_page_size()); + + // Save the test result, for recursive case, the result is zero + __ sd(swap_reg, Address(lock_reg, mark_word_offset)); + __ bnez(swap_reg, slow_path_lock); + } else { + __ j(slow_path_lock); + } + + // Slow path will re-enter here + __ bind(lock_done); + } + + + // Finally just about ready to make the JNI call + + // get JNIEnv* which is first argument to native + __ la(c_rarg0, Address(xthread, in_bytes(JavaThread::jni_environment_offset()))); + + // Now set thread in native + __ la(t1, Address(xthread, JavaThread::thread_state_offset())); + __ mv(t0, _thread_in_native); + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + __ sw(t0, Address(t1)); + + rt_call(masm, native_func); + + __ bind(native_return); + + intptr_t return_pc = (intptr_t) __ pc(); + oop_maps->add_gc_map(return_pc - start, map); + + // Unpack native results. + if (ret_type != T_OBJECT && ret_type != T_ARRAY) { + __ cast_primitive_type(ret_type, x10); + } + + Label safepoint_in_progress, safepoint_in_progress_done; + Label after_transition; + + // Switch thread to "native transition" state before reading the synchronization state. + // This additional state is necessary because reading and testing the synchronization + // state is not atomic w.r.t. GC, as this scenario demonstrates: + // Java thread A, in _thread_in_native state, loads _not_synchronized and is preempted. + // VM thread changes sync state to synchronizing and suspends threads for GC. + // Thread A is resumed to finish this native method, but doesn't block here since it + // didn't see any synchronization is progress, and escapes. + __ mv(t0, _thread_in_native_trans); + + __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); + + // Force this write out before the read below + __ membar(MacroAssembler::AnyAny); + + // check for safepoint operation in progress and/or pending suspend requests + { + // We need an acquire here to ensure that any subsequent load of the + // global SafepointSynchronize::_state flag is ordered after this load + // of the thread-local polling word. We don't want this poll to + // return false (i.e. not safepointing) and a later poll of the global + // SafepointSynchronize::_state spuriously to return true. + // This is to avoid a race when we're in a native->Java transition + // racing the code which wakes up from a safepoint. + + __ safepoint_poll(safepoint_in_progress, true /* at_return */, true /* acquire */, false /* in_nmethod */); + __ lwu(t0, Address(xthread, JavaThread::suspend_flags_offset())); + __ bnez(t0, safepoint_in_progress); + __ bind(safepoint_in_progress_done); + } + + // change thread state + __ la(t1, Address(xthread, JavaThread::thread_state_offset())); + __ mv(t0, _thread_in_Java); + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + __ sw(t0, Address(t1)); + __ bind(after_transition); + + Label reguard; + Label reguard_done; + __ lbu(t0, Address(xthread, JavaThread::stack_guard_state_offset())); + __ mv(t1, StackOverflow::stack_guard_yellow_reserved_disabled); + __ beq(t0, t1, reguard); + __ bind(reguard_done); + + // native result if any is live + + // Unlock + Label unlock_done; + Label slow_path_unlock; + if (method->is_synchronized()) { + + // Get locked oop from the handle we passed to jni + __ ld(obj_reg, Address(oop_handle_reg, 0)); + + Label done; + + if (!UseHeavyMonitors) { + // Simple recursive lock? + __ ld(t0, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); + __ beqz(t0, done); + } + + + // Must save x10 if if it is live now because cmpxchg must use it + if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { + save_native_result(masm, ret_type, stack_slots); + } + + if (!UseHeavyMonitors) { + // get address of the stack lock + __ la(x10, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); + // get old displaced header + __ ld(old_hdr, Address(x10, 0)); + + // Atomic swap old header if oop still contains the stack lock + Label succeed; + __ cmpxchg_obj_header(x10, old_hdr, obj_reg, t0, succeed, &slow_path_unlock); + __ bind(succeed); + } else { + __ j(slow_path_unlock); + } + + // slow path re-enters here + __ bind(unlock_done); + if (ret_type != T_FLOAT && ret_type != T_DOUBLE && ret_type != T_VOID) { + restore_native_result(masm, ret_type, stack_slots); + } + + __ bind(done); + } + + Label dtrace_method_exit, dtrace_method_exit_done; + { + int32_t offset = 0; + __ la_patchable(t0, ExternalAddress((address)&DTraceMethodProbes), offset); + __ lbu(t0, Address(t0, offset)); + __ bnez(t0, dtrace_method_exit); + __ bind(dtrace_method_exit_done); + } + + __ reset_last_Java_frame(false); + + // Unbox oop result, e.g. JNIHandles::resolve result. + if (is_reference_type(ret_type)) { + __ resolve_jobject(x10, xthread, t1); + } + + if (CheckJNICalls) { + // clear_pending_jni_exception_check + __ sd(zr, Address(xthread, JavaThread::pending_jni_exception_check_fn_offset())); + } + + // reset handle block + __ ld(x12, Address(xthread, JavaThread::active_handles_offset())); + __ sd(zr, Address(x12, JNIHandleBlock::top_offset_in_bytes())); + + __ leave(); + + // Any exception pending? + __ ld(t0, Address(xthread, in_bytes(Thread::pending_exception_offset()))); + __ bnez(t0, exception_pending); + + // We're done + __ ret(); + + // Unexpected paths are out of line and go here + + // forward the exception + __ bind(exception_pending); + + // and forward the exception + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + // Slow path locking & unlocking + if (method->is_synchronized()) { + + __ block_comment("Slow path lock {"); + __ bind(slow_path_lock); + + // has last_Java_frame setup. No exceptions so do vanilla call not call_VM + // args are (oop obj, BasicLock* lock, JavaThread* thread) + + // protect the args we've loaded + save_args(masm, total_c_args, c_arg, out_regs); + + __ mv(c_rarg0, obj_reg); + __ mv(c_rarg1, lock_reg); + __ mv(c_rarg2, xthread); + + // Not a leaf but we have last_Java_frame setup as we want + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_locking_C), 3); + restore_args(masm, total_c_args, c_arg, out_regs); + +#ifdef ASSERT + { Label L; + __ ld(t0, Address(xthread, in_bytes(Thread::pending_exception_offset()))); + __ beqz(t0, L); + __ stop("no pending exception allowed on exit from monitorenter"); + __ bind(L); + } +#endif + __ j(lock_done); + + __ block_comment("} Slow path lock"); + + __ block_comment("Slow path unlock {"); + __ bind(slow_path_unlock); + + if (ret_type == T_FLOAT || ret_type == T_DOUBLE) { + save_native_result(masm, ret_type, stack_slots); + } + + __ mv(c_rarg2, xthread); + __ la(c_rarg1, Address(sp, lock_slot_offset * VMRegImpl::stack_slot_size)); + __ mv(c_rarg0, obj_reg); + + // Save pending exception around call to VM (which contains an EXCEPTION_MARK) + // NOTE that obj_reg == x9 currently + __ ld(x9, Address(xthread, in_bytes(Thread::pending_exception_offset()))); + __ sd(zr, Address(xthread, in_bytes(Thread::pending_exception_offset()))); + + rt_call(masm, CAST_FROM_FN_PTR(address, SharedRuntime::complete_monitor_unlocking_C)); + +#ifdef ASSERT + { + Label L; + __ ld(t0, Address(xthread, in_bytes(Thread::pending_exception_offset()))); + __ beqz(t0, L); + __ stop("no pending exception allowed on exit complete_monitor_unlocking_C"); + __ bind(L); + } +#endif /* ASSERT */ + + __ sd(x9, Address(xthread, in_bytes(Thread::pending_exception_offset()))); + + if (ret_type == T_FLOAT || ret_type == T_DOUBLE) { + restore_native_result(masm, ret_type, stack_slots); + } + __ j(unlock_done); + + __ block_comment("} Slow path unlock"); + + } // synchronized + + // SLOW PATH Reguard the stack if needed + + __ bind(reguard); + save_native_result(masm, ret_type, stack_slots); + rt_call(masm, CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)); + restore_native_result(masm, ret_type, stack_slots); + // and continue + __ j(reguard_done); + + // SLOW PATH safepoint + { + __ block_comment("safepoint {"); + __ bind(safepoint_in_progress); + + // Don't use call_VM as it will see a possible pending exception and forward it + // and never return here preventing us from clearing _last_native_pc down below. + // + save_native_result(masm, ret_type, stack_slots); + __ mv(c_rarg0, xthread); +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + int32_t offset = 0; + __ la_patchable(t0, RuntimeAddress(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)), offset); + __ jalr(x1, t0, offset); + + // Restore any method result value + restore_native_result(masm, ret_type, stack_slots); + + __ j(safepoint_in_progress_done); + __ block_comment("} safepoint"); + } + + // SLOW PATH dtrace support + { + __ block_comment("dtrace entry {"); + __ bind(dtrace_method_entry); + + // We have all of the arguments setup at this point. We must not touch any register + // argument registers at this point (what if we save/restore them there are no oop? + + save_args(masm, total_c_args, c_arg, out_regs); + __ mov_metadata(c_rarg1, method()); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), + xthread, c_rarg1); + restore_args(masm, total_c_args, c_arg, out_regs); + __ j(dtrace_method_entry_done); + __ block_comment("} dtrace entry"); + } + + { + __ block_comment("dtrace exit {"); + __ bind(dtrace_method_exit); + save_native_result(masm, ret_type, stack_slots); + __ mov_metadata(c_rarg1, method()); + __ call_VM_leaf( + CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit), + xthread, c_rarg1); + restore_native_result(masm, ret_type, stack_slots); + __ j(dtrace_method_exit_done); + __ block_comment("} dtrace exit"); + } + + __ flush(); + + nmethod *nm = nmethod::new_native_nmethod(method, + compile_id, + masm->code(), + vep_offset, + frame_complete, + stack_slots / VMRegImpl::slots_per_word, + (is_static ? in_ByteSize(klass_offset) : in_ByteSize(receiver_offset)), + in_ByteSize(lock_slot_offset*VMRegImpl::stack_slot_size), + oop_maps); + assert(nm != NULL, "create native nmethod fail!"); + return nm; +} + +// this function returns the adjust size (in number of words) to a c2i adapter +// activation for use during deoptimization +int Deoptimization::last_frame_adjust(int callee_parameters, int callee_locals) { + assert(callee_locals >= callee_parameters, + "test and remove; got more parms than locals"); + if (callee_locals < callee_parameters) { + return 0; // No adjustment for negative locals + } + int diff = (callee_locals - callee_parameters) * Interpreter::stackElementWords; + // diff is counted in stack words + return align_up(diff, 2); +} + +//------------------------------generate_deopt_blob---------------------------- +void SharedRuntime::generate_deopt_blob() { + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + int pad = 0; + CodeBuffer buffer("deopt_blob", 2048 + pad, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + int frame_size_in_words = -1; + OopMap* map = NULL; + OopMapSet *oop_maps = new OopMapSet(); + assert_cond(masm != NULL && oop_maps != NULL); + RegisterSaver reg_saver(COMPILER2_OR_JVMCI != 0); + + // ------------- + // This code enters when returning to a de-optimized nmethod. A return + // address has been pushed on the the stack, and return values are in + // registers. + // If we are doing a normal deopt then we were called from the patched + // nmethod from the point we returned to the nmethod. So the return + // address on the stack is wrong by NativeCall::instruction_size + // We will adjust the value so it looks like we have the original return + // address on the stack (like when we eagerly deoptimized). + // In the case of an exception pending when deoptimizing, we enter + // with a return address on the stack that points after the call we patched + // into the exception handler. We have the following register state from, + // e.g., the forward exception stub (see stubGenerator_riscv.cpp). + // x10: exception oop + // x9: exception handler + // x13: throwing pc + // So in this case we simply jam x13 into the useless return address and + // the stack looks just like we want. + // + // At this point we need to de-opt. We save the argument return + // registers. We call the first C routine, fetch_unroll_info(). This + // routine captures the return values and returns a structure which + // describes the current frame size and the sizes of all replacement frames. + // The current frame is compiled code and may contain many inlined + // functions, each with their own JVM state. We pop the current frame, then + // push all the new frames. Then we call the C routine unpack_frames() to + // populate these frames. Finally unpack_frames() returns us the new target + // address. Notice that callee-save registers are BLOWN here; they have + // already been captured in the vframeArray at the time the return PC was + // patched. + address start = __ pc(); + Label cont; + + // Prolog for non exception case! + + // Save everything in sight. + map = reg_saver.save_live_registers(masm, 0, &frame_size_in_words); + + // Normal deoptimization. Save exec mode for unpack_frames. + __ mvw(xcpool, Deoptimization::Unpack_deopt); // callee-saved + __ j(cont); + + int reexecute_offset = __ pc() - start; + + // Reexecute case + // return address is the pc describes what bci to do re-execute at + + // No need to update map as each call to save_live_registers will produce identical oopmap + (void) reg_saver.save_live_registers(masm, 0, &frame_size_in_words); + + __ mvw(xcpool, Deoptimization::Unpack_reexecute); // callee-saved + __ j(cont); + + int exception_offset = __ pc() - start; + + // Prolog for exception case + + // all registers are dead at this entry point, except for x10, and + // x13 which contain the exception oop and exception pc + // respectively. Set them in TLS and fall thru to the + // unpack_with_exception_in_tls entry point. + + __ sd(x13, Address(xthread, JavaThread::exception_pc_offset())); + __ sd(x10, Address(xthread, JavaThread::exception_oop_offset())); + + int exception_in_tls_offset = __ pc() - start; + + // new implementation because exception oop is now passed in JavaThread + + // Prolog for exception case + // All registers must be preserved because they might be used by LinearScan + // Exceptiop oop and throwing PC are passed in JavaThread + // tos: stack at point of call to method that threw the exception (i.e. only + // args are on the stack, no return address) + + // The return address pushed by save_live_registers will be patched + // later with the throwing pc. The correct value is not available + // now because loading it from memory would destroy registers. + + // NB: The SP at this point must be the SP of the method that is + // being deoptimized. Deoptimization assumes that the frame created + // here by save_live_registers is immediately below the method's SP. + // This is a somewhat fragile mechanism. + + // Save everything in sight. + map = reg_saver.save_live_registers(masm, 0, &frame_size_in_words); + + // Now it is safe to overwrite any register + + // Deopt during an exception. Save exec mode for unpack_frames. + __ li(xcpool, Deoptimization::Unpack_exception); // callee-saved + + // load throwing pc from JavaThread and patch it as the return address + // of the current frame. Then clear the field in JavaThread + + __ ld(x13, Address(xthread, JavaThread::exception_pc_offset())); + __ sd(x13, Address(fp, frame::return_addr_offset * wordSize)); + __ sd(zr, Address(xthread, JavaThread::exception_pc_offset())); + +#ifdef ASSERT + // verify that there is really an exception oop in JavaThread + __ ld(x10, Address(xthread, JavaThread::exception_oop_offset())); + __ verify_oop(x10); + + // verify that there is no pending exception + Label no_pending_exception; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ beqz(t0, no_pending_exception); + __ stop("must not have pending exception here"); + __ bind(no_pending_exception); +#endif + + __ bind(cont); + + // Call C code. Need thread and this frame, but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. + // + // UnrollBlock* fetch_unroll_info(JavaThread* thread) + + // fetch_unroll_info needs to call last_java_frame(). + + Label retaddr; + __ set_last_Java_frame(sp, noreg, retaddr, t0); +#ifdef ASSERT + { + Label L; + __ ld(t0, Address(xthread, + JavaThread::last_Java_fp_offset())); + __ beqz(t0, L); + __ stop("SharedRuntime::generate_deopt_blob: last_Java_fp not cleared"); + __ bind(L); + } +#endif // ASSERT + __ mv(c_rarg0, xthread); + __ mv(c_rarg1, xcpool); + int32_t offset = 0; + __ la_patchable(t0, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::fetch_unroll_info)), offset); + __ jalr(x1, t0, offset); + __ bind(retaddr); + + // Need to have an oopmap that tells fetch_unroll_info where to + // find any register it might need. + oop_maps->add_gc_map(__ pc() - start, map); + + __ reset_last_Java_frame(false); + + // Load UnrollBlock* into x15 + __ mv(x15, x10); + + __ lwu(xcpool, Address(x15, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); + Label noException; + __ li(t0, Deoptimization::Unpack_exception); + __ bne(xcpool, t0, noException); // Was exception pending? + __ ld(x10, Address(xthread, JavaThread::exception_oop_offset())); + __ ld(x13, Address(xthread, JavaThread::exception_pc_offset())); + __ sd(zr, Address(xthread, JavaThread::exception_oop_offset())); + __ sd(zr, Address(xthread, JavaThread::exception_pc_offset())); + + __ verify_oop(x10); + + // Overwrite the result registers with the exception results. + __ sd(x10, Address(sp, reg_saver.reg_offset_in_bytes(x10))); + + __ bind(noException); + + // Only register save data is on the stack. + // Now restore the result registers. Everything else is either dead + // or captured in the vframeArray. + + // Restore fp result register + __ fld(f10, Address(sp, reg_saver.freg_offset_in_bytes(f10))); + // Restore integer result register + __ ld(x10, Address(sp, reg_saver.reg_offset_in_bytes(x10))); + + // Pop all of the register save area off the stack + __ add(sp, sp, frame_size_in_words * wordSize); + + // All of the register save area has been popped of the stack. Only the + // return address remains. + + // Pop all the frames we must move/replace. + // + // Frame picture (youngest to oldest) + // 1: self-frame (no frame link) + // 2: deopting frame (no frame link) + // 3: caller of deopting frame (could be compiled/interpreted). + // + // Note: by leaving the return address of self-frame on the stack + // and using the size of frame 2 to adjust the stack + // when we are done the return to frame 3 will still be on the stack. + + // Pop deoptimized frame + __ lwu(x12, Address(x15, Deoptimization::UnrollBlock::size_of_deoptimized_frame_offset_in_bytes())); + __ sub(x12, x12, 2 * wordSize); + __ add(sp, sp, x12); + __ ld(fp, Address(sp, 0)); + __ ld(ra, Address(sp, wordSize)); + __ addi(sp, sp, 2 * wordSize); + // RA should now be the return address to the caller (3) + +#ifdef ASSERT + // Compilers generate code that bang the stack by as much as the + // interpreter would need. So this stack banging should never + // trigger a fault. Verify that it does not on non product builds. + __ lwu(x9, Address(x15, Deoptimization::UnrollBlock::total_frame_sizes_offset_in_bytes())); + __ bang_stack_size(x9, x12); +#endif + // Load address of array of frame pcs into x12 + __ ld(x12, Address(x15, Deoptimization::UnrollBlock::frame_pcs_offset_in_bytes())); + + // Load address of array of frame sizes into x14 + __ ld(x14, Address(x15, Deoptimization::UnrollBlock::frame_sizes_offset_in_bytes())); + + // Load counter into x13 + __ lwu(x13, Address(x15, Deoptimization::UnrollBlock::number_of_frames_offset_in_bytes())); + + // Now adjust the caller's stack to make up for the extra locals + // but record the original sp so that we can save it in the skeletal interpreter + // frame and the stack walking of interpreter_sender will get the unextended sp + // value and not the "real" sp value. + + const Register sender_sp = x16; + + __ mv(sender_sp, sp); + __ lwu(x9, Address(x15, + Deoptimization::UnrollBlock:: + caller_adjustment_offset_in_bytes())); + __ sub(sp, sp, x9); + + // Push interpreter frames in a loop + __ li(t0, 0xDEADDEAD); // Make a recognizable pattern + __ mv(t1, t0); + Label loop; + __ bind(loop); + __ ld(x9, Address(x14, 0)); // Load frame size + __ addi(x14, x14, wordSize); + __ sub(x9, x9, 2 * wordSize); // We'll push pc and fp by hand + __ ld(ra, Address(x12, 0)); // Load pc + __ addi(x12, x12, wordSize); + __ enter(); // Save old & set new fp + __ sub(sp, sp, x9); // Prolog + // This value is corrected by layout_activation_impl + __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + __ sd(sender_sp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable + __ mv(sender_sp, sp); // Pass sender_sp to next frame + __ addi(x13, x13, -1); // Decrement counter + __ bnez(x13, loop); + + // Re-push self-frame + __ ld(ra, Address(x12)); + __ enter(); + + // Allocate a full sized register save area. We subtract 2 because + // enter() just pushed 2 words + __ sub(sp, sp, (frame_size_in_words - 2) * wordSize); + + // Restore frame locals after moving the frame + __ fsd(f10, Address(sp, reg_saver.freg_offset_in_bytes(f10))); + __ sd(x10, Address(sp, reg_saver.reg_offset_in_bytes(x10))); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // restore return values to their stack-slots with the new SP. + // + // void Deoptimization::unpack_frames(JavaThread* thread, int exec_mode) + + // Use fp because the frames look interpreted now + // Don't need the precise return PC here, just precise enough to point into this code blob. + address the_pc = __ pc(); + __ set_last_Java_frame(sp, fp, the_pc, t0); + + __ mv(c_rarg0, xthread); + __ mv(c_rarg1, xcpool); // second arg: exec_mode + offset = 0; + __ la_patchable(t0, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)), offset); + __ jalr(x1, t0, offset); + + // Set an oopmap for the call site + // Use the same PC we used for the last java frame + oop_maps->add_gc_map(the_pc - start, + new OopMap(frame_size_in_words, 0)); + + // Clear fp AND pc + __ reset_last_Java_frame(true); + + // Collect return values + __ fld(f10, Address(sp, reg_saver.freg_offset_in_bytes(f10))); + __ ld(x10, Address(sp, reg_saver.reg_offset_in_bytes(x10))); + + // Pop self-frame. + __ leave(); // Epilog + + // Jump to interpreter + __ ret(); + + // Make sure all code is generated + masm->flush(); + + _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words); + assert(_deopt_blob != NULL, "create deoptimization blob fail!"); + _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset); +} + +// Number of stack slots between incoming argument block and the start of +// a new frame. The PROLOG must add this many slots to the stack. The +// EPILOG must remove this many slots. +// RISCV needs two words for RA (return address) and FP (frame pointer). +uint SharedRuntime::in_preserve_stack_slots() { + return 2 * VMRegImpl::slots_per_word; +} + +uint SharedRuntime::out_preserve_stack_slots() { + return 0; +} + +#ifdef COMPILER2 +//------------------------------generate_uncommon_trap_blob-------------------- +void SharedRuntime::generate_uncommon_trap_blob() { + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + CodeBuffer buffer("uncommon_trap_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + assert_cond(masm != NULL); + + assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + + address start = __ pc(); + + // Push self-frame. We get here with a return address in RA + // and sp should be 16 byte aligned + // push fp and retaddr by hand + __ addi(sp, sp, -2 * wordSize); + __ sd(ra, Address(sp, wordSize)); + __ sd(fp, Address(sp, 0)); + // we don't expect an arg reg save area +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + // compiler left unloaded_class_index in j_rarg0 move to where the + // runtime expects it. + __ addiw(c_rarg1, j_rarg0, 0); + + // we need to set the past SP to the stack pointer of the stub frame + // and the pc to the address where this runtime call will return + // although actually any pc in this code blob will do). + Label retaddr; + __ set_last_Java_frame(sp, noreg, retaddr, t0); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // capture callee-saved registers as well as return values. + // + // UnrollBlock* uncommon_trap(JavaThread* thread, jint unloaded_class_index, jint exec_mode) + // + // n.b. 3 gp args, 0 fp args, integral return type + + __ mv(c_rarg0, xthread); + __ mvw(c_rarg2, (unsigned)Deoptimization::Unpack_uncommon_trap); + int32_t offset = 0; + __ la_patchable(t0, + RuntimeAddress(CAST_FROM_FN_PTR(address, + Deoptimization::uncommon_trap)), offset); + __ jalr(x1, t0, offset); + __ bind(retaddr); + + // Set an oopmap for the call site + OopMapSet* oop_maps = new OopMapSet(); + OopMap* map = new OopMap(SimpleRuntimeFrame::framesize, 0); + assert_cond(oop_maps != NULL && map != NULL); + + // location of fp is known implicitly by the frame sender code + + oop_maps->add_gc_map(__ pc() - start, map); + + __ reset_last_Java_frame(false); + + // move UnrollBlock* into x14 + __ mv(x14, x10); + +#ifdef ASSERT + { Label L; + __ lwu(t0, Address(x14, Deoptimization::UnrollBlock::unpack_kind_offset_in_bytes())); + __ mvw(t1, Deoptimization::Unpack_uncommon_trap); + __ beq(t0, t1, L); + __ stop("SharedRuntime::generate_deopt_blob: last_Java_fp not cleared"); + __ bind(L); + } +#endif + + // Pop all the frames we must move/replace. + // + // Frame picture (youngest to oldest) + // 1: self-frame (no frame link) + // 2: deopting frame (no frame link) + // 3: caller of deopting frame (could be compiled/interpreted). + + __ add(sp, sp, (SimpleRuntimeFrame::framesize) << LogBytesPerInt); // Epilog! + + // Pop deoptimized frame (int) + __ lwu(x12, Address(x14, + Deoptimization::UnrollBlock:: + size_of_deoptimized_frame_offset_in_bytes())); + __ sub(x12, x12, 2 * wordSize); + __ add(sp, sp, x12); + __ ld(fp, sp, 0); + __ ld(ra, sp, wordSize); + __ addi(sp, sp, 2 * wordSize); + // RA should now be the return address to the caller (3) frame + +#ifdef ASSERT + // Compilers generate code that bang the stack by as much as the + // interpreter would need. So this stack banging should never + // trigger a fault. Verify that it does not on non product builds. + __ lwu(x11, Address(x14, + Deoptimization::UnrollBlock:: + total_frame_sizes_offset_in_bytes())); + __ bang_stack_size(x11, x12); +#endif + + // Load address of array of frame pcs into x12 (address*) + __ ld(x12, Address(x14, + Deoptimization::UnrollBlock::frame_pcs_offset_in_bytes())); + + // Load address of array of frame sizes into x15 (intptr_t*) + __ ld(x15, Address(x14, + Deoptimization::UnrollBlock:: + frame_sizes_offset_in_bytes())); + + // Counter + __ lwu(x13, Address(x14, + Deoptimization::UnrollBlock:: + number_of_frames_offset_in_bytes())); // (int) + + // Now adjust the caller's stack to make up for the extra locals but + // record the original sp so that we can save it in the skeletal + // interpreter frame and the stack walking of interpreter_sender + // will get the unextended sp value and not the "real" sp value. + + const Register sender_sp = t1; // temporary register + + __ lwu(x11, Address(x14, + Deoptimization::UnrollBlock:: + caller_adjustment_offset_in_bytes())); // (int) + __ mv(sender_sp, sp); + __ sub(sp, sp, x11); + + // Push interpreter frames in a loop + Label loop; + __ bind(loop); + __ ld(x11, Address(x15, 0)); // Load frame size + __ sub(x11, x11, 2 * wordSize); // We'll push pc and fp by hand + __ ld(ra, Address(x12, 0)); // Save return address + __ enter(); // and old fp & set new fp + __ sub(sp, sp, x11); // Prolog + __ sd(sender_sp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // Make it walkable + // This value is corrected by layout_activation_impl + __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + __ mv(sender_sp, sp); // Pass sender_sp to next frame + __ add(x15, x15, wordSize); // Bump array pointer (sizes) + __ add(x12, x12, wordSize); // Bump array pointer (pcs) + __ subw(x13, x13, 1); // Decrement counter + __ bgtz(x13, loop); + __ ld(ra, Address(x12, 0)); // save final return address + // Re-push self-frame + __ enter(); // & old fp & set new fp + + // Use fp because the frames look interpreted now + // Save "the_pc" since it cannot easily be retrieved using the last_java_SP after we aligned SP. + // Don't need the precise return PC here, just precise enough to point into this code blob. + address the_pc = __ pc(); + __ set_last_Java_frame(sp, fp, the_pc, t0); + + // Call C code. Need thread but NOT official VM entry + // crud. We cannot block on this call, no GC can happen. Call should + // restore return values to their stack-slots with the new SP. + // + // BasicType unpack_frames(JavaThread* thread, int exec_mode) + // + + // n.b. 2 gp args, 0 fp args, integral return type + + // sp should already be aligned + __ mv(c_rarg0, xthread); + __ mvw(c_rarg1, (unsigned)Deoptimization::Unpack_uncommon_trap); + offset = 0; + __ la_patchable(t0, RuntimeAddress(CAST_FROM_FN_PTR(address, Deoptimization::unpack_frames)), offset); + __ jalr(x1, t0, offset); + + // Set an oopmap for the call site + // Use the same PC we used for the last java frame + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + // Clear fp AND pc + __ reset_last_Java_frame(true); + + // Pop self-frame. + __ leave(); // Epilog + + // Jump to interpreter + __ ret(); + + // Make sure all code is generated + masm->flush(); + + _uncommon_trap_blob = UncommonTrapBlob::create(&buffer, oop_maps, + SimpleRuntimeFrame::framesize >> 1); +} +#endif // COMPILER2 + +//------------------------------generate_handler_blob------ +// +// Generate a special Compile2Runtime blob that saves all registers, +// and setup oopmap. +// +SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) { + ResourceMark rm; + OopMapSet *oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + OopMap* map = NULL; + + // Allocate space for the code. Setup code generation tools. + CodeBuffer buffer("handler_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + assert_cond(masm != NULL); + + address start = __ pc(); + address call_pc = NULL; + int frame_size_in_words = -1; + bool cause_return = (poll_type == POLL_AT_RETURN); + RegisterSaver reg_saver(poll_type == POLL_AT_VECTOR_LOOP /* save_vectors */); + + // Save Integer and Float registers. + map = reg_saver.save_live_registers(masm, 0, &frame_size_in_words); + + // The following is basically a call_VM. However, we need the precise + // address of the call in order to generate an oopmap. Hence, we do all the + // work outselves. + + Label retaddr; + __ set_last_Java_frame(sp, noreg, retaddr, t0); + + // The return address must always be correct so that frame constructor never + // sees an invalid pc. + + if (!cause_return) { + // overwrite the return address pushed by save_live_registers + // Additionally, x18 is a callee-saved register so we can look at + // it later to determine if someone changed the return address for + // us! + __ ld(x18, Address(xthread, JavaThread::saved_exception_pc_offset())); + __ sd(x18, Address(fp, frame::return_addr_offset * wordSize)); + } + + // Do the call + __ mv(c_rarg0, xthread); + int32_t offset = 0; + __ la_patchable(t0, RuntimeAddress(call_ptr), offset); + __ jalr(x1, t0, offset); + __ bind(retaddr); + + // Set an oopmap for the call site. This oopmap will map all + // oop-registers and debug-info registers as callee-saved. This + // will allow deoptimization at this safepoint to find all possible + // debug-info recordings, as well as let GC find all oops. + + oop_maps->add_gc_map( __ pc() - start, map); + + Label noException; + + __ reset_last_Java_frame(false); + + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ beqz(t0, noException); + + // Exception pending + + reg_saver.restore_live_registers(masm); + + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + // No exception case + __ bind(noException); + + Label no_adjust, bail; + if (!cause_return) { + // If our stashed return pc was modified by the runtime we avoid touching it + __ ld(t0, Address(fp, frame::return_addr_offset * wordSize)); + __ bne(x18, t0, no_adjust); + +#ifdef ASSERT + // Verify the correct encoding of the poll we're about to skip. + // See NativeInstruction::is_lwu_to_zr() + __ lwu(t0, Address(x18)); + __ andi(t1, t0, 0b0000011); + __ mv(t2, 0b0000011); + __ bne(t1, t2, bail); // 0-6:0b0000011 + __ srli(t1, t0, 7); + __ andi(t1, t1, 0b00000); + __ bnez(t1, bail); // 7-11:0b00000 + __ srli(t1, t0, 12); + __ andi(t1, t1, 0b110); + __ mv(t2, 0b110); + __ bne(t1, t2, bail); // 12-14:0b110 +#endif + // Adjust return pc forward to step over the safepoint poll instruction + __ add(x18, x18, NativeInstruction::instruction_size); + __ sd(x18, Address(fp, frame::return_addr_offset * wordSize)); + } + + __ bind(no_adjust); + // Normal exit, restore registers and exit. + + reg_saver.restore_live_registers(masm); + __ ret(); + +#ifdef ASSERT + __ bind(bail); + __ stop("Attempting to adjust pc to skip safepoint poll but the return point is not what we expected"); +#endif + + // Make sure all code is generated + masm->flush(); + + // Fill-out other meta info + return SafepointBlob::create(&buffer, oop_maps, frame_size_in_words); +} + +// +// generate_resolve_blob - call resolution (static/virtual/opt-virtual/ic-miss +// +// Generate a stub that calls into vm to find out the proper destination +// of a java call. All the argument registers are live at this point +// but since this is generic code we don't know what they are and the caller +// must do any gc of the args. +// +RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const char* name) { + assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before"); + + // allocate space for the code + ResourceMark rm; + + CodeBuffer buffer(name, 1000, 512); + MacroAssembler* masm = new MacroAssembler(&buffer); + assert_cond(masm != NULL); + + int frame_size_in_words = -1; + RegisterSaver reg_saver(false /* save_vectors */); + + OopMapSet *oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + OopMap* map = NULL; + + int start = __ offset(); + + map = reg_saver.save_live_registers(masm, 0, &frame_size_in_words); + + int frame_complete = __ offset(); + + { + Label retaddr; + __ set_last_Java_frame(sp, noreg, retaddr, t0); + + __ mv(c_rarg0, xthread); + int32_t offset = 0; + __ la_patchable(t0, RuntimeAddress(destination), offset); + __ jalr(x1, t0, offset); + __ bind(retaddr); + } + + // Set an oopmap for the call site. + // We need this not only for callee-saved registers, but also for volatile + // registers that the compiler might be keeping live across a safepoint. + + oop_maps->add_gc_map( __ offset() - start, map); + + // x10 contains the address we are going to jump to assuming no exception got installed + + // clear last_Java_sp + __ reset_last_Java_frame(false); + // check for pending exceptions + Label pending; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ bnez(t0, pending); + + // get the returned Method* + __ get_vm_result_2(xmethod, xthread); + __ sd(xmethod, Address(sp, reg_saver.reg_offset_in_bytes(xmethod))); + + // x10 is where we want to jump, overwrite t0 which is saved and temporary + __ sd(x10, Address(sp, reg_saver.reg_offset_in_bytes(t0))); + reg_saver.restore_live_registers(masm); + + // We are back the the original state on entry and ready to go. + + __ jr(t0); + + // Pending exception after the safepoint + + __ bind(pending); + + reg_saver.restore_live_registers(masm); + + // exception pending => remove activation and forward to exception handler + + __ sd(zr, Address(xthread, JavaThread::vm_result_offset())); + + __ ld(x10, Address(xthread, Thread::pending_exception_offset())); + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + // ------------- + // make sure all code is generated + masm->flush(); + + // return the blob + return RuntimeStub::new_runtime_stub(name, &buffer, frame_complete, frame_size_in_words, oop_maps, true); +} + +#ifdef COMPILER2 +RuntimeStub* SharedRuntime::make_native_invoker(address call_target, + int shadow_space_bytes, + const GrowableArray& input_registers, + const GrowableArray& output_registers) { + Unimplemented(); + return nullptr; +} + +//------------------------------generate_exception_blob--------------------------- +// creates exception blob at the end +// Using exception blob, this code is jumped from a compiled method. +// (see emit_exception_handler in riscv.ad file) +// +// Given an exception pc at a call we call into the runtime for the +// handler in this method. This handler might merely restore state +// (i.e. callee save registers) unwind the frame and jump to the +// exception handler for the nmethod if there is no Java level handler +// for the nmethod. +// +// This code is entered with a jmp. +// +// Arguments: +// x10: exception oop +// x13: exception pc +// +// Results: +// x10: exception oop +// x13: exception pc in caller +// destination: exception handler of caller +// +// Note: the exception pc MUST be at a call (precise debug information) +// Registers x10, x13, x12, x14, x15, t0 are not callee saved. +// + +void OptoRuntime::generate_exception_blob() { + assert(!OptoRuntime::is_callee_saved_register(R13_num), ""); + assert(!OptoRuntime::is_callee_saved_register(R10_num), ""); + assert(!OptoRuntime::is_callee_saved_register(R12_num), ""); + + assert(SimpleRuntimeFrame::framesize % 4 == 0, "sp not 16-byte aligned"); + + // Allocate space for the code + ResourceMark rm; + // Setup code generation tools + CodeBuffer buffer("exception_blob", 2048, 1024); + MacroAssembler* masm = new MacroAssembler(&buffer); + assert_cond(masm != NULL); + + // TODO check various assumptions made here + // + // make sure we do so before running this + + address start = __ pc(); + + // push fp and retaddr by hand + // Exception pc is 'return address' for stack walker + __ addi(sp, sp, -2 * wordSize); + __ sd(ra, Address(sp, wordSize)); + __ sd(fp, Address(sp)); + // there are no callee save registers and we don't expect an + // arg reg save area +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + // Store exception in Thread object. We cannot pass any arguments to the + // handle_exception call, since we do not want to make any assumption + // about the size of the frame where the exception happened in. + __ sd(x10, Address(xthread, JavaThread::exception_oop_offset())); + __ sd(x13, Address(xthread, JavaThread::exception_pc_offset())); + + // This call does all the hard work. It checks if an exception handler + // exists in the method. + // If so, it returns the handler address. + // If not, it prepares for stack-unwinding, restoring the callee-save + // registers of the frame being removed. + // + // address OptoRuntime::handle_exception_C(JavaThread* thread) + // + // n.b. 1 gp arg, 0 fp args, integral return type + + // the stack should always be aligned + address the_pc = __ pc(); + __ set_last_Java_frame(sp, noreg, the_pc, t0); + __ mv(c_rarg0, xthread); + int32_t offset = 0; + __ la_patchable(t0, RuntimeAddress(CAST_FROM_FN_PTR(address, OptoRuntime::handle_exception_C)), offset); + __ jalr(x1, t0, offset); + + + // handle_exception_C is a special VM call which does not require an explicit + // instruction sync afterwards. + + // Set an oopmap for the call site. This oopmap will only be used if we + // are unwinding the stack. Hence, all locations will be dead. + // Callee-saved registers will be the same as the frame above (i.e., + // handle_exception_stub), since they were restored when we got the + // exception. + + OopMapSet* oop_maps = new OopMapSet(); + assert_cond(oop_maps != NULL); + + oop_maps->add_gc_map(the_pc - start, new OopMap(SimpleRuntimeFrame::framesize, 0)); + + __ reset_last_Java_frame(false); + + // Restore callee-saved registers + + // fp is an implicitly saved callee saved register (i.e. the calling + // convention will save restore it in prolog/epilog) Other than that + // there are no callee save registers now that adapter frames are gone. + // and we dont' expect an arg reg save area + __ ld(fp, Address(sp)); + __ ld(x13, Address(sp, wordSize)); + __ addi(sp, sp , 2 * wordSize); + + // x10: exception handler + + // We have a handler in x10 (could be deopt blob). + __ mv(t0, x10); + + // Get the exception oop + __ ld(x10, Address(xthread, JavaThread::exception_oop_offset())); + // Get the exception pc in case we are deoptimized + __ ld(x14, Address(xthread, JavaThread::exception_pc_offset())); +#ifdef ASSERT + __ sd(zr, Address(xthread, JavaThread::exception_handler_pc_offset())); + __ sd(zr, Address(xthread, JavaThread::exception_pc_offset())); +#endif + // Clear the exception oop so GC no longer processes it as a root. + __ sd(zr, Address(xthread, JavaThread::exception_oop_offset())); + + // x10: exception oop + // t0: exception handler + // x14: exception pc + // Jump to handler + + __ jr(t0); + + // Make sure all code is generated + masm->flush(); + + // Set exception blob + _exception_blob = ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1); +} +#endif // COMPILER2 diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp new file mode 100644 index 00000000000..b3fdd04db1b --- /dev/null +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -0,0 +1,3864 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "compiler/oopMap.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "interpreter/interpreter.hpp" +#include "memory/universe.hpp" +#include "nativeInst_riscv.hpp" +#include "oops/instanceOop.hpp" +#include "oops/method.hpp" +#include "oops/objArrayKlass.hpp" +#include "oops/oop.inline.hpp" +#include "prims/methodHandles.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/handles.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubCodeGenerator.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/thread.inline.hpp" +#include "utilities/align.hpp" +#include "utilities/powerOfTwo.hpp" +#ifdef COMPILER2 +#include "opto/runtime.hpp" +#endif +#if INCLUDE_ZGC +#include "gc/z/zThreadLocalData.hpp" +#endif + +// Declaration and definition of StubGenerator (no .hpp file). +// For a more detailed description of the stub routine structure +// see the comment in stubRoutines.hpp + +#undef __ +#define __ _masm-> + +#ifdef PRODUCT +#define BLOCK_COMMENT(str) /* nothing */ +#else +#define BLOCK_COMMENT(str) __ block_comment(str) +#endif + +#define BIND(label) bind(label); BLOCK_COMMENT(#label ":") + +// Stub Code definitions + +class StubGenerator: public StubCodeGenerator { + private: + +#ifdef PRODUCT +#define inc_counter_np(counter) ((void)0) +#else + void inc_counter_np_(int& counter) { + __ la(t1, ExternalAddress((address)&counter)); + __ lwu(t0, Address(t1, 0)); + __ addiw(t0, t0, 1); + __ sw(t0, Address(t1, 0)); + } +#define inc_counter_np(counter) \ + BLOCK_COMMENT("inc_counter " #counter); \ + inc_counter_np_(counter); +#endif + + // Call stubs are used to call Java from C + // + // Arguments: + // c_rarg0: call wrapper address address + // c_rarg1: result address + // c_rarg2: result type BasicType + // c_rarg3: method Method* + // c_rarg4: (interpreter) entry point address + // c_rarg5: parameters intptr_t* + // c_rarg6: parameter size (in words) int + // c_rarg7: thread Thread* + // + // There is no return from the stub itself as any Java result + // is written to result + // + // we save x1 (ra) as the return PC at the base of the frame and + // link x8 (fp) below it as the frame pointer installing sp (x2) + // into fp. + // + // we save x10-x17, which accounts for all the c arguments. + // + // TODO: strictly do we need to save them all? they are treated as + // volatile by C so could we omit saving the ones we are going to + // place in global registers (thread? method?) or those we only use + // during setup of the Java call? + // + // we don't need to save x5 which C uses as an indirect result location + // return register. + // + // we don't need to save x6-x7 and x28-x31 which both C and Java treat as + // volatile + // + // we save x18-x27 which Java uses as temporary registers and C + // expects to be callee-save + // + // so the stub frame looks like this when we enter Java code + // + // [ return_from_Java ] <--- sp + // [ argument word n ] + // ... + // -22 [ argument word 1 ] + // -21 [ saved x27 ] <--- sp_after_call + // -20 [ saved x26 ] + // -19 [ saved x25 ] + // -18 [ saved x24 ] + // -17 [ saved x23 ] + // -16 [ saved x22 ] + // -15 [ saved x21 ] + // -14 [ saved x20 ] + // -13 [ saved x19 ] + // -12 [ saved x18 ] + // -11 [ saved x9 ] + // -10 [ call wrapper (x10) ] + // -9 [ result (x11) ] + // -8 [ result type (x12) ] + // -7 [ method (x13) ] + // -6 [ entry point (x14) ] + // -5 [ parameters (x15) ] + // -4 [ parameter size (x16) ] + // -3 [ thread (x17) ] + // -2 [ saved fp (x8) ] + // -1 [ saved ra (x1) ] + // 0 [ ] <--- fp == saved sp (x2) + + // Call stub stack layout word offsets from fp + enum call_stub_layout { + sp_after_call_off = -21, + + x27_off = -21, + x26_off = -20, + x25_off = -19, + x24_off = -18, + x23_off = -17, + x22_off = -16, + x21_off = -15, + x20_off = -14, + x19_off = -13, + x18_off = -12, + x9_off = -11, + + call_wrapper_off = -10, + result_off = -9, + result_type_off = -8, + method_off = -7, + entry_point_off = -6, + parameters_off = -5, + parameter_size_off = -4, + thread_off = -3, + fp_f = -2, + retaddr_off = -1, + }; + + address generate_call_stub(address& return_address) { + assert((int)frame::entry_frame_after_call_words == -(int)sp_after_call_off + 1 && + (int)frame::entry_frame_call_wrapper_offset == (int)call_wrapper_off, + "adjust this code"); + + StubCodeMark mark(this, "StubRoutines", "call_stub"); + address start = __ pc(); + + const Address sp_after_call (fp, sp_after_call_off * wordSize); + + const Address call_wrapper (fp, call_wrapper_off * wordSize); + const Address result (fp, result_off * wordSize); + const Address result_type (fp, result_type_off * wordSize); + const Address method (fp, method_off * wordSize); + const Address entry_point (fp, entry_point_off * wordSize); + const Address parameters (fp, parameters_off * wordSize); + const Address parameter_size(fp, parameter_size_off * wordSize); + + const Address thread (fp, thread_off * wordSize); + + const Address x27_save (fp, x27_off * wordSize); + const Address x26_save (fp, x26_off * wordSize); + const Address x25_save (fp, x25_off * wordSize); + const Address x24_save (fp, x24_off * wordSize); + const Address x23_save (fp, x23_off * wordSize); + const Address x22_save (fp, x22_off * wordSize); + const Address x21_save (fp, x21_off * wordSize); + const Address x20_save (fp, x20_off * wordSize); + const Address x19_save (fp, x19_off * wordSize); + const Address x18_save (fp, x18_off * wordSize); + + const Address x9_save (fp, x9_off * wordSize); + + // stub code + + address riscv_entry = __ pc(); + + // set up frame and move sp to end of save area + __ enter(); + __ addi(sp, fp, sp_after_call_off * wordSize); + + // save register parameters and Java temporary/global registers + // n.b. we save thread even though it gets installed in + // xthread because we want to sanity check tp later + __ sd(c_rarg7, thread); + __ sw(c_rarg6, parameter_size); + __ sd(c_rarg5, parameters); + __ sd(c_rarg4, entry_point); + __ sd(c_rarg3, method); + __ sd(c_rarg2, result_type); + __ sd(c_rarg1, result); + __ sd(c_rarg0, call_wrapper); + + __ sd(x9, x9_save); + + __ sd(x18, x18_save); + __ sd(x19, x19_save); + __ sd(x20, x20_save); + __ sd(x21, x21_save); + __ sd(x22, x22_save); + __ sd(x23, x23_save); + __ sd(x24, x24_save); + __ sd(x25, x25_save); + __ sd(x26, x26_save); + __ sd(x27, x27_save); + + // install Java thread in global register now we have saved + // whatever value it held + __ mv(xthread, c_rarg7); + + // And method + __ mv(xmethod, c_rarg3); + + // set up the heapbase register + __ reinit_heapbase(); + +#ifdef ASSERT + // make sure we have no pending exceptions + { + Label L; + __ ld(t0, Address(xthread, in_bytes(Thread::pending_exception_offset()))); + __ beqz(t0, L); + __ stop("StubRoutines::call_stub: entered with pending exception"); + __ BIND(L); + } +#endif + // pass parameters if any + __ mv(esp, sp); + __ slli(t0, c_rarg6, LogBytesPerWord); + __ sub(t0, sp, t0); // Move SP out of the way + __ andi(sp, t0, -2 * wordSize); + + BLOCK_COMMENT("pass parameters if any"); + Label parameters_done; + // parameter count is still in c_rarg6 + // and parameter pointer identifying param 1 is in c_rarg5 + __ beqz(c_rarg6, parameters_done); + + address loop = __ pc(); + __ ld(t0, c_rarg5, 0); + __ addi(c_rarg5, c_rarg5, wordSize); + __ addi(c_rarg6, c_rarg6, -1); + __ push_reg(t0); + __ bgtz(c_rarg6, loop); + + __ BIND(parameters_done); + + // call Java entry -- passing methdoOop, and current sp + // xmethod: Method* + // x30: sender sp + BLOCK_COMMENT("call Java function"); + __ mv(x30, sp); + __ jalr(c_rarg4); + + // save current address for use by exception handling code + + return_address = __ pc(); + + // store result depending on type (everything that is not + // T_OBJECT, T_LONG, T_FLOAT or T_DOUBLE is treated as T_INT) + // n.b. this assumes Java returns an integral result in x10 + // and a floating result in j_farg0 + __ ld(j_rarg2, result); + Label is_long, is_float, is_double, exit; + __ ld(j_rarg1, result_type); + __ li(t0, (u1)T_OBJECT); + __ beq(j_rarg1, t0, is_long); + __ li(t0, (u1)T_LONG); + __ beq(j_rarg1, t0, is_long); + __ li(t0, (u1)T_FLOAT); + __ beq(j_rarg1, t0, is_float); + __ li(t0, (u1)T_DOUBLE); + __ beq(j_rarg1, t0, is_double); + + // handle T_INT case + __ sw(x10, Address(j_rarg2)); + + __ BIND(exit); + + // pop parameters + __ addi(esp, fp, sp_after_call_off * wordSize); + +#ifdef ASSERT + // verify that threads correspond + { + Label L, S; + __ ld(t0, thread); + __ bne(xthread, t0, S); + __ get_thread(t0); + __ beq(xthread, t0, L); + __ BIND(S); + __ stop("StubRoutines::call_stub: threads must correspond"); + __ BIND(L); + } +#endif + + // restore callee-save registers + __ ld(x27, x27_save); + __ ld(x26, x26_save); + __ ld(x25, x25_save); + __ ld(x24, x24_save); + __ ld(x23, x23_save); + __ ld(x22, x22_save); + __ ld(x21, x21_save); + __ ld(x20, x20_save); + __ ld(x19, x19_save); + __ ld(x18, x18_save); + + __ ld(x9, x9_save); + + __ ld(c_rarg0, call_wrapper); + __ ld(c_rarg1, result); + __ ld(c_rarg2, result_type); + __ ld(c_rarg3, method); + __ ld(c_rarg4, entry_point); + __ ld(c_rarg5, parameters); + __ ld(c_rarg6, parameter_size); + __ ld(c_rarg7, thread); + + // leave frame and return to caller + __ leave(); + __ ret(); + + // handle return types different from T_INT + + __ BIND(is_long); + __ sd(x10, Address(j_rarg2, 0)); + __ j(exit); + + __ BIND(is_float); + __ fsw(j_farg0, Address(j_rarg2, 0), t0); + __ j(exit); + + __ BIND(is_double); + __ fsd(j_farg0, Address(j_rarg2, 0), t0); + __ j(exit); + + return start; + } + + // Return point for a Java call if there's an exception thrown in + // Java code. The exception is caught and transformed into a + // pending exception stored in JavaThread that can be tested from + // within the VM. + // + // Note: Usually the parameters are removed by the callee. In case + // of an exception crossing an activation frame boundary, that is + // not the case if the callee is compiled code => need to setup the + // sp. + // + // x10: exception oop + + address generate_catch_exception() { + StubCodeMark mark(this, "StubRoutines", "catch_exception"); + address start = __ pc(); + + // same as in generate_call_stub(): + const Address thread(fp, thread_off * wordSize); + +#ifdef ASSERT + // verify that threads correspond + { + Label L, S; + __ ld(t0, thread); + __ bne(xthread, t0, S); + __ get_thread(t0); + __ beq(xthread, t0, L); + __ bind(S); + __ stop("StubRoutines::catch_exception: threads must correspond"); + __ bind(L); + } +#endif + + // set pending exception + __ verify_oop(x10); + + __ sd(x10, Address(xthread, Thread::pending_exception_offset())); + __ mv(t0, (address)__FILE__); + __ sd(t0, Address(xthread, Thread::exception_file_offset())); + __ mv(t0, (int)__LINE__); + __ sw(t0, Address(xthread, Thread::exception_line_offset())); + + // complete return to VM + assert(StubRoutines::_call_stub_return_address != NULL, + "_call_stub_return_address must have been generated before"); + __ j(StubRoutines::_call_stub_return_address); + + return start; + } + + // Continuation point for runtime calls returning with a pending + // exception. The pending exception check happened in the runtime + // or native call stub. The pending exception in Thread is + // converted into a Java-level exception. + // + // Contract with Java-level exception handlers: + // x10: exception + // x13: throwing pc + // + // NOTE: At entry of this stub, exception-pc must be in RA !! + + // NOTE: this is always used as a jump target within generated code + // so it just needs to be generated code with no x86 prolog + + address generate_forward_exception() { + StubCodeMark mark(this, "StubRoutines", "forward exception"); + address start = __ pc(); + + // Upon entry, RA points to the return address returning into + // Java (interpreted or compiled) code; i.e., the return address + // becomes the throwing pc. + // + // Arguments pushed before the runtime call are still on the stack + // but the exception handler will reset the stack pointer -> + // ignore them. A potential result in registers can be ignored as + // well. + +#ifdef ASSERT + // make sure this code is only executed if there is a pending exception + { + Label L; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ bnez(t0, L); + __ stop("StubRoutines::forward exception: no pending exception (1)"); + __ bind(L); + } +#endif + + // compute exception handler into x9 + + // call the VM to find the handler address associated with the + // caller address. pass thread in x10 and caller pc (ret address) + // in x11. n.b. the caller pc is in ra, unlike x86 where it is on + // the stack. + __ mv(c_rarg1, ra); + // ra will be trashed by the VM call so we move it to x9 + // (callee-saved) because we also need to pass it to the handler + // returned by this call. + __ mv(x9, ra); + BLOCK_COMMENT("call exception_handler_for_return_address"); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, + SharedRuntime::exception_handler_for_return_address), + xthread, c_rarg1); + // we should not really care that ra is no longer the callee + // address. we saved the value the handler needs in x9 so we can + // just copy it to x13. however, the C2 handler will push its own + // frame and then calls into the VM and the VM code asserts that + // the PC for the frame above the handler belongs to a compiled + // Java method. So, we restore ra here to satisfy that assert. + __ mv(ra, x9); + // setup x10 & x13 & clear pending exception + __ mv(x13, x9); + __ mv(x9, x10); + __ ld(x10, Address(xthread, Thread::pending_exception_offset())); + __ sd(zr, Address(xthread, Thread::pending_exception_offset())); + +#ifdef ASSERT + // make sure exception is set + { + Label L; + __ bnez(x10, L); + __ stop("StubRoutines::forward exception: no pending exception (2)"); + __ bind(L); + } +#endif + + // continue at exception handler + // x10: exception + // x13: throwing pc + // x9: exception handler + __ verify_oop(x10); + __ jr(x9); + + return start; + } + + // Non-destructive plausibility checks for oops + // + // Arguments: + // x10: oop to verify + // t0: error message + // + // Stack after saving c_rarg3: + // [tos + 0]: saved c_rarg3 + // [tos + 1]: saved c_rarg2 + // [tos + 2]: saved ra + // [tos + 3]: saved t1 + // [tos + 4]: saved x10 + // [tos + 5]: saved t0 + address generate_verify_oop() { + + StubCodeMark mark(this, "StubRoutines", "verify_oop"); + address start = __ pc(); + + Label exit, error; + + __ push_reg(0x3000, sp); // save c_rarg2 and c_rarg3 + + __ la(c_rarg2, ExternalAddress((address) StubRoutines::verify_oop_count_addr())); + __ ld(c_rarg3, Address(c_rarg2)); + __ add(c_rarg3, c_rarg3, 1); + __ sd(c_rarg3, Address(c_rarg2)); + + // object is in x10 + // make sure object is 'reasonable' + __ beqz(x10, exit); // if obj is NULL it is OK + +#if INCLUDE_ZGC + if (UseZGC) { + // Check if mask is good. + // verifies that ZAddressBadMask & x10 == 0 + __ ld(c_rarg3, Address(xthread, ZThreadLocalData::address_bad_mask_offset())); + __ andr(c_rarg2, x10, c_rarg3); + __ bnez(c_rarg2, error); + } +#endif + + // Check if the oop is in the right area of memory + __ mv(c_rarg3, (intptr_t) Universe::verify_oop_mask()); + __ andr(c_rarg2, x10, c_rarg3); + __ mv(c_rarg3, (intptr_t) Universe::verify_oop_bits()); + + // Compare c_rarg2 and c_rarg3. + __ bne(c_rarg2, c_rarg3, error); + + // make sure klass is 'reasonable', which is not zero. + __ load_klass(x10, x10); // get klass + __ beqz(x10, error); // if klass is NULL it is broken + + // return if everything seems ok + __ bind(exit); + + __ pop_reg(0x3000, sp); // pop c_rarg2 and c_rarg3 + __ ret(); + + // handle errors + __ bind(error); + __ pop_reg(0x3000, sp); // pop c_rarg2 and c_rarg3 + + __ pusha(); + // debug(char* msg, int64_t pc, int64_t regs[]) + __ mv(c_rarg0, t0); // pass address of error message + __ mv(c_rarg1, ra); // pass return address + __ mv(c_rarg2, sp); // pass address of regs on stack +#ifndef PRODUCT + assert(frame::arg_reg_save_area_bytes == 0, "not expecting frame reg save area"); +#endif + BLOCK_COMMENT("call MacroAssembler::debug"); + int32_t offset = 0; + __ movptr_with_offset(t0, CAST_FROM_FN_PTR(address, MacroAssembler::debug64), offset); + __ jalr(x1, t0, offset); + __ ebreak(); + + return start; + } + + // The inner part of zero_words(). + // + // Inputs: + // x28: the HeapWord-aligned base address of an array to zero. + // x29: the count in HeapWords, x29 > 0. + // + // Returns x28 and x29, adjusted for the caller to clear. + // x28: the base address of the tail of words left to clear. + // x29: the number of words in the tail. + // x29 < MacroAssembler::zero_words_block_size. + + address generate_zero_blocks() { + Label done; + + const Register base = x28, cnt = x29; + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "zero_blocks"); + address start = __ pc(); + + { + // Clear the remaining blocks. + Label loop; + __ sub(cnt, cnt, MacroAssembler::zero_words_block_size); + __ bltz(cnt, done); + __ bind(loop); + for (int i = 0; i < MacroAssembler::zero_words_block_size; i++) { + __ sd(zr, Address(base, 0)); + __ add(base, base, 8); + } + __ sub(cnt, cnt, MacroAssembler::zero_words_block_size); + __ bgez(cnt, loop); + __ bind(done); + __ add(cnt, cnt, MacroAssembler::zero_words_block_size); + } + + __ ret(); + + return start; + } + + typedef enum { + copy_forwards = 1, + copy_backwards = -1 + } copy_direction; + + // Bulk copy of blocks of 8 words. + // + // count is a count of words. + // + // Precondition: count >= 8 + // + // Postconditions: + // + // The least significant bit of count contains the remaining count + // of words to copy. The rest of count is trash. + // + // s and d are adjusted to point to the remaining words to copy + // + void generate_copy_longs(Label &start, Register s, Register d, Register count, + copy_direction direction) { + int unit = wordSize * direction; + int bias = wordSize; + + const Register tmp_reg0 = x13, tmp_reg1 = x14, tmp_reg2 = x15, tmp_reg3 = x16, + tmp_reg4 = x17, tmp_reg5 = x7, tmp_reg6 = x28, tmp_reg7 = x29; + + const Register stride = x30; + + assert_different_registers(t0, tmp_reg0, tmp_reg1, tmp_reg2, tmp_reg3, + tmp_reg4, tmp_reg5, tmp_reg6, tmp_reg7); + assert_different_registers(s, d, count, t0); + + Label again, drain; + const char* stub_name = NULL; + if (direction == copy_forwards) { + stub_name = "forward_copy_longs"; + } else { + stub_name = "backward_copy_longs"; + } + StubCodeMark mark(this, "StubRoutines", stub_name); + __ align(CodeEntryAlignment); + __ bind(start); + + if (direction == copy_forwards) { + __ sub(s, s, bias); + __ sub(d, d, bias); + } + +#ifdef ASSERT + // Make sure we are never given < 8 words + { + Label L; + + __ li(t0, 8); + __ bge(count, t0, L); + __ stop("genrate_copy_longs called with < 8 words"); + __ bind(L); + } +#endif + + __ ld(tmp_reg0, Address(s, 1 * unit)); + __ ld(tmp_reg1, Address(s, 2 * unit)); + __ ld(tmp_reg2, Address(s, 3 * unit)); + __ ld(tmp_reg3, Address(s, 4 * unit)); + __ ld(tmp_reg4, Address(s, 5 * unit)); + __ ld(tmp_reg5, Address(s, 6 * unit)); + __ ld(tmp_reg6, Address(s, 7 * unit)); + __ ld(tmp_reg7, Address(s, 8 * unit)); + __ addi(s, s, 8 * unit); + + __ sub(count, count, 16); + __ bltz(count, drain); + + __ bind(again); + + __ sd(tmp_reg0, Address(d, 1 * unit)); + __ sd(tmp_reg1, Address(d, 2 * unit)); + __ sd(tmp_reg2, Address(d, 3 * unit)); + __ sd(tmp_reg3, Address(d, 4 * unit)); + __ sd(tmp_reg4, Address(d, 5 * unit)); + __ sd(tmp_reg5, Address(d, 6 * unit)); + __ sd(tmp_reg6, Address(d, 7 * unit)); + __ sd(tmp_reg7, Address(d, 8 * unit)); + + __ ld(tmp_reg0, Address(s, 1 * unit)); + __ ld(tmp_reg1, Address(s, 2 * unit)); + __ ld(tmp_reg2, Address(s, 3 * unit)); + __ ld(tmp_reg3, Address(s, 4 * unit)); + __ ld(tmp_reg4, Address(s, 5 * unit)); + __ ld(tmp_reg5, Address(s, 6 * unit)); + __ ld(tmp_reg6, Address(s, 7 * unit)); + __ ld(tmp_reg7, Address(s, 8 * unit)); + + __ addi(s, s, 8 * unit); + __ addi(d, d, 8 * unit); + + __ sub(count, count, 8); + __ bgez(count, again); + + // Drain + __ bind(drain); + + __ sd(tmp_reg0, Address(d, 1 * unit)); + __ sd(tmp_reg1, Address(d, 2 * unit)); + __ sd(tmp_reg2, Address(d, 3 * unit)); + __ sd(tmp_reg3, Address(d, 4 * unit)); + __ sd(tmp_reg4, Address(d, 5 * unit)); + __ sd(tmp_reg5, Address(d, 6 * unit)); + __ sd(tmp_reg6, Address(d, 7 * unit)); + __ sd(tmp_reg7, Address(d, 8 * unit)); + __ addi(d, d, 8 * unit); + + { + Label L1, L2; + __ andi(t0, count, 4); + __ beqz(t0, L1); + + __ ld(tmp_reg0, Address(s, 1 * unit)); + __ ld(tmp_reg1, Address(s, 2 * unit)); + __ ld(tmp_reg2, Address(s, 3 * unit)); + __ ld(tmp_reg3, Address(s, 4 * unit)); + __ addi(s, s, 4 * unit); + + __ sd(tmp_reg0, Address(d, 1 * unit)); + __ sd(tmp_reg1, Address(d, 2 * unit)); + __ sd(tmp_reg2, Address(d, 3 * unit)); + __ sd(tmp_reg3, Address(d, 4 * unit)); + __ addi(d, d, 4 * unit); + + __ bind(L1); + + if (direction == copy_forwards) { + __ addi(s, s, bias); + __ addi(d, d, bias); + } + + __ andi(t0, count, 2); + __ beqz(t0, L2); + if (direction == copy_backwards) { + __ addi(s, s, 2 * unit); + __ ld(tmp_reg0, Address(s)); + __ ld(tmp_reg1, Address(s, wordSize)); + __ addi(d, d, 2 * unit); + __ sd(tmp_reg0, Address(d)); + __ sd(tmp_reg1, Address(d, wordSize)); + } else { + __ ld(tmp_reg0, Address(s)); + __ ld(tmp_reg1, Address(s, wordSize)); + __ addi(s, s, 2 * unit); + __ sd(tmp_reg0, Address(d)); + __ sd(tmp_reg1, Address(d, wordSize)); + __ addi(d, d, 2 * unit); + } + __ bind(L2); + } + + __ ret(); + } + + Label copy_f, copy_b; + + // All-singing all-dancing memory copy. + // + // Copy count units of memory from s to d. The size of a unit is + // step, which can be positive or negative depending on the direction + // of copy. If is_aligned is false, we align the source address. + // + /* + * if (is_aligned) { + * goto copy_8_bytes; + * } + * bool is_backwards = step < 0; + * int granularity = uabs(step); + * count = count * granularity; * count bytes + * + * if (is_backwards) { + * s += count; + * d += count; + * } + * + * count limit maybe greater than 16, for better performance + * if (count < 16) { + * goto copy_small; + * } + * + * if ((dst % 8) == (src % 8)) { + * aligned; + * goto copy8; + * } + * + * copy_small: + * load element one by one; + * done; + */ + + typedef void (MacroAssembler::*copy_insn)(Register Rd, const Address &adr, Register temp); + + void copy_memory_v(Register s, Register d, Register count, Register tmp, int step) { + bool is_backward = step < 0; + int granularity = uabs(step); + + const Register src = x30, dst = x31, vl = x14, cnt = x15, tmp1 = x16, tmp2 = x17; + assert_different_registers(s, d, cnt, vl, tmp, tmp1, tmp2); + Assembler::SEW sew = Assembler::elembytes_to_sew(granularity); + Label loop_forward, loop_backward, done; + + __ mv(dst, d); + __ mv(src, s); + __ mv(cnt, count); + + __ bind(loop_forward); + __ vsetvli(vl, cnt, sew, Assembler::m8); + if (is_backward) { + __ bne(vl, cnt, loop_backward); + } + + __ vlex_v(v0, src, sew); + __ sub(cnt, cnt, vl); + __ slli(vl, vl, (int)sew); + __ add(src, src, vl); + + __ vsex_v(v0, dst, sew); + __ add(dst, dst, vl); + __ bnez(cnt, loop_forward); + + if (is_backward) { + __ j(done); + + __ bind(loop_backward); + __ sub(tmp, cnt, vl); + __ slli(tmp, tmp, sew); + __ add(tmp1, s, tmp); + __ vlex_v(v0, tmp1, sew); + __ add(tmp2, d, tmp); + __ vsex_v(v0, tmp2, sew); + __ sub(cnt, cnt, vl); + __ bnez(cnt, loop_forward); + __ bind(done); + } + } + + void copy_memory(bool is_aligned, Register s, Register d, + Register count, Register tmp, int step) { + if (UseRVV) { + return copy_memory_v(s, d, count, tmp, step); + } + + bool is_backwards = step < 0; + int granularity = uabs(step); + + const Register src = x30, dst = x31, cnt = x15, tmp3 = x16, tmp4 = x17; + + Label same_aligned; + Label copy8, copy_small, done; + + copy_insn ld_arr = NULL, st_arr = NULL; + switch (granularity) { + case 1 : + ld_arr = (copy_insn)&MacroAssembler::lbu; + st_arr = (copy_insn)&MacroAssembler::sb; + break; + case 2 : + ld_arr = (copy_insn)&MacroAssembler::lhu; + st_arr = (copy_insn)&MacroAssembler::sh; + break; + case 4 : + ld_arr = (copy_insn)&MacroAssembler::lwu; + st_arr = (copy_insn)&MacroAssembler::sw; + break; + case 8 : + ld_arr = (copy_insn)&MacroAssembler::ld; + st_arr = (copy_insn)&MacroAssembler::sd; + break; + default : + ShouldNotReachHere(); + } + + __ beqz(count, done); + __ slli(cnt, count, exact_log2(granularity)); + if (is_backwards) { + __ add(src, s, cnt); + __ add(dst, d, cnt); + } else { + __ mv(src, s); + __ mv(dst, d); + } + + if (is_aligned) { + __ addi(tmp, cnt, -8); + __ bgez(tmp, copy8); + __ j(copy_small); + } + + __ mv(tmp, 16); + __ blt(cnt, tmp, copy_small); + + __ xorr(tmp, src, dst); + __ andi(tmp, tmp, 0b111); + __ bnez(tmp, copy_small); + + __ bind(same_aligned); + __ andi(tmp, src, 0b111); + __ beqz(tmp, copy8); + if (is_backwards) { + __ addi(src, src, step); + __ addi(dst, dst, step); + } + (_masm->*ld_arr)(tmp3, Address(src), t0); + (_masm->*st_arr)(tmp3, Address(dst), t0); + if (!is_backwards) { + __ addi(src, src, step); + __ addi(dst, dst, step); + } + __ addi(cnt, cnt, -granularity); + __ beqz(cnt, done); + __ j(same_aligned); + + __ bind(copy8); + if (is_backwards) { + __ addi(src, src, -wordSize); + __ addi(dst, dst, -wordSize); + } + __ ld(tmp3, Address(src)); + __ sd(tmp3, Address(dst)); + if (!is_backwards) { + __ addi(src, src, wordSize); + __ addi(dst, dst, wordSize); + } + __ addi(cnt, cnt, -wordSize); + __ addi(tmp4, cnt, -8); + __ bgez(tmp4, copy8); // cnt >= 8, do next loop + + __ beqz(cnt, done); + + __ bind(copy_small); + if (is_backwards) { + __ addi(src, src, step); + __ addi(dst, dst, step); + } + (_masm->*ld_arr)(tmp3, Address(src), t0); + (_masm->*st_arr)(tmp3, Address(dst), t0); + if (!is_backwards) { + __ addi(src, src, step); + __ addi(dst, dst, step); + } + __ addi(cnt, cnt, -granularity); + __ bgtz(cnt, copy_small); + + __ bind(done); + } + + // Scan over array at a for count oops, verifying each one. + // Preserves a and count, clobbers t0 and t1. + void verify_oop_array(size_t size, Register a, Register count, Register temp) { + Label loop, end; + __ mv(t1, zr); + __ slli(t0, count, exact_log2(size)); + __ bind(loop); + __ bgeu(t1, t0, end); + + __ add(temp, a, t1); + if (size == (size_t)wordSize) { + __ ld(temp, Address(temp, 0)); + __ verify_oop(temp); + } else { + __ lwu(temp, Address(temp, 0)); + __ decode_heap_oop(temp); // calls verify_oop + } + __ add(t1, t1, size); + __ j(loop); + __ bind(end); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary + // ignored + // is_oop - true => oop array, so generate store check code + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // + // If 'from' and/or 'to' are aligned on 4-byte boundaries, we let + // the hardware handle it. The two dwords within qwords that span + // cache line boundaries will still be loaded and stored atomicly. + // + // Side Effects: + // disjoint_int_copy_entry is set to the no-overlap entry point + // used by generate_conjoint_int_oop_copy(). + // + address generate_disjoint_copy(size_t size, bool aligned, bool is_oop, address* entry, + const char* name, bool dest_uninitialized = false) { + const Register s = c_rarg0, d = c_rarg1, count = c_rarg2; + RegSet saved_reg = RegSet::of(s, d, count); + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + __ enter(); + + if (entry != NULL) { + *entry = __ pc(); + // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) + BLOCK_COMMENT("Entry:"); + } + + DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_DISJOINT; + if (dest_uninitialized) { + decorators |= IS_DEST_UNINITIALIZED; + } + if (aligned) { + decorators |= ARRAYCOPY_ALIGNED; + } + + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->arraycopy_prologue(_masm, decorators, is_oop, s, d, count, saved_reg); + + if (is_oop) { + // save regs before copy_memory + __ push_reg(RegSet::of(d, count), sp); + } + + { + // UnsafeCopyMemory page error: continue after ucm + bool add_entry = !is_oop && (!aligned || sizeof(jlong) == size); + UnsafeCopyMemoryMark ucmm(this, add_entry, true); + copy_memory(aligned, s, d, count, t0, size); + } + + if (is_oop) { + __ pop_reg(RegSet::of(d, count), sp); + if (VerifyOops) { + verify_oop_array(size, d, count, t2); + } + } + + bs->arraycopy_epilogue(_masm, decorators, is_oop, d, count, t0, RegSet()); + + __ leave(); + __ mv(x10, zr); // return 0 + __ ret(); + return start; + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary + // ignored + // is_oop - true => oop array, so generate store check code + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // + // If 'from' and/or 'to' are aligned on 4-byte boundaries, we let + // the hardware handle it. The two dwords within qwords that span + // cache line boundaries will still be loaded and stored atomicly. + // + address generate_conjoint_copy(size_t size, bool aligned, bool is_oop, address nooverlap_target, + address* entry, const char* name, + bool dest_uninitialized = false) { + const Register s = c_rarg0, d = c_rarg1, count = c_rarg2; + RegSet saved_regs = RegSet::of(s, d, count); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + __ enter(); + + if (entry != NULL) { + *entry = __ pc(); + // caller can pass a 64-bit byte count here (from Unsafe.copyMemory) + BLOCK_COMMENT("Entry:"); + } + + // use fwd copy when (d-s) above_equal (count*size) + __ sub(t0, d, s); + __ slli(t1, count, exact_log2(size)); + __ bgeu(t0, t1, nooverlap_target); + + DecoratorSet decorators = IN_HEAP | IS_ARRAY; + if (dest_uninitialized) { + decorators |= IS_DEST_UNINITIALIZED; + } + if (aligned) { + decorators |= ARRAYCOPY_ALIGNED; + } + + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->arraycopy_prologue(_masm, decorators, is_oop, s, d, count, saved_regs); + + if (is_oop) { + // save regs before copy_memory + __ push_reg(RegSet::of(d, count), sp); + } + + { + // UnsafeCopyMemory page error: continue after ucm + bool add_entry = !is_oop && (!aligned || sizeof(jlong) == size); + UnsafeCopyMemoryMark ucmm(this, add_entry, true); + copy_memory(aligned, s, d, count, t0, -size); + } + + if (is_oop) { + __ pop_reg(RegSet::of(d, count), sp); + if (VerifyOops) { + verify_oop_array(size, d, count, t2); + } + } + bs->arraycopy_epilogue(_masm, decorators, is_oop, d, count, t0, RegSet()); + __ leave(); + __ mv(x10, zr); // return 0 + __ ret(); + return start; + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // + // If 'from' and/or 'to' are aligned on 4-, 2-, or 1-byte boundaries, + // we let the hardware handle it. The one to eight bytes within words, + // dwords or qwords that span cache line boundaries will still be loaded + // and stored atomically. + // + // Side Effects: + // disjoint_byte_copy_entry is set to the no-overlap entry point // + // If 'from' and/or 'to' are aligned on 4-, 2-, or 1-byte boundaries, + // we let the hardware handle it. The one to eight bytes within words, + // dwords or qwords that span cache line boundaries will still be loaded + // and stored atomically. + // + // Side Effects: + // disjoint_byte_copy_entry is set to the no-overlap entry point + // used by generate_conjoint_byte_copy(). + // + address generate_disjoint_byte_copy(bool aligned, address* entry, const char* name) { + const bool not_oop = false; + return generate_disjoint_copy(sizeof (jbyte), aligned, not_oop, entry, name); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // + // If 'from' and/or 'to' are aligned on 4-, 2-, or 1-byte boundaries, + // we let the hardware handle it. The one to eight bytes within words, + // dwords or qwords that span cache line boundaries will still be loaded + // and stored atomically. + // + address generate_conjoint_byte_copy(bool aligned, address nooverlap_target, + address* entry, const char* name) { + const bool not_oop = false; + return generate_conjoint_copy(sizeof (jbyte), aligned, not_oop, nooverlap_target, entry, name); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // + // If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we + // let the hardware handle it. The two or four words within dwords + // or qwords that span cache line boundaries will still be loaded + // and stored atomically. + // + // Side Effects: + // disjoint_short_copy_entry is set to the no-overlap entry point + // used by generate_conjoint_short_copy(). + // + address generate_disjoint_short_copy(bool aligned, + address* entry, const char* name) { + const bool not_oop = false; + return generate_disjoint_copy(sizeof (jshort), aligned, not_oop, entry, name); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // + // If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we + // let the hardware handle it. The two or four words within dwords + // or qwords that span cache line boundaries will still be loaded + // and stored atomically. + // + address generate_conjoint_short_copy(bool aligned, address nooverlap_target, + address* entry, const char* name) { + const bool not_oop = false; + return generate_conjoint_copy(sizeof (jshort), aligned, not_oop, nooverlap_target, entry, name); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // + // If 'from' and/or 'to' are aligned on 4-byte boundaries, we let + // the hardware handle it. The two dwords within qwords that span + // cache line boundaries will still be loaded and stored atomicly. + // + // Side Effects: + // disjoint_int_copy_entry is set to the no-overlap entry point + // used by generate_conjoint_int_oop_copy(). + // + address generate_disjoint_int_copy(bool aligned, address* entry, + const char* name, bool dest_uninitialized = false) { + const bool not_oop = false; + return generate_disjoint_copy(sizeof (jint), aligned, not_oop, entry, name); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord == 8-byte boundary + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // + // If 'from' and/or 'to' are aligned on 4-byte boundaries, we let + // the hardware handle it. The two dwords within qwords that span + // cache line boundaries will still be loaded and stored atomicly. + // + address generate_conjoint_int_copy(bool aligned, address nooverlap_target, + address* entry, const char* name, + bool dest_uninitialized = false) { + const bool not_oop = false; + return generate_conjoint_copy(sizeof (jint), aligned, not_oop, nooverlap_target, entry, name); + } + + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord boundary == 8 bytes + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as size_t, can be zero + // + // Side Effects: + // disjoint_oop_copy_entry or disjoint_long_copy_entry is set to the + // no-overlap entry point used by generate_conjoint_long_oop_copy(). + // + address generate_disjoint_long_copy(bool aligned, address* entry, + const char* name, bool dest_uninitialized = false) { + const bool not_oop = false; + return generate_disjoint_copy(sizeof (jlong), aligned, not_oop, entry, name); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord boundary == 8 bytes + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as size_t, can be zero + // + address generate_conjoint_long_copy(bool aligned, + address nooverlap_target, address* entry, + const char* name, bool dest_uninitialized = false) { + const bool not_oop = false; + return generate_conjoint_copy(sizeof (jlong), aligned, not_oop, nooverlap_target, entry, name); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord boundary == 8 bytes + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as size_t, can be zero + // + // Side Effects: + // disjoint_oop_copy_entry or disjoint_long_copy_entry is set to the + // no-overlap entry point used by generate_conjoint_long_oop_copy(). + // + address generate_disjoint_oop_copy(bool aligned, address* entry, + const char* name, bool dest_uninitialized) { + const bool is_oop = true; + const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); + return generate_disjoint_copy(size, aligned, is_oop, entry, name, dest_uninitialized); + } + + // Arguments: + // aligned - true => Input and output aligned on a HeapWord boundary == 8 bytes + // ignored + // name - stub name string + // + // Inputs: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as size_t, can be zero + // + address generate_conjoint_oop_copy(bool aligned, + address nooverlap_target, address* entry, + const char* name, bool dest_uninitialized) { + const bool is_oop = true; + const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); + return generate_conjoint_copy(size, aligned, is_oop, nooverlap_target, entry, + name, dest_uninitialized); + } + + // Helper for generating a dynamic type check. + // Smashes t0, t1. + void generate_type_check(Register sub_klass, + Register super_check_offset, + Register super_klass, + Label& L_success) { + assert_different_registers(sub_klass, super_check_offset, super_klass); + + BLOCK_COMMENT("type_check:"); + + Label L_miss; + + __ check_klass_subtype_fast_path(sub_klass, super_klass, noreg, &L_success, &L_miss, NULL, super_check_offset); + __ check_klass_subtype_slow_path(sub_klass, super_klass, noreg, noreg, &L_success, NULL); + + // Fall through on failure! + __ BIND(L_miss); + } + + // + // Generate checkcasting array copy stub + // + // Input: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - element count, treated as ssize_t, can be zero + // c_rarg3 - size_t ckoff (super_check_offset) + // c_rarg4 - oop ckval (super_klass) + // + // Output: + // x10 == 0 - success + // x10 == -1^K - failure, where K is partial transfer count + // + address generate_checkcast_copy(const char* name, address* entry, + bool dest_uninitialized = false) { + Label L_load_element, L_store_element, L_do_card_marks, L_done, L_done_pop; + + // Input registers (after setup_arg_regs) + const Register from = c_rarg0; // source array address + const Register to = c_rarg1; // destination array address + const Register count = c_rarg2; // elementscount + const Register ckoff = c_rarg3; // super_check_offset + const Register ckval = c_rarg4; // super_klass + + RegSet wb_pre_saved_regs = RegSet::range(c_rarg0, c_rarg4); + RegSet wb_post_saved_regs = RegSet::of(count); + + // Registers used as temps (x7, x9, x18 are save-on-entry) + const Register count_save = x19; // orig elementscount + const Register start_to = x18; // destination array start address + const Register copied_oop = x7; // actual oop copied + const Register r9_klass = x9; // oop._klass + + //--------------------------------------------------------------- + // Assembler stub will be used for this call to arraycopy + // if the two arrays are subtypes of Object[] but the + // destination array type is not equal to or a supertype + // of the source type. Each element must be separately + // checked. + + assert_different_registers(from, to, count, ckoff, ckval, start_to, + copied_oop, r9_klass, count_save); + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // Caller of this entry point must set up the argument registers. + if (entry != NULL) { + *entry = __ pc(); + BLOCK_COMMENT("Entry:"); + } + + // Empty array: Nothing to do + __ beqz(count, L_done); + + __ push_reg(RegSet::of(x7, x9, x18, x19), sp); + +#ifdef ASSERT + BLOCK_COMMENT("assert consistent ckoff/ckval"); + // The ckoff and ckval must be mutually consistent, + // even though caller generates both. + { Label L; + int sco_offset = in_bytes(Klass::super_check_offset_offset()); + __ lwu(start_to, Address(ckval, sco_offset)); + __ beq(ckoff, start_to, L); + __ stop("super_check_offset inconsistent"); + __ bind(L); + } +#endif //ASSERT + + DecoratorSet decorators = IN_HEAP | IS_ARRAY | ARRAYCOPY_CHECKCAST | ARRAYCOPY_DISJOINT; + bool is_oop = true; + if (dest_uninitialized) { + decorators |= IS_DEST_UNINITIALIZED; + } + + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->arraycopy_prologue(_masm, decorators, is_oop, from, to, count, wb_pre_saved_regs); + + // save the original count + __ mv(count_save, count); + + // Copy from low to high addresses + __ mv(start_to, to); // Save destination array start address + __ j(L_load_element); + + // ======== begin loop ======== + // (Loop is rotated; its entry is L_load_element.) + // Loop control: + // for count to 0 do + // copied_oop = load_heap_oop(from++) + // ... generate_type_check ... + // store_heap_oop(to++, copied_oop) + // end + + __ align(OptoLoopAlignment); + + __ BIND(L_store_element); + __ store_heap_oop(Address(to, 0), copied_oop, noreg, noreg, AS_RAW); // store the oop + __ add(to, to, UseCompressedOops ? 4 : 8); + __ sub(count, count, 1); + __ beqz(count, L_do_card_marks); + + // ======== loop entry is here ======== + __ BIND(L_load_element); + __ load_heap_oop(copied_oop, Address(from, 0), noreg, noreg, AS_RAW); // load the oop + __ add(from, from, UseCompressedOops ? 4 : 8); + __ beqz(copied_oop, L_store_element); + + __ load_klass(r9_klass, copied_oop);// query the object klass + generate_type_check(r9_klass, ckoff, ckval, L_store_element); + // ======== end loop ======== + + // It was a real error; we must depend on the caller to finish the job. + // Register count = remaining oops, count_orig = total oops. + // Emit GC store barriers for the oops we have copied and report + // their number to the caller. + + __ sub(count, count_save, count); // K = partially copied oop count + __ xori(count, count, -1); // report (-1^K) to caller + __ beqz(count, L_done_pop); + + __ BIND(L_do_card_marks); + bs->arraycopy_epilogue(_masm, decorators, is_oop, start_to, count_save, t0, wb_post_saved_regs); + + __ bind(L_done_pop); + __ pop_reg(RegSet::of(x7, x9, x18, x19), sp); + inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr); + + __ bind(L_done); + __ mv(x10, count); + __ leave(); + __ ret(); + + return start; + } + + // Perform range checks on the proposed arraycopy. + // Kills temp, but nothing else. + // Also, clean the sign bits of src_pos and dst_pos. + void arraycopy_range_checks(Register src, // source array oop (c_rarg0) + Register src_pos, // source position (c_rarg1) + Register dst, // destination array oo (c_rarg2) + Register dst_pos, // destination position (c_rarg3) + Register length, + Register temp, + Label& L_failed) { + BLOCK_COMMENT("arraycopy_range_checks:"); + + assert_different_registers(t0, temp); + + // if [src_pos + length > arrayOop(src)->length()] then FAIL + __ lwu(t0, Address(src, arrayOopDesc::length_offset_in_bytes())); + __ addw(temp, length, src_pos); + __ bgtu(temp, t0, L_failed); + + // if [dst_pos + length > arrayOop(dst)->length()] then FAIL + __ lwu(t0, Address(dst, arrayOopDesc::length_offset_in_bytes())); + __ addw(temp, length, dst_pos); + __ bgtu(temp, t0, L_failed); + + // Have to clean up high 32 bits of 'src_pos' and 'dst_pos'. + __ zero_extend(src_pos, src_pos, 32); + __ zero_extend(dst_pos, dst_pos, 32); + + BLOCK_COMMENT("arraycopy_range_checks done"); + } + + // + // Generate 'unsafe' array copy stub + // Though just as safe as the other stubs, it takes an unscaled + // size_t argument instead of an element count. + // + // Input: + // c_rarg0 - source array address + // c_rarg1 - destination array address + // c_rarg2 - byte count, treated as ssize_t, can be zero + // + // Examines the alignment of the operands and dispatches + // to a long, int, short, or byte copy loop. + // + address generate_unsafe_copy(const char* name, + address byte_copy_entry, + address short_copy_entry, + address int_copy_entry, + address long_copy_entry) { + assert_cond(byte_copy_entry != NULL && short_copy_entry != NULL && + int_copy_entry != NULL && long_copy_entry != NULL); + Label L_long_aligned, L_int_aligned, L_short_aligned; + const Register s = c_rarg0, d = c_rarg1, count = c_rarg2; + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // bump this on entry, not on exit: + inc_counter_np(SharedRuntime::_unsafe_array_copy_ctr); + + __ orr(t0, s, d); + __ orr(t0, t0, count); + + __ andi(t0, t0, BytesPerLong - 1); + __ beqz(t0, L_long_aligned); + __ andi(t0, t0, BytesPerInt - 1); + __ beqz(t0, L_int_aligned); + __ andi(t0, t0, 1); + __ beqz(t0, L_short_aligned); + __ j(RuntimeAddress(byte_copy_entry)); + + __ BIND(L_short_aligned); + __ srli(count, count, LogBytesPerShort); // size => short_count + __ j(RuntimeAddress(short_copy_entry)); + __ BIND(L_int_aligned); + __ srli(count, count, LogBytesPerInt); // size => int_count + __ j(RuntimeAddress(int_copy_entry)); + __ BIND(L_long_aligned); + __ srli(count, count, LogBytesPerLong); // size => long_count + __ j(RuntimeAddress(long_copy_entry)); + + return start; + } + + // + // Generate generic array copy stubs + // + // Input: + // c_rarg0 - src oop + // c_rarg1 - src_pos (32-bits) + // c_rarg2 - dst oop + // c_rarg3 - dst_pos (32-bits) + // c_rarg4 - element count (32-bits) + // + // Output: + // x10 == 0 - success + // x10 == -1^K - failure, where K is partial transfer count + // + address generate_generic_copy(const char* name, + address byte_copy_entry, address short_copy_entry, + address int_copy_entry, address oop_copy_entry, + address long_copy_entry, address checkcast_copy_entry) { + assert_cond(byte_copy_entry != NULL && short_copy_entry != NULL && + int_copy_entry != NULL && oop_copy_entry != NULL && + long_copy_entry != NULL && checkcast_copy_entry != NULL); + Label L_failed, L_failed_0, L_objArray; + Label L_copy_bytes, L_copy_shorts, L_copy_ints, L_copy_longs; + + // Input registers + const Register src = c_rarg0; // source array oop + const Register src_pos = c_rarg1; // source position + const Register dst = c_rarg2; // destination array oop + const Register dst_pos = c_rarg3; // destination position + const Register length = c_rarg4; + + // Registers used as temps + const Register dst_klass = c_rarg5; + + __ align(CodeEntryAlignment); + + StubCodeMark mark(this, "StubRoutines", name); + + address start = __ pc(); + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + // bump this on entry, not on exit: + inc_counter_np(SharedRuntime::_generic_array_copy_ctr); + + //----------------------------------------------------------------------- + // Assembler stub will be used for this call to arraycopy + // if the following conditions are met: + // + // (1) src and dst must not be null. + // (2) src_pos must not be negative. + // (3) dst_pos must not be negative. + // (4) length must not be negative. + // (5) src klass and dst klass should be the same and not NULL. + // (6) src and dst should be arrays. + // (7) src_pos + length must not exceed length of src. + // (8) dst_pos + length must not exceed length of dst. + // + + // if [src == NULL] then return -1 + __ beqz(src, L_failed); + + // if [src_pos < 0] then return -1 + // i.e. sign bit set + __ andi(t0, src_pos, 1UL << 31); + __ bnez(t0, L_failed); + + // if [dst == NULL] then return -1 + __ beqz(dst, L_failed); + + // if [dst_pos < 0] then return -1 + // i.e. sign bit set + __ andi(t0, dst_pos, 1UL << 31); + __ bnez(t0, L_failed); + + // registers used as temp + const Register scratch_length = x28; // elements count to copy + const Register scratch_src_klass = x29; // array klass + const Register lh = x30; // layout helper + + // if [length < 0] then return -1 + __ addw(scratch_length, length, zr); // length (elements count, 32-bits value) + // i.e. sign bit set + __ andi(t0, scratch_length, 1UL << 31); + __ bnez(t0, L_failed); + + __ load_klass(scratch_src_klass, src); +#ifdef ASSERT + { + BLOCK_COMMENT("assert klasses not null {"); + Label L1, L2; + __ bnez(scratch_src_klass, L2); // it is broken if klass is NULL + __ bind(L1); + __ stop("broken null klass"); + __ bind(L2); + __ load_klass(t0, dst); + __ beqz(t0, L1); // this would be broken also + BLOCK_COMMENT("} assert klasses not null done"); + } +#endif + + // Load layout helper (32-bits) + // + // |array_tag| | header_size | element_type | |log2_element_size| + // 32 30 24 16 8 2 0 + // + // array_tag: typeArray = 0x3, objArray = 0x2, non-array = 0x0 + // + + const int lh_offset = in_bytes(Klass::layout_helper_offset()); + + // Handle objArrays completely differently... + const jint objArray_lh = Klass::array_layout_helper(T_OBJECT); + __ lw(lh, Address(scratch_src_klass, lh_offset)); + __ mvw(t0, objArray_lh); + __ beq(lh, t0, L_objArray); + + // if [src->klass() != dst->klass()] then return -1 + __ load_klass(t1, dst); + __ bne(t1, scratch_src_klass, L_failed); + + // if [src->is_Array() != NULL] then return -1 + // i.e. (lh >= 0) + __ andi(t0, lh, 1UL << 31); + __ beqz(t0, L_failed); + + // At this point, it is known to be a typeArray (array_tag 0x3). +#ifdef ASSERT + { + BLOCK_COMMENT("assert primitive array {"); + Label L; + __ mvw(t1, Klass::_lh_array_tag_type_value << Klass::_lh_array_tag_shift); + __ bge(lh, t1, L); + __ stop("must be a primitive array"); + __ bind(L); + BLOCK_COMMENT("} assert primitive array done"); + } +#endif + + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + t1, L_failed); + + // TypeArrayKlass + // + // src_addr = (src + array_header_in_bytes()) + (src_pos << log2elemsize) + // dst_addr = (dst + array_header_in_bytes()) + (dst_pos << log2elemsize) + // + + const Register t0_offset = t0; // array offset + const Register x22_elsize = lh; // element size + + // Get array_header_in_bytes() + int lh_header_size_width = exact_log2(Klass::_lh_header_size_mask + 1); + int lh_header_size_msb = Klass::_lh_header_size_shift + lh_header_size_width; + __ slli(t0_offset, lh, XLEN - lh_header_size_msb); // left shift to remove 24 ~ 32; + __ srli(t0_offset, t0_offset, XLEN - lh_header_size_width); // array_offset + + __ add(src, src, t0_offset); // src array offset + __ add(dst, dst, t0_offset); // dst array offset + BLOCK_COMMENT("choose copy loop based on element size"); + + // next registers should be set before the jump to corresponding stub + const Register from = c_rarg0; // source array address + const Register to = c_rarg1; // destination array address + const Register count = c_rarg2; // elements count + + // 'from', 'to', 'count' registers should be set in such order + // since they are the same as 'src', 'src_pos', 'dst'. + + assert(Klass::_lh_log2_element_size_shift == 0, "fix this code"); + + // The possible values of elsize are 0-3, i.e. exact_log2(element + // size in bytes). We do a simple bitwise binary search. + __ BIND(L_copy_bytes); + __ andi(t0, x22_elsize, 2); + __ bnez(t0, L_copy_ints); + __ andi(t0, x22_elsize, 1); + __ bnez(t0, L_copy_shorts); + __ add(from, src, src_pos); // src_addr + __ add(to, dst, dst_pos); // dst_addr + __ addw(count, scratch_length, zr); // length + __ j(RuntimeAddress(byte_copy_entry)); + + __ BIND(L_copy_shorts); + __ shadd(from, src_pos, src, t0, 1); // src_addr + __ shadd(to, dst_pos, dst, t0, 1); // dst_addr + __ addw(count, scratch_length, zr); // length + __ j(RuntimeAddress(short_copy_entry)); + + __ BIND(L_copy_ints); + __ andi(t0, x22_elsize, 1); + __ bnez(t0, L_copy_longs); + __ shadd(from, src_pos, src, t0, 2); // src_addr + __ shadd(to, dst_pos, dst, t0, 2); // dst_addr + __ addw(count, scratch_length, zr); // length + __ j(RuntimeAddress(int_copy_entry)); + + __ BIND(L_copy_longs); +#ifdef ASSERT + { + BLOCK_COMMENT("assert long copy {"); + Label L; + __ andi(lh, lh, Klass::_lh_log2_element_size_mask); // lh -> x22_elsize + __ addw(lh, lh, zr); + __ mvw(t0, LogBytesPerLong); + __ beq(x22_elsize, t0, L); + __ stop("must be long copy, but elsize is wrong"); + __ bind(L); + BLOCK_COMMENT("} assert long copy done"); + } +#endif + __ shadd(from, src_pos, src, t0, 3); // src_addr + __ shadd(to, dst_pos, dst, t0, 3); // dst_addr + __ addw(count, scratch_length, zr); // length + __ j(RuntimeAddress(long_copy_entry)); + + // ObjArrayKlass + __ BIND(L_objArray); + // live at this point: scratch_src_klass, scratch_length, src[_pos], dst[_pos] + + Label L_plain_copy, L_checkcast_copy; + // test array classes for subtyping + __ load_klass(t2, dst); + __ bne(scratch_src_klass, t2, L_checkcast_copy); // usual case is exact equality + + // Identically typed arrays can be copied without element-wise checks. + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + t1, L_failed); + + __ shadd(from, src_pos, src, t0, LogBytesPerHeapOop); + __ add(from, from, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ shadd(to, dst_pos, dst, t0, LogBytesPerHeapOop); + __ add(to, to, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ addw(count, scratch_length, zr); // length + __ BIND(L_plain_copy); + __ j(RuntimeAddress(oop_copy_entry)); + + __ BIND(L_checkcast_copy); + // live at this point: scratch_src_klass, scratch_length, t2 (dst_klass) + { + // Before looking at dst.length, make sure dst is also an objArray. + __ lwu(t0, Address(t2, lh_offset)); + __ mvw(t1, objArray_lh); + __ bne(t0, t1, L_failed); + + // It is safe to examine both src.length and dst.length. + arraycopy_range_checks(src, src_pos, dst, dst_pos, scratch_length, + t2, L_failed); + + __ load_klass(dst_klass, dst); // reload + + // Marshal the base address arguments now, freeing registers. + __ shadd(from, src_pos, src, t0, LogBytesPerHeapOop); + __ add(from, from, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ shadd(to, dst_pos, dst, t0, LogBytesPerHeapOop); + __ add(to, to, arrayOopDesc::base_offset_in_bytes(T_OBJECT)); + __ addw(count, length, zr); // length (reloaded) + const Register sco_temp = c_rarg3; // this register is free now + assert_different_registers(from, to, count, sco_temp, + dst_klass, scratch_src_klass); + + // Generate the type check. + const int sco_offset = in_bytes(Klass::super_check_offset_offset()); + __ lwu(sco_temp, Address(dst_klass, sco_offset)); + + // Smashes t0, t1 + generate_type_check(scratch_src_klass, sco_temp, dst_klass, L_plain_copy); + + // Fetch destination element klass from the ObjArrayKlass header. + int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset()); + __ ld(dst_klass, Address(dst_klass, ek_offset)); + __ lwu(sco_temp, Address(dst_klass, sco_offset)); + + // the checkcast_copy loop needs two extra arguments: + assert(c_rarg3 == sco_temp, "#3 already in place"); + // Set up arguments for checkcast_copy_entry. + __ mv(c_rarg4, dst_klass); // dst.klass.element_klass + __ j(RuntimeAddress(checkcast_copy_entry)); + } + + __ BIND(L_failed); + __ li(x10, -1); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(); + + return start; + } + + // + // Generate stub for array fill. If "aligned" is true, the + // "to" address is assumed to be heapword aligned. + // + // Arguments for generated stub: + // to: c_rarg0 + // value: c_rarg1 + // count: c_rarg2 treated as signed + // + address generate_fill(BasicType t, bool aligned, const char* name) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", name); + address start = __ pc(); + + BLOCK_COMMENT("Entry:"); + + const Register to = c_rarg0; // source array address + const Register value = c_rarg1; // value + const Register count = c_rarg2; // elements count + + const Register bz_base = x28; // base for block_zero routine + const Register cnt_words = x29; // temp register + const Register tmp_reg = t1; + + __ enter(); + + Label L_fill_elements, L_exit1; + + int shift = -1; + switch (t) { + case T_BYTE: + shift = 0; + + // Zero extend value + // 8 bit -> 16 bit + __ andi(value, value, 0xff); + __ mv(tmp_reg, value); + __ slli(tmp_reg, tmp_reg, 8); + __ orr(value, value, tmp_reg); + + // 16 bit -> 32 bit + __ mv(tmp_reg, value); + __ slli(tmp_reg, tmp_reg, 16); + __ orr(value, value, tmp_reg); + + __ mv(tmp_reg, 8 >> shift); // Short arrays (< 8 bytes) fill by element + __ bltu(count, tmp_reg, L_fill_elements); + break; + case T_SHORT: + shift = 1; + // Zero extend value + // 16 bit -> 32 bit + __ andi(value, value, 0xffff); + __ mv(tmp_reg, value); + __ slli(tmp_reg, tmp_reg, 16); + __ orr(value, value, tmp_reg); + + // Short arrays (< 8 bytes) fill by element + __ mv(tmp_reg, 8 >> shift); + __ bltu(count, tmp_reg, L_fill_elements); + break; + case T_INT: + shift = 2; + + // Short arrays (< 8 bytes) fill by element + __ mv(tmp_reg, 8 >> shift); + __ bltu(count, tmp_reg, L_fill_elements); + break; + default: ShouldNotReachHere(); + } + + // Align source address at 8 bytes address boundary. + Label L_skip_align1, L_skip_align2, L_skip_align4; + if (!aligned) { + switch (t) { + case T_BYTE: + // One byte misalignment happens only for byte arrays. + __ andi(t0, to, 1); + __ beqz(t0, L_skip_align1); + __ sb(value, Address(to, 0)); + __ addi(to, to, 1); + __ addiw(count, count, -1); + __ bind(L_skip_align1); + // Fallthrough + case T_SHORT: + // Two bytes misalignment happens only for byte and short (char) arrays. + __ andi(t0, to, 2); + __ beqz(t0, L_skip_align2); + __ sh(value, Address(to, 0)); + __ addi(to, to, 2); + __ addiw(count, count, -(2 >> shift)); + __ bind(L_skip_align2); + // Fallthrough + case T_INT: + // Align to 8 bytes, we know we are 4 byte aligned to start. + __ andi(t0, to, 4); + __ beqz(t0, L_skip_align4); + __ sw(value, Address(to, 0)); + __ addi(to, to, 4); + __ addiw(count, count, -(4 >> shift)); + __ bind(L_skip_align4); + break; + default: ShouldNotReachHere(); + } + } + + // + // Fill large chunks + // + __ srliw(cnt_words, count, 3 - shift); // number of words + + // 32 bit -> 64 bit + __ andi(value, value, 0xffffffff); + __ mv(tmp_reg, value); + __ slli(tmp_reg, tmp_reg, 32); + __ orr(value, value, tmp_reg); + + __ slli(tmp_reg, cnt_words, 3 - shift); + __ subw(count, count, tmp_reg); + { + __ fill_words(to, cnt_words, value); + } + + // Remaining count is less than 8 bytes. Fill it by a single store. + // Note that the total length is no less than 8 bytes. + if (t == T_BYTE || t == T_SHORT) { + __ beqz(count, L_exit1); + __ shadd(to, count, to, tmp_reg, shift); // points to the end + __ sd(value, Address(to, -8)); // overwrite some elements + __ bind(L_exit1); + __ leave(); + __ ret(); + } + + // Handle copies less than 8 bytes. + Label L_fill_2, L_fill_4, L_exit2; + __ bind(L_fill_elements); + switch (t) { + case T_BYTE: + __ andi(t0, count, 1); + __ beqz(t0, L_fill_2); + __ sb(value, Address(to, 0)); + __ addi(to, to, 1); + __ bind(L_fill_2); + __ andi(t0, count, 2); + __ beqz(t0, L_fill_4); + __ sh(value, Address(to, 0)); + __ addi(to, to, 2); + __ bind(L_fill_4); + __ andi(t0, count, 4); + __ beqz(t0, L_exit2); + __ sw(value, Address(to, 0)); + break; + case T_SHORT: + __ andi(t0, count, 1); + __ beqz(t0, L_fill_4); + __ sh(value, Address(to, 0)); + __ addi(to, to, 2); + __ bind(L_fill_4); + __ andi(t0, count, 2); + __ beqz(t0, L_exit2); + __ sw(value, Address(to, 0)); + break; + case T_INT: + __ beqz(count, L_exit2); + __ sw(value, Address(to, 0)); + break; + default: ShouldNotReachHere(); + } + __ bind(L_exit2); + __ leave(); + __ ret(); + return start; + } + + void generate_arraycopy_stubs() { + address entry = NULL; + address entry_jbyte_arraycopy = NULL; + address entry_jshort_arraycopy = NULL; + address entry_jint_arraycopy = NULL; + address entry_oop_arraycopy = NULL; + address entry_jlong_arraycopy = NULL; + address entry_checkcast_arraycopy = NULL; + + generate_copy_longs(copy_f, c_rarg0, c_rarg1, t1, copy_forwards); + generate_copy_longs(copy_b, c_rarg0, c_rarg1, t1, copy_backwards); + + StubRoutines::riscv::_zero_blocks = generate_zero_blocks(); + + //*** jbyte + // Always need aligned and unaligned versions + StubRoutines::_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(false, &entry, + "jbyte_disjoint_arraycopy"); + StubRoutines::_jbyte_arraycopy = generate_conjoint_byte_copy(false, entry, + &entry_jbyte_arraycopy, + "jbyte_arraycopy"); + StubRoutines::_arrayof_jbyte_disjoint_arraycopy = generate_disjoint_byte_copy(true, &entry, + "arrayof_jbyte_disjoint_arraycopy"); + StubRoutines::_arrayof_jbyte_arraycopy = generate_conjoint_byte_copy(true, entry, NULL, + "arrayof_jbyte_arraycopy"); + + //*** jshort + // Always need aligned and unaligned versions + StubRoutines::_jshort_disjoint_arraycopy = generate_disjoint_short_copy(false, &entry, + "jshort_disjoint_arraycopy"); + StubRoutines::_jshort_arraycopy = generate_conjoint_short_copy(false, entry, + &entry_jshort_arraycopy, + "jshort_arraycopy"); + StubRoutines::_arrayof_jshort_disjoint_arraycopy = generate_disjoint_short_copy(true, &entry, + "arrayof_jshort_disjoint_arraycopy"); + StubRoutines::_arrayof_jshort_arraycopy = generate_conjoint_short_copy(true, entry, NULL, + "arrayof_jshort_arraycopy"); + + //*** jint + // Aligned versions + StubRoutines::_arrayof_jint_disjoint_arraycopy = generate_disjoint_int_copy(true, &entry, + "arrayof_jint_disjoint_arraycopy"); + StubRoutines::_arrayof_jint_arraycopy = generate_conjoint_int_copy(true, entry, &entry_jint_arraycopy, + "arrayof_jint_arraycopy"); + // In 64 bit we need both aligned and unaligned versions of jint arraycopy. + // entry_jint_arraycopy always points to the unaligned version + StubRoutines::_jint_disjoint_arraycopy = generate_disjoint_int_copy(false, &entry, + "jint_disjoint_arraycopy"); + StubRoutines::_jint_arraycopy = generate_conjoint_int_copy(false, entry, + &entry_jint_arraycopy, + "jint_arraycopy"); + + //*** jlong + // It is always aligned + StubRoutines::_arrayof_jlong_disjoint_arraycopy = generate_disjoint_long_copy(true, &entry, + "arrayof_jlong_disjoint_arraycopy"); + StubRoutines::_arrayof_jlong_arraycopy = generate_conjoint_long_copy(true, entry, &entry_jlong_arraycopy, + "arrayof_jlong_arraycopy"); + StubRoutines::_jlong_disjoint_arraycopy = StubRoutines::_arrayof_jlong_disjoint_arraycopy; + StubRoutines::_jlong_arraycopy = StubRoutines::_arrayof_jlong_arraycopy; + + //*** oops + { + // With compressed oops we need unaligned versions; notice that + // we overwrite entry_oop_arraycopy. + bool aligned = !UseCompressedOops; + + StubRoutines::_arrayof_oop_disjoint_arraycopy + = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy", + /*dest_uninitialized*/false); + StubRoutines::_arrayof_oop_arraycopy + = generate_conjoint_oop_copy(aligned, entry, &entry_oop_arraycopy, "arrayof_oop_arraycopy", + /*dest_uninitialized*/false); + // Aligned versions without pre-barriers + StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit + = generate_disjoint_oop_copy(aligned, &entry, "arrayof_oop_disjoint_arraycopy_uninit", + /*dest_uninitialized*/true); + StubRoutines::_arrayof_oop_arraycopy_uninit + = generate_conjoint_oop_copy(aligned, entry, NULL, "arrayof_oop_arraycopy_uninit", + /*dest_uninitialized*/true); + } + + StubRoutines::_oop_disjoint_arraycopy = StubRoutines::_arrayof_oop_disjoint_arraycopy; + StubRoutines::_oop_arraycopy = StubRoutines::_arrayof_oop_arraycopy; + StubRoutines::_oop_disjoint_arraycopy_uninit = StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit; + StubRoutines::_oop_arraycopy_uninit = StubRoutines::_arrayof_oop_arraycopy_uninit; + + StubRoutines::_checkcast_arraycopy = generate_checkcast_copy("checkcast_arraycopy", &entry_checkcast_arraycopy); + StubRoutines::_checkcast_arraycopy_uninit = generate_checkcast_copy("checkcast_arraycopy_uninit", NULL, + /*dest_uninitialized*/true); + + + StubRoutines::_unsafe_arraycopy = generate_unsafe_copy("unsafe_arraycopy", + entry_jbyte_arraycopy, + entry_jshort_arraycopy, + entry_jint_arraycopy, + entry_jlong_arraycopy); + + StubRoutines::_generic_arraycopy = generate_generic_copy("generic_arraycopy", + entry_jbyte_arraycopy, + entry_jshort_arraycopy, + entry_jint_arraycopy, + entry_oop_arraycopy, + entry_jlong_arraycopy, + entry_checkcast_arraycopy); + + StubRoutines::_jbyte_fill = generate_fill(T_BYTE, false, "jbyte_fill"); + StubRoutines::_jshort_fill = generate_fill(T_SHORT, false, "jshort_fill"); + StubRoutines::_jint_fill = generate_fill(T_INT, false, "jint_fill"); + StubRoutines::_arrayof_jbyte_fill = generate_fill(T_BYTE, true, "arrayof_jbyte_fill"); + StubRoutines::_arrayof_jshort_fill = generate_fill(T_SHORT, true, "arrayof_jshort_fill"); + StubRoutines::_arrayof_jint_fill = generate_fill(T_INT, true, "arrayof_jint_fill"); + } + + // Safefetch stubs. + void generate_safefetch(const char* name, int size, address* entry, + address* fault_pc, address* continuation_pc) { + // safefetch signatures: + // int SafeFetch32(int* adr, int errValue) + // intptr_t SafeFetchN (intptr_t* adr, intptr_t errValue) + // + // arguments: + // c_rarg0 = adr + // c_rarg1 = errValue + // + // result: + // PPC_RET = *adr or errValue + assert_cond(entry != NULL && fault_pc != NULL && continuation_pc != NULL); + StubCodeMark mark(this, "StubRoutines", name); + + // Entry point, pc or function descriptor. + *entry = __ pc(); + + // Load *adr into c_rarg1, may fault. + *fault_pc = __ pc(); + switch (size) { + case 4: + // int32_t + __ lw(c_rarg1, Address(c_rarg0, 0)); + break; + case 8: + // int64_t + __ ld(c_rarg1, Address(c_rarg0, 0)); + break; + default: + ShouldNotReachHere(); + } + + // return errValue or *adr + *continuation_pc = __ pc(); + __ mv(x10, c_rarg1); + __ ret(); + } + + // code for comparing 16 bytes of strings with same encoding + void compare_string_16_bytes_same(Label &DIFF1, Label &DIFF2) { + const Register result = x10, str1 = x11, cnt1 = x12, str2 = x13, tmp1 = x28, tmp2 = x29, tmp4 = x7, tmp5 = x31; + __ ld(tmp5, Address(str1)); + __ addi(str1, str1, 8); + __ xorr(tmp4, tmp1, tmp2); + __ ld(cnt1, Address(str2)); + __ addi(str2, str2, 8); + __ bnez(tmp4, DIFF1); + __ ld(tmp1, Address(str1)); + __ addi(str1, str1, 8); + __ xorr(tmp4, tmp5, cnt1); + __ ld(tmp2, Address(str2)); + __ addi(str2, str2, 8); + __ bnez(tmp4, DIFF2); + } + + // code for comparing 8 characters of strings with Latin1 and Utf16 encoding + void compare_string_8_x_LU(Register tmpL, Register tmpU, Label &DIFF1, + Label &DIFF2) { + const Register strU = x12, curU = x7, strL = x29, tmp = x30; + __ ld(tmpL, Address(strL)); + __ addi(strL, strL, 8); + __ ld(tmpU, Address(strU)); + __ addi(strU, strU, 8); + __ inflate_lo32(tmp, tmpL); + __ mv(t0, tmp); + __ xorr(tmp, curU, t0); + __ bnez(tmp, DIFF2); + + __ ld(curU, Address(strU)); + __ addi(strU, strU, 8); + __ inflate_hi32(tmp, tmpL); + __ mv(t0, tmp); + __ xorr(tmp, tmpU, t0); + __ bnez(tmp, DIFF1); + } + + // x10 = result + // x11 = str1 + // x12 = cnt1 + // x13 = str2 + // x14 = cnt2 + // x28 = tmp1 + // x29 = tmp2 + // x30 = tmp3 + address generate_compare_long_string_different_encoding(bool isLU) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", isLU ? "compare_long_string_different_encoding LU" : "compare_long_string_different_encoding UL"); + address entry = __ pc(); + Label SMALL_LOOP, TAIL, TAIL_LOAD_16, LOAD_LAST, DIFF1, DIFF2, + DONE, CALCULATE_DIFFERENCE; + const Register result = x10, str1 = x11, cnt1 = x12, str2 = x13, cnt2 = x14, + tmp1 = x28, tmp2 = x29, tmp3 = x30, tmp4 = x7, tmp5 = x31; + RegSet spilled_regs = RegSet::of(tmp4, tmp5); + + // cnt2 == amount of characters left to compare + // Check already loaded first 4 symbols + __ inflate_lo32(tmp3, isLU ? tmp1 : tmp2); + __ mv(isLU ? tmp1 : tmp2, tmp3); + __ addi(str1, str1, isLU ? wordSize / 2 : wordSize); + __ addi(str2, str2, isLU ? wordSize : wordSize / 2); + __ sub(cnt2, cnt2, 8); // Already loaded 4 symbols. Last 4 is special case. + __ push_reg(spilled_regs, sp); + + if (isLU) { + __ add(str1, str1, cnt2); + __ shadd(str2, cnt2, str2, t0, 1); + } else { + __ shadd(str1, cnt2, str1, t0, 1); + __ add(str2, str2, cnt2); + } + __ xorr(tmp3, tmp1, tmp2); + __ mv(tmp5, tmp2); + __ bnez(tmp3, CALCULATE_DIFFERENCE); + + Register strU = isLU ? str2 : str1, + strL = isLU ? str1 : str2, + tmpU = isLU ? tmp5 : tmp1, // where to keep U for comparison + tmpL = isLU ? tmp1 : tmp5; // where to keep L for comparison + + __ sub(tmp2, strL, cnt2); // strL pointer to load from + __ slli(t0, cnt2, 1); + __ sub(cnt1, strU, t0); // strU pointer to load from + + __ ld(tmp4, Address(cnt1)); + __ addi(cnt1, cnt1, 8); + __ beqz(cnt2, LOAD_LAST); // no characters left except last load + __ sub(cnt2, cnt2, 16); + __ bltz(cnt2, TAIL); + __ bind(SMALL_LOOP); // smaller loop + __ sub(cnt2, cnt2, 16); + compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); + compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); + __ bgez(cnt2, SMALL_LOOP); + __ addi(t0, cnt2, 16); + __ beqz(t0, LOAD_LAST); + __ bind(TAIL); // 1..15 characters left until last load (last 4 characters) + // Address of 8 bytes before last 4 characters in UTF-16 string + __ shadd(cnt1, cnt2, cnt1, t0, 1); + // Address of 16 bytes before last 4 characters in Latin1 string + __ add(tmp2, tmp2, cnt2); + __ ld(tmp4, Address(cnt1, -8)); + // last 16 characters before last load + compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); + compare_string_8_x_LU(tmpL, tmpU, DIFF1, DIFF2); + __ j(LOAD_LAST); + __ bind(DIFF2); + __ mv(tmpU, tmp4); + __ bind(DIFF1); + __ mv(tmpL, t0); + __ j(CALCULATE_DIFFERENCE); + __ bind(LOAD_LAST); + // Last 4 UTF-16 characters are already pre-loaded into tmp4 by compare_string_8_x_LU. + // No need to load it again + __ mv(tmpU, tmp4); + __ ld(tmpL, Address(strL)); + __ inflate_lo32(tmp3, tmpL); + __ mv(tmpL, tmp3); + __ xorr(tmp3, tmpU, tmpL); + __ beqz(tmp3, DONE); + + // Find the first different characters in the longwords and + // compute their difference. + __ bind(CALCULATE_DIFFERENCE); + __ ctzc_bit(tmp4, tmp3); + __ srl(tmp1, tmp1, tmp4); + __ srl(tmp5, tmp5, tmp4); + __ andi(tmp1, tmp1, 0xFFFF); + __ andi(tmp5, tmp5, 0xFFFF); + __ sub(result, tmp1, tmp5); + __ bind(DONE); + __ pop_reg(spilled_regs, sp); + __ ret(); + return entry; + } + + address generate_method_entry_barrier() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "nmethod_entry_barrier"); + + Label deoptimize_label; + + address start = __ pc(); + + __ set_last_Java_frame(sp, fp, ra, t0); + + __ enter(); + __ add(t1, sp, wordSize); + + __ sub(sp, sp, 4 * wordSize); + + __ push_call_clobbered_registers(); + + __ mv(c_rarg0, t1); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSetNMethod::nmethod_stub_entry_barrier), 1); + + __ reset_last_Java_frame(true); + + __ mv(t0, x10); + + __ pop_call_clobbered_registers(); + + __ bnez(t0, deoptimize_label); + + __ leave(); + __ ret(); + + __ BIND(deoptimize_label); + + __ ld(t0, Address(sp, 0)); + __ ld(fp, Address(sp, wordSize)); + __ ld(ra, Address(sp, wordSize * 2)); + __ ld(t1, Address(sp, wordSize * 3)); + + __ mv(sp, t0); + __ jr(t1); + + return start; + } + + // x10 = result + // x11 = str1 + // x12 = cnt1 + // x13 = str2 + // x14 = cnt2 + // x28 = tmp1 + // x29 = tmp2 + // x30 = tmp3 + // x31 = tmp4 + address generate_compare_long_string_same_encoding(bool isLL) { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", isLL ? + "compare_long_string_same_encoding LL" : "compare_long_string_same_encoding UU"); + address entry = __ pc(); + Label SMALL_LOOP, CHECK_LAST, DIFF2, TAIL, + LENGTH_DIFF, DIFF, LAST_CHECK_AND_LENGTH_DIFF; + const Register result = x10, str1 = x11, cnt1 = x12, str2 = x13, cnt2 = x14, + tmp1 = x28, tmp2 = x29, tmp3 = x30, tmp4 = x7, tmp5 = x31; + RegSet spilled_regs = RegSet::of(tmp4, tmp5); + + // cnt1/cnt2 contains amount of characters to compare. cnt1 can be re-used + // update cnt2 counter with already loaded 8 bytes + __ sub(cnt2, cnt2, wordSize / (isLL ? 1 : 2)); + // update pointers, because of previous read + __ add(str1, str1, wordSize); + __ add(str2, str2, wordSize); + // less than 16 bytes left? + __ sub(cnt2, cnt2, isLL ? 16 : 8); + __ push_reg(spilled_regs, sp); + __ bltz(cnt2, TAIL); + __ bind(SMALL_LOOP); + compare_string_16_bytes_same(DIFF, DIFF2); + __ sub(cnt2, cnt2, isLL ? 16 : 8); + __ bgez(cnt2, SMALL_LOOP); + __ bind(TAIL); + __ addi(cnt2, cnt2, isLL ? 16 : 8); + __ beqz(cnt2, LAST_CHECK_AND_LENGTH_DIFF); + __ sub(cnt2, cnt2, isLL ? 8 : 4); + __ blez(cnt2, CHECK_LAST); + __ xorr(tmp4, tmp1, tmp2); + __ bnez(tmp4, DIFF); + __ ld(tmp1, Address(str1)); + __ addi(str1, str1, 8); + __ ld(tmp2, Address(str2)); + __ addi(str2, str2, 8); + __ sub(cnt2, cnt2, isLL ? 8 : 4); + __ bind(CHECK_LAST); + if (!isLL) { + __ add(cnt2, cnt2, cnt2); // now in bytes + } + __ xorr(tmp4, tmp1, tmp2); + __ bnez(tmp4, DIFF); + __ add(str1, str1, cnt2); + __ ld(tmp5, Address(str1)); + __ add(str2, str2, cnt2); + __ ld(cnt1, Address(str2)); + __ xorr(tmp4, tmp5, cnt1); + __ beqz(tmp4, LENGTH_DIFF); + // Find the first different characters in the longwords and + // compute their difference. + __ bind(DIFF2); + __ ctzc_bit(tmp3, tmp4, isLL); // count zero from lsb to msb + __ srl(tmp5, tmp5, tmp3); + __ srl(cnt1, cnt1, tmp3); + if (isLL) { + __ andi(tmp5, tmp5, 0xFF); + __ andi(cnt1, cnt1, 0xFF); + } else { + __ andi(tmp5, tmp5, 0xFFFF); + __ andi(cnt1, cnt1, 0xFFFF); + } + __ sub(result, tmp5, cnt1); + __ j(LENGTH_DIFF); + __ bind(DIFF); + __ ctzc_bit(tmp3, tmp4, isLL); // count zero from lsb to msb + __ srl(tmp1, tmp1, tmp3); + __ srl(tmp2, tmp2, tmp3); + if (isLL) { + __ andi(tmp1, tmp1, 0xFF); + __ andi(tmp2, tmp2, 0xFF); + } else { + __ andi(tmp1, tmp1, 0xFFFF); + __ andi(tmp2, tmp2, 0xFFFF); + } + __ sub(result, tmp1, tmp2); + __ j(LENGTH_DIFF); + __ bind(LAST_CHECK_AND_LENGTH_DIFF); + __ xorr(tmp4, tmp1, tmp2); + __ bnez(tmp4, DIFF); + __ bind(LENGTH_DIFF); + __ pop_reg(spilled_regs, sp); + __ ret(); + return entry; + } + + void generate_compare_long_strings() { + StubRoutines::riscv::_compare_long_string_LL = generate_compare_long_string_same_encoding(true); + StubRoutines::riscv::_compare_long_string_UU = generate_compare_long_string_same_encoding(false); + StubRoutines::riscv::_compare_long_string_LU = generate_compare_long_string_different_encoding(true); + StubRoutines::riscv::_compare_long_string_UL = generate_compare_long_string_different_encoding(false); + } + + // x10 result + // x11 src + // x12 src count + // x13 pattern + // x14 pattern count + address generate_string_indexof_linear(bool needle_isL, bool haystack_isL) + { + const char* stubName = needle_isL + ? (haystack_isL ? "indexof_linear_ll" : "indexof_linear_ul") + : "indexof_linear_uu"; + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", stubName); + address entry = __ pc(); + + int needle_chr_size = needle_isL ? 1 : 2; + int haystack_chr_size = haystack_isL ? 1 : 2; + int needle_chr_shift = needle_isL ? 0 : 1; + int haystack_chr_shift = haystack_isL ? 0 : 1; + bool isL = needle_isL && haystack_isL; + // parameters + Register result = x10, haystack = x11, haystack_len = x12, needle = x13, needle_len = x14; + // temporary registers + Register mask1 = x20, match_mask = x21, first = x22, trailing_zeros = x23, mask2 = x24, tmp = x25; + // redefinitions + Register ch1 = x28, ch2 = x29; + RegSet spilled_regs = RegSet::range(x20, x25) + RegSet::range(x28, x29); + + __ push_reg(spilled_regs, sp); + + Label L_LOOP, L_LOOP_PROCEED, L_SMALL, L_HAS_ZERO, + L_HAS_ZERO_LOOP, L_CMP_LOOP, L_CMP_LOOP_NOMATCH, L_SMALL_PROCEED, + L_SMALL_HAS_ZERO_LOOP, L_SMALL_CMP_LOOP_NOMATCH, L_SMALL_CMP_LOOP, + L_POST_LOOP, L_CMP_LOOP_LAST_CMP, L_HAS_ZERO_LOOP_NOMATCH, + L_SMALL_CMP_LOOP_LAST_CMP, L_SMALL_CMP_LOOP_LAST_CMP2, + L_CMP_LOOP_LAST_CMP2, DONE, NOMATCH; + + __ ld(ch1, Address(needle)); + __ ld(ch2, Address(haystack)); + // src.length - pattern.length + __ sub(haystack_len, haystack_len, needle_len); + + // first is needle[0] + __ andi(first, ch1, needle_isL ? 0xFF : 0xFFFF, first); + uint64_t mask0101 = UCONST64(0x0101010101010101); + uint64_t mask0001 = UCONST64(0x0001000100010001); + __ mv(mask1, haystack_isL ? mask0101 : mask0001); + __ mul(first, first, mask1); + uint64_t mask7f7f = UCONST64(0x7f7f7f7f7f7f7f7f); + uint64_t mask7fff = UCONST64(0x7fff7fff7fff7fff); + __ mv(mask2, haystack_isL ? mask7f7f : mask7fff); + if (needle_isL != haystack_isL) { + __ mv(tmp, ch1); + } + __ sub(haystack_len, haystack_len, wordSize / haystack_chr_size - 1); + __ blez(haystack_len, L_SMALL); + + if (needle_isL != haystack_isL) { + __ inflate_lo32(ch1, tmp, match_mask, trailing_zeros); + } + // xorr, sub, orr, notr, andr + // compare and set match_mask[i] with 0x80/0x8000 (Latin1/UTF16) if ch2[i] == first[i] + // eg: + // first: aa aa aa aa aa aa aa aa + // ch2: aa aa li nx jd ka aa aa + // match_mask: 80 80 00 00 00 00 80 80 + __ compute_match_mask(ch2, first, match_mask, mask1, mask2); + + // search first char of needle, if success, goto L_HAS_ZERO; + __ bnez(match_mask, L_HAS_ZERO); + __ sub(haystack_len, haystack_len, wordSize / haystack_chr_size); + __ add(result, result, wordSize / haystack_chr_size); + __ add(haystack, haystack, wordSize); + __ bltz(haystack_len, L_POST_LOOP); + + __ bind(L_LOOP); + __ ld(ch2, Address(haystack)); + __ compute_match_mask(ch2, first, match_mask, mask1, mask2); + __ bnez(match_mask, L_HAS_ZERO); + + __ bind(L_LOOP_PROCEED); + __ sub(haystack_len, haystack_len, wordSize / haystack_chr_size); + __ add(haystack, haystack, wordSize); + __ add(result, result, wordSize / haystack_chr_size); + __ bgez(haystack_len, L_LOOP); + + __ bind(L_POST_LOOP); + __ mv(ch2, -wordSize / haystack_chr_size); + __ ble(haystack_len, ch2, NOMATCH); // no extra characters to check + __ ld(ch2, Address(haystack)); + __ slli(haystack_len, haystack_len, LogBitsPerByte + haystack_chr_shift); + __ neg(haystack_len, haystack_len); + __ xorr(ch2, first, ch2); + __ sub(match_mask, ch2, mask1); + __ orr(ch2, ch2, mask2); + __ mv(trailing_zeros, -1); // all bits set + __ j(L_SMALL_PROCEED); + + __ align(OptoLoopAlignment); + __ bind(L_SMALL); + __ slli(haystack_len, haystack_len, LogBitsPerByte + haystack_chr_shift); + __ neg(haystack_len, haystack_len); + if (needle_isL != haystack_isL) { + __ inflate_lo32(ch1, tmp, match_mask, trailing_zeros); + } + __ xorr(ch2, first, ch2); + __ sub(match_mask, ch2, mask1); + __ orr(ch2, ch2, mask2); + __ mv(trailing_zeros, -1); // all bits set + + __ bind(L_SMALL_PROCEED); + __ srl(trailing_zeros, trailing_zeros, haystack_len); // mask. zeroes on useless bits. + __ notr(ch2, ch2); + __ andr(match_mask, match_mask, ch2); + __ andr(match_mask, match_mask, trailing_zeros); // clear useless bits and check + __ beqz(match_mask, NOMATCH); + + __ bind(L_SMALL_HAS_ZERO_LOOP); + __ ctzc_bit(trailing_zeros, match_mask, haystack_isL, ch2, tmp); // count trailing zeros + __ addi(trailing_zeros, trailing_zeros, haystack_isL ? 7 : 15); + __ mv(ch2, wordSize / haystack_chr_size); + __ ble(needle_len, ch2, L_SMALL_CMP_LOOP_LAST_CMP2); + __ compute_index(haystack, trailing_zeros, match_mask, result, ch2, tmp, haystack_isL); + __ mv(trailing_zeros, wordSize / haystack_chr_size); + __ bne(ch1, ch2, L_SMALL_CMP_LOOP_NOMATCH); + + __ bind(L_SMALL_CMP_LOOP); + __ shadd(first, trailing_zeros, needle, first, needle_chr_shift); + __ shadd(ch2, trailing_zeros, haystack, ch2, haystack_chr_shift); + needle_isL ? __ lbu(first, Address(first)) : __ lhu(first, Address(first)); + haystack_isL ? __ lbu(ch2, Address(ch2)) : __ lhu(ch2, Address(ch2)); + __ add(trailing_zeros, trailing_zeros, 1); + __ bge(trailing_zeros, needle_len, L_SMALL_CMP_LOOP_LAST_CMP); + __ beq(first, ch2, L_SMALL_CMP_LOOP); + + __ bind(L_SMALL_CMP_LOOP_NOMATCH); + __ beqz(match_mask, NOMATCH); + __ ctzc_bit(trailing_zeros, match_mask, haystack_isL, tmp, ch2); + __ addi(trailing_zeros, trailing_zeros, haystack_isL ? 7 : 15); + __ add(result, result, 1); + __ add(haystack, haystack, haystack_chr_size); + __ j(L_SMALL_HAS_ZERO_LOOP); + + __ align(OptoLoopAlignment); + __ bind(L_SMALL_CMP_LOOP_LAST_CMP); + __ bne(first, ch2, L_SMALL_CMP_LOOP_NOMATCH); + __ j(DONE); + + __ align(OptoLoopAlignment); + __ bind(L_SMALL_CMP_LOOP_LAST_CMP2); + __ compute_index(haystack, trailing_zeros, match_mask, result, ch2, tmp, haystack_isL); + __ bne(ch1, ch2, L_SMALL_CMP_LOOP_NOMATCH); + __ j(DONE); + + __ align(OptoLoopAlignment); + __ bind(L_HAS_ZERO); + __ ctzc_bit(trailing_zeros, match_mask, haystack_isL, tmp, ch2); + __ addi(trailing_zeros, trailing_zeros, haystack_isL ? 7 : 15); + __ slli(needle_len, needle_len, BitsPerByte * wordSize / 2); + __ orr(haystack_len, haystack_len, needle_len); // restore needle_len(32bits) + __ sub(result, result, 1); // array index from 0, so result -= 1 + + __ bind(L_HAS_ZERO_LOOP); + __ mv(needle_len, wordSize / haystack_chr_size); + __ srli(ch2, haystack_len, BitsPerByte * wordSize / 2); + __ bge(needle_len, ch2, L_CMP_LOOP_LAST_CMP2); + // load next 8 bytes from haystack, and increase result index + __ compute_index(haystack, trailing_zeros, match_mask, result, ch2, tmp, haystack_isL); + __ add(result, result, 1); + __ mv(trailing_zeros, wordSize / haystack_chr_size); + __ bne(ch1, ch2, L_CMP_LOOP_NOMATCH); + + // compare one char + __ bind(L_CMP_LOOP); + __ shadd(needle_len, trailing_zeros, needle, needle_len, needle_chr_shift); + needle_isL ? __ lbu(needle_len, Address(needle_len)) : __ lhu(needle_len, Address(needle_len)); + __ shadd(ch2, trailing_zeros, haystack, ch2, haystack_chr_shift); + haystack_isL ? __ lbu(ch2, Address(ch2)) : __ lhu(ch2, Address(ch2)); + __ add(trailing_zeros, trailing_zeros, 1); // next char index + __ srli(tmp, haystack_len, BitsPerByte * wordSize / 2); + __ bge(trailing_zeros, tmp, L_CMP_LOOP_LAST_CMP); + __ beq(needle_len, ch2, L_CMP_LOOP); + + __ bind(L_CMP_LOOP_NOMATCH); + __ beqz(match_mask, L_HAS_ZERO_LOOP_NOMATCH); + __ ctzc_bit(trailing_zeros, match_mask, haystack_isL, needle_len, ch2); // find next "first" char index + __ addi(trailing_zeros, trailing_zeros, haystack_isL ? 7 : 15); + __ add(haystack, haystack, haystack_chr_size); + __ j(L_HAS_ZERO_LOOP); + + __ align(OptoLoopAlignment); + __ bind(L_CMP_LOOP_LAST_CMP); + __ bne(needle_len, ch2, L_CMP_LOOP_NOMATCH); + __ j(DONE); + + __ align(OptoLoopAlignment); + __ bind(L_CMP_LOOP_LAST_CMP2); + __ compute_index(haystack, trailing_zeros, match_mask, result, ch2, tmp, haystack_isL); + __ add(result, result, 1); + __ bne(ch1, ch2, L_CMP_LOOP_NOMATCH); + __ j(DONE); + + __ align(OptoLoopAlignment); + __ bind(L_HAS_ZERO_LOOP_NOMATCH); + // 1) Restore "result" index. Index was wordSize/str2_chr_size * N until + // L_HAS_ZERO block. Byte octet was analyzed in L_HAS_ZERO_LOOP, + // so, result was increased at max by wordSize/str2_chr_size - 1, so, + // respective high bit wasn't changed. L_LOOP_PROCEED will increase + // result by analyzed characters value, so, we can just reset lower bits + // in result here. Clear 2 lower bits for UU/UL and 3 bits for LL + // 2) restore needle_len and haystack_len values from "compressed" haystack_len + // 3) advance haystack value to represent next haystack octet. result & 7/3 is + // index of last analyzed substring inside current octet. So, haystack in at + // respective start address. We need to advance it to next octet + __ andi(match_mask, result, wordSize / haystack_chr_size - 1); + __ srli(needle_len, haystack_len, BitsPerByte * wordSize / 2); + __ andi(result, result, haystack_isL ? -8 : -4); + __ slli(tmp, match_mask, haystack_chr_shift); + __ sub(haystack, haystack, tmp); + __ addw(haystack_len, haystack_len, zr); + __ j(L_LOOP_PROCEED); + + __ align(OptoLoopAlignment); + __ bind(NOMATCH); + __ mv(result, -1); + + __ bind(DONE); + __ pop_reg(spilled_regs, sp); + __ ret(); + return entry; + } + + void generate_string_indexof_stubs() + { + StubRoutines::riscv::_string_indexof_linear_ll = generate_string_indexof_linear(true, true); + StubRoutines::riscv::_string_indexof_linear_uu = generate_string_indexof_linear(false, false); + StubRoutines::riscv::_string_indexof_linear_ul = generate_string_indexof_linear(true, false); + } + +#ifdef COMPILER2 + address generate_mulAdd() + { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "mulAdd"); + + address entry = __ pc(); + + const Register out = x10; + const Register in = x11; + const Register offset = x12; + const Register len = x13; + const Register k = x14; + const Register tmp = x28; + + BLOCK_COMMENT("Entry:"); + __ enter(); + __ mul_add(out, in, offset, len, k, tmp); + __ leave(); + __ ret(); + + return entry; + } + + /** + * Arguments: + * + * Input: + * c_rarg0 - x address + * c_rarg1 - x length + * c_rarg2 - y address + * c_rarg3 - y length + * c_rarg4 - z address + * c_rarg5 - z length + */ + address generate_multiplyToLen() + { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "multiplyToLen"); + address entry = __ pc(); + + const Register x = x10; + const Register xlen = x11; + const Register y = x12; + const Register ylen = x13; + const Register z = x14; + const Register zlen = x15; + + const Register tmp1 = x16; + const Register tmp2 = x17; + const Register tmp3 = x7; + const Register tmp4 = x28; + const Register tmp5 = x29; + const Register tmp6 = x30; + const Register tmp7 = x31; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(); + + return entry; + } + + address generate_squareToLen() + { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "squareToLen"); + address entry = __ pc(); + + const Register x = x10; + const Register xlen = x11; + const Register z = x12; + const Register zlen = x13; + const Register y = x14; // == x + const Register ylen = x15; // == xlen + + const Register tmp1 = x16; + const Register tmp2 = x17; + const Register tmp3 = x7; + const Register tmp4 = x28; + const Register tmp5 = x29; + const Register tmp6 = x30; + const Register tmp7 = x31; + + BLOCK_COMMENT("Entry:"); + __ enter(); + __ mv(y, x); + __ mv(ylen, xlen); + __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7); + __ leave(); + __ ret(); + + return entry; + } + + // Arguments: + // + // Input: + // c_rarg0 - newArr address + // c_rarg1 - oldArr address + // c_rarg2 - newIdx + // c_rarg3 - shiftCount + // c_rarg4 - numIter + // + address generate_bigIntegerLeftShift() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "bigIntegerLeftShiftWorker"); + address entry = __ pc(); + + Label loop, exit; + + Register newArr = c_rarg0; + Register oldArr = c_rarg1; + Register newIdx = c_rarg2; + Register shiftCount = c_rarg3; + Register numIter = c_rarg4; + + Register shiftRevCount = c_rarg5; + Register oldArrNext = t1; + + __ beqz(numIter, exit); + __ shadd(newArr, newIdx, newArr, t0, 2); + + __ li(shiftRevCount, 32); + __ sub(shiftRevCount, shiftRevCount, shiftCount); + + __ bind(loop); + __ addi(oldArrNext, oldArr, 4); + __ vsetvli(t0, numIter, Assembler::e32, Assembler::m4); + __ vle32_v(v0, oldArr); + __ vle32_v(v4, oldArrNext); + __ vsll_vx(v0, v0, shiftCount); + __ vsrl_vx(v4, v4, shiftRevCount); + __ vor_vv(v0, v0, v4); + __ vse32_v(v0, newArr); + __ sub(numIter, numIter, t0); + __ shadd(oldArr, t0, oldArr, t1, 2); + __ shadd(newArr, t0, newArr, t1, 2); + __ bnez(numIter, loop); + + __ bind(exit); + __ ret(); + + return entry; + } + + // Arguments: + // + // Input: + // c_rarg0 - newArr address + // c_rarg1 - oldArr address + // c_rarg2 - newIdx + // c_rarg3 - shiftCount + // c_rarg4 - numIter + // + address generate_bigIntegerRightShift() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "bigIntegerRightShiftWorker"); + address entry = __ pc(); + + Label loop, exit; + + Register newArr = c_rarg0; + Register oldArr = c_rarg1; + Register newIdx = c_rarg2; + Register shiftCount = c_rarg3; + Register numIter = c_rarg4; + Register idx = numIter; + + Register shiftRevCount = c_rarg5; + Register oldArrNext = c_rarg6; + Register newArrCur = t0; + Register oldArrCur = t1; + + __ beqz(idx, exit); + __ shadd(newArr, newIdx, newArr, t0, 2); + + __ li(shiftRevCount, 32); + __ sub(shiftRevCount, shiftRevCount, shiftCount); + + __ bind(loop); + __ vsetvli(t0, idx, Assembler::e32, Assembler::m4); + __ sub(idx, idx, t0); + __ shadd(oldArrNext, idx, oldArr, t1, 2); + __ shadd(newArrCur, idx, newArr, t1, 2); + __ addi(oldArrCur, oldArrNext, 4); + __ vle32_v(v0, oldArrCur); + __ vle32_v(v4, oldArrNext); + __ vsrl_vx(v0, v0, shiftCount); + __ vsll_vx(v4, v4, shiftRevCount); + __ vor_vv(v0, v0, v4); + __ vse32_v(v0, newArrCur); + __ bnez(idx, loop); + + __ bind(exit); + __ ret(); + + return entry; + } +#endif + +#ifdef COMPILER2 + class MontgomeryMultiplyGenerator : public MacroAssembler { + + Register Pa_base, Pb_base, Pn_base, Pm_base, inv, Rlen, Ra, Rb, Rm, Rn, + Pa, Pb, Pn, Pm, Rhi_ab, Rlo_ab, Rhi_mn, Rlo_mn, tmp0, tmp1, tmp2, Ri, Rj; + + RegSet _toSave; + bool _squaring; + + public: + MontgomeryMultiplyGenerator (Assembler *as, bool squaring) + : MacroAssembler(as->code()), _squaring(squaring) { + + // Register allocation + + Register reg = c_rarg0; + Pa_base = reg; // Argument registers + if (squaring) { + Pb_base = Pa_base; + } else { + Pb_base = ++reg; + } + Pn_base = ++reg; + Rlen= ++reg; + inv = ++reg; + Pm_base = ++reg; + + // Working registers: + Ra = ++reg; // The current digit of a, b, n, and m. + Rb = ++reg; + Rm = ++reg; + Rn = ++reg; + + Pa = ++reg; // Pointers to the current/next digit of a, b, n, and m. + Pb = ++reg; + Pm = ++reg; + Pn = ++reg; + + tmp0 = ++reg; // Three registers which form a + tmp1 = ++reg; // triple-precision accumuator. + tmp2 = ++reg; + + Ri = x6; // Inner and outer loop indexes. + Rj = x7; + + Rhi_ab = x28; // Product registers: low and high parts + Rlo_ab = x29; // of a*b and m*n. + Rhi_mn = x30; + Rlo_mn = x31; + + // x18 and up are callee-saved. + _toSave = RegSet::range(x18, reg) + Pm_base; + } + + private: + void save_regs() { + push_reg(_toSave, sp); + } + + void restore_regs() { + pop_reg(_toSave, sp); + } + + template + void unroll_2(Register count, T block) { + Label loop, end, odd; + beqz(count, end); + andi(t0, count, 0x1); + bnez(t0, odd); + align(16); + bind(loop); + (this->*block)(); + bind(odd); + (this->*block)(); + addi(count, count, -2); + bgtz(count, loop); + bind(end); + } + + template + void unroll_2(Register count, T block, Register d, Register s, Register tmp) { + Label loop, end, odd; + beqz(count, end); + andi(tmp, count, 0x1); + bnez(tmp, odd); + align(16); + bind(loop); + (this->*block)(d, s, tmp); + bind(odd); + (this->*block)(d, s, tmp); + addi(count, count, -2); + bgtz(count, loop); + bind(end); + } + + void pre1(RegisterOrConstant i) { + block_comment("pre1"); + // Pa = Pa_base; + // Pb = Pb_base + i; + // Pm = Pm_base; + // Pn = Pn_base + i; + // Ra = *Pa; + // Rb = *Pb; + // Rm = *Pm; + // Rn = *Pn; + if (i.is_register()) { + slli(t0, i.as_register(), LogBytesPerWord); + } else { + mv(t0, i.as_constant()); + slli(t0, t0, LogBytesPerWord); + } + + mv(Pa, Pa_base); + add(Pb, Pb_base, t0); + mv(Pm, Pm_base); + add(Pn, Pn_base, t0); + + ld(Ra, Address(Pa)); + ld(Rb, Address(Pb)); + ld(Rm, Address(Pm)); + ld(Rn, Address(Pn)); + + // Zero the m*n result. + mv(Rhi_mn, zr); + mv(Rlo_mn, zr); + } + + // The core multiply-accumulate step of a Montgomery + // multiplication. The idea is to schedule operations as a + // pipeline so that instructions with long latencies (loads and + // multiplies) have time to complete before their results are + // used. This most benefits in-order implementations of the + // architecture but out-of-order ones also benefit. + void step() { + block_comment("step"); + // MACC(Ra, Rb, tmp0, tmp1, tmp2); + // Ra = *++Pa; + // Rb = *--Pb; + mulhu(Rhi_ab, Ra, Rb); + mul(Rlo_ab, Ra, Rb); + addi(Pa, Pa, wordSize); + ld(Ra, Address(Pa)); + addi(Pb, Pb, -wordSize); + ld(Rb, Address(Pb)); + acc(Rhi_mn, Rlo_mn, tmp0, tmp1, tmp2); // The pending m*n from the + // previous iteration. + // MACC(Rm, Rn, tmp0, tmp1, tmp2); + // Rm = *++Pm; + // Rn = *--Pn; + mulhu(Rhi_mn, Rm, Rn); + mul(Rlo_mn, Rm, Rn); + addi(Pm, Pm, wordSize); + ld(Rm, Address(Pm)); + addi(Pn, Pn, -wordSize); + ld(Rn, Address(Pn)); + acc(Rhi_ab, Rlo_ab, tmp0, tmp1, tmp2); + } + + void post1() { + block_comment("post1"); + + // MACC(Ra, Rb, tmp0, tmp1, tmp2); + // Ra = *++Pa; + // Rb = *--Pb; + mulhu(Rhi_ab, Ra, Rb); + mul(Rlo_ab, Ra, Rb); + acc(Rhi_mn, Rlo_mn, tmp0, tmp1, tmp2); // The pending m*n + acc(Rhi_ab, Rlo_ab, tmp0, tmp1, tmp2); + + // *Pm = Rm = tmp0 * inv; + mul(Rm, tmp0, inv); + sd(Rm, Address(Pm)); + + // MACC(Rm, Rn, tmp0, tmp1, tmp2); + // tmp0 = tmp1; tmp1 = tmp2; tmp2 = 0; + mulhu(Rhi_mn, Rm, Rn); + +#ifndef PRODUCT + // assert(m[i] * n[0] + tmp0 == 0, "broken Montgomery multiply"); + { + mul(Rlo_mn, Rm, Rn); + add(Rlo_mn, tmp0, Rlo_mn); + Label ok; + beqz(Rlo_mn, ok); + stop("broken Montgomery multiply"); + bind(ok); + } +#endif + // We have very carefully set things up so that + // m[i]*n[0] + tmp0 == 0 (mod b), so we don't have to calculate + // the lower half of Rm * Rn because we know the result already: + // it must be -tmp0. tmp0 + (-tmp0) must generate a carry iff + // tmp0 != 0. So, rather than do a mul and an cad we just set + // the carry flag iff tmp0 is nonzero. + // + // mul(Rlo_mn, Rm, Rn); + // cad(zr, tmp0, Rlo_mn); + addi(t0, tmp0, -1); + sltu(t0, t0, tmp0); // Set carry iff tmp0 is nonzero + cadc(tmp0, tmp1, Rhi_mn, t0); + adc(tmp1, tmp2, zr, t0); + mv(tmp2, zr); + } + + void pre2(Register i, Register len) { + block_comment("pre2"); + // Pa = Pa_base + i-len; + // Pb = Pb_base + len; + // Pm = Pm_base + i-len; + // Pn = Pn_base + len; + + sub(Rj, i, len); + // Rj == i-len + + // Ra as temp register + slli(Ra, Rj, LogBytesPerWord); + add(Pa, Pa_base, Ra); + add(Pm, Pm_base, Ra); + slli(Ra, len, LogBytesPerWord); + add(Pb, Pb_base, Ra); + add(Pn, Pn_base, Ra); + + // Ra = *++Pa; + // Rb = *--Pb; + // Rm = *++Pm; + // Rn = *--Pn; + add(Pa, Pa, wordSize); + ld(Ra, Address(Pa)); + add(Pb, Pb, -wordSize); + ld(Rb, Address(Pb)); + add(Pm, Pm, wordSize); + ld(Rm, Address(Pm)); + add(Pn, Pn, -wordSize); + ld(Rn, Address(Pn)); + + mv(Rhi_mn, zr); + mv(Rlo_mn, zr); + } + + void post2(Register i, Register len) { + block_comment("post2"); + sub(Rj, i, len); + + cad(tmp0, tmp0, Rlo_mn, t0); // The pending m*n, low part + + // As soon as we know the least significant digit of our result, + // store it. + // Pm_base[i-len] = tmp0; + // Rj as temp register + slli(Rj, Rj, LogBytesPerWord); + add(Rj, Pm_base, Rj); + sd(tmp0, Address(Rj)); + + // tmp0 = tmp1; tmp1 = tmp2; tmp2 = 0; + cadc(tmp0, tmp1, Rhi_mn, t0); // The pending m*n, high part + adc(tmp1, tmp2, zr, t0); + mv(tmp2, zr); + } + + // A carry in tmp0 after Montgomery multiplication means that we + // should subtract multiples of n from our result in m. We'll + // keep doing that until there is no carry. + void normalize(Register len) { + block_comment("normalize"); + // while (tmp0) + // tmp0 = sub(Pm_base, Pn_base, tmp0, len); + Label loop, post, again; + Register cnt = tmp1, i = tmp2; // Re-use registers; we're done with them now + beqz(tmp0, post); { + bind(again); { + mv(i, zr); + mv(cnt, len); + slli(Rn, i, LogBytesPerWord); + add(Rm, Pm_base, Rn); + ld(Rm, Address(Rm)); + add(Rn, Pn_base, Rn); + ld(Rn, Address(Rn)); + li(t0, 1); // set carry flag, i.e. no borrow + align(16); + bind(loop); { + notr(Rn, Rn); + add(Rm, Rm, t0); + add(Rm, Rm, Rn); + sltu(t0, Rm, Rn); + slli(Rn, i, LogBytesPerWord); // Rn as temp register + add(Rn, Pm_base, Rn); + sd(Rm, Address(Rn)); + add(i, i, 1); + slli(Rn, i, LogBytesPerWord); + add(Rm, Pm_base, Rn); + ld(Rm, Address(Rm)); + add(Rn, Pn_base, Rn); + ld(Rn, Address(Rn)); + sub(cnt, cnt, 1); + } bnez(cnt, loop); + addi(tmp0, tmp0, -1); + add(tmp0, tmp0, t0); + } bnez(tmp0, again); + } bind(post); + } + + // Move memory at s to d, reversing words. + // Increments d to end of copied memory + // Destroys tmp1, tmp2 + // Preserves len + // Leaves s pointing to the address which was in d at start + void reverse(Register d, Register s, Register len, Register tmp1, Register tmp2) { + assert(tmp1 < x28 && tmp2 < x28, "register corruption"); + + slli(tmp1, len, LogBytesPerWord); + add(s, s, tmp1); + mv(tmp1, len); + unroll_2(tmp1, &MontgomeryMultiplyGenerator::reverse1, d, s, tmp2); + slli(tmp1, len, LogBytesPerWord); + sub(s, d, tmp1); + } + // [63...0] -> [31...0][63...32] + void reverse1(Register d, Register s, Register tmp) { + addi(s, s, -wordSize); + ld(tmp, Address(s)); + ror_imm(tmp, tmp, 32, t0); + sd(tmp, Address(d)); + addi(d, d, wordSize); + } + + void step_squaring() { + // An extra ACC + step(); + acc(Rhi_ab, Rlo_ab, tmp0, tmp1, tmp2); + } + + void last_squaring(Register i) { + Label dont; + // if ((i & 1) == 0) { + andi(t0, i, 0x1); + bnez(t0, dont); { + // MACC(Ra, Rb, tmp0, tmp1, tmp2); + // Ra = *++Pa; + // Rb = *--Pb; + mulhu(Rhi_ab, Ra, Rb); + mul(Rlo_ab, Ra, Rb); + acc(Rhi_ab, Rlo_ab, tmp0, tmp1, tmp2); + } bind(dont); + } + + void extra_step_squaring() { + acc(Rhi_mn, Rlo_mn, tmp0, tmp1, tmp2); // The pending m*n + + // MACC(Rm, Rn, tmp0, tmp1, tmp2); + // Rm = *++Pm; + // Rn = *--Pn; + mulhu(Rhi_mn, Rm, Rn); + mul(Rlo_mn, Rm, Rn); + addi(Pm, Pm, wordSize); + ld(Rm, Address(Pm)); + addi(Pn, Pn, -wordSize); + ld(Rn, Address(Pn)); + } + + void post1_squaring() { + acc(Rhi_mn, Rlo_mn, tmp0, tmp1, tmp2); // The pending m*n + + // *Pm = Rm = tmp0 * inv; + mul(Rm, tmp0, inv); + sd(Rm, Address(Pm)); + + // MACC(Rm, Rn, tmp0, tmp1, tmp2); + // tmp0 = tmp1; tmp1 = tmp2; tmp2 = 0; + mulhu(Rhi_mn, Rm, Rn); + +#ifndef PRODUCT + // assert(m[i] * n[0] + tmp0 == 0, "broken Montgomery multiply"); + { + mul(Rlo_mn, Rm, Rn); + add(Rlo_mn, tmp0, Rlo_mn); + Label ok; + beqz(Rlo_mn, ok); { + stop("broken Montgomery multiply"); + } bind(ok); + } +#endif + // We have very carefully set things up so that + // m[i]*n[0] + tmp0 == 0 (mod b), so we don't have to calculate + // the lower half of Rm * Rn because we know the result already: + // it must be -tmp0. tmp0 + (-tmp0) must generate a carry iff + // tmp0 != 0. So, rather than do a mul and a cad we just set + // the carry flag iff tmp0 is nonzero. + // + // mul(Rlo_mn, Rm, Rn); + // cad(zr, tmp, Rlo_mn); + addi(t0, tmp0, -1); + sltu(t0, t0, tmp0); // Set carry iff tmp0 is nonzero + cadc(tmp0, tmp1, Rhi_mn, t0); + adc(tmp1, tmp2, zr, t0); + mv(tmp2, zr); + } + + // use t0 as carry + void acc(Register Rhi, Register Rlo, + Register tmp0, Register tmp1, Register tmp2) { + cad(tmp0, tmp0, Rlo, t0); + cadc(tmp1, tmp1, Rhi, t0); + adc(tmp2, tmp2, zr, t0); + } + + public: + /** + * Fast Montgomery multiplication. The derivation of the + * algorithm is in A Cryptographic Library for the Motorola + * DSP56000, Dusse and Kaliski, Proc. EUROCRYPT 90, pp. 230-237. + * + * Arguments: + * + * Inputs for multiplication: + * c_rarg0 - int array elements a + * c_rarg1 - int array elements b + * c_rarg2 - int array elements n (the modulus) + * c_rarg3 - int length + * c_rarg4 - int inv + * c_rarg5 - int array elements m (the result) + * + * Inputs for squaring: + * c_rarg0 - int array elements a + * c_rarg1 - int array elements n (the modulus) + * c_rarg2 - int length + * c_rarg3 - int inv + * c_rarg4 - int array elements m (the result) + * + */ + address generate_multiply() { + Label argh, nothing; + bind(argh); + stop("MontgomeryMultiply total_allocation must be <= 8192"); + + align(CodeEntryAlignment); + address entry = pc(); + + beqz(Rlen, nothing); + + enter(); + + // Make room. + li(Ra, 512); + bgt(Rlen, Ra, argh); + slli(Ra, Rlen, exact_log2(4 * sizeof(jint))); + sub(Ra, sp, Ra); + andi(sp, Ra, -2 * wordSize); + + srliw(Rlen, Rlen, 1); // length in longwords = len/2 + + { + // Copy input args, reversing as we go. We use Ra as a + // temporary variable. + reverse(Ra, Pa_base, Rlen, Ri, Rj); + if (!_squaring) + reverse(Ra, Pb_base, Rlen, Ri, Rj); + reverse(Ra, Pn_base, Rlen, Ri, Rj); + } + + // Push all call-saved registers and also Pm_base which we'll need + // at the end. + save_regs(); + +#ifndef PRODUCT + // assert(inv * n[0] == -1UL, "broken inverse in Montgomery multiply"); + { + ld(Rn, Address(Pn_base)); + mul(Rlo_mn, Rn, inv); + li(t0, -1); + Label ok; + beq(Rlo_mn, t0, ok); + stop("broken inverse in Montgomery multiply"); + bind(ok); + } +#endif + + mv(Pm_base, Ra); + + mv(tmp0, zr); + mv(tmp1, zr); + mv(tmp2, zr); + + block_comment("for (int i = 0; i < len; i++) {"); + mv(Ri, zr); { + Label loop, end; + bge(Ri, Rlen, end); + + bind(loop); + pre1(Ri); + + block_comment(" for (j = i; j; j--) {"); { + mv(Rj, Ri); + unroll_2(Rj, &MontgomeryMultiplyGenerator::step); + } block_comment(" } // j"); + + post1(); + addw(Ri, Ri, 1); + blt(Ri, Rlen, loop); + bind(end); + block_comment("} // i"); + } + + block_comment("for (int i = len; i < 2*len; i++) {"); + mv(Ri, Rlen); { + Label loop, end; + slli(t0, Rlen, 1); + bge(Ri, t0, end); + + bind(loop); + pre2(Ri, Rlen); + + block_comment(" for (j = len*2-i-1; j; j--) {"); { + slliw(Rj, Rlen, 1); + subw(Rj, Rj, Ri); + subw(Rj, Rj, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::step); + } block_comment(" } // j"); + + post2(Ri, Rlen); + addw(Ri, Ri, 1); + slli(t0, Rlen, 1); + blt(Ri, t0, loop); + bind(end); + } + block_comment("} // i"); + + normalize(Rlen); + + mv(Ra, Pm_base); // Save Pm_base in Ra + restore_regs(); // Restore caller's Pm_base + + // Copy our result into caller's Pm_base + reverse(Pm_base, Ra, Rlen, Ri, Rj); + + leave(); + bind(nothing); + ret(); + + return entry; + } + + /** + * + * Arguments: + * + * Inputs: + * c_rarg0 - int array elements a + * c_rarg1 - int array elements n (the modulus) + * c_rarg2 - int length + * c_rarg3 - int inv + * c_rarg4 - int array elements m (the result) + * + */ + address generate_square() { + Label argh; + bind(argh); + stop("MontgomeryMultiply total_allocation must be <= 8192"); + + align(CodeEntryAlignment); + address entry = pc(); + + enter(); + + // Make room. + li(Ra, 512); + bgt(Rlen, Ra, argh); + slli(Ra, Rlen, exact_log2(4 * sizeof(jint))); + sub(Ra, sp, Ra); + andi(sp, Ra, -2 * wordSize); + + srliw(Rlen, Rlen, 1); // length in longwords = len/2 + + { + // Copy input args, reversing as we go. We use Ra as a + // temporary variable. + reverse(Ra, Pa_base, Rlen, Ri, Rj); + reverse(Ra, Pn_base, Rlen, Ri, Rj); + } + + // Push all call-saved registers and also Pm_base which we'll need + // at the end. + save_regs(); + + mv(Pm_base, Ra); + + mv(tmp0, zr); + mv(tmp1, zr); + mv(tmp2, zr); + + block_comment("for (int i = 0; i < len; i++) {"); + mv(Ri, zr); { + Label loop, end; + bind(loop); + bge(Ri, Rlen, end); + + pre1(Ri); + + block_comment("for (j = (i+1)/2; j; j--) {"); { + addi(Rj, Ri, 1); + srliw(Rj, Rj, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::step_squaring); + } block_comment(" } // j"); + + last_squaring(Ri); + + block_comment(" for (j = i/2; j; j--) {"); { + srliw(Rj, Ri, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::extra_step_squaring); + } block_comment(" } // j"); + + post1_squaring(); + addi(Ri, Ri, 1); + blt(Ri, Rlen, loop); + + bind(end); + block_comment("} // i"); + } + + block_comment("for (int i = len; i < 2*len; i++) {"); + mv(Ri, Rlen); { + Label loop, end; + bind(loop); + slli(t0, Rlen, 1); + bge(Ri, t0, end); + + pre2(Ri, Rlen); + + block_comment(" for (j = (2*len-i-1)/2; j; j--) {"); { + slli(Rj, Rlen, 1); + sub(Rj, Rj, Ri); + sub(Rj, Rj, 1); + srliw(Rj, Rj, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::step_squaring); + } block_comment(" } // j"); + + last_squaring(Ri); + + block_comment(" for (j = (2*len-i)/2; j; j--) {"); { + slli(Rj, Rlen, 1); + sub(Rj, Rj, Ri); + srliw(Rj, Rj, 1); + unroll_2(Rj, &MontgomeryMultiplyGenerator::extra_step_squaring); + } block_comment(" } // j"); + + post2(Ri, Rlen); + addi(Ri, Ri, 1); + slli(t0, Rlen, 1); + blt(Ri, t0, loop); + + bind(end); + block_comment("} // i"); + } + + normalize(Rlen); + + mv(Ra, Pm_base); // Save Pm_base in Ra + restore_regs(); // Restore caller's Pm_base + + // Copy our result into caller's Pm_base + reverse(Pm_base, Ra, Rlen, Ri, Rj); + + leave(); + ret(); + + return entry; + } + }; +#endif // COMPILER2 + + // Continuation point for throwing of implicit exceptions that are + // not handled in the current activation. Fabricates an exception + // oop and initiates normal exception dispatching in this + // frame. Since we need to preserve callee-saved values (currently + // only for C2, but done for C1 as well) we need a callee-saved oop + // map and therefore have to make these stubs into RuntimeStubs + // rather than BufferBlobs. If the compiler needs all registers to + // be preserved between the fault point and the exception handler + // then it must assume responsibility for that in + // AbstractCompiler::continuation_for_implicit_null_exception or + // continuation_for_implicit_division_by_zero_exception. All other + // implicit exceptions (e.g., NullPointerException or + // AbstractMethodError on entry) are either at call sites or + // otherwise assume that stack unwinding will be initiated, so + // caller saved registers were assumed volatile in the compiler. + +#undef __ +#define __ masm-> + + address generate_throw_exception(const char* name, + address runtime_entry, + Register arg1 = noreg, + Register arg2 = noreg) { + // Information about frame layout at time of blocking runtime call. + // Note that we only have to preserve callee-saved registers since + // the compilers are responsible for supplying a continuation point + // if they expect all registers to be preserved. + // n.b. riscv asserts that frame::arg_reg_save_area_bytes == 0 + assert_cond(runtime_entry != NULL); + enum layout { + fp_off = 0, + fp_off2, + return_off, + return_off2, + framesize // inclusive of return address + }; + + const int insts_size = 512; + const int locs_size = 64; + + CodeBuffer code(name, insts_size, locs_size); + OopMapSet* oop_maps = new OopMapSet(); + MacroAssembler* masm = new MacroAssembler(&code); + assert_cond(oop_maps != NULL && masm != NULL); + + address start = __ pc(); + + // This is an inlined and slightly modified version of call_VM + // which has the ability to fetch the return PC out of + // thread-local storage and also sets up last_Java_sp slightly + // differently than the real call_VM + + __ enter(); // Save FP and RA before call + + assert(is_even(framesize / 2), "sp not 16-byte aligned"); + + // ra and fp are already in place + __ addi(sp, fp, 0 - ((unsigned)framesize << LogBytesPerInt)); // prolog + + int frame_complete = __ pc() - start; + + // Set up last_Java_sp and last_Java_fp + address the_pc = __ pc(); + __ set_last_Java_frame(sp, fp, the_pc, t0); + + // Call runtime + if (arg1 != noreg) { + assert(arg2 != c_rarg1, "clobbered"); + __ mv(c_rarg1, arg1); + } + if (arg2 != noreg) { + __ mv(c_rarg2, arg2); + } + __ mv(c_rarg0, xthread); + BLOCK_COMMENT("call runtime_entry"); + int32_t offset = 0; + __ movptr_with_offset(t0, runtime_entry, offset); + __ jalr(x1, t0, offset); + + // Generate oop map + OopMap* map = new OopMap(framesize, 0); + assert_cond(map != NULL); + + oop_maps->add_gc_map(the_pc - start, map); + + __ reset_last_Java_frame(true); + + __ leave(); + + // check for pending exceptions +#ifdef ASSERT + Label L; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ bnez(t0, L); + __ should_not_reach_here(); + __ bind(L); +#endif // ASSERT + __ far_jump(RuntimeAddress(StubRoutines::forward_exception_entry())); + + + // codeBlob framesize is in words (not VMRegImpl::slot_size) + RuntimeStub* stub = + RuntimeStub::new_runtime_stub(name, + &code, + frame_complete, + (framesize >> (LogBytesPerWord - LogBytesPerInt)), + oop_maps, false); + assert(stub != NULL, "create runtime stub fail!"); + return stub->entry_point(); + } + + // Initialization + void generate_initial() { + // Generate initial stubs and initializes the entry points + + // entry points that exist in all platforms Note: This is code + // that could be shared among different platforms - however the + // benefit seems to be smaller than the disadvantage of having a + // much more complicated generator structure. See also comment in + // stubRoutines.hpp. + + StubRoutines::_forward_exception_entry = generate_forward_exception(); + + StubRoutines::_call_stub_entry = + generate_call_stub(StubRoutines::_call_stub_return_address); + + // is referenced by megamorphic call + StubRoutines::_catch_exception_entry = generate_catch_exception(); + + // Build this early so it's available for the interpreter. + StubRoutines::_throw_StackOverflowError_entry = + generate_throw_exception("StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime::throw_StackOverflowError)); + StubRoutines::_throw_delayed_StackOverflowError_entry = + generate_throw_exception("delayed StackOverflowError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime::throw_delayed_StackOverflowError)); + // Safefetch stubs. + generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry, + &StubRoutines::_safefetch32_fault_pc, + &StubRoutines::_safefetch32_continuation_pc); + generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry, + &StubRoutines::_safefetchN_fault_pc, + &StubRoutines::_safefetchN_continuation_pc); + } + + void generate_all() { + // support for verify_oop (must happen after universe_init) + StubRoutines::_verify_oop_subroutine_entry = generate_verify_oop(); + StubRoutines::_throw_AbstractMethodError_entry = + generate_throw_exception("AbstractMethodError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime:: + throw_AbstractMethodError)); + + StubRoutines::_throw_IncompatibleClassChangeError_entry = + generate_throw_exception("IncompatibleClassChangeError throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime:: + throw_IncompatibleClassChangeError)); + + StubRoutines::_throw_NullPointerException_at_call_entry = + generate_throw_exception("NullPointerException at call throw_exception", + CAST_FROM_FN_PTR(address, + SharedRuntime:: + throw_NullPointerException_at_call)); + // arraycopy stubs used by compilers + generate_arraycopy_stubs(); + +#ifdef COMPILER2 + if (UseMulAddIntrinsic) { + StubRoutines::_mulAdd = generate_mulAdd(); + } + + if (UseMultiplyToLenIntrinsic) { + StubRoutines::_multiplyToLen = generate_multiplyToLen(); + } + + if (UseSquareToLenIntrinsic) { + StubRoutines::_squareToLen = generate_squareToLen(); + } + + if (UseMontgomeryMultiplyIntrinsic) { + StubCodeMark mark(this, "StubRoutines", "montgomeryMultiply"); + MontgomeryMultiplyGenerator g(_masm, /*squaring*/false); + StubRoutines::_montgomeryMultiply = g.generate_multiply(); + } + + if (UseMontgomerySquareIntrinsic) { + StubCodeMark mark(this, "StubRoutines", "montgomerySquare"); + MontgomeryMultiplyGenerator g(_masm, /*squaring*/true); + StubRoutines::_montgomerySquare = g.generate_square(); + } + + if (UseRVVForBigIntegerShiftIntrinsics) { + StubRoutines::_bigIntegerLeftShiftWorker = generate_bigIntegerLeftShift(); + StubRoutines::_bigIntegerRightShiftWorker = generate_bigIntegerRightShift(); + } +#endif + + generate_compare_long_strings(); + + generate_string_indexof_stubs(); + + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + if (bs_nm != NULL) { + StubRoutines::riscv::_method_entry_barrier = generate_method_entry_barrier(); + } + + StubRoutines::riscv::set_completed(); + } + + public: + StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) { + if (all) { + generate_all(); + } else { + generate_initial(); + } + } + + ~StubGenerator() {} +}; // end class declaration + +#define UCM_TABLE_MAX_ENTRIES 8 +void StubGenerator_generate(CodeBuffer* code, bool all) { + if (UnsafeCopyMemory::_table == NULL) { + UnsafeCopyMemory::create_table(UCM_TABLE_MAX_ENTRIES); + } + + StubGenerator g(code, all); +} diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp new file mode 100644 index 00000000000..395a2d338e4 --- /dev/null +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/thread.inline.hpp" +#include "utilities/globalDefinitions.hpp" + +// Implementation of the platform-specific part of StubRoutines - for +// a description of how to extend it, see the stubRoutines.hpp file. + +address StubRoutines::riscv::_get_previous_sp_entry = NULL; + +address StubRoutines::riscv::_f2i_fixup = NULL; +address StubRoutines::riscv::_f2l_fixup = NULL; +address StubRoutines::riscv::_d2i_fixup = NULL; +address StubRoutines::riscv::_d2l_fixup = NULL; +address StubRoutines::riscv::_float_sign_mask = NULL; +address StubRoutines::riscv::_float_sign_flip = NULL; +address StubRoutines::riscv::_double_sign_mask = NULL; +address StubRoutines::riscv::_double_sign_flip = NULL; +address StubRoutines::riscv::_zero_blocks = NULL; +address StubRoutines::riscv::_compare_long_string_LL = NULL; +address StubRoutines::riscv::_compare_long_string_UU = NULL; +address StubRoutines::riscv::_compare_long_string_LU = NULL; +address StubRoutines::riscv::_compare_long_string_UL = NULL; +address StubRoutines::riscv::_string_indexof_linear_ll = NULL; +address StubRoutines::riscv::_string_indexof_linear_uu = NULL; +address StubRoutines::riscv::_string_indexof_linear_ul = NULL; +address StubRoutines::riscv::_large_byte_array_inflate = NULL; +address StubRoutines::riscv::_method_entry_barrier = NULL; + +bool StubRoutines::riscv::_completed = false; diff --git a/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp new file mode 100644 index 00000000000..51f07819c33 --- /dev/null +++ b/src/hotspot/cpu/riscv/stubRoutines_riscv.hpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_STUBROUTINES_RISCV_HPP +#define CPU_RISCV_STUBROUTINES_RISCV_HPP + +// This file holds the platform specific parts of the StubRoutines +// definition. See stubRoutines.hpp for a description on how to +// extend it. + +static bool returns_to_call_stub(address return_pc) { + return return_pc == _call_stub_return_address; +} + +enum platform_dependent_constants { + code_size1 = 19000, // simply increase if too small (assembler will crash if too small) + code_size2 = 28000 // simply increase if too small (assembler will crash if too small) +}; + +class riscv { + friend class StubGenerator; + + private: + static address _get_previous_sp_entry; + + static address _f2i_fixup; + static address _f2l_fixup; + static address _d2i_fixup; + static address _d2l_fixup; + + static address _float_sign_mask; + static address _float_sign_flip; + static address _double_sign_mask; + static address _double_sign_flip; + + static address _zero_blocks; + + static address _compare_long_string_LL; + static address _compare_long_string_LU; + static address _compare_long_string_UL; + static address _compare_long_string_UU; + static address _string_indexof_linear_ll; + static address _string_indexof_linear_uu; + static address _string_indexof_linear_ul; + static address _large_byte_array_inflate; + + static address _method_entry_barrier; + + static bool _completed; + + public: + + static address get_previous_sp_entry() { + return _get_previous_sp_entry; + } + + static address f2i_fixup() { + return _f2i_fixup; + } + + static address f2l_fixup() { + return _f2l_fixup; + } + + static address d2i_fixup() { + return _d2i_fixup; + } + + static address d2l_fixup() { + return _d2l_fixup; + } + + static address float_sign_mask() { + return _float_sign_mask; + } + + static address float_sign_flip() { + return _float_sign_flip; + } + + static address double_sign_mask() { + return _double_sign_mask; + } + + static address double_sign_flip() { + return _double_sign_flip; + } + + static address zero_blocks() { + return _zero_blocks; + } + + static address compare_long_string_LL() { + return _compare_long_string_LL; + } + + static address compare_long_string_LU() { + return _compare_long_string_LU; + } + + static address compare_long_string_UL() { + return _compare_long_string_UL; + } + + static address compare_long_string_UU() { + return _compare_long_string_UU; + } + + static address string_indexof_linear_ul() { + return _string_indexof_linear_ul; + } + + static address string_indexof_linear_ll() { + return _string_indexof_linear_ll; + } + + static address string_indexof_linear_uu() { + return _string_indexof_linear_uu; + } + + static address large_byte_array_inflate() { + return _large_byte_array_inflate; + } + + static address method_entry_barrier() { + return _method_entry_barrier; + } + + static bool complete() { + return _completed; + } + + static void set_completed() { + _completed = true; + } +}; + +#endif // CPU_RISCV_STUBROUTINES_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp new file mode 100644 index 00000000000..6537b2dbd94 --- /dev/null +++ b/src/hotspot/cpu/riscv/templateInterpreterGenerator_riscv.cpp @@ -0,0 +1,1794 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "interpreter/bytecodeHistogram.hpp" +#include "interpreter/bytecodeTracer.hpp" +#include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "interpreter/templateInterpreterGenerator.hpp" +#include "interpreter/templateTable.hpp" +#include "memory/resourceArea.hpp" +#include "oops/arrayOop.hpp" +#include "oops/method.hpp" +#include "oops/methodData.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiThreadState.hpp" +#include "runtime/arguments.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/jniHandles.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/synchronizer.hpp" +#include "runtime/timer.hpp" +#include "runtime/vframeArray.hpp" +#include "utilities/debug.hpp" +#include "utilities/powerOfTwo.hpp" +#include + +#ifndef PRODUCT +#include "oops/method.hpp" +#endif // !PRODUCT + +// Size of interpreter code. Increase if too small. Interpreter will +// fail with a guarantee ("not enough space for interpreter generation"); +// if too small. +// Run with +PrintInterpreter to get the VM to print out the size. +// Max size with JVMTI +int TemplateInterpreter::InterpreterCodeSize = 256 * 1024; + +#define __ _masm-> + +//----------------------------------------------------------------------------- + +address TemplateInterpreterGenerator::generate_slow_signature_handler() { + address entry = __ pc(); + + __ andi(esp, esp, -16); + __ mv(c_rarg3, esp); + // xmethod + // xlocals + // c_rarg3: first stack arg - wordSize + // adjust sp + + __ addi(sp, c_rarg3, -18 * wordSize); + __ addi(sp, sp, -2 * wordSize); + __ sd(ra, Address(sp, 0)); + + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::slow_signature_handler), + xmethod, xlocals, c_rarg3); + + // x10: result handler + + // Stack layout: + // sp: return address <- sp + // 1 garbage + // 8 integer args (if static first is unused) + // 1 float/double identifiers + // 8 double args + // stack args <- esp + // garbage + // expression stack bottom + // bcp (NULL) + // ... + + // Restore ra + __ ld(ra, Address(sp, 0)); + __ addi(sp, sp , 2 * wordSize); + + // Do FP first so we can use c_rarg3 as temp + __ lwu(c_rarg3, Address(sp, 9 * wordSize)); // float/double identifiers + + for (int i = 0; i < Argument::n_float_register_parameters_c; i++) { + const FloatRegister r = g_FPArgReg[i]; + Label d, done; + + __ andi(t0, c_rarg3, 1UL << i); + __ bnez(t0, d); + __ flw(r, Address(sp, (10 + i) * wordSize)); + __ j(done); + __ bind(d); + __ fld(r, Address(sp, (10 + i) * wordSize)); + __ bind(done); + } + + // c_rarg0 contains the result from the call of + // InterpreterRuntime::slow_signature_handler so we don't touch it + // here. It will be loaded with the JNIEnv* later. + for (int i = 1; i < Argument::n_int_register_parameters_c; i++) { + const Register rm = g_INTArgReg[i]; + __ ld(rm, Address(sp, i * wordSize)); + } + + __ addi(sp, sp, 18 * wordSize); + __ ret(); + + return entry; +} + +// Various method entries +address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::MethodKind kind) { + // xmethod: Method* + // x30: sender sp + // esp: args + + if (!InlineIntrinsics) { + return NULL; // Generate a vanilla entry + } + + // These don't need a safepoint check because they aren't virtually + // callable. We won't enter these intrinsics from compiled code. + // If in the future we added an intrinsic which was virtually callable + // we'd have to worry about how to safepoint so that this code is used. + + // mathematical functions inlined by compiler + // (interpreter must provide identical implementation + // in order to avoid monotonicity bugs when switching + // from interpreter to compiler in the middle of some + // computation) + // + // stack: + // [ arg ] <-- esp + // [ arg ] + // retaddr in ra + + address fn = NULL; + address entry_point = NULL; + Register continuation = ra; + switch (kind) { + case Interpreter::java_lang_math_abs: + entry_point = __ pc(); + __ fld(f10, Address(esp)); + __ fabs_d(f10, f10); + __ mv(sp, x30); // Restore caller's SP + break; + case Interpreter::java_lang_math_sqrt: + entry_point = __ pc(); + __ fld(f10, Address(esp)); + __ fsqrt_d(f10, f10); + __ mv(sp, x30); + break; + case Interpreter::java_lang_math_sin : + entry_point = __ pc(); + __ fld(f10, Address(esp)); + __ mv(sp, x30); + __ mv(x9, ra); + continuation = x9; // The first callee-saved register + if (StubRoutines::dsin() == NULL) { + fn = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); + } else { + fn = CAST_FROM_FN_PTR(address, StubRoutines::dsin()); + } + __ mv(t0, fn); + __ jalr(t0); + break; + case Interpreter::java_lang_math_cos : + entry_point = __ pc(); + __ fld(f10, Address(esp)); + __ mv(sp, x30); + __ mv(x9, ra); + continuation = x9; // The first callee-saved register + if (StubRoutines::dcos() == NULL) { + fn = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); + } else { + fn = CAST_FROM_FN_PTR(address, StubRoutines::dcos()); + } + __ mv(t0, fn); + __ jalr(t0); + break; + case Interpreter::java_lang_math_tan : + entry_point = __ pc(); + __ fld(f10, Address(esp)); + __ mv(sp, x30); + __ mv(x9, ra); + continuation = x9; // The first callee-saved register + if (StubRoutines::dtan() == NULL) { + fn = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); + } else { + fn = CAST_FROM_FN_PTR(address, StubRoutines::dtan()); + } + __ mv(t0, fn); + __ jalr(t0); + break; + case Interpreter::java_lang_math_log : + entry_point = __ pc(); + __ fld(f10, Address(esp)); + __ mv(sp, x30); + __ mv(x9, ra); + continuation = x9; // The first callee-saved register + if (StubRoutines::dlog() == NULL) { + fn = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); + } else { + fn = CAST_FROM_FN_PTR(address, StubRoutines::dlog()); + } + __ mv(t0, fn); + __ jalr(t0); + break; + case Interpreter::java_lang_math_log10 : + entry_point = __ pc(); + __ fld(f10, Address(esp)); + __ mv(sp, x30); + __ mv(x9, ra); + continuation = x9; // The first callee-saved register + if (StubRoutines::dlog10() == NULL) { + fn = CAST_FROM_FN_PTR(address, SharedRuntime::dlog10); + } else { + fn = CAST_FROM_FN_PTR(address, StubRoutines::dlog10()); + } + __ mv(t0, fn); + __ jalr(t0); + break; + case Interpreter::java_lang_math_exp : + entry_point = __ pc(); + __ fld(f10, Address(esp)); + __ mv(sp, x30); + __ mv(x9, ra); + continuation = x9; // The first callee-saved register + if (StubRoutines::dexp() == NULL) { + fn = CAST_FROM_FN_PTR(address, SharedRuntime::dexp); + } else { + fn = CAST_FROM_FN_PTR(address, StubRoutines::dexp()); + } + __ mv(t0, fn); + __ jalr(t0); + break; + case Interpreter::java_lang_math_pow : + entry_point = __ pc(); + __ mv(x9, ra); + continuation = x9; + __ fld(f10, Address(esp, 2 * Interpreter::stackElementSize)); + __ fld(f11, Address(esp)); + __ mv(sp, x30); + if (StubRoutines::dpow() == NULL) { + fn = CAST_FROM_FN_PTR(address, SharedRuntime::dpow); + } else { + fn = CAST_FROM_FN_PTR(address, StubRoutines::dpow()); + } + __ mv(t0, fn); + __ jalr(t0); + break; + case Interpreter::java_lang_math_fmaD : + if (UseFMA) { + entry_point = __ pc(); + __ fld(f10, Address(esp, 4 * Interpreter::stackElementSize)); + __ fld(f11, Address(esp, 2 * Interpreter::stackElementSize)); + __ fld(f12, Address(esp)); + __ fmadd_d(f10, f10, f11, f12); + __ mv(sp, x30); // Restore caller's SP + } + break; + case Interpreter::java_lang_math_fmaF : + if (UseFMA) { + entry_point = __ pc(); + __ flw(f10, Address(esp, 2 * Interpreter::stackElementSize)); + __ flw(f11, Address(esp, Interpreter::stackElementSize)); + __ flw(f12, Address(esp)); + __ fmadd_s(f10, f10, f11, f12); + __ mv(sp, x30); // Restore caller's SP + } + break; + default: + ; + } + if (entry_point != NULL) { + __ jr(continuation); + } + + return entry_point; +} + +// Abstract method entry +// Attempt to execute abstract method. Throw exception +address TemplateInterpreterGenerator::generate_abstract_entry(void) { + // xmethod: Method* + // x30: sender SP + + address entry_point = __ pc(); + + // abstract method entry + + // pop return address, reset last_sp to NULL + __ empty_expression_stack(); + __ restore_bcp(); // bcp must be correct for exception handler (was destroyed) + __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) + + // throw exception + __ call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_AbstractMethodErrorWithMethod), + xmethod); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + + return entry_point; +} + +address TemplateInterpreterGenerator::generate_StackOverflowError_handler() { + address entry = __ pc(); + +#ifdef ASSERT + { + Label L; + __ ld(t0, Address(fp, frame::interpreter_frame_monitor_block_top_offset * wordSize)); + __ mv(t1, sp); + // maximal sp for current fp (stack grows negative) + // check if frame is complete + __ bge(t0, t1, L); + __ stop ("interpreter frame not set up"); + __ bind(L); + } +#endif // ASSERT + // Restore bcp under the assumption that the current frame is still + // interpreted + __ restore_bcp(); + + // expression stack must be empty before entering the VM if an + // exception happened + __ empty_expression_stack(); + // throw exception + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_StackOverflowError)); + return entry; +} + +address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler() { + address entry = __ pc(); + // expression stack must be empty before entering the VM if an + // exception happened + __ empty_expression_stack(); + // setup parameters + + // convention: expect aberrant index in register x11 + __ zero_extend(c_rarg2, x11, 32); + // convention: expect array in register x13 + __ mv(c_rarg1, x13); + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime:: + throw_ArrayIndexOutOfBoundsException), + c_rarg1, c_rarg2); + return entry; +} + +address TemplateInterpreterGenerator::generate_ClassCastException_handler() { + address entry = __ pc(); + + // object is at TOS + __ pop_reg(c_rarg1); + + // expression stack must be empty before entering the VM if an + // exception happened + __ empty_expression_stack(); + + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime:: + throw_ClassCastException), + c_rarg1); + return entry; +} + +address TemplateInterpreterGenerator::generate_exception_handler_common( + const char* name, const char* message, bool pass_oop) { + assert(!pass_oop || message == NULL, "either oop or message but not both"); + address entry = __ pc(); + if (pass_oop) { + // object is at TOS + __ pop_reg(c_rarg2); + } + // expression stack must be empty before entering the VM if an + // exception happened + __ empty_expression_stack(); + // setup parameters + __ la(c_rarg1, Address((address)name)); + if (pass_oop) { + __ call_VM(x10, CAST_FROM_FN_PTR(address, + InterpreterRuntime:: + create_klass_exception), + c_rarg1, c_rarg2); + } else { + // kind of lame ExternalAddress can't take NULL because + // external_word_Relocation will assert. + if (message != NULL) { + __ la(c_rarg2, Address((address)message)); + } else { + __ mv(c_rarg2, NULL_WORD); + } + __ call_VM(x10, + CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception), + c_rarg1, c_rarg2); + } + // throw exception + __ j(address(Interpreter::throw_exception_entry())); + return entry; +} + +address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, size_t index_size) { + address entry = __ pc(); + + // Restore stack bottom in case i2c adjusted stack + __ ld(esp, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + // and NULL it as marker that esp is now tos until next java call + __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + __ restore_bcp(); + __ restore_locals(); + __ restore_constant_pool_cache(); + __ get_method(xmethod); + + if (state == atos) { + Register obj = x10; + Register mdp = x11; + Register tmp = x12; + __ ld(mdp, Address(xmethod, Method::method_data_offset())); + __ profile_return_type(mdp, obj, tmp); + } + + // Pop N words from the stack + __ get_cache_and_index_at_bcp(x11, x12, 1, index_size); + __ ld(x11, Address(x11, ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())); + __ andi(x11, x11, ConstantPoolCacheEntry::parameter_size_mask); + + __ shadd(esp, x11, esp, t0, 3); + + // Restore machine SP + __ ld(t0, Address(xmethod, Method::const_offset())); + __ lhu(t0, Address(t0, ConstMethod::max_stack_offset())); + __ addi(t0, t0, frame::interpreter_frame_monitor_size() + 2); + __ ld(t1, + Address(fp, frame::interpreter_frame_initial_sp_offset * wordSize)); + __ slli(t0, t0, 3); + __ sub(t0, t1, t0); + __ andi(sp, t0, -16); + + __ check_and_handle_popframe(xthread); + __ check_and_handle_earlyret(xthread); + + __ get_dispatch(); + __ dispatch_next(state, step); + + return entry; +} + +address TemplateInterpreterGenerator::generate_deopt_entry_for(TosState state, + int step, + address continuation) { + address entry = __ pc(); + __ restore_bcp(); + __ restore_locals(); + __ restore_constant_pool_cache(); + __ get_method(xmethod); + __ get_dispatch(); + + // Calculate stack limit + __ ld(t0, Address(xmethod, Method::const_offset())); + __ lhu(t0, Address(t0, ConstMethod::max_stack_offset())); + __ addi(t0, t0, frame::interpreter_frame_monitor_size() + 2); + __ ld(t1, Address(fp, frame::interpreter_frame_initial_sp_offset * wordSize)); + __ slli(t0, t0, 3); + __ sub(t0, t1, t0); + __ andi(sp, t0, -16); + + // Restore expression stack pointer + __ ld(esp, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + // NULL last_sp until next java call + __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + + // handle exceptions + { + Label L; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ beqz(t0, L); + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_pending_exception)); + __ should_not_reach_here(); + __ bind(L); + } + + if (continuation == NULL) { + __ dispatch_next(state, step); + } else { + __ jump_to_entry(continuation); + } + return entry; +} + +address TemplateInterpreterGenerator::generate_result_handler_for(BasicType type) { + address entry = __ pc(); + if (type == T_OBJECT) { + // retrieve result from frame + __ ld(x10, Address(fp, frame::interpreter_frame_oop_temp_offset * wordSize)); + // and verify it + __ verify_oop(x10); + } else { + __ cast_primitive_type(type, x10); + } + + __ ret(); // return from result handler + return entry; +} + +address TemplateInterpreterGenerator::generate_safept_entry_for(TosState state, + address runtime_entry) { + assert_cond(runtime_entry != NULL); + address entry = __ pc(); + __ push(state); + __ call_VM(noreg, runtime_entry); + __ fence(0xf, 0xf); + __ dispatch_via(vtos, Interpreter::_normal_table.table_for(vtos)); + return entry; +} + +// Helpers for commoning out cases in the various type of method entries. +// + + +// increment invocation count & check for overflow +// +// Note: checking for negative value instead of overflow +// so we have a 'sticky' overflow test +// +// xmethod: method +// +void TemplateInterpreterGenerator::generate_counter_incr(Label* overflow) { + Label done; + // Note: In tiered we increment either counters in Method* or in MDO depending if we're profiling or not. + int increment = InvocationCounter::count_increment; + Label no_mdo; + if (ProfileInterpreter) { + // Are we profiling? + __ ld(x10, Address(xmethod, Method::method_data_offset())); + __ beqz(x10, no_mdo); + // Increment counter in the MDO + const Address mdo_invocation_counter(x10, in_bytes(MethodData::invocation_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + const Address mask(x10, in_bytes(MethodData::invoke_mask_offset())); + __ increment_mask_and_jump(mdo_invocation_counter, increment, mask, t0, t1, false, overflow); + __ j(done); + } + __ bind(no_mdo); + // Increment counter in MethodCounters + const Address invocation_counter(t1, + MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset()); + __ get_method_counters(xmethod, t1, done); + const Address mask(t1, in_bytes(MethodCounters::invoke_mask_offset())); + __ increment_mask_and_jump(invocation_counter, increment, mask, t0, x11, false, overflow); + __ bind(done); +} + +void TemplateInterpreterGenerator::generate_counter_overflow(Label& do_continue) { + __ mv(c_rarg1, zr); + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow), c_rarg1); + __ j(do_continue); +} + +// See if we've got enough room on the stack for locals plus overhead +// below JavaThread::stack_overflow_limit(). If not, throw a StackOverflowError +// without going through the signal handler, i.e., reserved and yellow zones +// will not be made usable. The shadow zone must suffice to handle the +// overflow. +// The expression stack grows down incrementally, so the normal guard +// page mechanism will work for that. +// +// NOTE: Since the additional locals are also always pushed (wasn't +// obvious in generate_method_entry) so the guard should work for them +// too. +// +// Args: +// x13: number of additional locals this frame needs (what we must check) +// xmethod: Method* +// +// Kills: +// x10 +void TemplateInterpreterGenerator::generate_stack_overflow_check(void) { + + // monitor entry size: see picture of stack set + // (generate_method_entry) and frame_amd64.hpp + const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + + // total overhead size: entry_size + (saved fp through expr stack + // bottom). be sure to change this if you add/subtract anything + // to/from the overhead area + const int overhead_size = + -(frame::interpreter_frame_initial_sp_offset * wordSize) + entry_size; + + const int page_size = os::vm_page_size(); + + Label after_frame_check; + + // see if the frame is greater than one page in size. If so, + // then we need to verify there is enough stack space remaining + // for the additional locals. + __ mv(t0, (page_size - overhead_size) / Interpreter::stackElementSize); + __ bleu(x13, t0, after_frame_check); + + // compute sp as if this were going to be the last frame on + // the stack before the red zone + + // locals + overhead, in bytes + __ mv(x10, overhead_size); + __ shadd(x10, x13, x10, t0, Interpreter::logStackElementSize); // 2 slots per parameter. + + const Address stack_limit(xthread, JavaThread::stack_overflow_limit_offset()); + __ ld(t0, stack_limit); + +#ifdef ASSERT + Label limit_okay; + // Verify that thread stack limit is non-zero. + __ bnez(t0, limit_okay); + __ stop("stack overflow limit is zero"); + __ bind(limit_okay); +#endif + + // Add stack limit to locals. + __ add(x10, x10, t0); + + // Check against the current stack bottom. + __ bgtu(sp, x10, after_frame_check); + + // Remove the incoming args, peeling the machine SP back to where it + // was in the caller. This is not strictly necessary, but unless we + // do so the stack frame may have a garbage FP; this ensures a + // correct call stack that we can always unwind. The ANDI should be + // unnecessary because the sender SP in x30 is always aligned, but + // it doesn't hurt. + __ andi(sp, x30, -16); + + // Note: the restored frame is not necessarily interpreted. + // Use the shared runtime version of the StackOverflowError. + assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "stub not yet generated"); + __ far_jump(RuntimeAddress(StubRoutines::throw_StackOverflowError_entry())); + + // all done with frame size check + __ bind(after_frame_check); +} + +// Allocate monitor and lock method (asm interpreter) +// +// Args: +// xmethod: Method* +// xlocals: locals +// +// Kills: +// x10 +// c_rarg0, c_rarg1, c_rarg2, c_rarg3, ...(param regs) +// t0, t1 (temporary regs) +void TemplateInterpreterGenerator::lock_method() { + // synchronize method + const Address access_flags(xmethod, Method::access_flags_offset()); + const Address monitor_block_top(fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); + const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + +#ifdef ASSERT + __ lwu(x10, access_flags); + __ verify_access_flags(x10, JVM_ACC_SYNCHRONIZED, "method doesn't need synchronization", false); +#endif // ASSERT + + // get synchronization object + { + Label done; + __ lwu(x10, access_flags); + __ andi(t0, x10, JVM_ACC_STATIC); + // get receiver (assume this is frequent case) + __ ld(x10, Address(xlocals, Interpreter::local_offset_in_bytes(0))); + __ beqz(t0, done); + __ load_mirror(x10, xmethod); + +#ifdef ASSERT + { + Label L; + __ bnez(x10, L); + __ stop("synchronization object is NULL"); + __ bind(L); + } +#endif // ASSERT + + __ bind(done); + } + + // add space for monitor & lock + __ add(sp, sp, - entry_size); // add space for a monitor entry + __ add(esp, esp, - entry_size); + __ mv(t0, esp); + __ sd(t0, monitor_block_top); // set new monitor block top + // store object + __ sd(x10, Address(esp, BasicObjectLock::obj_offset_in_bytes())); + __ mv(c_rarg1, esp); // object address + __ lock_object(c_rarg1); +} + +// Generate a fixed interpreter frame. This is identical setup for +// interpreted methods and for native methods hence the shared code. +// +// Args: +// ra: return address +// xmethod: Method* +// xlocals: pointer to locals +// xcpool: cp cache +// stack_pointer: previous sp +void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { + // initialize fixed part of activation frame + if (native_call) { + __ add(esp, sp, - 14 * wordSize); + __ mv(xbcp, zr); + __ add(sp, sp, - 14 * wordSize); + // add 2 zero-initialized slots for native calls + __ sd(zr, Address(sp, 13 * wordSize)); + __ sd(zr, Address(sp, 12 * wordSize)); + } else { + __ add(esp, sp, - 12 * wordSize); + __ ld(t0, Address(xmethod, Method::const_offset())); // get ConstMethod + __ add(xbcp, t0, in_bytes(ConstMethod::codes_offset())); // get codebase + __ add(sp, sp, - 12 * wordSize); + } + __ sd(xbcp, Address(sp, wordSize)); + __ sd(esp, Address(sp, 0)); + + if (ProfileInterpreter) { + Label method_data_continue; + __ ld(t0, Address(xmethod, Method::method_data_offset())); + __ beqz(t0, method_data_continue); + __ la(t0, Address(t0, in_bytes(MethodData::data_offset()))); + __ bind(method_data_continue); + } + + __ sd(xmethod, Address(sp, 7 * wordSize)); + __ sd(ProfileInterpreter ? t0 : zr, Address(sp, 6 * wordSize)); + + // Get mirror and store it in the frame as GC root for this Method* + __ load_mirror(t2, xmethod); + __ sd(zr, Address(sp, 5 * wordSize)); + __ sd(t2, Address(sp, 4 * wordSize)); + + __ ld(xcpool, Address(xmethod, Method::const_offset())); + __ ld(xcpool, Address(xcpool, ConstMethod::constants_offset())); + __ ld(xcpool, Address(xcpool, ConstantPool::cache_offset_in_bytes())); + __ sd(xcpool, Address(sp, 3 * wordSize)); + __ sd(xlocals, Address(sp, 2 * wordSize)); + + __ sd(ra, Address(sp, 11 * wordSize)); + __ sd(fp, Address(sp, 10 * wordSize)); + __ la(fp, Address(sp, 12 * wordSize)); // include ra & fp + + // set sender sp + // leave last_sp as null + __ sd(x30, Address(sp, 9 * wordSize)); + __ sd(zr, Address(sp, 8 * wordSize)); + + // Move SP out of the way + if (!native_call) { + __ ld(t0, Address(xmethod, Method::const_offset())); + __ lhu(t0, Address(t0, ConstMethod::max_stack_offset())); + __ add(t0, t0, frame::interpreter_frame_monitor_size() + 2); + __ slli(t0, t0, 3); + __ sub(t0, sp, t0); + __ andi(sp, t0, -16); + } +} + +// End of helpers + +// Various method entries +//------------------------------------------------------------------------------------------------------------------------ +// +// + +// Method entry for java.lang.ref.Reference.get. +address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { + // Code: _aload_0, _getfield, _areturn + // parameter size = 1 + // + // The code that gets generated by this routine is split into 2 parts: + // 1. The "intrinsified" code for G1 (or any SATB based GC), + // 2. The slow path - which is an expansion of the regular method entry. + // + // Notes:- + // * In the G1 code we do not check whether we need to block for + // a safepoint. If G1 is enabled then we must execute the specialized + // code for Reference.get (except when the Reference object is null) + // so that we can log the value in the referent field with an SATB + // update buffer. + // If the code for the getfield template is modified so that the + // G1 pre-barrier code is executed when the current method is + // Reference.get() then going through the normal method entry + // will be fine. + // * The G1 code can, however, check the receiver object (the instance + // of java.lang.Reference) and jump to the slow path if null. If the + // Reference object is null then we obviously cannot fetch the referent + // and so we don't need to call the G1 pre-barrier. Thus we can use the + // regular method entry code to generate the NPE. + // + // This code is based on generate_accessor_entry. + // + // xmethod: Method* + // x30: senderSP must preserve for slow path, set SP to it on fast path + + // ra is live. It must be saved around calls. + + address entry = __ pc(); + + const int referent_offset = java_lang_ref_Reference::referent_offset(); + guarantee(referent_offset > 0, "referent offset not initialized"); + + Label slow_path; + const Register local_0 = c_rarg0; + // Check if local 0 != NULL + // If the receiver is null then it is OK to jump to the slow path. + __ ld(local_0, Address(esp, 0)); + __ beqz(local_0, slow_path); + + __ mv(x9, x30); // Move senderSP to a callee-saved register + + // Load the value of the referent field. + const Address field_address(local_0, referent_offset); + BarrierSetAssembler *bs = BarrierSet::barrier_set()->barrier_set_assembler(); + bs->load_at(_masm, IN_HEAP | ON_WEAK_OOP_REF, T_OBJECT, local_0, field_address, /*tmp1*/ t1, /*tmp2*/ t0); + + // areturn + __ andi(sp, x9, -16); // done with stack + __ ret(); + + // generate a vanilla interpreter entry as the slow path + __ bind(slow_path); + __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals)); + return entry; +} + +/** + * Method entry for static native methods: + * int java.util.zip.CRC32.update(int crc, int b) + */ +address TemplateInterpreterGenerator::generate_CRC32_update_entry() { + // TODO: Unimplemented generate_CRC32_update_entry + return 0; +} + +/** + * Method entry for static native methods: + * int java.util.zip.CRC32.updateBytes(int crc, byte[] b, int off, int len) + * int java.util.zip.CRC32.updateByteBuffer(int crc, long buf, int off, int len) + */ +address TemplateInterpreterGenerator::generate_CRC32_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + // TODO: Unimplemented generate_CRC32_updateBytes_entry + return 0; +} + +/** + * Method entry for intrinsic-candidate (non-native) methods: + * int java.util.zip.CRC32C.updateBytes(int crc, byte[] b, int off, int end) + * int java.util.zip.CRC32C.updateDirectByteBuffer(int crc, long buf, int off, int end) + * Unlike CRC32, CRC32C does not have any methods marked as native + * CRC32C also uses an "end" variable instead of the length variable CRC32 uses + */ +address TemplateInterpreterGenerator::generate_CRC32C_updateBytes_entry(AbstractInterpreter::MethodKind kind) { + // TODO: Unimplemented generate_CRC32C_updateBytes_entry + return 0; +} + +void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { + // See more discussion in stackOverflow.hpp. + + const int shadow_zone_size = checked_cast(StackOverflow::stack_shadow_zone_size()); + const int page_size = os::vm_page_size(); + const int n_shadow_pages = shadow_zone_size / page_size; + +#ifdef ASSERT + Label L_good_limit; + __ ld(t0, Address(xthread, JavaThread::shadow_zone_safe_limit())); + __ bnez(t0, L_good_limit); + __ stop("shadow zone safe limit is not initialized"); + __ bind(L_good_limit); + + Label L_good_watermark; + __ ld(t0, Address(xthread, JavaThread::shadow_zone_growth_watermark())); + __ bnez(t0, L_good_watermark); + __ stop("shadow zone growth watermark is not initialized"); + __ bind(L_good_watermark); +#endif + + Label L_done; + + __ ld(t0, Address(xthread, JavaThread::shadow_zone_growth_watermark())); + __ bgtu(sp, t0, L_done); + + for (int p = 1; p <= n_shadow_pages; p++) { + __ bang_stack_with_offset(p * page_size); + } + + // Record the new watermark, but only if the update is above the safe limit. + // Otherwise, the next time around the check above would pass the safe limit. + __ ld(t0, Address(xthread, JavaThread::shadow_zone_safe_limit())); + __ bleu(sp, t0, L_done); + __ sd(sp, Address(xthread, JavaThread::shadow_zone_growth_watermark())); + + __ bind(L_done); +} + +// Interpreter stub for calling a native method. (asm interpreter) +// This sets up a somewhat different looking stack for calling the +// native method than the typical interpreter frame setup. +address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) { + // determine code generation flags + bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; + + // x11: Method* + // x30: sender sp + + address entry_point = __ pc(); + + const Address constMethod (xmethod, Method::const_offset()); + const Address access_flags (xmethod, Method::access_flags_offset()); + const Address size_of_parameters(x12, ConstMethod:: + size_of_parameters_offset()); + + // get parameter size (always needed) + __ ld(x12, constMethod); + __ load_unsigned_short(x12, size_of_parameters); + + // Native calls don't need the stack size check since they have no + // expression stack and the arguments are already on the stack and + // we only add a handful of words to the stack. + + // xmethod: Method* + // x12: size of parameters + // x30: sender sp + + // for natives the size of locals is zero + + // compute beginning of parameters (xlocals) + __ shadd(xlocals, x12, esp, xlocals, 3); + __ addi(xlocals, xlocals, -wordSize); + + // Pull SP back to minimum size: this avoids holes in the stack + __ andi(sp, esp, -16); + + // initialize fixed part of activation frame + generate_fixed_frame(true); + + // make sure method is native & not abstract +#ifdef ASSERT + __ lwu(x10, access_flags); + __ verify_access_flags(x10, JVM_ACC_NATIVE, "tried to execute non-native method as native", false); + __ verify_access_flags(x10, JVM_ACC_ABSTRACT, "tried to execute abstract method in interpreter"); +#endif + + // Since at this point in the method invocation the exception + // handler would try to exit the monitor of synchronized methods + // which hasn't been entered yet, we set the thread local variable + // _do_not_unlock_if_synchronized to true. The remove_activation + // will check this flag. + + const Address do_not_unlock_if_synchronized(xthread, + in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); + __ mv(t1, true); + __ sb(t1, do_not_unlock_if_synchronized); + + // increment invocation count & check for overflow + Label invocation_counter_overflow; + if (inc_counter) { + generate_counter_incr(&invocation_counter_overflow); + } + + Label continue_after_compile; + __ bind(continue_after_compile); + + bang_stack_shadow_pages(true); + + // reset the _do_not_unlock_if_synchronized flag + __ sb(zr, do_not_unlock_if_synchronized); + + // check for synchronized methods + // Must happen AFTER invocation_counter check and stack overflow check, + // so method is not locked if overflows. + if (synchronized) { + lock_method(); + } else { + // no synchronization necessary +#ifdef ASSERT + __ lwu(x10, access_flags); + __ verify_access_flags(x10, JVM_ACC_SYNCHRONIZED, "method needs synchronization"); +#endif + } + + // start execution +#ifdef ASSERT + __ verify_frame_setup(); +#endif + + // jvmti support + __ notify_method_entry(); + + // work registers + const Register t = x18; + const Register result_handler = x19; + + // allocate space for parameters + __ ld(t, Address(xmethod, Method::const_offset())); + __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset())); + + __ slli(t, t, Interpreter::logStackElementSize); + __ sub(x30, esp, t); + __ andi(sp, x30, -16); + __ mv(esp, x30); + + // get signature handler + { + Label L; + __ ld(t, Address(xmethod, Method::signature_handler_offset())); + __ bnez(t, L); + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::prepare_native_call), + xmethod); + __ ld(t, Address(xmethod, Method::signature_handler_offset())); + __ bind(L); + } + + // call signature handler + assert(InterpreterRuntime::SignatureHandlerGenerator::from() == xlocals, + "adjust this code"); + assert(InterpreterRuntime::SignatureHandlerGenerator::to() == sp, + "adjust this code"); + assert(InterpreterRuntime::SignatureHandlerGenerator::temp() == t0, + "adjust this code"); + + // The generated handlers do not touch xmethod (the method). + // However, large signatures cannot be cached and are generated + // each time here. The slow-path generator can do a GC on return, + // so we must reload it after the call. + __ jalr(t); + __ get_method(xmethod); // slow path can do a GC, reload xmethod + + + // result handler is in x10 + // set result handler + __ mv(result_handler, x10); + // pass mirror handle if static call + { + Label L; + __ lwu(t, Address(xmethod, Method::access_flags_offset())); + __ andi(t0, t, JVM_ACC_STATIC); + __ beqz(t0, L); + // get mirror + __ load_mirror(t, xmethod); + // copy mirror into activation frame + __ sd(t, Address(fp, frame::interpreter_frame_oop_temp_offset * wordSize)); + // pass handle to mirror + __ addi(c_rarg1, fp, frame::interpreter_frame_oop_temp_offset * wordSize); + __ bind(L); + } + + // get native function entry point in x28 + { + Label L; + __ ld(x28, Address(xmethod, Method::native_function_offset())); + address unsatisfied = (SharedRuntime::native_method_throw_unsatisfied_link_error_entry()); + __ mv(t1, unsatisfied); + __ ld(t1, t1); + __ bne(x28, t1, L); + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::prepare_native_call), + xmethod); + __ get_method(xmethod); + __ ld(x28, Address(xmethod, Method::native_function_offset())); + __ bind(L); + } + + // pass JNIEnv + __ add(c_rarg0, xthread, in_bytes(JavaThread::jni_environment_offset())); + + // It is enough that the pc() points into the right code + // segment. It does not have to be the correct return pc. + Label native_return; + __ set_last_Java_frame(esp, fp, native_return, x30); + + // change thread state +#ifdef ASSERT + { + Label L; + __ lwu(t, Address(xthread, JavaThread::thread_state_offset())); + __ addi(t0, zr, (u1)_thread_in_Java); + __ beq(t, t0, L); + __ stop("Wrong thread state in native stub"); + __ bind(L); + } +#endif + + // Change state to native + __ la(t1, Address(xthread, JavaThread::thread_state_offset())); + __ mv(t0, _thread_in_native); + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + __ sw(t0, Address(t1)); + + // Call the native method. + __ jalr(x28); + __ bind(native_return); + __ get_method(xmethod); + // result potentially in x10 or f10 + + // make room for the pushes we're about to do + __ sub(t0, esp, 4 * wordSize); + __ andi(sp, t0, -16); + + // NOTE: The order of these pushes is known to frame::interpreter_frame_result + // in order to extract the result of a method call. If the order of these + // pushes change or anything else is added to the stack then the code in + // interpreter_frame_result must also change. + __ push(dtos); + __ push(ltos); + + // change thread state + // Force all preceding writes to be observed prior to thread state change + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + + __ mv(t0, _thread_in_native_trans); + __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); + + // Force this write out before the read below + __ membar(MacroAssembler::AnyAny); + + // check for safepoint operation in progress and/or pending suspend requests + { + Label L, Continue; + + // We need an acquire here to ensure that any subsequent load of the + // global SafepointSynchronize::_state flag is ordered after this load + // of the thread-local polling word. We don't want this poll to + // return false (i.e. not safepointing) and a later poll of the global + // SafepointSynchronize::_state spuriously to return true. + // + // This is to avoid a race when we're in a native->Java transition + // racing the code which wakes up from a safepoint. + __ safepoint_poll(L, true /* at_return */, true /* acquire */, false /* in_nmethod */); + __ lwu(t1, Address(xthread, JavaThread::suspend_flags_offset())); + __ beqz(t1, Continue); + __ bind(L); + + // Don't use call_VM as it will see a possible pending exception + // and forward it and never return here preventing us from + // clearing _last_native_pc down below. So we do a runtime call by + // hand. + // + __ mv(c_rarg0, xthread); + __ mv(t1, CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans)); + __ jalr(t1); + __ get_method(xmethod); + __ reinit_heapbase(); + __ bind(Continue); + } + + // change thread state + // Force all preceding writes to be observed prior to thread state change + __ membar(MacroAssembler::LoadStore | MacroAssembler::StoreStore); + + __ mv(t0, _thread_in_Java); + __ sw(t0, Address(xthread, JavaThread::thread_state_offset())); + + // reset_last_Java_frame + __ reset_last_Java_frame(true); + + if (CheckJNICalls) { + // clear_pending_jni_exception_check + __ sd(zr, Address(xthread, JavaThread::pending_jni_exception_check_fn_offset())); + } + + // reset handle block + __ ld(t, Address(xthread, JavaThread::active_handles_offset())); + __ sd(zr, Address(t, JNIHandleBlock::top_offset_in_bytes())); + + // If result is an oop unbox and store it in frame where gc will see it + // and result handler will pick it up + + { + Label no_oop; + __ la(t, ExternalAddress(AbstractInterpreter::result_handler(T_OBJECT))); + __ bne(t, result_handler, no_oop); + // Unbox oop result, e.g. JNIHandles::resolve result. + __ pop(ltos); + __ resolve_jobject(x10, xthread, t); + __ sd(x10, Address(fp, frame::interpreter_frame_oop_temp_offset * wordSize)); + // keep stack depth as expected by pushing oop which will eventually be discarded + __ push(ltos); + __ bind(no_oop); + } + + { + Label no_reguard; + __ lwu(t0, Address(xthread, in_bytes(JavaThread::stack_guard_state_offset()))); + __ addi(t1, zr, (u1)StackOverflow::stack_guard_yellow_reserved_disabled); + __ bne(t0, t1, no_reguard); + + __ pusha(); // only save smashed registers + __ mv(c_rarg0, xthread); + __ mv(t1, CAST_FROM_FN_PTR(address, SharedRuntime::reguard_yellow_pages)); + __ jalr(t1); + __ popa(); // only restore smashed registers + __ bind(no_reguard); + } + + // The method register is junk from after the thread_in_native transition + // until here. Also can't call_VM until the bcp has been + // restored. Need bcp for throwing exception below so get it now. + __ get_method(xmethod); + + // restore bcp to have legal interpreter frame, i.e., bci == 0 <=> + // xbcp == code_base() + __ ld(xbcp, Address(xmethod, Method::const_offset())); // get ConstMethod* + __ add(xbcp, xbcp, in_bytes(ConstMethod::codes_offset())); // get codebase + // handle exceptions (exception handling will handle unlocking!) + { + Label L; + __ ld(t0, Address(xthread, Thread::pending_exception_offset())); + __ beqz(t0, L); + // Note: At some point we may want to unify this with the code + // used in call_VM_base(); i.e., we should use the + // StubRoutines::forward_exception code. For now this doesn't work + // here because the sp is not correctly set at this point. + __ MacroAssembler::call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_pending_exception)); + __ should_not_reach_here(); + __ bind(L); + } + + // do unlocking if necessary + { + Label L; + __ lwu(t, Address(xmethod, Method::access_flags_offset())); + __ andi(t0, t, JVM_ACC_SYNCHRONIZED); + __ beqz(t0, L); + // the code below should be shared with interpreter macro + // assembler implementation + { + Label unlock; + // BasicObjectLock will be first in list, since this is a + // synchronized method. However, need to check that the object + // has not been unlocked by an explicit monitorexit bytecode. + + // monitor expect in c_rarg1 for slow unlock path + __ la(c_rarg1, Address(fp, // address of first monitor + (intptr_t)(frame::interpreter_frame_initial_sp_offset * + wordSize - sizeof(BasicObjectLock)))); + + __ ld(t, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes())); + __ bnez(t, unlock); + + // Entry already unlocked, need to throw exception + __ MacroAssembler::call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_illegal_monitor_state_exception)); + __ should_not_reach_here(); + + __ bind(unlock); + __ unlock_object(c_rarg1); + } + __ bind(L); + } + + // jvmti support + // Note: This must happen _after_ handling/throwing any exceptions since + // the exception handler code notifies the runtime of method exits + // too. If this happens before, method entry/exit notifications are + // not properly paired (was bug - gri 11/22/99). + __ notify_method_exit(vtos, InterpreterMacroAssembler::NotifyJVMTI); + + __ pop(ltos); + __ pop(dtos); + + __ jalr(result_handler); + + // remove activation + __ ld(esp, Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); // get sender sp + // remove frame anchor + __ leave(); + + // restore sender sp + __ mv(sp, esp); + + __ ret(); + + if (inc_counter) { + // Handle overflow of counter and compile method + __ bind(invocation_counter_overflow); + generate_counter_overflow(continue_after_compile); + } + + return entry_point; +} + +// +// Generic interpreted method entry to (asm) interpreter +// +address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) { + + // determine code generation flags + const bool inc_counter = UseCompiler || CountCompiledCalls || LogTouchedMethods; + + // t0: sender sp + address entry_point = __ pc(); + + const Address constMethod(xmethod, Method::const_offset()); + const Address access_flags(xmethod, Method::access_flags_offset()); + const Address size_of_parameters(x13, + ConstMethod::size_of_parameters_offset()); + const Address size_of_locals(x13, ConstMethod::size_of_locals_offset()); + + // get parameter size (always needed) + // need to load the const method first + __ ld(x13, constMethod); + __ load_unsigned_short(x12, size_of_parameters); + + // x12: size of parameters + + __ load_unsigned_short(x13, size_of_locals); // get size of locals in words + __ sub(x13, x13, x12); // x13 = no. of additional locals + + // see if we've got enough room on the stack for locals plus overhead. + generate_stack_overflow_check(); + + // compute beginning of parameters (xlocals) + __ shadd(xlocals, x12, esp, t1, 3); + __ add(xlocals, xlocals, -wordSize); + + // Make room for additional locals + __ slli(t1, x13, 3); + __ sub(t0, esp, t1); + + // Padding between locals and fixed part of activation frame to ensure + // SP is always 16-byte aligned. + __ andi(sp, t0, -16); + + // x13 - # of additional locals + // allocate space for locals + // explicitly initialize locals + { + Label exit, loop; + __ blez(x13, exit); // do nothing if x13 <= 0 + __ bind(loop); + __ sd(zr, Address(t0)); + __ add(t0, t0, wordSize); + __ add(x13, x13, -1); // until everything initialized + __ bnez(x13, loop); + __ bind(exit); + } + + // And the base dispatch table + __ get_dispatch(); + + // initialize fixed part of activation frame + generate_fixed_frame(false); + + // make sure method is not native & not abstract +#ifdef ASSERT + __ lwu(x10, access_flags); + __ verify_access_flags(x10, JVM_ACC_NATIVE, "tried to execute native method as non-native"); + __ verify_access_flags(x10, JVM_ACC_ABSTRACT, "tried to execute abstract method in interpreter"); +#endif + + // Since at this point in the method invocation the exception + // handler would try to exit the monitor of synchronized methods + // which hasn't been entered yet, we set the thread local variable + // _do_not_unlock_if_synchronized to true. The remove_activation + // will check this flag. + + const Address do_not_unlock_if_synchronized(xthread, + in_bytes(JavaThread::do_not_unlock_if_synchronized_offset())); + __ mv(t1, true); + __ sb(t1, do_not_unlock_if_synchronized); + + Label no_mdp; + const Register mdp = x13; + __ ld(mdp, Address(xmethod, Method::method_data_offset())); + __ beqz(mdp, no_mdp); + __ add(mdp, mdp, in_bytes(MethodData::data_offset())); + __ profile_parameters_type(mdp, x11, x12, x14); // use x11, x12, x14 as tmp registers + __ bind(no_mdp); + + // increment invocation count & check for overflow + Label invocation_counter_overflow; + if (inc_counter) { + generate_counter_incr(&invocation_counter_overflow); + } + + Label continue_after_compile; + __ bind(continue_after_compile); + + bang_stack_shadow_pages(false); + + // reset the _do_not_unlock_if_synchronized flag + __ sb(zr, do_not_unlock_if_synchronized); + + // check for synchronized methods + // Must happen AFTER invocation_counter check and stack overflow check, + // so method is not locked if overflows. + if (synchronized) { + // Allocate monitor and lock method + lock_method(); + } else { + // no synchronization necessary +#ifdef ASSERT + __ lwu(x10, access_flags); + __ verify_access_flags(x10, JVM_ACC_SYNCHRONIZED, "method needs synchronization"); +#endif + } + + // start execution +#ifdef ASSERT + __ verify_frame_setup(); +#endif + + // jvmti support + __ notify_method_entry(); + + __ dispatch_next(vtos); + + // invocation counter overflow + if (inc_counter) { + // Handle overflow of counter and compile method + __ bind(invocation_counter_overflow); + generate_counter_overflow(continue_after_compile); + } + + return entry_point; +} + +//----------------------------------------------------------------------------- +// Exceptions + +void TemplateInterpreterGenerator::generate_throw_exception() { + // Entry point in previous activation (i.e., if the caller was + // interpreted) + Interpreter::_rethrow_exception_entry = __ pc(); + // Restore sp to interpreter_frame_last_sp even though we are going + // to empty the expression stack for the exception processing. + __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + // x10: exception + // x13: return address/pc that threw exception + __ restore_bcp(); // xbcp points to call/send + __ restore_locals(); + __ restore_constant_pool_cache(); + __ reinit_heapbase(); // restore xheapbase as heapbase. + __ get_dispatch(); + + // Entry point for exceptions thrown within interpreter code + Interpreter::_throw_exception_entry = __ pc(); + // If we came here via a NullPointerException on the receiver of a + // method, xthread may be corrupt. + __ get_method(xmethod); + // expression stack is undefined here + // x10: exception + // xbcp: exception bcp + __ verify_oop(x10); + __ mv(c_rarg1, x10); + + // expression stack must be empty before entering the VM in case of + // an exception + __ empty_expression_stack(); + // find exception handler address and preserve exception oop + __ call_VM(x13, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::exception_handler_for_exception), + c_rarg1); + + // Calculate stack limit + __ ld(t0, Address(xmethod, Method::const_offset())); + __ lhu(t0, Address(t0, ConstMethod::max_stack_offset())); + __ add(t0, t0, frame::interpreter_frame_monitor_size() + 4); + __ ld(t1, Address(fp, frame::interpreter_frame_initial_sp_offset * wordSize)); + __ slli(t0, t0, 3); + __ sub(t0, t1, t0); + __ andi(sp, t0, -16); + + // x10: exception handler entry point + // x13: preserved exception oop + // xbcp: bcp for exception handler + __ push_ptr(x13); // push exception which is now the only value on the stack + __ jr(x10); // jump to exception handler (may be _remove_activation_entry!) + + // If the exception is not handled in the current frame the frame is + // removed and the exception is rethrown (i.e. exception + // continuation is _rethrow_exception). + // + // Note: At this point the bci is still the bxi for the instruction + // which caused the exception and the expression stack is + // empty. Thus, for any VM calls at this point, GC will find a legal + // oop map (with empty expression stack). + + // + // JVMTI PopFrame support + // + + Interpreter::_remove_activation_preserving_args_entry = __ pc(); + __ empty_expression_stack(); + // Set the popframe_processing bit in pending_popframe_condition + // indicating that we are currently handling popframe, so that + // call_VMs that may happen later do not trigger new popframe + // handling cycles. + __ lwu(x13, Address(xthread, JavaThread::popframe_condition_offset())); + __ ori(x13, x13, JavaThread::popframe_processing_bit); + __ sw(x13, Address(xthread, JavaThread::popframe_condition_offset())); + + { + // Check to see whether we are returning to a deoptimized frame. + // (The PopFrame call ensures that the caller of the popped frame is + // either interpreted or compiled and deoptimizes it if compiled.) + // In this case, we can't call dispatch_next() after the frame is + // popped, but instead must save the incoming arguments and restore + // them after deoptimization has occurred. + // + // Note that we don't compare the return PC against the + // deoptimization blob's unpack entry because of the presence of + // adapter frames in C2. + Label caller_not_deoptimized; + __ ld(c_rarg1, Address(fp, frame::return_addr_offset * wordSize)); + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::interpreter_contains), c_rarg1); + __ bnez(x10, caller_not_deoptimized); + + // Compute size of arguments for saving when returning to + // deoptimized caller + __ get_method(x10); + __ ld(x10, Address(x10, Method::const_offset())); + __ load_unsigned_short(x10, Address(x10, in_bytes(ConstMethod:: + size_of_parameters_offset()))); + __ slli(x10, x10, Interpreter::logStackElementSize); + __ restore_locals(); + __ sub(xlocals, xlocals, x10); + __ add(xlocals, xlocals, wordSize); + // Save these arguments + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, + Deoptimization:: + popframe_preserve_args), + xthread, x10, xlocals); + + __ remove_activation(vtos, + /* throw_monitor_exception */ false, + /* install_monitor_exception */ false, + /* notify_jvmdi */ false); + + // Inform deoptimization that it is responsible for restoring + // these arguments + __ mv(t0, JavaThread::popframe_force_deopt_reexecution_bit); + __ sw(t0, Address(xthread, JavaThread::popframe_condition_offset())); + + // Continue in deoptimization handler + __ ret(); + + __ bind(caller_not_deoptimized); + } + + __ remove_activation(vtos, + /* throw_monitor_exception */ false, + /* install_monitor_exception */ false, + /* notify_jvmdi */ false); + + // Restore the last_sp and null it out + __ ld(esp, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + __ sd(zr, Address(fp, frame::interpreter_frame_last_sp_offset * wordSize)); + + __ restore_bcp(); + __ restore_locals(); + __ restore_constant_pool_cache(); + __ get_method(xmethod); + __ get_dispatch(); + + // The method data pointer was incremented already during + // call profiling. We have to restore the mdp for the current bcp. + if (ProfileInterpreter) { + __ set_method_data_pointer_for_bcp(); + } + + // Clear the popframe condition flag + __ sw(zr, Address(xthread, JavaThread::popframe_condition_offset())); + assert(JavaThread::popframe_inactive == 0, "fix popframe_inactive"); + +#if INCLUDE_JVMTI + { + Label L_done; + + __ lbu(t0, Address(xbcp, 0)); + __ li(t1, Bytecodes::_invokestatic); + __ bne(t1, t0, L_done); + + // The member name argument must be restored if _invokestatic is re-executed after a PopFrame call. + // Detect such a case in the InterpreterRuntime function and return the member name argument,or NULL. + + __ ld(c_rarg0, Address(xlocals, 0)); + __ call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::member_name_arg_or_null),c_rarg0, xmethod, xbcp); + + __ beqz(x10, L_done); + + __ sd(x10, Address(esp, 0)); + __ bind(L_done); + } +#endif // INCLUDE_JVMTI + + // Restore machine SP + __ ld(t0, Address(xmethod, Method::const_offset())); + __ lhu(t0, Address(t0, ConstMethod::max_stack_offset())); + __ add(t0, t0, frame::interpreter_frame_monitor_size() + 4); + __ ld(t1, Address(fp, frame::interpreter_frame_initial_sp_offset * wordSize)); + __ slliw(t0, t0, 3); + __ sub(t0, t1, t0); + __ andi(sp, t0, -16); + + __ dispatch_next(vtos); + // end of PopFrame support + + Interpreter::_remove_activation_entry = __ pc(); + + // preserve exception over this code sequence + __ pop_ptr(x10); + __ sd(x10, Address(xthread, JavaThread::vm_result_offset())); + // remove the activation (without doing throws on illegalMonitorExceptions) + __ remove_activation(vtos, false, true, false); + // restore exception + __ get_vm_result(x10, xthread); + + // In between activations - previous activation type unknown yet + // compute continuation point - the continuation point expects the + // following registers set up: + // + // x10: exception + // ra: return address/pc that threw exception + // sp: expression stack of caller + // fp: fp of caller + // FIXME: There's no point saving ra here because VM calls don't trash it + __ sub(sp, sp, 2 * wordSize); + __ sd(x10, Address(sp, 0)); // save exception + __ sd(ra, Address(sp, wordSize)); // save return address + __ super_call_VM_leaf(CAST_FROM_FN_PTR(address, + SharedRuntime::exception_handler_for_return_address), + xthread, ra); + __ mv(x11, x10); // save exception handler + __ ld(x10, Address(sp, 0)); // restore exception + __ ld(ra, Address(sp, wordSize)); // restore return address + __ add(sp, sp, 2 * wordSize); + // We might be returning to a deopt handler that expects x13 to + // contain the exception pc + __ mv(x13, ra); + // Note that an "issuing PC" is actually the next PC after the call + __ jr(x11); // jump to exception + // handler of caller +} + +// +// JVMTI ForceEarlyReturn support +// +address TemplateInterpreterGenerator::generate_earlyret_entry_for(TosState state) { + address entry = __ pc(); + + __ restore_bcp(); + __ restore_locals(); + __ empty_expression_stack(); + __ load_earlyret_value(state); + + __ ld(t0, Address(xthread, JavaThread::jvmti_thread_state_offset())); + Address cond_addr(t0, JvmtiThreadState::earlyret_state_offset()); + + // Clear the earlyret state + assert(JvmtiThreadState::earlyret_inactive == 0, "should be"); + __ sd(zr, cond_addr); + + __ remove_activation(state, + false, /* throw_monitor_exception */ + false, /* install_monitor_exception */ + true); /* notify_jvmdi */ + __ ret(); + + return entry; +} +// end of ForceEarlyReturn support + +//----------------------------------------------------------------------------- +// Helper for vtos entry point generation + +void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, + address& bep, + address& cep, + address& sep, + address& aep, + address& iep, + address& lep, + address& fep, + address& dep, + address& vep) { + assert(t != NULL && t->is_valid() && t->tos_in() == vtos, "illegal template"); + Label L; + aep = __ pc(); __ push_ptr(); __ j(L); + fep = __ pc(); __ push_f(); __ j(L); + dep = __ pc(); __ push_d(); __ j(L); + lep = __ pc(); __ push_l(); __ j(L); + bep = cep = sep = + iep = __ pc(); __ push_i(); + vep = __ pc(); + __ bind(L); + generate_and_dispatch(t); +} + +//----------------------------------------------------------------------------- + +// Non-product code +#ifndef PRODUCT +address TemplateInterpreterGenerator::generate_trace_code(TosState state) { + address entry = __ pc(); + + __ push_reg(ra); + __ push(state); + __ push_reg(RegSet::range(x10, x17) + RegSet::range(x5, x7) + RegSet::range(x28, x31), sp); + __ mv(c_rarg2, x10); // Pass itos + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::trace_bytecode), c_rarg1, c_rarg2, c_rarg3); + __ pop_reg(RegSet::range(x10, x17) + RegSet::range(x5, x7) + RegSet::range(x28, x31), sp); + __ pop(state); + __ pop_reg(ra); + __ ret(); // return from result handler + + return entry; +} + +void TemplateInterpreterGenerator::count_bytecode() { + __ push_reg(t0); + __ push_reg(x10); + __ mv(x10, (address) &BytecodeCounter::_counter_value); + __ li(t0, 1); + __ amoadd_d(zr, x10, t0, Assembler::aqrl); + __ pop_reg(x10); + __ pop_reg(t0); +} + +void TemplateInterpreterGenerator::histogram_bytecode(Template* t) { ; } + +void TemplateInterpreterGenerator::histogram_bytecode_pair(Template* t) { ; } + +void TemplateInterpreterGenerator::trace_bytecode(Template* t) { + // Call a little run-time stub to avoid blow-up for each bytecode. + // The run-time runtime saves the right registers, depending on + // the tosca in-state for the given template. + + assert(Interpreter::trace_code(t->tos_in()) != NULL, "entry must have been generated"); + __ jal(Interpreter::trace_code(t->tos_in())); + __ reinit_heapbase(); +} + +void TemplateInterpreterGenerator::stop_interpreter_at() { + Label L; + __ push_reg(t0); + __ mv(t0, (address) &BytecodeCounter::_counter_value); + __ ld(t0, Address(t0)); + __ mv(t1, StopInterpreterAt); + __ bne(t0, t1, L); + __ ebreak(); + __ bind(L); + __ pop_reg(t0); +} + +#endif // !PRODUCT diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp new file mode 100644 index 00000000000..d2a301c6e74 --- /dev/null +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -0,0 +1,3951 @@ +/* + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "gc/shared/barrierSetAssembler.hpp" +#include "gc/shared/collectedHeap.hpp" +#include "gc/shared/tlab_globals.hpp" +#include "interpreter/interp_masm.hpp" +#include "interpreter/interpreter.hpp" +#include "interpreter/interpreterRuntime.hpp" +#include "interpreter/templateTable.hpp" +#include "memory/universe.hpp" +#include "oops/method.hpp" +#include "oops/methodData.hpp" +#include "oops/objArrayKlass.hpp" +#include "oops/oop.inline.hpp" +#include "prims/jvmtiExport.hpp" +#include "prims/methodHandles.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/synchronizer.hpp" +#include "utilities/powerOfTwo.hpp" + +#define __ _masm-> + +// Address computation: local variables + +static inline Address iaddress(int n) { + return Address(xlocals, Interpreter::local_offset_in_bytes(n)); +} + +static inline Address laddress(int n) { + return iaddress(n + 1); +} + +static inline Address faddress(int n) { + return iaddress(n); +} + +static inline Address daddress(int n) { + return laddress(n); +} + +static inline Address aaddress(int n) { + return iaddress(n); +} + +static inline Address iaddress(Register r, Register temp, InterpreterMacroAssembler* _masm) { + assert_cond(_masm != NULL); + _masm->shadd(temp, r, xlocals, temp, 3); + return Address(temp, 0); +} + +static inline Address laddress(Register r, Register temp, + InterpreterMacroAssembler* _masm) { + assert_cond(_masm != NULL); + _masm->shadd(temp, r, xlocals, temp, 3); + return Address(temp, Interpreter::local_offset_in_bytes(1));; +} + +static inline Address faddress(Register r, Register temp, InterpreterMacroAssembler* _masm) { + return iaddress(r, temp, _masm); +} + +static inline Address daddress(Register r, Register temp, + InterpreterMacroAssembler* _masm) { + return laddress(r, temp, _masm); +} + +static inline Address aaddress(Register r, Register temp, InterpreterMacroAssembler* _masm) { + return iaddress(r, temp, _masm); +} + +static inline Address at_rsp() { + return Address(esp, 0); +} + +// At top of Java expression stack which may be different than esp(). It +// isn't for category 1 objects. +static inline Address at_tos () { + return Address(esp, Interpreter::expr_offset_in_bytes(0)); +} + +static inline Address at_tos_p1() { + return Address(esp, Interpreter::expr_offset_in_bytes(1)); +} + +static inline Address at_tos_p2() { + return Address(esp, Interpreter::expr_offset_in_bytes(2)); +} + +static inline Address at_tos_p3() { + return Address(esp, Interpreter::expr_offset_in_bytes(3)); +} + +static inline Address at_tos_p4() { + return Address(esp, Interpreter::expr_offset_in_bytes(4)); +} + +static inline Address at_tos_p5() { + return Address(esp, Interpreter::expr_offset_in_bytes(5)); +} + +// Miscelaneous helper routines +// Store an oop (or NULL) at the Address described by obj. +// If val == noreg this means store a NULL +static void do_oop_store(InterpreterMacroAssembler* _masm, + Address dst, + Register val, + DecoratorSet decorators) { + assert(val == noreg || val == x10, "parameter is just for looks"); + assert_cond(_masm != NULL); + __ store_heap_oop(dst, val, x29, x11, decorators); +} + +static void do_oop_load(InterpreterMacroAssembler* _masm, + Address src, + Register dst, + DecoratorSet decorators) { + assert_cond(_masm != NULL); + __ load_heap_oop(dst, src, x7, x11, decorators); +} + +Address TemplateTable::at_bcp(int offset) { + assert(_desc->uses_bcp(), "inconsistent uses_bcp information"); + return Address(xbcp, offset); +} + +void TemplateTable::patch_bytecode(Bytecodes::Code bc, Register bc_reg, + Register temp_reg, bool load_bc_into_bc_reg/*=true*/, + int byte_no) +{ + if (!RewriteBytecodes) { return; } + Label L_patch_done; + + switch (bc) { + case Bytecodes::_fast_aputfield: // fall through + case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through + case Bytecodes::_fast_cputfield: // fall through + case Bytecodes::_fast_dputfield: // fall through + case Bytecodes::_fast_fputfield: // fall through + case Bytecodes::_fast_iputfield: // fall through + case Bytecodes::_fast_lputfield: // fall through + case Bytecodes::_fast_sputfield: { + // We skip bytecode quickening for putfield instructions when + // the put_code written to the constant pool cache is zero. + // This is required so that every execution of this instruction + // calls out to InterpreterRuntime::resolve_get_put to do + // additional, required work. + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + assert(load_bc_into_bc_reg, "we use bc_reg as temp"); + __ get_cache_and_index_and_bytecode_at_bcp(temp_reg, bc_reg, temp_reg, byte_no, 1); + __ mv(bc_reg, bc); + __ beqz(temp_reg, L_patch_done); + break; + } + default: + assert(byte_no == -1, "sanity"); + // the pair bytecodes have already done the load. + if (load_bc_into_bc_reg) { + __ mv(bc_reg, bc); + } + } + + if (JvmtiExport::can_post_breakpoint()) { + Label L_fast_patch; + // if a breakpoint is present we can't rewrite the stream directly + __ load_unsigned_byte(temp_reg, at_bcp(0)); + __ addi(temp_reg, temp_reg, -Bytecodes::_breakpoint); // temp_reg is temporary register. + __ bnez(temp_reg, L_fast_patch); + // Let breakpoint table handling rewrite to quicker bytecode + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::set_original_bytecode_at), xmethod, xbcp, bc_reg); + __ j(L_patch_done); + __ bind(L_fast_patch); + } + +#ifdef ASSERT + Label L_okay; + __ load_unsigned_byte(temp_reg, at_bcp(0)); + __ beq(temp_reg, bc_reg, L_okay); + __ addi(temp_reg, temp_reg, -(int) Bytecodes::java_code(bc)); + __ beqz(temp_reg, L_okay); + __ stop("patching the wrong bytecode"); + __ bind(L_okay); +#endif + + // patch bytecode + __ sb(bc_reg, at_bcp(0)); + __ bind(L_patch_done); +} + +// Individual instructions + +void TemplateTable::nop() { + transition(vtos, vtos); + // nothing to do +} + +void TemplateTable::shouldnotreachhere() { + transition(vtos, vtos); + __ stop("should not reach here bytecode"); +} + +void TemplateTable::aconst_null() +{ + transition(vtos, atos); + __ mv(x10, zr); +} + +void TemplateTable::iconst(int value) +{ + transition(vtos, itos); + __ li(x10, value); +} + +void TemplateTable::lconst(int value) +{ + transition(vtos, ltos); + __ li(x10, value); +} + +void TemplateTable::fconst(int value) +{ + transition(vtos, ftos); + static float fBuf[2] = {1.0, 2.0}; + __ mv(t0, (intptr_t)fBuf); + switch (value) { + case 0: + __ fmv_w_x(f10, zr); + break; + case 1: + __ flw(f10, t0, 0); + break; + case 2: + __ flw(f10, t0, sizeof(float)); + break; + default: + ShouldNotReachHere(); + } +} + +void TemplateTable::dconst(int value) +{ + transition(vtos, dtos); + static double dBuf[2] = {1.0, 2.0}; + __ mv(t0, (intptr_t)dBuf); + switch (value) { + case 0: + __ fmv_d_x(f10, zr); + break; + case 1: + __ fld(f10, t0, 0); + break; + case 2: + __ fld(f10, t0, sizeof(double)); + break; + default: + ShouldNotReachHere(); + } +} + +void TemplateTable::bipush() +{ + transition(vtos, itos); + __ load_signed_byte(x10, at_bcp(1)); +} + +void TemplateTable::sipush() +{ + transition(vtos, itos); + __ load_unsigned_short(x10, at_bcp(1)); + __ revb_w_w(x10, x10); + __ sraiw(x10, x10, 16); +} + +void TemplateTable::ldc(bool wide) +{ + transition(vtos, vtos); + Label call_ldc, notFloat, notClass, notInt, Done; + + if (wide) { + __ get_unsigned_2_byte_index_at_bcp(x11, 1); + } else { + __ load_unsigned_byte(x11, at_bcp(1)); + } + __ get_cpool_and_tags(x12, x10); + + const int base_offset = ConstantPool::header_size() * wordSize; + const int tags_offset = Array::base_offset_in_bytes(); + + // get type + __ addi(x13, x11, tags_offset); + __ add(x13, x10, x13); + __ membar(MacroAssembler::AnyAny); + __ lbu(x13, Address(x13, 0)); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + + // unresolved class - get the resolved class + __ mv(t1, (u1)JVM_CONSTANT_UnresolvedClass); + __ beq(x13, t1, call_ldc); + + // unresolved class in error state - call into runtime to throw the error + // from the first resolution attempt + __ mv(t1, (u1)JVM_CONSTANT_UnresolvedClassInError); + __ beq(x13, t1, call_ldc); + + // resolved class - need to call vm to get java mirror of the class + __ mv(t1, (u1)JVM_CONSTANT_Class); + __ bne(x13, t1, notClass); + + __ bind(call_ldc); + __ mv(c_rarg1, wide); + call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::ldc), c_rarg1); + __ push_ptr(x10); + __ verify_oop(x10); + __ j(Done); + + __ bind(notClass); + __ mv(t1, (u1)JVM_CONSTANT_Float); + __ bne(x13, t1, notFloat); + + // ftos + __ shadd(x11, x11, x12, x11, 3); + __ flw(f10, Address(x11, base_offset)); + __ push_f(f10); + __ j(Done); + + __ bind(notFloat); + + __ mv(t1, (u1)JVM_CONSTANT_Integer); + __ bne(x13, t1, notInt); + + // itos + __ shadd(x11, x11, x12, x11, 3); + __ lw(x10, Address(x11, base_offset)); + __ push_i(x10); + __ j(Done); + + __ bind(notInt); + condy_helper(Done); + + __ bind(Done); +} + +// Fast path for caching oop constants. +void TemplateTable::fast_aldc(bool wide) +{ + transition(vtos, atos); + + const Register result = x10; + const Register tmp = x11; + const Register rarg = x12; + + const int index_size = wide ? sizeof(u2) : sizeof(u1); + + Label resolved; + + // We are resolved if the resolved reference cache entry contains a + // non-null object (String, MethodType, etc.) + assert_different_registers(result, tmp); + __ get_cache_index_at_bcp(tmp, 1, index_size); + __ load_resolved_reference_at_index(result, tmp); + __ bnez(result, resolved); + + const address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); + + // first time invocation - must resolve first + __ mv(rarg, (int)bytecode()); + __ call_VM(result, entry, rarg); + + __ bind(resolved); + + { // Check for the null sentinel. + // If we just called the VM, it already did the mapping for us, + // but it's harmless to retry. + Label notNull; + + // Stash null_sentinel address to get its value later + int32_t offset = 0; + __ movptr_with_offset(rarg, Universe::the_null_sentinel_addr(), offset); + __ ld(tmp, Address(rarg, offset)); + __ resolve_oop_handle(tmp); + __ bne(result, tmp, notNull); + __ mv(result, zr); // NULL object reference + __ bind(notNull); + } + + if (VerifyOops) { + // Safe to call with 0 result + __ verify_oop(result); + } +} + +void TemplateTable::ldc2_w() +{ + transition(vtos, vtos); + Label notDouble, notLong, Done; + __ get_unsigned_2_byte_index_at_bcp(x10, 1); + + __ get_cpool_and_tags(x11, x12); + const int base_offset = ConstantPool::header_size() * wordSize; + const int tags_offset = Array::base_offset_in_bytes(); + + // get type + __ add(x12, x12, x10); + __ load_unsigned_byte(x12, Address(x12, tags_offset)); + __ mv(t1, JVM_CONSTANT_Double); + __ bne(x12, t1, notDouble); + + // dtos + __ shadd(x12, x10, x11, x12, 3); + __ fld(f10, Address(x12, base_offset)); + __ push_d(f10); + __ j(Done); + + __ bind(notDouble); + __ mv(t1, (int)JVM_CONSTANT_Long); + __ bne(x12, t1, notLong); + + // ltos + __ shadd(x10, x10, x11, x10, 3); + __ ld(x10, Address(x10, base_offset)); + __ push_l(x10); + __ j(Done); + + __ bind(notLong); + condy_helper(Done); + __ bind(Done); +} + +void TemplateTable::condy_helper(Label& Done) +{ + const Register obj = x10; + const Register rarg = x11; + const Register flags = x12; + const Register off = x13; + + const address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_ldc); + + __ mv(rarg, (int) bytecode()); + __ call_VM(obj, entry, rarg); + + __ get_vm_result_2(flags, xthread); + + // VMr = obj = base address to find primitive value to push + // VMr2 = flags = (tos, off) using format of CPCE::_flags + __ mv(off, flags); + __ mv(t0, ConstantPoolCacheEntry::field_index_mask); + __ andrw(off, off, t0); + + __ add(off, obj, off); + const Address field(off, 0); // base + R---->base + offset + + __ slli(flags, flags, XLEN - (ConstantPoolCacheEntry::tos_state_shift + ConstantPoolCacheEntry::tos_state_bits)); + __ srli(flags, flags, XLEN - ConstantPoolCacheEntry::tos_state_bits); // (1 << 5) - 4 --> 28~31==> flags:0~3 + + switch (bytecode()) { + case Bytecodes::_ldc: // fall through + case Bytecodes::_ldc_w: { + // tos in (itos, ftos, stos, btos, ctos, ztos) + Label notInt, notFloat, notShort, notByte, notChar, notBool; + __ mv(t1, itos); + __ bne(flags, t1, notInt); + // itos + __ lw(x10, field); + __ push(itos); + __ j(Done); + + __ bind(notInt); + __ mv(t1, ftos); + __ bne(flags, t1, notFloat); + // ftos + __ load_float(field); + __ push(ftos); + __ j(Done); + + __ bind(notFloat); + __ mv(t1, stos); + __ bne(flags, t1, notShort); + // stos + __ load_signed_short(x10, field); + __ push(stos); + __ j(Done); + + __ bind(notShort); + __ mv(t1, btos); + __ bne(flags, t1, notByte); + // btos + __ load_signed_byte(x10, field); + __ push(btos); + __ j(Done); + + __ bind(notByte); + __ mv(t1, ctos); + __ bne(flags, t1, notChar); + // ctos + __ load_unsigned_short(x10, field); + __ push(ctos); + __ j(Done); + + __ bind(notChar); + __ mv(t1, ztos); + __ bne(flags, t1, notBool); + // ztos + __ load_signed_byte(x10, field); + __ push(ztos); + __ j(Done); + + __ bind(notBool); + break; + } + + case Bytecodes::_ldc2_w: { + Label notLong, notDouble; + __ mv(t1, ltos); + __ bne(flags, t1, notLong); + // ltos + __ ld(x10, field); + __ push(ltos); + __ j(Done); + + __ bind(notLong); + __ mv(t1, dtos); + __ bne(flags, t1, notDouble); + // dtos + __ load_double(field); + __ push(dtos); + __ j(Done); + + __ bind(notDouble); + break; + } + + default: + ShouldNotReachHere(); + } + + __ stop("bad ldc/condy"); +} + +void TemplateTable::locals_index(Register reg, int offset) +{ + __ lbu(reg, at_bcp(offset)); + __ neg(reg, reg); +} + +void TemplateTable::iload() { + iload_internal(); +} + +void TemplateTable::nofast_iload() { + iload_internal(may_not_rewrite); +} + +void TemplateTable::iload_internal(RewriteControl rc) { + transition(vtos, itos); + if (RewriteFrequentPairs && rc == may_rewrite) { + Label rewrite, done; + const Register bc = x14; + + // get next bytecode + __ load_unsigned_byte(x11, at_bcp(Bytecodes::length_for(Bytecodes::_iload))); + + // if _iload, wait to rewrite to iload2. We only want to rewrite the + // last two iloads in a pair. Comparing against fast_iload means that + // the next bytecode is neither an iload or a caload, and therefore + // an iload pair. + __ mv(t1, Bytecodes::_iload); + __ beq(x11, t1, done); + + // if _fast_iload rewrite to _fast_iload2 + __ mv(t1, Bytecodes::_fast_iload); + __ mv(bc, Bytecodes::_fast_iload2); + __ beq(x11, t1, rewrite); + + // if _caload rewrite to _fast_icaload + __ mv(t1, Bytecodes::_caload); + __ mv(bc, Bytecodes::_fast_icaload); + __ beq(x11, t1, rewrite); + + // else rewrite to _fast_iload + __ mv(bc, Bytecodes::_fast_iload); + + // rewrite + // bc: new bytecode + __ bind(rewrite); + patch_bytecode(Bytecodes::_iload, bc, x11, false); + __ bind(done); + + } + + // do iload, get the local value into tos + locals_index(x11); + __ lw(x10, iaddress(x11, x10, _masm)); +} + +void TemplateTable::fast_iload2() +{ + transition(vtos, itos); + locals_index(x11); + __ lw(x10, iaddress(x11, x10, _masm)); + __ push(itos); + locals_index(x11, 3); + __ lw(x10, iaddress(x11, x10, _masm)); +} + +void TemplateTable::fast_iload() +{ + transition(vtos, itos); + locals_index(x11); + __ lw(x10, iaddress(x11, x10, _masm)); +} + +void TemplateTable::lload() +{ + transition(vtos, ltos); + __ lbu(x11, at_bcp(1)); + __ slli(x11, x11, LogBytesPerWord); + __ sub(x11, xlocals, x11); + __ ld(x10, Address(x11, Interpreter::local_offset_in_bytes(1))); +} + +void TemplateTable::fload() +{ + transition(vtos, ftos); + locals_index(x11); + __ flw(f10, faddress(x11, t0, _masm)); +} + +void TemplateTable::dload() +{ + transition(vtos, dtos); + __ lbu(x11, at_bcp(1)); + __ slli(x11, x11, LogBytesPerWord); + __ sub(x11, xlocals, x11); + __ fld(f10, Address(x11, Interpreter::local_offset_in_bytes(1))); +} + +void TemplateTable::aload() +{ + transition(vtos, atos); + locals_index(x11); + __ ld(x10, iaddress(x11, x10, _masm)); + +} + +void TemplateTable::locals_index_wide(Register reg) { + __ lhu(reg, at_bcp(2)); + __ revb_h_h_u(reg, reg); // reverse bytes in half-word and zero-extend + __ neg(reg, reg); +} + +void TemplateTable::wide_iload() { + transition(vtos, itos); + locals_index_wide(x11); + __ lw(x10, iaddress(x11, t0, _masm)); +} + +void TemplateTable::wide_lload() +{ + transition(vtos, ltos); + __ lhu(x11, at_bcp(2)); + __ revb_h_h_u(x11, x11); // reverse bytes in half-word and zero-extend + __ slli(x11, x11, LogBytesPerWord); + __ sub(x11, xlocals, x11); + __ ld(x10, Address(x11, Interpreter::local_offset_in_bytes(1))); +} + +void TemplateTable::wide_fload() +{ + transition(vtos, ftos); + locals_index_wide(x11); + __ flw(f10, faddress(x11, t0, _masm)); +} + +void TemplateTable::wide_dload() +{ + transition(vtos, dtos); + __ lhu(x11, at_bcp(2)); + __ revb_h_h_u(x11, x11); // reverse bytes in half-word and zero-extend + __ slli(x11, x11, LogBytesPerWord); + __ sub(x11, xlocals, x11); + __ fld(f10, Address(x11, Interpreter::local_offset_in_bytes(1))); +} + +void TemplateTable::wide_aload() +{ + transition(vtos, atos); + locals_index_wide(x11); + __ ld(x10, aaddress(x11, t0, _masm)); +} + +void TemplateTable::index_check(Register array, Register index) +{ + // destroys x11, t0 + // check array + __ null_check(array, arrayOopDesc::length_offset_in_bytes()); + // sign extend index for use by indexed load + // check index + const Register length = t0; + __ lwu(length, Address(array, arrayOopDesc::length_offset_in_bytes())); + if (index != x11) { + assert(x11 != array, "different registers"); + __ mv(x11, index); + } + Label ok; + __ addw(index, index, zr); + __ bltu(index, length, ok); + __ mv(x13, array); + __ mv(t0, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry); + __ jr(t0); + __ bind(ok); +} + +void TemplateTable::iaload() +{ + transition(itos, itos); + __ mv(x11, x10); + __ pop_ptr(x10); + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_INT) >> 2); + __ shadd(x10, x11, x10, t0, 2); + __ access_load_at(T_INT, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg); + __ addw(x10, x10, zr); // signed extended +} + +void TemplateTable::laload() +{ + transition(itos, ltos); + __ mv(x11, x10); + __ pop_ptr(x10); + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_LONG) >> 3); + __ shadd(x10, x11, x10, t0, 3); + __ access_load_at(T_LONG, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg); +} + +void TemplateTable::faload() +{ + transition(itos, ftos); + __ mv(x11, x10); + __ pop_ptr(x10); + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_FLOAT) >> 2); + __ shadd(x10, x11, x10, t0, 2); + __ access_load_at(T_FLOAT, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg); +} + +void TemplateTable::daload() +{ + transition(itos, dtos); + __ mv(x11, x10); + __ pop_ptr(x10); + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_DOUBLE) >> 3); + __ shadd(x10, x11, x10, t0, 3); + __ access_load_at(T_DOUBLE, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg); +} + +void TemplateTable::aaload() +{ + transition(itos, atos); + __ mv(x11, x10); + __ pop_ptr(x10); + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop); + __ shadd(x10, x11, x10, t0, LogBytesPerHeapOop); + do_oop_load(_masm, + Address(x10), + x10, + IS_ARRAY); +} + +void TemplateTable::baload() +{ + transition(itos, itos); + __ mv(x11, x10); + __ pop_ptr(x10); + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_BYTE) >> 0); + __ shadd(x10, x11, x10, t0, 0); + __ access_load_at(T_BYTE, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg); +} + +void TemplateTable::caload() +{ + transition(itos, itos); + __ mv(x11, x10); + __ pop_ptr(x10); + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_CHAR) >> 1); + __ shadd(x10, x11, x10, t0, 1); + __ access_load_at(T_CHAR, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg); +} + +// iload followed by caload frequent pair +void TemplateTable::fast_icaload() +{ + transition(vtos, itos); + // load index out of locals + locals_index(x12); + __ lw(x11, iaddress(x12, x11, _masm)); + __ pop_ptr(x10); + + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11, kills t0 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_CHAR) >> 1); // addi, max imm is 2^11 + __ shadd(x10, x11, x10, t0, 1); + __ access_load_at(T_CHAR, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg); +} + +void TemplateTable::saload() +{ + transition(itos, itos); + __ mv(x11, x10); + __ pop_ptr(x10); + // x10: array + // x11: index + index_check(x10, x11); // leaves index in x11, kills t0 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_SHORT) >> 1); + __ shadd(x10, x11, x10, t0, 1); + __ access_load_at(T_SHORT, IN_HEAP | IS_ARRAY, x10, Address(x10), noreg, noreg); +} + +void TemplateTable::iload(int n) +{ + transition(vtos, itos); + __ lw(x10, iaddress(n)); +} + +void TemplateTable::lload(int n) +{ + transition(vtos, ltos); + __ ld(x10, laddress(n)); +} + +void TemplateTable::fload(int n) +{ + transition(vtos, ftos); + __ flw(f10, faddress(n)); +} + +void TemplateTable::dload(int n) +{ + transition(vtos, dtos); + __ fld(f10, daddress(n)); +} + +void TemplateTable::aload(int n) +{ + transition(vtos, atos); + __ ld(x10, iaddress(n)); +} + +void TemplateTable::aload_0() { + aload_0_internal(); +} + +void TemplateTable::nofast_aload_0() { + aload_0_internal(may_not_rewrite); +} + +void TemplateTable::aload_0_internal(RewriteControl rc) { + // According to bytecode histograms, the pairs: + // + // _aload_0, _fast_igetfield + // _aload_0, _fast_agetfield + // _aload_0, _fast_fgetfield + // + // occur frequently. If RewriteFrequentPairs is set, the (slow) + // _aload_0 bytecode checks if the next bytecode is either + // _fast_igetfield, _fast_agetfield or _fast_fgetfield and then + // rewrites the current bytecode into a pair bytecode; otherwise it + // rewrites the current bytecode into _fast_aload_0 that doesn't do + // the pair check anymore. + // + // Note: If the next bytecode is _getfield, the rewrite must be + // delayed, otherwise we may miss an opportunity for a pair. + // + // Also rewrite frequent pairs + // aload_0, aload_1 + // aload_0, iload_1 + // These bytecodes with a small amount of code are most profitable + // to rewrite + if (RewriteFrequentPairs && rc == may_rewrite) { + Label rewrite, done; + const Register bc = x14; + + // get next bytecode + __ load_unsigned_byte(x11, at_bcp(Bytecodes::length_for(Bytecodes::_aload_0))); + + // if _getfield then wait with rewrite + __ mv(t1, Bytecodes::Bytecodes::_getfield); + __ beq(x11, t1, done); + + // if _igetfield then rewrite to _fast_iaccess_0 + assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); + __ mv(t1, Bytecodes::_fast_igetfield); + __ mv(bc, Bytecodes::_fast_iaccess_0); + __ beq(x11, t1, rewrite); + + // if _agetfield then rewrite to _fast_aaccess_0 + assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); + __ mv(t1, Bytecodes::_fast_agetfield); + __ mv(bc, Bytecodes::_fast_aaccess_0); + __ beq(x11, t1, rewrite); + + // if _fgetfield then rewrite to _fast_faccess_0 + assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "fix bytecode definition"); + __ mv(t1, Bytecodes::_fast_fgetfield); + __ mv(bc, Bytecodes::_fast_faccess_0); + __ beq(x11, t1, rewrite); + + // else rewrite to _fast_aload0 + assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "fix bytecode definition"); + __ mv(bc, Bytecodes::Bytecodes::_fast_aload_0); + + // rewrite + // bc: new bytecode + __ bind(rewrite); + patch_bytecode(Bytecodes::_aload_0, bc, x11, false); + + __ bind(done); + } + + // Do actual aload_0 (must do this after patch_bytecode which might call VM and GC might change oop). + aload(0); +} + +void TemplateTable::istore() +{ + transition(itos, vtos); + locals_index(x11); + __ sw(x10, iaddress(x11, t0, _masm)); +} + +void TemplateTable::lstore() +{ + transition(ltos, vtos); + locals_index(x11); + __ sd(x10, laddress(x11, t0, _masm)); +} + +void TemplateTable::fstore() { + transition(ftos, vtos); + locals_index(x11); + __ fsw(f10, iaddress(x11, t0, _masm)); +} + +void TemplateTable::dstore() { + transition(dtos, vtos); + locals_index(x11); + __ fsd(f10, daddress(x11, t0, _masm)); +} + +void TemplateTable::astore() +{ + transition(vtos, vtos); + __ pop_ptr(x10); + locals_index(x11); + __ sd(x10, aaddress(x11, t0, _masm)); +} + +void TemplateTable::wide_istore() { + transition(vtos, vtos); + __ pop_i(); + locals_index_wide(x11); + __ sw(x10, iaddress(x11, t0, _masm)); +} + +void TemplateTable::wide_lstore() { + transition(vtos, vtos); + __ pop_l(); + locals_index_wide(x11); + __ sd(x10, laddress(x11, t0, _masm)); +} + +void TemplateTable::wide_fstore() { + transition(vtos, vtos); + __ pop_f(); + locals_index_wide(x11); + __ fsw(f10, faddress(x11, t0, _masm)); +} + +void TemplateTable::wide_dstore() { + transition(vtos, vtos); + __ pop_d(); + locals_index_wide(x11); + __ fsd(f10, daddress(x11, t0, _masm)); +} + +void TemplateTable::wide_astore() { + transition(vtos, vtos); + __ pop_ptr(x10); + locals_index_wide(x11); + __ sd(x10, aaddress(x11, t0, _masm)); +} + +void TemplateTable::iastore() { + transition(itos, vtos); + __ pop_i(x11); + __ pop_ptr(x13); + // x10: value + // x11: index + // x13: array + index_check(x13, x11); // prefer index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_INT) >> 2); + __ shadd(t0, x11, x13, t0, 2); + __ access_store_at(T_INT, IN_HEAP | IS_ARRAY, Address(t0, 0), x10, noreg, noreg); +} + +void TemplateTable::lastore() { + transition(ltos, vtos); + __ pop_i(x11); + __ pop_ptr(x13); + // x10: value + // x11: index + // x13: array + index_check(x13, x11); // prefer index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_LONG) >> 3); + __ shadd(t0, x11, x13, t0, 3); + __ access_store_at(T_LONG, IN_HEAP | IS_ARRAY, Address(t0, 0), x10, noreg, noreg); +} + +void TemplateTable::fastore() { + transition(ftos, vtos); + __ pop_i(x11); + __ pop_ptr(x13); + // f10: value + // x11: index + // x13: array + index_check(x13, x11); // prefer index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_FLOAT) >> 2); + __ shadd(t0, x11, x13, t0, 2); + __ access_store_at(T_FLOAT, IN_HEAP | IS_ARRAY, Address(t0, 0), noreg /* ftos */, noreg, noreg); +} + +void TemplateTable::dastore() { + transition(dtos, vtos); + __ pop_i(x11); + __ pop_ptr(x13); + // f10: value + // x11: index + // x13: array + index_check(x13, x11); // prefer index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_DOUBLE) >> 3); + __ shadd(t0, x11, x13, t0, 3); + __ access_store_at(T_DOUBLE, IN_HEAP | IS_ARRAY, Address(t0, 0), noreg /* dtos */, noreg, noreg); +} + +void TemplateTable::aastore() { + Label is_null, ok_is_subtype, done; + transition(vtos, vtos); + // stack: ..., array, index, value + __ ld(x10, at_tos()); // value + __ ld(x12, at_tos_p1()); // index + __ ld(x13, at_tos_p2()); // array + + index_check(x13, x12); // kills x11 + __ add(x14, x12, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop); + __ shadd(x14, x14, x13, x14, LogBytesPerHeapOop); + + Address element_address(x14, 0); + + // do array store check - check for NULL value first + __ beqz(x10, is_null); + + // Move subklass into x11 + __ load_klass(x11, x10); + // Move superklass into x10 + __ load_klass(x10, x13); + __ ld(x10, Address(x10, + ObjArrayKlass::element_klass_offset())); + // Compress array + index * oopSize + 12 into a single register. Frees x12. + + // Generate subtype check. Blows x12, x15 + // Superklass in x10. Subklass in x11. + __ gen_subtype_check(x11, ok_is_subtype); //todo + + // Come here on failure + // object is at TOS + __ j(Interpreter::_throw_ArrayStoreException_entry); + + // Come here on success + __ bind(ok_is_subtype); + + // Get the value we will store + __ ld(x10, at_tos()); + // Now store using the appropriate barrier + do_oop_store(_masm, element_address, x10, IS_ARRAY); + __ j(done); + + // Have a NULL in x10, x13=array, x12=index. Store NULL at ary[idx] + __ bind(is_null); + __ profile_null_seen(x12); + + // Store a NULL + do_oop_store(_masm, element_address, noreg, IS_ARRAY); + + // Pop stack arguments + __ bind(done); + __ add(esp, esp, 3 * Interpreter::stackElementSize); + +} + +void TemplateTable::bastore() +{ + transition(itos, vtos); + __ pop_i(x11); + __ pop_ptr(x13); + // x10: value + // x11: index + // x13: array + index_check(x13, x11); // prefer index in x11 + + // Need to check whether array is boolean or byte + // since both types share the bastore bytecode. + __ load_klass(x12, x13); + __ lwu(x12, Address(x12, Klass::layout_helper_offset())); + Label L_skip; + __ andi(t0, x12, Klass::layout_helper_boolean_diffbit()); + __ beqz(t0, L_skip); + __ andi(x10, x10, 1); // if it is a T_BOOLEAN array, mask the stored value to 0/1 + __ bind(L_skip); + + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_BYTE) >> 0); + + __ add(x11, x13, x11); + __ access_store_at(T_BYTE, IN_HEAP | IS_ARRAY, Address(x11, 0), x10, noreg, noreg); +} + +void TemplateTable::castore() +{ + transition(itos, vtos); + __ pop_i(x11); + __ pop_ptr(x13); + // x10: value + // x11: index + // x13: array + index_check(x13, x11); // prefer index in x11 + __ add(x11, x11, arrayOopDesc::base_offset_in_bytes(T_CHAR) >> 1); + __ shadd(t0, x11, x13, t0, 1); + __ access_store_at(T_CHAR, IN_HEAP | IS_ARRAY, Address(t0, 0), x10, noreg, noreg); +} + +void TemplateTable::sastore() +{ + castore(); +} + +void TemplateTable::istore(int n) +{ + transition(itos, vtos); + __ sd(x10, iaddress(n)); +} + +void TemplateTable::lstore(int n) +{ + transition(ltos, vtos); + __ sd(x10, laddress(n)); +} + +void TemplateTable::fstore(int n) +{ + transition(ftos, vtos); + __ fsw(f10, faddress(n)); +} + +void TemplateTable::dstore(int n) +{ + transition(dtos, vtos); + __ fsd(f10, daddress(n)); +} + +void TemplateTable::astore(int n) +{ + transition(vtos, vtos); + __ pop_ptr(x10); + __ sd(x10, iaddress(n)); +} + +void TemplateTable::pop() +{ + transition(vtos, vtos); + __ addi(esp, esp, Interpreter::stackElementSize); +} + +void TemplateTable::pop2() +{ + transition(vtos, vtos); + __ addi(esp, esp, 2 * Interpreter::stackElementSize); +} + +void TemplateTable::dup() +{ + transition(vtos, vtos); + __ ld(x10, Address(esp, 0)); + __ push_reg(x10); + // stack: ..., a, a +} + +void TemplateTable::dup_x1() +{ + transition(vtos, vtos); + // stack: ..., a, b + __ ld(x10, at_tos()); // load b + __ ld(x12, at_tos_p1()); // load a + __ sd(x10, at_tos_p1()); // store b + __ sd(x12, at_tos()); // store a + __ push_reg(x10); // push b + // stack: ..., b, a, b +} + +void TemplateTable::dup_x2() +{ + transition(vtos, vtos); + // stack: ..., a, b, c + __ ld(x10, at_tos()); // load c + __ ld(x12, at_tos_p2()); // load a + __ sd(x10, at_tos_p2()); // store c in a + __ push_reg(x10); // push c + // stack: ..., c, b, c, c + __ ld(x10, at_tos_p2()); // load b + __ sd(x12, at_tos_p2()); // store a in b + // stack: ..., c, a, c, c + __ sd(x10, at_tos_p1()); // store b in c + // stack: ..., c, a, b, c +} + +void TemplateTable::dup2() +{ + transition(vtos, vtos); + // stack: ..., a, b + __ ld(x10, at_tos_p1()); // load a + __ push_reg(x10); // push a + __ ld(x10, at_tos_p1()); // load b + __ push_reg(x10); // push b + // stack: ..., a, b, a, b +} + +void TemplateTable::dup2_x1() +{ + transition(vtos, vtos); + // stack: ..., a, b, c + __ ld(x12, at_tos()); // load c + __ ld(x10, at_tos_p1()); // load b + __ push_reg(x10); // push b + __ push_reg(x12); // push c + // stack: ..., a, b, c, b, c + __ sd(x12, at_tos_p3()); // store c in b + // stack: ..., a, c, c, b, c + __ ld(x12, at_tos_p4()); // load a + __ sd(x12, at_tos_p2()); // store a in 2nd c + // stack: ..., a, c, a, b, c + __ sd(x10, at_tos_p4()); // store b in a + // stack: ..., b, c, a, b, c +} + +void TemplateTable::dup2_x2() +{ + transition(vtos, vtos); + // stack: ..., a, b, c, d + __ ld(x12, at_tos()); // load d + __ ld(x10, at_tos_p1()); // load c + __ push_reg(x10); // push c + __ push_reg(x12); // push d + // stack: ..., a, b, c, d, c, d + __ ld(x10, at_tos_p4()); // load b + __ sd(x10, at_tos_p2()); // store b in d + __ sd(x12, at_tos_p4()); // store d in b + // stack: ..., a, d, c, b, c, d + __ ld(x12, at_tos_p5()); // load a + __ ld(x10, at_tos_p3()); // load c + __ sd(x12, at_tos_p3()); // store a in c + __ sd(x10, at_tos_p5()); // store c in a + // stack: ..., c, d, a, b, c, d +} + +void TemplateTable::swap() +{ + transition(vtos, vtos); + // stack: ..., a, b + __ ld(x12, at_tos_p1()); // load a + __ ld(x10, at_tos()); // load b + __ sd(x12, at_tos()); // store a in b + __ sd(x10, at_tos_p1()); // store b in a + // stack: ..., b, a +} + +void TemplateTable::iop2(Operation op) +{ + transition(itos, itos); + // x10 <== x11 op x10 + __ pop_i(x11); + switch (op) { + case add : __ addw(x10, x11, x10); break; + case sub : __ subw(x10, x11, x10); break; + case mul : __ mulw(x10, x11, x10); break; + case _and : __ andrw(x10, x11, x10); break; + case _or : __ orrw(x10, x11, x10); break; + case _xor : __ xorrw(x10, x11, x10); break; + case shl : __ sllw(x10, x11, x10); break; + case shr : __ sraw(x10, x11, x10); break; + case ushr : __ srlw(x10, x11, x10); break; + default : ShouldNotReachHere(); + } +} + +void TemplateTable::lop2(Operation op) +{ + transition(ltos, ltos); + // x10 <== x11 op x10 + __ pop_l(x11); + switch (op) { + case add : __ add(x10, x11, x10); break; + case sub : __ sub(x10, x11, x10); break; + case mul : __ mul(x10, x11, x10); break; + case _and : __ andr(x10, x11, x10); break; + case _or : __ orr(x10, x11, x10); break; + case _xor : __ xorr(x10, x11, x10); break; + default : ShouldNotReachHere(); + } +} + +void TemplateTable::idiv() +{ + transition(itos, itos); + // explicitly check for div0 + Label no_div0; + __ bnez(x10, no_div0); + __ mv(t0, Interpreter::_throw_ArithmeticException_entry); + __ jr(t0); + __ bind(no_div0); + __ pop_i(x11); + // x10 <== x11 idiv x10 + __ corrected_idivl(x10, x11, x10, /* want_remainder */ false); +} + +void TemplateTable::irem() +{ + transition(itos, itos); + // explicitly check for div0 + Label no_div0; + __ bnez(x10, no_div0); + __ mv(t0, Interpreter::_throw_ArithmeticException_entry); + __ jr(t0); + __ bind(no_div0); + __ pop_i(x11); + // x10 <== x11 irem x10 + __ corrected_idivl(x10, x11, x10, /* want_remainder */ true); +} + +void TemplateTable::lmul() +{ + transition(ltos, ltos); + __ pop_l(x11); + __ mul(x10, x10, x11); +} + +void TemplateTable::ldiv() +{ + transition(ltos, ltos); + // explicitly check for div0 + Label no_div0; + __ bnez(x10, no_div0); + __ mv(t0, Interpreter::_throw_ArithmeticException_entry); + __ jr(t0); + __ bind(no_div0); + __ pop_l(x11); + // x10 <== x11 ldiv x10 + __ corrected_idivq(x10, x11, x10, /* want_remainder */ false); +} + +void TemplateTable::lrem() +{ + transition(ltos, ltos); + // explicitly check for div0 + Label no_div0; + __ bnez(x10, no_div0); + __ mv(t0, Interpreter::_throw_ArithmeticException_entry); + __ jr(t0); + __ bind(no_div0); + __ pop_l(x11); + // x10 <== x11 lrem x10 + __ corrected_idivq(x10, x11, x10, /* want_remainder */ true); +} + +void TemplateTable::lshl() +{ + transition(itos, ltos); + // shift count is in x10 + __ pop_l(x11); + __ sll(x10, x11, x10); +} + +void TemplateTable::lshr() +{ + transition(itos, ltos); + // shift count is in x10 + __ pop_l(x11); + __ sra(x10, x11, x10); +} + +void TemplateTable::lushr() +{ + transition(itos, ltos); + // shift count is in x10 + __ pop_l(x11); + __ srl(x10, x11, x10); +} + +void TemplateTable::fop2(Operation op) +{ + transition(ftos, ftos); + switch (op) { + case add: + __ pop_f(f11); + __ fadd_s(f10, f11, f10); + break; + case sub: + __ pop_f(f11); + __ fsub_s(f10, f11, f10); + break; + case mul: + __ pop_f(f11); + __ fmul_s(f10, f11, f10); + break; + case div: + __ pop_f(f11); + __ fdiv_s(f10, f11, f10); + break; + case rem: + __ fmv_s(f11, f10); + __ pop_f(f10); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::frem)); + break; + default: + ShouldNotReachHere(); + } +} + +void TemplateTable::dop2(Operation op) +{ + transition(dtos, dtos); + switch (op) { + case add: + __ pop_d(f11); + __ fadd_d(f10, f11, f10); + break; + case sub: + __ pop_d(f11); + __ fsub_d(f10, f11, f10); + break; + case mul: + __ pop_d(f11); + __ fmul_d(f10, f11, f10); + break; + case div: + __ pop_d(f11); + __ fdiv_d(f10, f11, f10); + break; + case rem: + __ fmv_d(f11, f10); + __ pop_d(f10); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::drem)); + break; + default: + ShouldNotReachHere(); + } +} + +void TemplateTable::ineg() +{ + transition(itos, itos); + __ negw(x10, x10); +} + +void TemplateTable::lneg() +{ + transition(ltos, ltos); + __ neg(x10, x10); +} + +void TemplateTable::fneg() +{ + transition(ftos, ftos); + __ fneg_s(f10, f10); +} + +void TemplateTable::dneg() +{ + transition(dtos, dtos); + __ fneg_d(f10, f10); +} + +void TemplateTable::iinc() +{ + transition(vtos, vtos); + __ load_signed_byte(x11, at_bcp(2)); // get constant + locals_index(x12); + __ ld(x10, iaddress(x12, x10, _masm)); + __ addw(x10, x10, x11); + __ sd(x10, iaddress(x12, t0, _masm)); +} + +void TemplateTable::wide_iinc() +{ + transition(vtos, vtos); + __ lwu(x11, at_bcp(2)); // get constant and index + __ revb_h_w_u(x11, x11); // reverse bytes in half-word (32bit) and zero-extend + __ zero_extend(x12, x11, 16); + __ neg(x12, x12); + __ slli(x11, x11, 32); + __ srai(x11, x11, 48); + __ ld(x10, iaddress(x12, t0, _masm)); + __ addw(x10, x10, x11); + __ sd(x10, iaddress(x12, t0, _masm)); +} + +void TemplateTable::convert() +{ + // Checking +#ifdef ASSERT + { + TosState tos_in = ilgl; + TosState tos_out = ilgl; + switch (bytecode()) { + case Bytecodes::_i2l: // fall through + case Bytecodes::_i2f: // fall through + case Bytecodes::_i2d: // fall through + case Bytecodes::_i2b: // fall through + case Bytecodes::_i2c: // fall through + case Bytecodes::_i2s: tos_in = itos; break; + case Bytecodes::_l2i: // fall through + case Bytecodes::_l2f: // fall through + case Bytecodes::_l2d: tos_in = ltos; break; + case Bytecodes::_f2i: // fall through + case Bytecodes::_f2l: // fall through + case Bytecodes::_f2d: tos_in = ftos; break; + case Bytecodes::_d2i: // fall through + case Bytecodes::_d2l: // fall through + case Bytecodes::_d2f: tos_in = dtos; break; + default : ShouldNotReachHere(); + } + switch (bytecode()) { + case Bytecodes::_l2i: // fall through + case Bytecodes::_f2i: // fall through + case Bytecodes::_d2i: // fall through + case Bytecodes::_i2b: // fall through + case Bytecodes::_i2c: // fall through + case Bytecodes::_i2s: tos_out = itos; break; + case Bytecodes::_i2l: // fall through + case Bytecodes::_f2l: // fall through + case Bytecodes::_d2l: tos_out = ltos; break; + case Bytecodes::_i2f: // fall through + case Bytecodes::_l2f: // fall through + case Bytecodes::_d2f: tos_out = ftos; break; + case Bytecodes::_i2d: // fall through + case Bytecodes::_l2d: // fall through + case Bytecodes::_f2d: tos_out = dtos; break; + default : ShouldNotReachHere(); + } + transition(tos_in, tos_out); + } +#endif // ASSERT + + // Conversion + switch (bytecode()) { + case Bytecodes::_i2l: + __ sign_extend(x10, x10, 32); + break; + case Bytecodes::_i2f: + __ fcvt_s_w(f10, x10); + break; + case Bytecodes::_i2d: + __ fcvt_d_w(f10, x10); + break; + case Bytecodes::_i2b: + __ sign_extend(x10, x10, 8); + break; + case Bytecodes::_i2c: + __ zero_extend(x10, x10, 16); + break; + case Bytecodes::_i2s: + __ sign_extend(x10, x10, 16); + break; + case Bytecodes::_l2i: + __ addw(x10, x10, zr); + break; + case Bytecodes::_l2f: + __ fcvt_s_l(f10, x10); + break; + case Bytecodes::_l2d: + __ fcvt_d_l(f10, x10); + break; + case Bytecodes::_f2i: + __ fcvt_w_s_safe(x10, f10); + break; + case Bytecodes::_f2l: + __ fcvt_l_s_safe(x10, f10); + break; + case Bytecodes::_f2d: + __ fcvt_d_s(f10, f10); + break; + case Bytecodes::_d2i: + __ fcvt_w_d_safe(x10, f10); + break; + case Bytecodes::_d2l: + __ fcvt_l_d_safe(x10, f10); + break; + case Bytecodes::_d2f: + __ fcvt_s_d(f10, f10); + break; + default: + ShouldNotReachHere(); + } +} + +void TemplateTable::lcmp() +{ + transition(ltos, itos); + __ pop_l(x11); + __ cmp_l2i(t0, x11, x10); + __ mv(x10, t0); +} + +void TemplateTable::float_cmp(bool is_float, int unordered_result) +{ + // For instruction feq, flt and fle, the result is 0 if either operand is NaN + if (is_float) { + __ pop_f(f11); + // if unordered_result < 0: + // we want -1 for unordered or less than, 0 for equal and 1 for + // greater than. + // else: + // we want -1 for less than, 0 for equal and 1 for unordered or + // greater than. + // f11 primary, f10 secondary + __ float_compare(x10, f11, f10, unordered_result); + } else { + __ pop_d(f11); + // if unordered_result < 0: + // we want -1 for unordered or less than, 0 for equal and 1 for + // greater than. + // else: + // we want -1 for less than, 0 for equal and 1 for unordered or + // greater than. + // f11 primary, f10 secondary + __ double_compare(x10, f11, f10, unordered_result); + } +} + +void TemplateTable::branch(bool is_jsr, bool is_wide) +{ + // We might be moving to a safepoint. The thread which calls + // Interpreter::notice_safepoints() will effectively flush its cache + // when it makes a system call, but we need to do something to + // ensure that we see the changed dispatch table. + __ membar(MacroAssembler::LoadLoad); + + __ profile_taken_branch(x10, x11); + const ByteSize be_offset = MethodCounters::backedge_counter_offset() + + InvocationCounter::counter_offset(); + const ByteSize inv_offset = MethodCounters::invocation_counter_offset() + + InvocationCounter::counter_offset(); + + // load branch displacement + if (!is_wide) { + __ lhu(x12, at_bcp(1)); + __ revb_h_h(x12, x12); // reverse bytes in half-word and sign-extend + } else { + __ lwu(x12, at_bcp(1)); + __ revb_w_w(x12, x12); // reverse bytes in word and sign-extend + } + + // Handle all the JSR stuff here, then exit. + // It's much shorter and cleaner than intermingling with the non-JSR + // normal-branch stuff occurring below. + + if (is_jsr) { + // compute return address as bci + __ ld(t1, Address(xmethod, Method::const_offset())); + __ add(t1, t1, + in_bytes(ConstMethod::codes_offset()) - (is_wide ? 5 : 3)); + __ sub(x11, xbcp, t1); + __ push_i(x11); + // Adjust the bcp by the 16-bit displacement in x12 + __ add(xbcp, xbcp, x12); + __ load_unsigned_byte(t0, Address(xbcp, 0)); + // load the next target bytecode into t0, it is the argument of dispatch_only + __ dispatch_only(vtos, /*generate_poll*/true); + return; + } + + // Normal (non-jsr) branch handling + + // Adjust the bcp by the displacement in x12 + __ add(xbcp, xbcp, x12); + + assert(UseLoopCounter || !UseOnStackReplacement, + "on-stack-replacement requires loop counters"); + Label backedge_counter_overflow; + Label dispatch; + if (UseLoopCounter) { + // increment backedge counter for backward branches + // x10: MDO + // x11: MDO bumped taken-count + // x12: target offset + __ bgtz(x12, dispatch); // count only if backward branch + + // check if MethodCounters exists + Label has_counters; + __ ld(t0, Address(xmethod, Method::method_counters_offset())); + __ bnez(t0, has_counters); + __ push_reg(x10); + __ push_reg(x11); + __ push_reg(x12); + __ call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::build_method_counters), xmethod); + __ pop_reg(x12); + __ pop_reg(x11); + __ pop_reg(x10); + __ ld(t0, Address(xmethod, Method::method_counters_offset())); + __ beqz(t0, dispatch); // No MethodCounters allocated, OutOfMemory + __ bind(has_counters); + + Label no_mdo; + int increment = InvocationCounter::count_increment; + if (ProfileInterpreter) { + // Are we profiling? + __ ld(x11, Address(xmethod, in_bytes(Method::method_data_offset()))); + __ beqz(x11, no_mdo); + // Increment the MDO backedge counter + const Address mdo_backedge_counter(x11, in_bytes(MethodData::backedge_counter_offset()) + + in_bytes(InvocationCounter::counter_offset())); + const Address mask(x11, in_bytes(MethodData::backedge_mask_offset())); + __ increment_mask_and_jump(mdo_backedge_counter, increment, mask, + x10, t0, false, + UseOnStackReplacement ? &backedge_counter_overflow : &dispatch); + __ j(dispatch); + } + __ bind(no_mdo); + // Increment backedge counter in MethodCounters* + __ ld(t0, Address(xmethod, Method::method_counters_offset())); + const Address mask(t0, in_bytes(MethodCounters::backedge_mask_offset())); + __ increment_mask_and_jump(Address(t0, be_offset), increment, mask, + x10, t1, false, + UseOnStackReplacement ? &backedge_counter_overflow : &dispatch); + __ bind(dispatch); + } + + // Pre-load the next target bytecode into t0 + __ load_unsigned_byte(t0, Address(xbcp, 0)); + + // continue with the bytecode @ target + // t0: target bytecode + // xbcp: target bcp + __ dispatch_only(vtos, /*generate_poll*/true); + + if (UseLoopCounter && UseOnStackReplacement) { + // invocation counter overflow + __ bind(backedge_counter_overflow); + __ neg(x12, x12); + __ add(x12, x12, xbcp); // branch xbcp + // IcoResult frequency_counter_overflow([JavaThread*], address branch_bcp) + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::frequency_counter_overflow), + x12); + __ load_unsigned_byte(x11, Address(xbcp, 0)); // restore target bytecode + + // x10: osr nmethod (osr ok) or NULL (osr not possible) + // w11: target bytecode + // x12: temporary + __ beqz(x10, dispatch); // test result -- no osr if null + // nmethod may have been invalidated (VM may block upon call_VM return) + __ lbu(x12, Address(x10, nmethod::state_offset())); + if (nmethod::in_use != 0) { + __ sub(x12, x12, nmethod::in_use); + } + __ bnez(x12, dispatch); + + // We have the address of an on stack replacement routine in x10 + // We need to prepare to execute the OSR method. First we must + // migrate the locals and monitors off of the stack. + + __ mv(x9, x10); // save the nmethod + + call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::OSR_migration_begin)); + + // x10 is OSR buffer, move it to expected parameter location + __ mv(j_rarg0, x10); + + // remove activation + // get sender esp + __ ld(esp, + Address(fp, frame::interpreter_frame_sender_sp_offset * wordSize)); + // remove frame anchor + __ leave(); + // Ensure compiled code always sees stack at proper alignment + __ andi(sp, esp, -16); + + // and begin the OSR nmethod + __ ld(t0, Address(x9, nmethod::osr_entry_point_offset())); + __ jr(t0); + } +} + +void TemplateTable::if_0cmp(Condition cc) +{ + transition(itos, vtos); + // assume branch is more often taken than not (loops use backward branches) + Label not_taken; + + __ addw(x10, x10, zr); + switch (cc) { + case equal: + __ bnez(x10, not_taken); + break; + case not_equal: + __ beqz(x10, not_taken); + break; + case less: + __ bgez(x10, not_taken); + break; + case less_equal: + __ bgtz(x10, not_taken); + break; + case greater: + __ blez(x10, not_taken); + break; + case greater_equal: + __ bltz(x10, not_taken); + break; + default: + break; + } + + branch(false, false); + __ bind(not_taken); + __ profile_not_taken_branch(x10); +} + +void TemplateTable::if_icmp(Condition cc) +{ + transition(itos, vtos); + // assume branch is more often taken than not (loops use backward branches) + Label not_taken; + __ pop_i(x11); + __ addw(x10, x10, zr); + switch (cc) { + case equal: + __ bne(x11, x10, not_taken); + break; + case not_equal: + __ beq(x11, x10, not_taken); + break; + case less: + __ bge(x11, x10, not_taken); + break; + case less_equal: + __ bgt(x11, x10, not_taken); + break; + case greater: + __ ble(x11, x10, not_taken); + break; + case greater_equal: + __ blt(x11, x10, not_taken); + break; + default: + break; + } + + branch(false, false); + __ bind(not_taken); + __ profile_not_taken_branch(x10); +} + +void TemplateTable::if_nullcmp(Condition cc) +{ + transition(atos, vtos); + // assume branch is more often taken than not (loops use backward branches) + Label not_taken; + if (cc == equal) { + __ bnez(x10, not_taken); + } else { + __ beqz(x10, not_taken); + } + branch(false, false); + __ bind(not_taken); + __ profile_not_taken_branch(x10); +} + +void TemplateTable::if_acmp(Condition cc) +{ + transition(atos, vtos); + // assume branch is more often taken than not (loops use backward branches) + Label not_taken; + __ pop_ptr(x11); + + if (cc == equal) { + __ bne(x11, x10, not_taken); + } else if (cc == not_equal) { + __ beq(x11, x10, not_taken); + } + branch(false, false); + __ bind(not_taken); + __ profile_not_taken_branch(x10); +} + +void TemplateTable::ret() { + transition(vtos, vtos); + // We might be moving to a safepoint. The thread which calls + // Interpreter::notice_safepoints() will effectively flush its cache + // when it makes a system call, but we need to do something to + // ensure that we see the changed dispatch table. + __ membar(MacroAssembler::LoadLoad); + + locals_index(x11); + __ ld(x11, aaddress(x11, t1, _masm)); // get return bci, compute return bcp + __ profile_ret(x11, x12); + __ ld(xbcp, Address(xmethod, Method::const_offset())); + __ add(xbcp, xbcp, x11); + __ addi(xbcp, xbcp, in_bytes(ConstMethod::codes_offset())); + __ dispatch_next(vtos, 0, /*generate_poll*/true); +} + +void TemplateTable::wide_ret() { + transition(vtos, vtos); + locals_index_wide(x11); + __ ld(x11, aaddress(x11, t0, _masm)); // get return bci, compute return bcp + __ profile_ret(x11, x12); + __ ld(xbcp, Address(xmethod, Method::const_offset())); + __ add(xbcp, xbcp, x11); + __ add(xbcp, xbcp, in_bytes(ConstMethod::codes_offset())); + __ dispatch_next(vtos, 0, /*generate_poll*/true); +} + +void TemplateTable::tableswitch() { + Label default_case, continue_execution; + transition(itos, vtos); + // align xbcp + __ la(x11, at_bcp(BytesPerInt)); + __ andi(x11, x11, -BytesPerInt); + // load lo & hi + __ lwu(x12, Address(x11, BytesPerInt)); + __ lwu(x13, Address(x11, 2 * BytesPerInt)); + __ revb_w_w(x12, x12); // reverse bytes in word (32bit) and sign-extend + __ revb_w_w(x13, x13); // reverse bytes in word (32bit) and sign-extend + // check against lo & hi + __ blt(x10, x12, default_case); + __ bgt(x10, x13, default_case); + // lookup dispatch offset + __ subw(x10, x10, x12); + __ shadd(x13, x10, x11, t0, 2); + __ lwu(x13, Address(x13, 3 * BytesPerInt)); + __ profile_switch_case(x10, x11, x12); + // continue execution + __ bind(continue_execution); + __ revb_w_w(x13, x13); // reverse bytes in word (32bit) and sign-extend + __ add(xbcp, xbcp, x13); + __ load_unsigned_byte(t0, Address(xbcp)); + __ dispatch_only(vtos, /*generate_poll*/true); + // handle default + __ bind(default_case); + __ profile_switch_default(x10); + __ lwu(x13, Address(x11, 0)); + __ j(continue_execution); +} + +void TemplateTable::lookupswitch() { + transition(itos, itos); + __ stop("lookupswitch bytecode should have been rewritten"); +} + +void TemplateTable::fast_linearswitch() { + transition(itos, vtos); + Label loop_entry, loop, found, continue_execution; + // bswap x10 so we can avoid bswapping the table entries + __ revb_w_w(x10, x10); // reverse bytes in word (32bit) and sign-extend + // align xbcp + __ la(x9, at_bcp(BytesPerInt)); // btw: should be able to get rid of + // this instruction (change offsets + // below) + __ andi(x9, x9, -BytesPerInt); + // set counter + __ lwu(x11, Address(x9, BytesPerInt)); + __ revb_w(x11, x11); + __ j(loop_entry); + // table search + __ bind(loop); + __ shadd(t0, x11, x9, t0, 3); + __ lw(t0, Address(t0, 2 * BytesPerInt)); + __ beq(x10, t0, found); + __ bind(loop_entry); + __ addi(x11, x11, -1); + __ bgez(x11, loop); + // default case + __ profile_switch_default(x10); + __ lwu(x13, Address(x9, 0)); + __ j(continue_execution); + // entry found -> get offset + __ bind(found); + __ shadd(t0, x11, x9, t0, 3); + __ lwu(x13, Address(t0, 3 * BytesPerInt)); + __ profile_switch_case(x11, x10, x9); + // continue execution + __ bind(continue_execution); + __ revb_w_w(x13, x13); // reverse bytes in word (32bit) and sign-extend + __ add(xbcp, xbcp, x13); + __ lbu(t0, Address(xbcp, 0)); + __ dispatch_only(vtos, /*generate_poll*/true); +} + +void TemplateTable::fast_binaryswitch() { + transition(itos, vtos); + // Implementation using the following core algorithm: + // + // int binary_search(int key, LookupswitchPair* array, int n) + // binary_search start: + // #Binary search according to "Methodik des Programmierens" by + // # Edsger W. Dijkstra and W.H.J. Feijen, Addison Wesley Germany 1985. + // int i = 0; + // int j = n; + // while (i + 1 < j) do + // # invariant P: 0 <= i < j <= n and (a[i] <= key < a[j] or Q) + // # with Q: for all i: 0 <= i < n: key < a[i] + // # where a stands for the array and assuming that the (inexisting) + // # element a[n] is infinitely big. + // int h = (i + j) >> 1 + // # i < h < j + // if (key < array[h].fast_match()) + // then [j = h] + // else [i = h] + // end + // # R: a[i] <= key < a[i+1] or Q + // # (i.e., if key is within array, i is the correct index) + // return i + // binary_search end + + + // Register allocation + const Register key = x10; // already set (tosca) + const Register array = x11; + const Register i = x12; + const Register j = x13; + const Register h = x14; + const Register temp = x15; + + // Find array start + __ la(array, at_bcp(3 * BytesPerInt)); // btw: should be able to + // get rid of this + // instruction (change + // offsets below) + __ andi(array, array, -BytesPerInt); + + // Initialize i & j + __ mv(i, zr); // i = 0 + __ lwu(j, Address(array, -BytesPerInt)); // j = length(array) + + // Convert j into native byteordering + __ revb_w(j, j); + + // And start + Label entry; + __ j(entry); + + // binary search loop + { + Label loop; + __ bind(loop); + __ addw(h, i, j); // h = i + j + __ srliw(h, h, 1); // h = (i + j) >> 1 + // if [key < array[h].fast_match()] + // then [j = h] + // else [i = h] + // Convert array[h].match to native byte-ordering before compare + __ shadd(temp, h, array, temp, 3); + __ ld(temp, Address(temp, 0)); + __ revb_w_w(temp, temp); // reverse bytes in word (32bit) and sign-extend + + Label L_done, L_greater; + __ bge(key, temp, L_greater); + // if [key < array[h].fast_match()] then j = h + __ mv(j, h); + __ j(L_done); + __ bind(L_greater); + // if [key >= array[h].fast_match()] then i = h + __ mv(i, h); + __ bind(L_done); + + // while [i + 1 < j] + __ bind(entry); + __ addiw(h, i, 1); // i + 1 + __ blt(h, j, loop); // i + 1 < j + } + + // end of binary search, result index is i (must check again!) + Label default_case; + // Convert array[i].match to native byte-ordering before compare + __ shadd(temp, i, array, temp, 3); + __ ld(temp, Address(temp, 0)); + __ revb_w_w(temp, temp); // reverse bytes in word (32bit) and sign-extend + __ bne(key, temp, default_case); + + // entry found -> j = offset + __ shadd(temp, i, array, temp, 3); + __ lwu(j, Address(temp, BytesPerInt)); + __ profile_switch_case(i, key, array); + __ revb_w_w(j, j); // reverse bytes in word (32bit) and sign-extend + + __ add(temp, xbcp, j); + __ load_unsigned_byte(t0, Address(temp, 0)); + + __ add(xbcp, xbcp, j); + __ la(xbcp, Address(xbcp, 0)); + __ dispatch_only(vtos, /*generate_poll*/true); + + // default case -> j = default offset + __ bind(default_case); + __ profile_switch_default(i); + __ lwu(j, Address(array, -2 * BytesPerInt)); + __ revb_w_w(j, j); // reverse bytes in word (32bit) and sign-extend + + __ add(temp, xbcp, j); + __ load_unsigned_byte(t0, Address(temp, 0)); + + __ add(xbcp, xbcp, j); + __ la(xbcp, Address(xbcp, 0)); + __ dispatch_only(vtos, /*generate_poll*/true); +} + +void TemplateTable::_return(TosState state) +{ + transition(state, state); + assert(_desc->calls_vm(), + "inconsistent calls_vm information"); // call in remove_activation + + if (_desc->bytecode() == Bytecodes::_return_register_finalizer) { + assert(state == vtos, "only valid state"); + + __ ld(c_rarg1, aaddress(0)); + __ load_klass(x13, c_rarg1); + __ lwu(x13, Address(x13, Klass::access_flags_offset())); + Label skip_register_finalizer; + __ andi(t0, x13, JVM_ACC_HAS_FINALIZER); + __ beqz(t0, skip_register_finalizer); + + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::register_finalizer), c_rarg1); + + __ bind(skip_register_finalizer); + } + + // Issue a StoreStore barrier after all stores but before return + // from any constructor for any class with a final field. We don't + // know if this is a finalizer, so we always do so. + if (_desc->bytecode() == Bytecodes::_return) { + __ membar(MacroAssembler::StoreStore); + } + + // Narrow result if state is itos but result type is smaller. + // Need to narrow in the return bytecode rather than in generate_return_entry + // since compiled code callers expect the result to already be narrowed. + if (state == itos) { + __ narrow(x10); + } + + __ remove_activation(state); + __ ret(); +} + + +// ---------------------------------------------------------------------------- +// Volatile variables demand their effects be made known to all CPU's +// in order. Store buffers on most chips allow reads & writes to +// reorder; the JMM's ReadAfterWrite.java test fails in -Xint mode +// without some kind of memory barrier (i.e., it's not sufficient that +// the interpreter does not reorder volatile references, the hardware +// also must not reorder them). +// +// According to the new Java Memory Model (JMM): +// (1) All volatiles are serialized wrt to each other. ALSO reads & +// writes act as aquire & release, so: +// (2) A read cannot let unrelated NON-volatile memory refs that +// happen after the read float up to before the read. It's OK for +// non-volatile memory refs that happen before the volatile read to +// float down below it. +// (3) Similar a volatile write cannot let unrelated NON-volatile +// memory refs that happen BEFORE the write float down to after the +// write. It's OK for non-volatile memory refs that happen after the +// volatile write to float up before it. +// +// We only put in barriers around volatile refs (they are expensive), +// not _between_ memory refs (that would require us to track the +// flavor of the previous memory refs). Requirements (2) and (3) +// require some barriers before volatile stores and after volatile +// loads. These nearly cover requirement (1) but miss the +// volatile-store-volatile-load case. This final case is placed after +// volatile-stores although it could just as well go before +// volatile-loads. + +void TemplateTable::resolve_cache_and_index(int byte_no, + Register Rcache, + Register index, + size_t index_size) { + const Register temp = x9; + assert_different_registers(Rcache, index, temp); + + Label resolved, clinit_barrier_slow; + + Bytecodes::Code code = bytecode(); + switch (code) { + case Bytecodes::_nofast_getfield: code = Bytecodes::_getfield; break; + case Bytecodes::_nofast_putfield: code = Bytecodes::_putfield; break; + default: break; + } + + assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); + __ get_cache_and_index_and_bytecode_at_bcp(Rcache, index, temp, byte_no, 1, index_size); + __ mv(t0, (int) code); + __ beq(temp, t0, resolved); + + // resolve first time through + // Class initialization barrier slow path lands here as well. + __ bind(clinit_barrier_slow); + + address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::resolve_from_cache); + __ mv(temp, (int) code); + __ call_VM(noreg, entry, temp); + + // Update registers with resolved info + __ get_cache_and_index_at_bcp(Rcache, index, 1, index_size); + // n.b. unlike x86 Rcache is now rcpool plus the indexed offset + // so all clients ofthis method must be modified accordingly + __ bind(resolved); + + // Class initialization barrier for static methods + if (VM_Version::supports_fast_class_init_checks() && bytecode() == Bytecodes::_invokestatic) { + __ load_resolved_method_at_index(byte_no, temp, Rcache); + __ load_method_holder(temp, temp); + __ clinit_barrier(temp, t0, NULL, &clinit_barrier_slow); + } +} + +// The Rcache and index registers must be set before call +// n.b unlike x86 cache already includes the index offset +void TemplateTable::load_field_cp_cache_entry(Register obj, + Register cache, + Register index, + Register off, + Register flags, + bool is_static = false) { + assert_different_registers(cache, index, flags, off); + + ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + // Field offset + __ ld(off, Address(cache, in_bytes(cp_base_offset + + ConstantPoolCacheEntry::f2_offset()))); + // Flags + __ lwu(flags, Address(cache, in_bytes(cp_base_offset + + ConstantPoolCacheEntry::flags_offset()))); + + // klass overwrite register + if (is_static) { + __ ld(obj, Address(cache, in_bytes(cp_base_offset + + ConstantPoolCacheEntry::f1_offset()))); + const int mirror_offset = in_bytes(Klass::java_mirror_offset()); + __ ld(obj, Address(obj, mirror_offset)); + __ resolve_oop_handle(obj); + } +} + +void TemplateTable::load_invoke_cp_cache_entry(int byte_no, + Register method, + Register itable_index, + Register flags, + bool is_invokevirtual, + bool is_invokevfinal, /*unused*/ + bool is_invokedynamic) { + // setup registers + const Register cache = t1; + const Register index = x14; + assert_different_registers(method, flags); + assert_different_registers(method, cache, index); + assert_different_registers(itable_index, flags); + assert_different_registers(itable_index, cache, index); + // determine constant pool cache field offsets + assert(is_invokevirtual == (byte_no == f2_byte), "is_invokevirtual flag redundant"); + const int method_offset = in_bytes(ConstantPoolCache::base_offset() + + (is_invokevirtual ? + ConstantPoolCacheEntry::f2_offset() : + ConstantPoolCacheEntry::f1_offset())); + const int flags_offset = in_bytes(ConstantPoolCache::base_offset() + + ConstantPoolCacheEntry::flags_offset()); + // access constant pool cache fields + const int index_offset = in_bytes(ConstantPoolCache::base_offset() + + ConstantPoolCacheEntry::f2_offset()); + + const size_t index_size = (is_invokedynamic ? sizeof(u4) : sizeof(u2)); + resolve_cache_and_index(byte_no, cache, index, index_size); + __ ld(method, Address(cache, method_offset)); + + if (itable_index != noreg) { + __ ld(itable_index, Address(cache, index_offset)); + } + __ lwu(flags, Address(cache, flags_offset)); +} + +// The registers cache and index expected to be set before call. +// Correct values of the cache and index registers are preserved. +void TemplateTable::jvmti_post_field_access(Register cache, Register index, + bool is_static, bool has_tos) { + // do the JVMTI work here to avoid disturbing the register state below + // We use c_rarg registers here beacause we want to use the register used in + // the call to the VM + if (JvmtiExport::can_post_field_access()) { + // Check to see if a field access watch has been set before we + // take the time to call into the VM. + Label L1; + assert_different_registers(cache, index, x10); + int32_t offset = 0; + __ la_patchable(t0, ExternalAddress((address) JvmtiExport::get_field_access_count_addr()), offset); + __ lwu(x10, Address(t0, offset)); + + __ beqz(x10, L1); + + __ get_cache_and_index_at_bcp(c_rarg2, c_rarg3, 1); + __ la(c_rarg2, Address(c_rarg2, in_bytes(ConstantPoolCache::base_offset()))); + + if (is_static) { + __ mv(c_rarg1, zr); // NULL object reference + } else { + __ ld(c_rarg1, at_tos()); // get object pointer without popping it + __ verify_oop(c_rarg1); + } + // c_rarg1: object pointer or NULL + // c_rarg2: cache entry pointer + // c_rarg3: jvalue object on the stack + __ call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::post_field_access), + c_rarg1, c_rarg2, c_rarg3); + __ get_cache_and_index_at_bcp(cache, index, 1); + __ bind(L1); + } +} + +void TemplateTable::pop_and_check_object(Register r) +{ + __ pop_ptr(r); + __ null_check(r); // for field access must check obj. + __ verify_oop(r); +} + +void TemplateTable::getfield_or_static(int byte_no, bool is_static, RewriteControl rc) +{ + const Register cache = x12; + const Register index = x13; + const Register obj = x14; + const Register off = x9; + const Register flags = x10; + const Register raw_flags = x16; + const Register bc = x14; // uses same reg as obj, so don't mix them + + resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); + jvmti_post_field_access(cache, index, is_static, false); + load_field_cp_cache_entry(obj, cache, index, off, raw_flags, is_static); + + if (!is_static) { + // obj is on the stack + pop_and_check_object(obj); + } + + __ add(off, obj, off); + const Address field(off); + + Label Done, notByte, notBool, notInt, notShort, notChar, + notLong, notFloat, notObj, notDouble; + + __ slli(flags, raw_flags, XLEN - (ConstantPoolCacheEntry::tos_state_shift + + ConstantPoolCacheEntry::tos_state_bits)); + __ srli(flags, flags, XLEN - ConstantPoolCacheEntry::tos_state_bits); + + assert(btos == 0, "change code, btos != 0"); + __ bnez(flags, notByte); + + // Dont't rewrite getstatic, only getfield + if (is_static) { + rc = may_not_rewrite; + } + + // btos + __ access_load_at(T_BYTE, IN_HEAP, x10, field, noreg, noreg); + __ push(btos); + // Rewrite bytecode to be faster + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_bgetfield, bc, x11); + } + __ j(Done); + + __ bind(notByte); + __ sub(t0, flags, (u1)ztos); + __ bnez(t0, notBool); + + // ztos (same code as btos) + __ access_load_at(T_BOOLEAN, IN_HEAP, x10, field, noreg, noreg); + __ push(ztos); + // Rewirte bytecode to be faster + if (rc == may_rewrite) { + // uses btos rewriting, no truncating to t/f bit is needed for getfield + patch_bytecode(Bytecodes::_fast_bgetfield, bc, x11); + } + __ j(Done); + + __ bind(notBool); + __ sub(t0, flags, (u1)atos); + __ bnez(t0, notObj); + // atos + do_oop_load(_masm, field, x10, IN_HEAP); + __ push(atos); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_agetfield, bc, x11); + } + __ j(Done); + + __ bind(notObj); + __ sub(t0, flags, (u1)itos); + __ bnez(t0, notInt); + // itos + __ access_load_at(T_INT, IN_HEAP, x10, field, noreg, noreg); + __ addw(x10, x10, zr); // signed extended + __ push(itos); + // Rewrite bytecode to be faster + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_igetfield, bc, x11); + } + __ j(Done); + + __ bind(notInt); + __ sub(t0, flags, (u1)ctos); + __ bnez(t0, notChar); + // ctos + __ access_load_at(T_CHAR, IN_HEAP, x10, field, noreg, noreg); + __ push(ctos); + // Rewrite bytecode to be faster + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_cgetfield, bc, x11); + } + __ j(Done); + + __ bind(notChar); + __ sub(t0, flags, (u1)stos); + __ bnez(t0, notShort); + // stos + __ access_load_at(T_SHORT, IN_HEAP, x10, field, noreg, noreg); + __ push(stos); + // Rewrite bytecode to be faster + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_sgetfield, bc, x11); + } + __ j(Done); + + __ bind(notShort); + __ sub(t0, flags, (u1)ltos); + __ bnez(t0, notLong); + // ltos + __ access_load_at(T_LONG, IN_HEAP, x10, field, noreg, noreg); + __ push(ltos); + // Rewrite bytecode to be faster + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_lgetfield, bc, x11); + } + __ j(Done); + + __ bind(notLong); + __ sub(t0, flags, (u1)ftos); + __ bnez(t0, notFloat); + // ftos + __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); + __ push(ftos); + // Rewrite bytecode to be faster + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_fgetfield, bc, x11); + } + __ j(Done); + + __ bind(notFloat); +#ifdef ASSERT + __ sub(t0, flags, (u1)dtos); + __ bnez(t0, notDouble); +#endif + // dtos + __ access_load_at(T_DOUBLE, IN_HEAP, noreg /* ftos */, field, noreg, noreg); + __ push(dtos); + // Rewrite bytecode to be faster + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_dgetfield, bc, x11); + } +#ifdef ASSERT + __ j(Done); + + __ bind(notDouble); + __ stop("Bad state"); +#endif + + __ bind(Done); + + Label notVolatile; + __ andi(t0, raw_flags, 1UL << ConstantPoolCacheEntry::is_volatile_shift); + __ beqz(t0, notVolatile); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ bind(notVolatile); +} + +void TemplateTable::getfield(int byte_no) +{ + getfield_or_static(byte_no, false); +} + +void TemplateTable::nofast_getfield(int byte_no) { + getfield_or_static(byte_no, false, may_not_rewrite); +} + +void TemplateTable::getstatic(int byte_no) +{ + getfield_or_static(byte_no, true); +} + +// The registers cache and index expected to be set before call. +// The function may destroy various registers, just not the cache and index registers. +void TemplateTable::jvmti_post_field_mod(Register cache, Register index, bool is_static) { + transition(vtos, vtos); + + ByteSize cp_base_offset = ConstantPoolCache::base_offset(); + + if (JvmtiExport::can_post_field_modification()) { + // Check to see if a field modification watch has been set before + // we take the time to call into the VM. + Label L1; + assert_different_registers(cache, index, x10); + int32_t offset = 0; + __ la_patchable(t0, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr()), offset); + __ lwu(x10, Address(t0, offset)); + __ beqz(x10, L1); + + __ get_cache_and_index_at_bcp(c_rarg2, t0, 1); + + if (is_static) { + // Life is simple. Null out the object pointer. + __ mv(c_rarg1, zr); + } else { + // Life is harder. The stack holds the value on top, followed by + // the object. We don't know the size of the value, though; it + // could be one or two words depending on its type. As a result, + // we must find the type to determine where the object is. + __ lwu(c_rarg3, Address(c_rarg2, + in_bytes(cp_base_offset + + ConstantPoolCacheEntry::flags_offset()))); + __ srli(c_rarg3, c_rarg3, ConstantPoolCacheEntry::tos_state_shift); + ConstantPoolCacheEntry::verify_tos_state_shift(); + Label nope2, done, ok; + __ ld(c_rarg1, at_tos_p1()); // initially assume a one word jvalue + __ sub(t0, c_rarg3, ltos); + __ beqz(t0, ok); + __ sub(t0, c_rarg3, dtos); + __ bnez(t0, nope2); + __ bind(ok); + __ ld(c_rarg1, at_tos_p2()); // ltos (two word jvalue); + __ bind(nope2); + } + // cache entry pointer + __ add(c_rarg2, c_rarg2, in_bytes(cp_base_offset)); + // object (tos) + __ mv(c_rarg3, esp); + // c_rarg1: object pointer set up above (NULL if static) + // c_rarg2: cache entry pointer + // c_rarg3: jvalue object on the stack + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::post_field_modification), + c_rarg1, c_rarg2, c_rarg3); + __ get_cache_and_index_at_bcp(cache, index, 1); + __ bind(L1); + } +} + +void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteControl rc) { + transition(vtos, vtos); + + const Register cache = x12; + const Register index = x13; + const Register obj = x12; + const Register off = x9; + const Register flags = x10; + const Register bc = x14; + + resolve_cache_and_index(byte_no, cache, index, sizeof(u2)); + jvmti_post_field_mod(cache, index, is_static); + load_field_cp_cache_entry(obj, cache, index, off, flags, is_static); + + Label Done; + __ mv(x15, flags); + + { + Label notVolatile; + __ andi(t0, x15, 1UL << ConstantPoolCacheEntry::is_volatile_shift); + __ beqz(t0, notVolatile); + __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); + __ bind(notVolatile); + } + + Label notByte, notBool, notInt, notShort, notChar, + notLong, notFloat, notObj, notDouble; + + __ slli(flags, flags, XLEN - (ConstantPoolCacheEntry::tos_state_shift + + ConstantPoolCacheEntry::tos_state_bits)); + __ srli(flags, flags, XLEN - ConstantPoolCacheEntry::tos_state_bits); + + assert(btos == 0, "change code, btos != 0"); + __ bnez(flags, notByte); + + // Don't rewrite putstatic, only putfield + if (is_static) { + rc = may_not_rewrite; + } + + // btos + { + __ pop(btos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); // off register as temparator register. + __ access_store_at(T_BYTE, IN_HEAP, field, x10, noreg, noreg); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_bputfield, bc, x11, true, byte_no); + } + __ j(Done); + } + + __ bind(notByte); + __ sub(t0, flags, (u1)ztos); + __ bnez(t0, notBool); + + // ztos + { + __ pop(ztos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); + __ access_store_at(T_BOOLEAN, IN_HEAP, field, x10, noreg, noreg); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_zputfield, bc, x11, true, byte_no); + } + __ j(Done); + } + + __ bind(notBool); + __ sub(t0, flags, (u1)atos); + __ bnez(t0, notObj); + + // atos + { + __ pop(atos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); + // Store into the field + do_oop_store(_masm, field, x10, IN_HEAP); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_aputfield, bc, x11, true, byte_no); + } + __ j(Done); + } + + __ bind(notObj); + __ sub(t0, flags, (u1)itos); + __ bnez(t0, notInt); + + // itos + { + __ pop(itos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); + __ access_store_at(T_INT, IN_HEAP, field, x10, noreg, noreg); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_iputfield, bc, x11, true, byte_no); + } + __ j(Done); + } + + __ bind(notInt); + __ sub(t0, flags, (u1)ctos); + __ bnez(t0, notChar); + + // ctos + { + __ pop(ctos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); + __ access_store_at(T_CHAR, IN_HEAP, field, x10, noreg, noreg); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_cputfield, bc, x11, true, byte_no); + } + __ j(Done); + } + + __ bind(notChar); + __ sub(t0, flags, (u1)stos); + __ bnez(t0, notShort); + + // stos + { + __ pop(stos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); + __ access_store_at(T_SHORT, IN_HEAP, field, x10, noreg, noreg); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_sputfield, bc, x11, true, byte_no); + } + __ j(Done); + } + + __ bind(notShort); + __ sub(t0, flags, (u1)ltos); + __ bnez(t0, notLong); + + // ltos + { + __ pop(ltos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); + __ access_store_at(T_LONG, IN_HEAP, field, x10, noreg, noreg); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_lputfield, bc, x11, true, byte_no); + } + __ j(Done); + } + + __ bind(notLong); + __ sub(t0, flags, (u1)ftos); + __ bnez(t0, notFloat); + + // ftos + { + __ pop(ftos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); + __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos */, noreg, noreg); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_fputfield, bc, x11, true, byte_no); + } + __ j(Done); + } + + __ bind(notFloat); +#ifdef ASSERT + __ sub(t0, flags, (u1)dtos); + __ bnez(t0, notDouble); +#endif + + // dtos + { + __ pop(dtos); + // field address + if (!is_static) { + pop_and_check_object(obj); + } + __ add(off, obj, off); // if static, obj from cache, else obj from stack. + const Address field(off, 0); + __ access_store_at(T_DOUBLE, IN_HEAP, field, noreg /* dtos */, noreg, noreg); + if (rc == may_rewrite) { + patch_bytecode(Bytecodes::_fast_dputfield, bc, x11, true, byte_no); + } + } + +#ifdef ASSERT + __ j(Done); + + __ bind(notDouble); + __ stop("Bad state"); +#endif + + __ bind(Done); + + { + Label notVolatile; + __ andi(t0, x15, 1UL << ConstantPoolCacheEntry::is_volatile_shift); + __ beqz(t0, notVolatile); + __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore); + __ bind(notVolatile); + } +} + +void TemplateTable::putfield(int byte_no) +{ + putfield_or_static(byte_no, false); +} + +void TemplateTable::nofast_putfield(int byte_no) { + putfield_or_static(byte_no, false, may_not_rewrite); +} + +void TemplateTable::putstatic(int byte_no) { + putfield_or_static(byte_no, true); +} + +void TemplateTable::jvmti_post_fast_field_mod() +{ + if (JvmtiExport::can_post_field_modification()) { + // Check to see if a field modification watch has been set before + // we take the time to call into the VM. + Label L2; + int32_t offset = 0; + __ la_patchable(t0, ExternalAddress((address)JvmtiExport::get_field_modification_count_addr()), offset); + __ lwu(c_rarg3, Address(t0, offset)); + __ beqz(c_rarg3, L2); + __ pop_ptr(x9); // copy the object pointer from tos + __ verify_oop(x9); + __ push_ptr(x9); // put the object pointer back on tos + // Save tos values before call_VM() clobbers them. Since we have + // to do it for every data type, we use the saved values as the + // jvalue object. + switch (bytecode()) { // load values into the jvalue object + case Bytecodes::_fast_aputfield: __ push_ptr(x10); break; + case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through + case Bytecodes::_fast_sputfield: // fall through + case Bytecodes::_fast_cputfield: // fall through + case Bytecodes::_fast_iputfield: __ push_i(x10); break; + case Bytecodes::_fast_dputfield: __ push_d(); break; + case Bytecodes::_fast_fputfield: __ push_f(); break; + case Bytecodes::_fast_lputfield: __ push_l(x10); break; + + default: + ShouldNotReachHere(); + } + __ mv(c_rarg3, esp); // points to jvalue on the stack + // access constant pool cache entry + __ get_cache_entry_pointer_at_bcp(c_rarg2, x10, 1); + __ verify_oop(x9); + // x9: object pointer copied above + // c_rarg2: cache entry pointer + // c_rarg3: jvalue object on the stack + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::post_field_modification), + x9, c_rarg2, c_rarg3); + + switch (bytecode()) { // restore tos values + case Bytecodes::_fast_aputfield: __ pop_ptr(x10); break; + case Bytecodes::_fast_bputfield: // fall through + case Bytecodes::_fast_zputfield: // fall through + case Bytecodes::_fast_sputfield: // fall through + case Bytecodes::_fast_cputfield: // fall through + case Bytecodes::_fast_iputfield: __ pop_i(x10); break; + case Bytecodes::_fast_dputfield: __ pop_d(); break; + case Bytecodes::_fast_fputfield: __ pop_f(); break; + case Bytecodes::_fast_lputfield: __ pop_l(x10); break; + default: break; + } + __ bind(L2); + } +} + +void TemplateTable::fast_storefield(TosState state) +{ + transition(state, vtos); + + ByteSize base = ConstantPoolCache::base_offset(); + + jvmti_post_fast_field_mod(); + + // access constant pool cache + __ get_cache_and_index_at_bcp(x12, x11, 1); + + // Must prevent reordering of the following cp cache loads with bytecode load + __ membar(MacroAssembler::LoadLoad); + + // test for volatile with x13 + __ lwu(x13, Address(x12, in_bytes(base + + ConstantPoolCacheEntry::flags_offset()))); + + // replace index with field offset from cache entry + __ ld(x11, Address(x12, in_bytes(base + ConstantPoolCacheEntry::f2_offset()))); + + { + Label notVolatile; + __ andi(t0, x13, 1UL << ConstantPoolCacheEntry::is_volatile_shift); + __ beqz(t0, notVolatile); + __ membar(MacroAssembler::StoreStore | MacroAssembler::LoadStore); + __ bind(notVolatile); + } + + // Get object from stack + pop_and_check_object(x12); + + // field address + __ add(x11, x12, x11); + const Address field(x11, 0); + + // access field + switch (bytecode()) { + case Bytecodes::_fast_aputfield: + do_oop_store(_masm, field, x10, IN_HEAP); + break; + case Bytecodes::_fast_lputfield: + __ access_store_at(T_LONG, IN_HEAP, field, x10, noreg, noreg); + break; + case Bytecodes::_fast_iputfield: + __ access_store_at(T_INT, IN_HEAP, field, x10, noreg, noreg); + break; + case Bytecodes::_fast_zputfield: + __ access_store_at(T_BOOLEAN, IN_HEAP, field, x10, noreg, noreg); + break; + case Bytecodes::_fast_bputfield: + __ access_store_at(T_BYTE, IN_HEAP, field, x10, noreg, noreg); + break; + case Bytecodes::_fast_sputfield: + __ access_store_at(T_SHORT, IN_HEAP, field, x10, noreg, noreg); + break; + case Bytecodes::_fast_cputfield: + __ access_store_at(T_CHAR, IN_HEAP, field, x10, noreg, noreg); + break; + case Bytecodes::_fast_fputfield: + __ access_store_at(T_FLOAT, IN_HEAP, field, noreg /* ftos */, noreg, noreg); + break; + case Bytecodes::_fast_dputfield: + __ access_store_at(T_DOUBLE, IN_HEAP, field, noreg /* dtos */, noreg, noreg); + break; + default: + ShouldNotReachHere(); + } + + { + Label notVolatile; + __ andi(t0, x13, 1UL << ConstantPoolCacheEntry::is_volatile_shift); + __ beqz(t0, notVolatile); + __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore); + __ bind(notVolatile); + } +} + +void TemplateTable::fast_accessfield(TosState state) +{ + transition(atos, state); + // Do the JVMTI work here to avoid disturbing the register state below + if (JvmtiExport::can_post_field_access()) { + // Check to see if a field access watch has been set before we + // take the time to call into the VM. + Label L1; + int32_t offset = 0; + __ la_patchable(t0, ExternalAddress((address)JvmtiExport::get_field_access_count_addr()), offset); + __ lwu(x12, Address(t0, offset)); + __ beqz(x12, L1); + // access constant pool cache entry + __ get_cache_entry_pointer_at_bcp(c_rarg2, t1, 1); + __ verify_oop(x10); + __ push_ptr(x10); // save object pointer before call_VM() clobbers it + __ mv(c_rarg1, x10); + // c_rarg1: object pointer copied above + // c_rarg2: cache entry pointer + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::post_field_access), + c_rarg1, c_rarg2); + __ pop_ptr(x10); // restore object pointer + __ bind(L1); + } + + // access constant pool cache + __ get_cache_and_index_at_bcp(x12, x11, 1); + + // Must prevent reordering of the following cp cache loads with bytecode load + __ membar(MacroAssembler::LoadLoad); + + __ ld(x11, Address(x12, in_bytes(ConstantPoolCache::base_offset() + + ConstantPoolCacheEntry::f2_offset()))); + __ lwu(x13, Address(x12, in_bytes(ConstantPoolCache::base_offset() + + ConstantPoolCacheEntry::flags_offset()))); + + // x10: object + __ verify_oop(x10); + __ null_check(x10); + __ add(x11, x10, x11); + const Address field(x11, 0); + + // access field + switch (bytecode()) { + case Bytecodes::_fast_agetfield: + do_oop_load(_masm, field, x10, IN_HEAP); + __ verify_oop(x10); + break; + case Bytecodes::_fast_lgetfield: + __ access_load_at(T_LONG, IN_HEAP, x10, field, noreg, noreg); + break; + case Bytecodes::_fast_igetfield: + __ access_load_at(T_INT, IN_HEAP, x10, field, noreg, noreg); + __ addw(x10, x10, zr); // signed extended + break; + case Bytecodes::_fast_bgetfield: + __ access_load_at(T_BYTE, IN_HEAP, x10, field, noreg, noreg); + break; + case Bytecodes::_fast_sgetfield: + __ access_load_at(T_SHORT, IN_HEAP, x10, field, noreg, noreg); + break; + case Bytecodes::_fast_cgetfield: + __ access_load_at(T_CHAR, IN_HEAP, x10, field, noreg, noreg); + break; + case Bytecodes::_fast_fgetfield: + __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, field, noreg, noreg); + break; + case Bytecodes::_fast_dgetfield: + __ access_load_at(T_DOUBLE, IN_HEAP, noreg /* dtos */, field, noreg, noreg); + break; + default: + ShouldNotReachHere(); + } + { + Label notVolatile; + __ andi(t0, x13, 1UL << ConstantPoolCacheEntry::is_volatile_shift); + __ beqz(t0, notVolatile); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ bind(notVolatile); + } +} + +void TemplateTable::fast_xaccess(TosState state) +{ + transition(vtos, state); + + // get receiver + __ ld(x10, aaddress(0)); + // access constant pool cache + __ get_cache_and_index_at_bcp(x12, x13, 2); + __ ld(x11, Address(x12, in_bytes(ConstantPoolCache::base_offset() + + ConstantPoolCacheEntry::f2_offset()))); + + // make sure exception is reported in correct bcp range (getfield is + // next instruction) + __ addi(xbcp, xbcp, 1); + __ null_check(x10); + switch (state) { + case itos: + __ add(x10, x10, x11); + __ access_load_at(T_INT, IN_HEAP, x10, Address(x10, 0), noreg, noreg); + __ addw(x10, x10, zr); // signed extended + break; + case atos: + __ add(x10, x10, x11); + do_oop_load(_masm, Address(x10, 0), x10, IN_HEAP); + __ verify_oop(x10); + break; + case ftos: + __ add(x10, x10, x11); + __ access_load_at(T_FLOAT, IN_HEAP, noreg /* ftos */, Address(x10), noreg, noreg); + break; + default: + ShouldNotReachHere(); + } + + { + Label notVolatile; + __ lwu(x13, Address(x12, in_bytes(ConstantPoolCache::base_offset() + + ConstantPoolCacheEntry::flags_offset()))); + __ andi(t0, x13, 1UL << ConstantPoolCacheEntry::is_volatile_shift); + __ beqz(t0, notVolatile); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ bind(notVolatile); + } + + __ sub(xbcp, xbcp, 1); +} + +//----------------------------------------------------------------------------- +// Calls + +void TemplateTable::prepare_invoke(int byte_no, + Register method, // linked method (or i-klass) + Register index, // itable index, MethodType, etc. + Register recv, // if caller wants to see it + Register flags // if caller wants to test it + ) { + // determine flags + const Bytecodes::Code code = bytecode(); + const bool is_invokeinterface = code == Bytecodes::_invokeinterface; + const bool is_invokedynamic = code == Bytecodes::_invokedynamic; + const bool is_invokehandle = code == Bytecodes::_invokehandle; + const bool is_invokevirtual = code == Bytecodes::_invokevirtual; + const bool is_invokespecial = code == Bytecodes::_invokespecial; + const bool load_receiver = (recv != noreg); + const bool save_flags = (flags != noreg); + assert(load_receiver == (code != Bytecodes::_invokestatic && code != Bytecodes::_invokedynamic), ""); + assert(save_flags == (is_invokeinterface || is_invokevirtual), "need flags for vfinal"); + assert(flags == noreg || flags == x13, ""); + assert(recv == noreg || recv == x12, ""); + + // setup registers & access constant pool cache + if (recv == noreg) { + recv = x12; + } + if (flags == noreg) { + flags = x13; + } + assert_different_registers(method, index, recv, flags); + + // save 'interpreter return address' + __ save_bcp(); + + load_invoke_cp_cache_entry(byte_no, method, index, flags, is_invokevirtual, false, is_invokedynamic); + + // maybe push appendix to arguments (just before return address) + if (is_invokedynamic || is_invokehandle) { + Label L_no_push; + __ andi(t0, flags, 1UL << ConstantPoolCacheEntry::has_appendix_shift); + __ beqz(t0, L_no_push); + // Push the appendix as a trailing parameter. + // This must be done before we get the receiver, + // since the parameter_size includes it. + __ push_reg(x9); + __ mv(x9, index); + __ load_resolved_reference_at_index(index, x9); + __ pop_reg(x9); + __ push_reg(index); // push appendix (MethodType, CallSite, etc.) + __ bind(L_no_push); + } + + // load receiver if needed (note: no return address pushed yet) + if (load_receiver) { + __ andi(recv, flags, ConstantPoolCacheEntry::parameter_size_mask); // parameter_size_mask = 1 << 8 + __ shadd(t0, recv, esp, t0, 3); + __ ld(recv, Address(t0, -Interpreter::expr_offset_in_bytes(1))); + __ verify_oop(recv); + } + + // compute return type + __ slli(t1, flags, XLEN - (ConstantPoolCacheEntry::tos_state_shift + ConstantPoolCacheEntry::tos_state_bits)); + __ srli(t1, t1, XLEN - ConstantPoolCacheEntry::tos_state_bits); // (1 << 5) - 4 --> 28~31==> t1:0~3 + + // load return address + { + const address table_addr = (address) Interpreter::invoke_return_entry_table_for(code); + __ mv(t0, table_addr); + __ shadd(t0, t1, t0, t1, 3); + __ ld(ra, Address(t0, 0)); + } +} + +void TemplateTable::invokevirtual_helper(Register index, + Register recv, + Register flags) +{ + // Uses temporary registers x10, x13 + assert_different_registers(index, recv, x10, x13); + // Test for an invoke of a final method + Label notFinal; + __ andi(t0, flags, 1UL << ConstantPoolCacheEntry::is_vfinal_shift); + __ beqz(t0, notFinal); + + const Register method = index; // method must be xmethod + assert(method == xmethod, "Method must be xmethod for interpreter calling convention"); + + // do the call - the index is actually the method to call + // that is, f2 is a vtable index if !is_vfinal, else f2 is a Method* + + // It's final, need a null check here! + __ null_check(recv); + + // profile this call + __ profile_final_call(x10); + __ profile_arguments_type(x10, method, x14, true); + + __ jump_from_interpreted(method); + + __ bind(notFinal); + + // get receiver klass + __ null_check(recv, oopDesc::klass_offset_in_bytes()); + __ load_klass(x10, recv); + + // profile this call + __ profile_virtual_call(x10, xlocals, x13); + + // get target Method & entry point + __ lookup_virtual_method(x10, index, method); + __ profile_arguments_type(x13, method, x14, true); + __ jump_from_interpreted(method); +} + +void TemplateTable::invokevirtual(int byte_no) +{ + transition(vtos, vtos); + assert(byte_no == f2_byte, "use this argument"); + + prepare_invoke(byte_no, xmethod, noreg, x12, x13); + + // xmethod: index (actually a Method*) + // x12: receiver + // x13: flags + + invokevirtual_helper(xmethod, x12, x13); +} + +void TemplateTable::invokespecial(int byte_no) +{ + transition(vtos, vtos); + assert(byte_no == f1_byte, "use this argument"); + + prepare_invoke(byte_no, xmethod, noreg, // get f1 Method* + x12); // get receiver also for null check + __ verify_oop(x12); + __ null_check(x12); + // do the call + __ profile_call(x10); + __ profile_arguments_type(x10, xmethod, xbcp, false); + __ jump_from_interpreted(xmethod); +} + +void TemplateTable::invokestatic(int byte_no) +{ + transition(vtos, vtos); + assert(byte_no == f1_byte, "use this arugment"); + + prepare_invoke(byte_no, xmethod); // get f1 Method* + // do the call + __ profile_call(x10); + __ profile_arguments_type(x10, xmethod, x14, false); + __ jump_from_interpreted(xmethod); +} + +void TemplateTable::fast_invokevfinal(int byte_no) +{ + __ call_Unimplemented(); +} + +void TemplateTable::invokeinterface(int byte_no) { + transition(vtos, vtos); + assert(byte_no == f1_byte, "use this argument"); + + prepare_invoke(byte_no, x10, xmethod, // get f1 Klass*, f2 Method* + x12, x13); // recv, flags + + // x10: interface klass (from f1) + // xmethod: method (from f2) + // x12: receiver + // x13: flags + + // First check for Object case, then private interface method, + // then regular interface method. + + // Special case of invokeinterface called for virtual method of + // java.lang.Object. See cpCache.cpp for details + Label notObjectMethod; + __ andi(t0, x13, 1UL << ConstantPoolCacheEntry::is_forced_virtual_shift); + __ beqz(t0, notObjectMethod); + + invokevirtual_helper(xmethod, x12, x13); + __ bind(notObjectMethod); + + Label no_such_interface; + + // Check for private method invocation - indicated by vfinal + Label notVFinal; + __ andi(t0, x13, 1UL << ConstantPoolCacheEntry::is_vfinal_shift); + __ beqz(t0, notVFinal); + + // Check receiver klass into x13 - also a null check + __ null_check(x12, oopDesc::klass_offset_in_bytes()); + __ load_klass(x13, x12); + + Label subtype; + __ check_klass_subtype(x13, x10, x14, subtype); + // If we get here the typecheck failed + __ j(no_such_interface); + __ bind(subtype); + + __ profile_final_call(x10); + __ profile_arguments_type(x10, xmethod, x14, true); + __ jump_from_interpreted(xmethod); + + __ bind(notVFinal); + + // Get receiver klass into x13 - also a null check + __ restore_locals(); + __ null_check(x12, oopDesc::klass_offset_in_bytes()); + __ load_klass(x13, x12); + + Label no_such_method; + + // Preserve method for the throw_AbstractMethodErrorVerbose. + __ mv(x28, xmethod); + // Receiver subtype check against REFC. + // Superklass in x10. Subklass in x13. Blows t1, x30 + __ lookup_interface_method(// inputs: rec. class, interface, itable index + x13, x10, noreg, + // outputs: scan temp. reg, scan temp. reg + t1, x30, + no_such_interface, + /*return_method=*/false); + + // profile this call + __ profile_virtual_call(x13, x30, x9); + + // Get declaring interface class from method, and itable index + __ load_method_holder(x10, xmethod); + __ lwu(xmethod, Address(xmethod, Method::itable_index_offset())); + __ subw(xmethod, xmethod, Method::itable_index_max); + __ negw(xmethod, xmethod); + + // Preserve recvKlass for throw_AbstractMethodErrorVerbose + __ mv(xlocals, x13); + __ lookup_interface_method(// inputs: rec. class, interface, itable index + xlocals, x10, xmethod, + // outputs: method, scan temp. reg + xmethod, x30, + no_such_interface); + + // xmethod: Method to call + // x12: receiver + // Check for abstract method error + // Note: This should be done more efficiently via a throw_abstract_method_error + // interpreter entry point and a conditional jump to it in case of a null + // method. + __ beqz(xmethod, no_such_method); + + __ profile_arguments_type(x13, xmethod, x30, true); + + // do the call + // x12: receiver + // xmethod: Method + __ jump_from_interpreted(xmethod); + __ should_not_reach_here(); + + // exception handling code follows ... + // note: must restore interpreter registers to canonical + // state for exception handling to work correctly! + + __ bind(no_such_method); + // throw exception + __ restore_bcp(); // bcp must be correct for exception handler (was destroyed) + __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) + // Pass arguments for generating a verbose error message. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodErrorVerbose), x13, x28); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + + __ bind(no_such_interface); + // throw exceptiong + __ restore_bcp(); // bcp must be correct for exception handler (was destroyed) + __ restore_locals(); // make sure locals pointer is correct as well (was destroyed) + // Pass arguments for generating a verbose error message. + __ call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_IncompatibleClassChangeErrorVerbose), x13, x10); + // the call_VM checks for exception, so we should never return here. + __ should_not_reach_here(); + return; +} + +void TemplateTable::invokehandle(int byte_no) { + transition(vtos, vtos); + assert(byte_no == f1_byte, "use this argument"); + + prepare_invoke(byte_no, xmethod, x10, x12); + __ verify_method_ptr(x12); + __ verify_oop(x12); + __ null_check(x12); + + // FIXME: profile the LambdaForm also + + // x30 is safe to use here as a temp reg because it is about to + // be clobbered by jump_from_interpreted(). + __ profile_final_call(x30); + __ profile_arguments_type(x30, xmethod, x14, true); + + __ jump_from_interpreted(xmethod); +} + +void TemplateTable::invokedynamic(int byte_no) { + transition(vtos, vtos); + assert(byte_no == f1_byte, "use this argument"); + + prepare_invoke(byte_no, xmethod, x10); + + // x10: CallSite object (from cpool->resolved_references[]) + // xmethod: MH.linkToCallSite method (from f2) + + // Note: x10_callsite is already pushed by prepare_invoke + + // %%% should make a type profile for any invokedynamic that takes a ref argument + // profile this call + __ profile_call(xbcp); + __ profile_arguments_type(x13, xmethod, x30, false); + + __ verify_oop(x10); + + __ jump_from_interpreted(xmethod); +} + +//----------------------------------------------------------------------------- +// Allocation + +void TemplateTable::_new() { + transition(vtos, atos); + + __ get_unsigned_2_byte_index_at_bcp(x13, 1); + Label slow_case; + Label done; + Label initialize_header; + Label initialize_object; // including clearing the fields + + __ get_cpool_and_tags(x14, x10); + // Make sure the class we're about to instantiate has been resolved. + // This is done before loading InstanceKlass to be consistent with the order + // how Constant Pool is update (see ConstantPool::klass_at_put) + const int tags_offset = Array::base_offset_in_bytes(); + __ add(t0, x10, x13); + __ la(t0, Address(t0, tags_offset)); + __ membar(MacroAssembler::AnyAny); + __ lbu(t0, t0); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ sub(t1, t0, (u1)JVM_CONSTANT_Class); + __ bnez(t1, slow_case); + + // get InstanceKlass + __ load_resolved_klass_at_offset(x14, x13, x14, t0); + + // make sure klass is initialized & doesn't have finalizer + // make sure klass is fully initialized + __ lbu(t0, Address(x14, InstanceKlass::init_state_offset())); + __ sub(t1, t0, (u1)InstanceKlass::fully_initialized); + __ bnez(t1, slow_case); + + // get instance_size in InstanceKlass (scaled to a count of bytes) + __ lwu(x13, Address(x14, Klass::layout_helper_offset())); + // test to see if it has a finalizer or is malformed in some way + __ andi(t0, x13, Klass::_lh_instance_slow_path_bit); + __ bnez(t0, slow_case); + + // Allocate the instance: + // If TLAB is enabled: + // Try to allocate in the TLAB. + // If fails, go to the slow path. + // Else If inline contiguous allocations are enabled: + // Try to allocate in eden. + // If fails due to heap end, go to slow path + // + // If TLAB is enabled OR inline contiguous is enabled: + // Initialize the allocation. + // Exit. + // Go to slow path. + const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc(); + + if (UseTLAB) { + __ tlab_allocate(x10, x13, 0, noreg, x11, slow_case); + + if (ZeroTLAB) { + // the fields have been already cleared + __ j(initialize_header); + } else { + // initialize both the header and fields + __ j(initialize_object); + } + } else { + // Allocation in the shared Eden, if allowed. + // + // x13: instance size in bytes + if (allow_shared_alloc) { + __ eden_allocate(x10, x13, 0, x28, slow_case); + } + } + + // If USETLAB or allow_shared_alloc are true, the object is created above and + // there is an initialized need. Otherwise, skip and go to the slow path. + if (UseTLAB || allow_shared_alloc) { + // The object is initialized before the header. If the object size is + // zero, go directly to the header initialization. + __ bind(initialize_object); + __ sub(x13, x13, sizeof(oopDesc)); + __ beqz(x13, initialize_header); + + // Initialize obejct fields + { + __ add(x12, x10, sizeof(oopDesc)); + Label loop; + __ bind(loop); + __ sd(zr, Address(x12)); + __ add(x12, x12, BytesPerLong); + __ sub(x13, x13, BytesPerLong); + __ bnez(x13, loop); + } + + // initialize object hader only. + __ bind(initialize_header); + __ mv(t0, (intptr_t)markWord::prototype().value()); + __ sd(t0, Address(x10, oopDesc::mark_offset_in_bytes())); + __ store_klass_gap(x10, zr); // zero klass gap for compressed oops + __ store_klass(x10, x14); // store klass last + + { + SkipIfEqual skip(_masm, &DTraceAllocProbes, false); + // Trigger dtrace event for fastpath + __ push(atos); // save the return value + __ call_VM_leaf(CAST_FROM_FN_PTR(address, static_cast(SharedRuntime::dtrace_object_alloc)), x10); + __ pop(atos); // restore the return value + } + __ j(done); + } + + // slow case + __ bind(slow_case); + __ get_constant_pool(c_rarg1); + __ get_unsigned_2_byte_index_at_bcp(c_rarg2, 1); + call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::_new), c_rarg1, c_rarg2); + __ verify_oop(x10); + + // continue + __ bind(done); + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(MacroAssembler::StoreStore); +} + +void TemplateTable::newarray() { + transition(itos, atos); + __ load_unsigned_byte(c_rarg1, at_bcp(1)); + __ mv(c_rarg2, x10); + call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray), + c_rarg1, c_rarg2); + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(MacroAssembler::StoreStore); +} + +void TemplateTable::anewarray() { + transition(itos, atos); + __ get_unsigned_2_byte_index_at_bcp(c_rarg2, 1); + __ get_constant_pool(c_rarg1); + __ mv(c_rarg3, x10); + call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::anewarray), + c_rarg1, c_rarg2, c_rarg3); + // Must prevent reordering of stores for object initialization with stores that publish the new object. + __ membar(MacroAssembler::StoreStore); +} + +void TemplateTable::arraylength() { + transition(atos, itos); + __ null_check(x10, arrayOopDesc::length_offset_in_bytes()); + __ lwu(x10, Address(x10, arrayOopDesc::length_offset_in_bytes())); +} + +void TemplateTable::checkcast() +{ + transition(atos, atos); + Label done, is_null, ok_is_subtype, quicked, resolved; + __ beqz(x10, is_null); + + // Get cpool & tags index + __ get_cpool_and_tags(x12, x13); // x12=cpool, x13=tags array + __ get_unsigned_2_byte_index_at_bcp(x9, 1); // x9=index + // See if bytecode has already been quicked + __ add(t0, x13, Array::base_offset_in_bytes()); + __ add(x11, t0, x9); + __ membar(MacroAssembler::AnyAny); + __ lbu(x11, x11); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ sub(t0, x11, (u1)JVM_CONSTANT_Class); + __ beqz(t0, quicked); + + __ push(atos); // save receiver for result, and for GC + call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); + // vm_result_2 has metadata result + __ get_vm_result_2(x10, xthread); + __ pop_reg(x13); // restore receiver + __ j(resolved); + + // Get superklass in x10 and subklass in x13 + __ bind(quicked); + __ mv(x13, x10); // Save object in x13; x10 needed for subtype check + __ load_resolved_klass_at_offset(x12, x9, x10, t0); // x10 = klass + + __ bind(resolved); + __ load_klass(x9, x13); + + // Generate subtype check. Blows x12, x15. Object in x13. + // Superklass in x10. Subklass in x9. + __ gen_subtype_check(x9, ok_is_subtype); + + // Come here on failure + __ push_reg(x13); + // object is at TOS + __ j(Interpreter::_throw_ClassCastException_entry); + + // Come here on success + __ bind(ok_is_subtype); + __ mv(x10, x13); // Restore object in x13 + + // Collect counts on whether this test sees NULLs a lot or not. + if (ProfileInterpreter) { + __ j(done); + __ bind(is_null); + __ profile_null_seen(x12); + } else { + __ bind(is_null); // same as 'done' + } + __ bind(done); +} + +void TemplateTable::instanceof() { + transition(atos, itos); + Label done, is_null, ok_is_subtype, quicked, resolved; + __ beqz(x10, is_null); + + // Get cpool & tags index + __ get_cpool_and_tags(x12, x13); // x12=cpool, x13=tags array + __ get_unsigned_2_byte_index_at_bcp(x9, 1); // x9=index + // See if bytecode has already been quicked + __ add(t0, x13, Array::base_offset_in_bytes()); + __ add(x11, t0, x9); + __ membar(MacroAssembler::AnyAny); + __ lbu(x11, x11); + __ membar(MacroAssembler::LoadLoad | MacroAssembler::LoadStore); + __ sub(t0, x11, (u1)JVM_CONSTANT_Class); + __ beqz(t0, quicked); + + __ push(atos); // save receiver for result, and for GC + call_VM(x10, CAST_FROM_FN_PTR(address, InterpreterRuntime::quicken_io_cc)); + // vm_result_2 has metadata result + __ get_vm_result_2(x10, xthread); + __ pop_reg(x13); // restore receiver + __ verify_oop(x13); + __ load_klass(x13, x13); + __ j(resolved); + + // Get superklass in x10 and subklass in x13 + __ bind(quicked); + __ load_klass(x13, x10); + __ load_resolved_klass_at_offset(x12, x9, x10, t0); + + __ bind(resolved); + + // Generate subtype check. Blows x12, x15 + // Superklass in x10. Subklass in x13. + __ gen_subtype_check(x13, ok_is_subtype); + + // Come here on failure + __ mv(x10, zr); + __ j(done); + // Come here on success + __ bind(ok_is_subtype); + __ li(x10, 1); + + // Collect counts on whether this test sees NULLs a lot or not. + if (ProfileInterpreter) { + __ j(done); + __ bind(is_null); + __ profile_null_seen(x12); + } else { + __ bind(is_null); // same as 'done' + } + __ bind(done); + // x10 = 0: obj == NULL or obj is not an instanceof the specified klass + // x10 = 1: obj != NULL and obj is an instanceof the specified klass +} + +//----------------------------------------------------------------------------- +// Breakpoints +void TemplateTable::_breakpoint() { + // Note: We get here even if we are single stepping.. + // jbug inists on setting breakpoints at every bytecode + // even if we are in single step mode. + + transition(vtos, vtos); + + // get the unpatched byte code + __ get_method(c_rarg1); + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, + InterpreterRuntime::get_original_bytecode_at), + c_rarg1, xbcp); + __ mv(x9, x10); + + // post the breakpoint event + __ call_VM(noreg, + CAST_FROM_FN_PTR(address, InterpreterRuntime::_breakpoint), + xmethod, xbcp); + + // complete the execution of original bytecode + __ mv(t0, x9); + __ dispatch_only_normal(vtos); +} + +//----------------------------------------------------------------------------- +// Exceptions + +void TemplateTable::athrow() { + transition(atos, vtos); + __ null_check(x10); + __ j(Interpreter::throw_exception_entry()); +} + +//----------------------------------------------------------------------------- +// Synchronization +// +// Note: monitorenter & exit are symmetric routines; which is reflected +// in the assembly code structure as well +// +// Stack layout: +// +// [expressions ] <--- esp = expression stack top +// .. +// [expressions ] +// [monitor entry] <--- monitor block top = expression stack bot +// .. +// [monitor entry] +// [frame data ] <--- monitor block bot +// ... +// [saved fp ] <--- fp +void TemplateTable::monitorenter() +{ + transition(atos, vtos); + + // check for NULL object + __ null_check(x10); + + const Address monitor_block_top( + fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); + const Address monitor_block_bot( + fp, frame::interpreter_frame_initial_sp_offset * wordSize); + const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + + Label allocated; + + // initialize entry pointer + __ mv(c_rarg1, zr); // points to free slot or NULL + + // find a free slot in the monitor block (result in c_rarg1) + { + Label entry, loop, exit, notUsed; + __ ld(c_rarg3, monitor_block_top); // points to current entry, + // starting with top-most entry + __ la(c_rarg2, monitor_block_bot); // points to word before bottom + + __ j(entry); + + __ bind(loop); + // check if current entry is used + // if not used then remember entry in c_rarg1 + __ ld(t0, Address(c_rarg3, BasicObjectLock::obj_offset_in_bytes())); + __ bnez(t0, notUsed); + __ mv(c_rarg1, c_rarg3); + __ bind(notUsed); + // check if current entry is for same object + // if same object then stop searching + __ beq(x10, t0, exit); + // otherwise advance to next entry + __ add(c_rarg3, c_rarg3, entry_size); + __ bind(entry); + // check if bottom reached + // if not at bottom then check this entry + __ bne(c_rarg3, c_rarg2, loop); + __ bind(exit); + } + + __ bnez(c_rarg1, allocated); // check if a slot has been found and + // if found, continue with that on + + // allocate one if there's no free slot + { + Label entry, loop; + // 1. compute new pointers // esp: old expression stack top + __ ld(c_rarg1, monitor_block_bot); // c_rarg1: old expression stack bottom + __ sub(esp, esp, entry_size); // move expression stack top + __ sub(c_rarg1, c_rarg1, entry_size); // move expression stack bottom + __ mv(c_rarg3, esp); // set start value for copy loop + __ sd(c_rarg1, monitor_block_bot); // set new monitor block bottom + __ sub(sp, sp, entry_size); // make room for the monitor + + __ j(entry); + // 2. move expression stack contents + __ bind(loop); + __ ld(c_rarg2, Address(c_rarg3, entry_size)); // load expression stack + // word from old location + __ sd(c_rarg2, Address(c_rarg3, 0)); // and store it at new location + __ add(c_rarg3, c_rarg3, wordSize); // advance to next word + __ bind(entry); + __ bne(c_rarg3, c_rarg1, loop); // check if bottom reached.if not at bottom + // then copy next word + } + + // call run-time routine + // c_rarg1: points to monitor entry + __ bind(allocated); + + // Increment bcp to point to the next bytecode, so exception + // handling for async. exceptions work correctly. + // The object has already been poped from the stack, so the + // expression stack looks correct. + __ addi(xbcp, xbcp, 1); + + // store object + __ sd(x10, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes())); + __ lock_object(c_rarg1); + + // check to make sure this monitor doesn't cause stack overflow after locking + __ save_bcp(); // in case of exception + __ generate_stack_overflow_check(0); + + // The bcp has already been incremented. Just need to dispatch to + // next instruction. + __ dispatch_next(vtos); +} + +void TemplateTable::monitorexit() +{ + transition(atos, vtos); + + // check for NULL object + __ null_check(x10); + + const Address monitor_block_top( + fp, frame::interpreter_frame_monitor_block_top_offset * wordSize); + const Address monitor_block_bot( + fp, frame::interpreter_frame_initial_sp_offset * wordSize); + const int entry_size = frame::interpreter_frame_monitor_size() * wordSize; + + Label found; + + // find matching slot + { + Label entry, loop; + __ ld(c_rarg1, monitor_block_top); // points to current entry, + // starting with top-most entry + __ la(c_rarg2, monitor_block_bot); // points to word before bottom + // of monitor block + __ j(entry); + + __ bind(loop); + // check if current entry is for same object + __ ld(t0, Address(c_rarg1, BasicObjectLock::obj_offset_in_bytes())); + // if same object then stop searching + __ beq(x10, t0, found); + // otherwise advance to next entry + __ add(c_rarg1, c_rarg1, entry_size); + __ bind(entry); + // check if bottom reached + // if not at bottom then check this entry + __ bne(c_rarg1, c_rarg2, loop); + } + + // error handling. Unlocking was not block-structured + __ call_VM(noreg, CAST_FROM_FN_PTR(address, + InterpreterRuntime::throw_illegal_monitor_state_exception)); + __ should_not_reach_here(); + + // call run-time routine + __ bind(found); + __ push_ptr(x10); // make sure object is on stack (contract with oopMaps) + __ unlock_object(c_rarg1); + __ pop_ptr(x10); // discard object +} + +// Wide instructions +void TemplateTable::wide() +{ + __ load_unsigned_byte(x9, at_bcp(1)); + __ mv(t0, (address)Interpreter::_wentry_point); + __ shadd(t0, x9, t0, t1, 3); + __ ld(t0, Address(t0)); + __ jr(t0); +} + +// Multi arrays +void TemplateTable::multianewarray() { + transition(vtos, atos); + __ load_unsigned_byte(x10, at_bcp(3)); // get number of dimensions + // last dim is on top of stack; we want address of first one: + // first_addr = last_addr + (ndims - 1) * wordSize + __ shadd(c_rarg1, x10, esp, c_rarg1, 3); + __ sub(c_rarg1, c_rarg1, wordSize); + call_VM(x10, + CAST_FROM_FN_PTR(address, InterpreterRuntime::multianewarray), + c_rarg1); + __ load_unsigned_byte(x11, at_bcp(3)); + __ shadd(esp, x11, esp, t0, 3); +} diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.hpp b/src/hotspot/cpu/riscv/templateTable_riscv.hpp new file mode 100644 index 00000000000..fcc86108d28 --- /dev/null +++ b/src/hotspot/cpu/riscv/templateTable_riscv.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_TEMPLATETABLE_RISCV_HPP +#define CPU_RISCV_TEMPLATETABLE_RISCV_HPP + +static void prepare_invoke(int byte_no, + Register method, // linked method (or i-klass) + Register index = noreg, // itable index, MethodType, etc. + Register recv = noreg, // if caller wants to see it + Register flags = noreg // if caller wants to test it + ); +static void invokevirtual_helper(Register index, Register recv, + Register flags); + +// Helpers +static void index_check(Register array, Register index); + +#endif // CPU_RISCV_TEMPLATETABLE_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/universalNativeInvoker_riscv.cpp b/src/hotspot/cpu/riscv/universalNativeInvoker_riscv.cpp new file mode 100644 index 00000000000..4f50adb05c3 --- /dev/null +++ b/src/hotspot/cpu/riscv/universalNativeInvoker_riscv.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "prims/universalNativeInvoker.hpp" +#include "utilities/debug.hpp" + +address ProgrammableInvoker::generate_adapter(jobject jabi, jobject jlayout) { + Unimplemented(); + return nullptr; +} diff --git a/src/hotspot/cpu/riscv/universalUpcallHandle_riscv.cpp b/src/hotspot/cpu/riscv/universalUpcallHandle_riscv.cpp new file mode 100644 index 00000000000..ce70da72f2e --- /dev/null +++ b/src/hotspot/cpu/riscv/universalUpcallHandle_riscv.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "prims/universalUpcallHandler.hpp" +#include "utilities/debug.hpp" + +address ProgrammableUpcallHandler::generate_upcall_stub(jobject jrec, jobject jabi, jobject jlayout) { + Unimplemented(); + return nullptr; +} + +address ProgrammableUpcallHandler::generate_optimized_upcall_stub(jobject mh, Method* entry, jobject jabi, jobject jconv) { + ShouldNotCallThis(); + return nullptr; +} + +bool ProgrammableUpcallHandler::supports_optimized_upcalls() { + return false; +} diff --git a/src/hotspot/cpu/riscv/vmStructs_riscv.hpp b/src/hotspot/cpu/riscv/vmStructs_riscv.hpp new file mode 100644 index 00000000000..6c89133de02 --- /dev/null +++ b/src/hotspot/cpu/riscv/vmStructs_riscv.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_VMSTRUCTS_RISCV_HPP +#define CPU_RISCV_VMSTRUCTS_RISCV_HPP + +// These are the CPU-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) + +#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) + +#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#endif // CPU_RISCV_VMSTRUCTS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp new file mode 100644 index 00000000000..768c7633ca6 --- /dev/null +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "runtime/java.hpp" +#include "runtime/os.hpp" +#include "runtime/vm_version.hpp" +#include "utilities/formatBuffer.hpp" +#include "utilities/macros.hpp" + +#include OS_HEADER_INLINE(os) + +const char* VM_Version::_uarch = ""; +uint32_t VM_Version::_initial_vector_length = 0; + +void VM_Version::initialize() { + get_os_cpu_info(); + + if (FLAG_IS_DEFAULT(UseFMA)) { + FLAG_SET_DEFAULT(UseFMA, true); + } + + if (FLAG_IS_DEFAULT(AllocatePrefetchDistance)) { + FLAG_SET_DEFAULT(AllocatePrefetchDistance, 0); + } + + if (UseAES || UseAESIntrinsics) { + if (UseAES && !FLAG_IS_DEFAULT(UseAES)) { + warning("AES instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseAES, false); + } + if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) { + warning("AES intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESIntrinsics, false); + } + } + + if (UseAESCTRIntrinsics) { + warning("AES/CTR intrinsics are not available on this CPU"); + FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); + } + + if (UseSHA) { + warning("SHA instructions are not available on this CPU"); + FLAG_SET_DEFAULT(UseSHA, false); + } + + if (UseSHA1Intrinsics) { + warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU."); + FLAG_SET_DEFAULT(UseSHA1Intrinsics, false); + } + + if (UseSHA256Intrinsics) { + warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU."); + FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); + } + + if (UseSHA512Intrinsics) { + warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU."); + FLAG_SET_DEFAULT(UseSHA512Intrinsics, false); + } + + if (UseSHA3Intrinsics) { + warning("Intrinsics for SHA3-224, SHA3-256, SHA3-384 and SHA3-512 crypto hash functions not available on this CPU."); + FLAG_SET_DEFAULT(UseSHA3Intrinsics, false); + } + + if (UseCRC32Intrinsics) { + warning("CRC32 intrinsics are not available on this CPU."); + FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); + } + + if (UseCRC32CIntrinsics) { + warning("CRC32C intrinsics are not available on this CPU."); + FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false); + } + + if (UseMD5Intrinsics) { + warning("MD5 intrinsics are not available on this CPU."); + FLAG_SET_DEFAULT(UseMD5Intrinsics, false); + } + + if (UseRVV) { + if (!(_features & CPU_V)) { + warning("RVV is not supported on this CPU"); + FLAG_SET_DEFAULT(UseRVV, false); + } else { + // read vector length from vector CSR vlenb + _initial_vector_length = get_current_vector_length(); + } + } + + if (UseRVB && !(_features & CPU_B)) { + warning("RVB is not supported on this CPU"); + FLAG_SET_DEFAULT(UseRVB, false); + } + + if (UseRVC && !(_features & CPU_C)) { + warning("RVC is not supported on this CPU"); + FLAG_SET_DEFAULT(UseRVC, false); + } + + if (FLAG_IS_DEFAULT(AvoidUnalignedAccesses)) { + FLAG_SET_DEFAULT(AvoidUnalignedAccesses, true); + } + + if (UseRVB) { + if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { + FLAG_SET_DEFAULT(UsePopCountInstruction, true); + } + } else { + FLAG_SET_DEFAULT(UsePopCountInstruction, false); + } + + char buf[512]; + buf[0] = '\0'; + if (_uarch != NULL && strcmp(_uarch, "") != 0) snprintf(buf, sizeof(buf), "%s,", _uarch); + strcat(buf, "rv64"); +#define ADD_FEATURE_IF_SUPPORTED(id, name, bit) if (_features & CPU_##id) strcat(buf, name); + CPU_FEATURE_FLAGS(ADD_FEATURE_IF_SUPPORTED) +#undef ADD_FEATURE_IF_SUPPORTED + + _features_string = os::strdup(buf); + +#ifdef COMPILER2 + c2_initialize(); +#endif // COMPILER2 +} + +#ifdef COMPILER2 +void VM_Version::c2_initialize() { + if (UseCMoveUnconditionally) { + FLAG_SET_DEFAULT(UseCMoveUnconditionally, false); + } + + if (ConditionalMoveLimit > 0) { + FLAG_SET_DEFAULT(ConditionalMoveLimit, 0); + } + + if (!UseRVV) { + FLAG_SET_DEFAULT(SpecialEncodeISOArray, false); + } + + if (!UseRVV && MaxVectorSize) { + FLAG_SET_DEFAULT(MaxVectorSize, 0); + } + + if (!UseRVV) { + FLAG_SET_DEFAULT(UseRVVForBigIntegerShiftIntrinsics, false); + } + + if (UseRVV) { + if (FLAG_IS_DEFAULT(MaxVectorSize)) { + MaxVectorSize = _initial_vector_length; + } else if (MaxVectorSize < 16) { + warning("RVV does not support vector length less than 16 bytes. Disabling RVV."); + UseRVV = false; + } else if (is_power_of_2(MaxVectorSize)) { + if (MaxVectorSize > _initial_vector_length) { + warning("Current system only supports max RVV vector length %d. Set MaxVectorSize to %d", + _initial_vector_length, _initial_vector_length); + } + MaxVectorSize = _initial_vector_length; + } else { + vm_exit_during_initialization(err_msg("Unsupported MaxVectorSize: %d", (int)MaxVectorSize)); + } + } + + // disable prefetch + if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { + FLAG_SET_DEFAULT(AllocatePrefetchStyle, 0); + } + + if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) { + FLAG_SET_DEFAULT(UseMulAddIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) { + FLAG_SET_DEFAULT(UseSquareToLenIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) { + FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) { + FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true); + } +} +#endif // COMPILER2 + +void VM_Version::initialize_cpu_information(void) { + // do nothing if cpu info has been initialized + if (_initialized) { + return; + } + + _no_of_cores = os::processor_count(); + _no_of_threads = _no_of_cores; + _no_of_sockets = _no_of_cores; + snprintf(_cpu_name, CPU_TYPE_DESC_BUF_SIZE - 1, "RISCV64"); + snprintf(_cpu_desc, CPU_DETAILED_DESC_BUF_SIZE, "RISCV64 %s", _features_string); + _initialized = true; +} diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp new file mode 100644 index 00000000000..8e35530359a --- /dev/null +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_VM_VERSION_RISCV_HPP +#define CPU_RISCV_VM_VERSION_RISCV_HPP + +#include "runtime/abstract_vm_version.hpp" +#include "runtime/arguments.hpp" +#include "runtime/globals_extension.hpp" +#include "utilities/sizes.hpp" + +class VM_Version : public Abstract_VM_Version { +#ifdef COMPILER2 +private: + static void c2_initialize(); +#endif // COMPILER2 + +protected: + static const char* _uarch; + static uint32_t _initial_vector_length; + static void get_os_cpu_info(); + static uint32_t get_current_vector_length(); + +public: + // Initialization + static void initialize(); + + constexpr static bool supports_stack_watermark_barrier() { return true; } + + enum Feature_Flag { +#define CPU_FEATURE_FLAGS(decl) \ + decl(I, "i", 8) \ + decl(M, "m", 12) \ + decl(A, "a", 0) \ + decl(F, "f", 5) \ + decl(D, "d", 3) \ + decl(C, "c", 2) \ + decl(V, "v", 21) \ + decl(B, "b", 1) + +#define DECLARE_CPU_FEATURE_FLAG(id, name, bit) CPU_##id = (1 << bit), + CPU_FEATURE_FLAGS(DECLARE_CPU_FEATURE_FLAG) +#undef DECLARE_CPU_FEATURE_FLAG + }; + + static void initialize_cpu_information(void); +}; + +#endif // CPU_RISCV_VM_VERSION_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/vmreg_riscv.cpp b/src/hotspot/cpu/riscv/vmreg_riscv.cpp new file mode 100644 index 00000000000..aa7222dc64a --- /dev/null +++ b/src/hotspot/cpu/riscv/vmreg_riscv.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/assembler.hpp" +#include "code/vmreg.hpp" + +void VMRegImpl::set_regName() { + int i = 0; + Register reg = ::as_Register(0); + for ( ; i < ConcreteRegisterImpl::max_gpr ; ) { + for (int j = 0 ; j < RegisterImpl::max_slots_per_register ; j++) { + regName[i++] = reg->name(); + } + reg = reg->successor(); + } + + FloatRegister freg = ::as_FloatRegister(0); + for ( ; i < ConcreteRegisterImpl::max_fpr ; ) { + for (int j = 0 ; j < FloatRegisterImpl::max_slots_per_register ; j++) { + regName[i++] = reg->name(); + } + freg = freg->successor(); + } + + VectorRegister vreg = ::as_VectorRegister(0); + for ( ; i < ConcreteRegisterImpl::max_vpr ; ) { + for (int j = 0 ; j < VectorRegisterImpl::max_slots_per_register ; j++) { + regName[i++] = reg->name(); + } + vreg = vreg->successor(); + } + + for ( ; i < ConcreteRegisterImpl::number_of_registers ; i++) { + regName[i] = "NON-GPR-FPR-VPR"; + } +} + +VMReg VMRegImpl::vmStorageToVMReg(int type, int index) { + Unimplemented(); + return VMRegImpl::Bad(); +} diff --git a/src/hotspot/cpu/riscv/vmreg_riscv.hpp b/src/hotspot/cpu/riscv/vmreg_riscv.hpp new file mode 100644 index 00000000000..9e611b1f671 --- /dev/null +++ b/src/hotspot/cpu/riscv/vmreg_riscv.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_VMREG_RISCV_HPP +#define CPU_RISCV_VMREG_RISCV_HPP + +inline bool is_Register() { + return (unsigned int) value() < (unsigned int) ConcreteRegisterImpl::max_gpr; +} + +inline bool is_FloatRegister() { + return value() >= ConcreteRegisterImpl::max_gpr && value() < ConcreteRegisterImpl::max_fpr; +} + +inline bool is_VectorRegister() { + return value() >= ConcreteRegisterImpl::max_fpr && value() < ConcreteRegisterImpl::max_vpr; +} + +inline Register as_Register() { + assert(is_Register(), "must be"); + return ::as_Register(value() / RegisterImpl::max_slots_per_register); +} + +inline FloatRegister as_FloatRegister() { + assert(is_FloatRegister() && is_even(value()), "must be"); + return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) / + FloatRegisterImpl::max_slots_per_register); +} + +inline VectorRegister as_VectorRegister() { + assert(is_VectorRegister() && ((value() & (VectorRegisterImpl::max_slots_per_register - 1)) == 0), "must be"); + return ::as_VectorRegister((value() - ConcreteRegisterImpl::max_fpr) / + VectorRegisterImpl::max_slots_per_register); +} + +inline bool is_concrete() { + assert(is_reg(), "must be"); + if (is_VectorRegister()) { + int base = value() - ConcreteRegisterImpl::max_fpr; + return (base % VectorRegisterImpl::max_slots_per_register) == 0; + } else { + return is_even(value()); + } +} + +#endif // CPU_RISCV_VMREG_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/vmreg_riscv.inline.hpp b/src/hotspot/cpu/riscv/vmreg_riscv.inline.hpp new file mode 100644 index 00000000000..06b70020b4b --- /dev/null +++ b/src/hotspot/cpu/riscv/vmreg_riscv.inline.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef CPU_RISCV_VM_VMREG_RISCV_INLINE_HPP +#define CPU_RISCV_VM_VMREG_RISCV_INLINE_HPP + +inline VMReg RegisterImpl::as_VMReg() const { + if (this == noreg) { + return VMRegImpl::Bad(); + } + return VMRegImpl::as_VMReg(encoding() * RegisterImpl::max_slots_per_register); +} + +inline VMReg FloatRegisterImpl::as_VMReg() const { + return VMRegImpl::as_VMReg((encoding() * FloatRegisterImpl::max_slots_per_register) + + ConcreteRegisterImpl::max_gpr); +} + +inline VMReg VectorRegisterImpl::as_VMReg() const { + return VMRegImpl::as_VMReg((encoding() * VectorRegisterImpl::max_slots_per_register) + + ConcreteRegisterImpl::max_fpr); +} + +#endif // CPU_RISCV_VM_VMREG_RISCV_INLINE_HPP diff --git a/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp new file mode 100644 index 00000000000..78b81138003 --- /dev/null +++ b/src/hotspot/cpu/riscv/vtableStubs_riscv.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "assembler_riscv.inline.hpp" +#include "code/vtableStubs.hpp" +#include "interp_masm_riscv.hpp" +#include "memory/resourceArea.hpp" +#include "oops/compiledICHolder.hpp" +#include "oops/instanceKlass.hpp" +#include "oops/klassVtable.hpp" +#include "runtime/sharedRuntime.hpp" +#include "vmreg_riscv.inline.hpp" +#ifdef COMPILER2 +#include "opto/runtime.hpp" +#endif + +// machine-dependent part of VtableStubs: create VtableStub of correct size and +// initialize its code + +#define __ masm-> + +#ifndef PRODUCT +extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index); +#endif + +VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { + // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing. + const int stub_code_length = code_size_limit(true); + VtableStub* s = new(stub_code_length) VtableStub(true, vtable_index); + // Can be NULL if there is no free space in the code cache. + if (s == NULL) { + return NULL; + } + + // Count unused bytes in instruction sequences of variable size. + // We add them to the computed buffer size in order to avoid + // overflow in subsequently generated stubs. + address start_pc = NULL; + int slop_bytes = 0; + int slop_delta = 0; + + ResourceMark rm; + CodeBuffer cb(s->entry_point(), stub_code_length); + MacroAssembler* masm = new MacroAssembler(&cb); + assert_cond(masm != NULL); + +#if (!defined(PRODUCT) && defined(COMPILER2)) + if (CountCompiledCalls) { + __ la(t2, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); + __ add_memory_int64(Address(t2), 1); + } +#endif + + // get receiver (need to skip return address on top of stack) + assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); + + // get receiver klass + address npe_addr = __ pc(); + __ load_klass(t2, j_rarg0); + +#ifndef PRODUCT + if (DebugVtables) { + Label L; + start_pc = __ pc(); + + // check offset vs vtable length + __ lwu(t0, Address(t2, Klass::vtable_length_offset())); + __ mvw(t1, vtable_index * vtableEntry::size()); + __ bgt(t0, t1, L); + __ enter(); + __ mv(x12, vtable_index); + + __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), j_rarg0, x12); + const ptrdiff_t estimate = 256; + const ptrdiff_t codesize = __ pc() - start_pc; + slop_delta = estimate - codesize; // call_VM varies in length, depending on data + slop_bytes += slop_delta; + assert(slop_delta >= 0, "vtable #%d: Code size estimate (%d) for DebugVtables too small, required: %d", vtable_index, (int)estimate, (int)codesize); + + __ leave(); + __ bind(L); + } +#endif // PRODUCT + + start_pc = __ pc(); + __ lookup_virtual_method(t2, vtable_index, xmethod); + // lookup_virtual_method generates + // 4 instructions (maximum value encountered in normal case):li(lui + addiw) + add + ld + // 1 instruction (best case):ld * 1 + slop_delta = 16 - (int)(__ pc() - start_pc); + slop_bytes += slop_delta; + assert(slop_delta >= 0, "negative slop(%d) encountered, adjust code size estimate!", slop_delta); + +#ifndef PRODUCT + if (DebugVtables) { + Label L; + __ beqz(xmethod, L); + __ ld(t0, Address(xmethod, Method::from_compiled_offset())); + __ bnez(t0, L); + __ stop("Vtable entry is NULL"); + __ bind(L); + } +#endif // PRODUCT + + // x10: receiver klass + // xmethod: Method* + // x12: receiver + address ame_addr = __ pc(); + __ ld(t0, Address(xmethod, Method::from_compiled_offset())); + __ jr(t0); + + masm->flush(); + bookkeeping(masm, tty, s, npe_addr, ame_addr, true, vtable_index, slop_bytes, 0); + + return s; +} + +VtableStub* VtableStubs::create_itable_stub(int itable_index) { + // Read "A word on VtableStub sizing" in share/code/vtableStubs.hpp for details on stub sizing. + const int stub_code_length = code_size_limit(false); + VtableStub* s = new(stub_code_length) VtableStub(false, itable_index); + // Can be NULL if there is no free space in the code cache. + if (s == NULL) { + return NULL; + } + // Count unused bytes in instruction sequences of variable size. + // We add them to the computed buffer size in order to avoid + // overflow in subsequently generated stubs. + address start_pc = NULL; + int slop_bytes = 0; + int slop_delta = 0; + + ResourceMark rm; + CodeBuffer cb(s->entry_point(), stub_code_length); + MacroAssembler* masm = new MacroAssembler(&cb); + assert_cond(masm != NULL); + +#if (!defined(PRODUCT) && defined(COMPILER2)) + if (CountCompiledCalls) { + __ la(x18, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); + __ add_memory_int64(Address(x18), 1); + } +#endif + + // get receiver (need to skip return address on top of stack) + assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); + + // Entry arguments: + // t2: CompiledICHolder + // j_rarg0: Receiver + + // This stub is called from compiled code which has no callee-saved registers, + // so all registers except arguments are free at this point. + const Register recv_klass_reg = x18; + const Register holder_klass_reg = x19; // declaring interface klass (DECC) + const Register resolved_klass_reg = xmethod; // resolved interface klass (REFC) + const Register temp_reg = x28; + const Register temp_reg2 = x29; + const Register icholder_reg = t1; + + Label L_no_such_interface; + + __ ld(resolved_klass_reg, Address(icholder_reg, CompiledICHolder::holder_klass_offset())); + __ ld(holder_klass_reg, Address(icholder_reg, CompiledICHolder::holder_metadata_offset())); + + start_pc = __ pc(); + + // get receiver klass (also an implicit null-check) + address npe_addr = __ pc(); + __ load_klass(recv_klass_reg, j_rarg0); + + // Receiver subtype check against REFC. + __ lookup_interface_method(// inputs: rec. class, interface + recv_klass_reg, resolved_klass_reg, noreg, + // outputs: scan temp. reg1, scan temp. reg2 + temp_reg2, temp_reg, + L_no_such_interface, + /*return_method=*/false); + + const ptrdiff_t typecheckSize = __ pc() - start_pc; + start_pc = __ pc(); + + // Get selected method from declaring class and itable index + __ lookup_interface_method(// inputs: rec. class, interface, itable index + recv_klass_reg, holder_klass_reg, itable_index, + // outputs: method, scan temp. reg + xmethod, temp_reg, + L_no_such_interface); + + const ptrdiff_t lookupSize = __ pc() - start_pc; + + // Reduce "estimate" such that "padding" does not drop below 8. + const ptrdiff_t estimate = 256; + const ptrdiff_t codesize = typecheckSize + lookupSize; + slop_delta = (int)(estimate - codesize); + slop_bytes += slop_delta; + assert(slop_delta >= 0, "itable #%d: Code size estimate (%d) for lookup_interface_method too small, required: %d", itable_index, (int)estimate, (int)codesize); + +#ifdef ASSERT + if (DebugVtables) { + Label L2; + __ beqz(xmethod, L2); + __ ld(t0, Address(xmethod, Method::from_compiled_offset())); + __ bnez(t0, L2); + __ stop("compiler entrypoint is null"); + __ bind(L2); + } +#endif // ASSERT + + // xmethod: Method* + // j_rarg0: receiver + address ame_addr = __ pc(); + __ ld(t0, Address(xmethod, Method::from_compiled_offset())); + __ jr(t0); + + __ bind(L_no_such_interface); + // Handle IncompatibleClassChangeError in itable stubs. + // More detailed error message. + // We force resolving of the call site by jumping to the "handle + // wrong method" stub, and so let the interpreter runtime do all the + // dirty work. + assert(SharedRuntime::get_handle_wrong_method_stub() != NULL, "check initialization order"); + __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); + + masm->flush(); + bookkeeping(masm, tty, s, npe_addr, ame_addr, false, itable_index, slop_bytes, 0); + + return s; +} + +int VtableStub::pd_code_alignment() { + // RISCV cache line size is not an architected constant. We just align on word size. + const unsigned int icache_line_size = wordSize; + return icache_line_size; +} diff --git a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp index 1d1f163826e..efa142332ef 100644 --- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -1440,7 +1440,10 @@ void LIR_Assembler::comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Op } // result = condition ? opr1 : opr2 -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type, + LIR_Opr cmp_opr1, LIR_Opr cmp_opr2) { + assert(cmp_opr1 == LIR_OprFact::illegalOpr && cmp_opr2 == LIR_OprFact::illegalOpr, "unnecessary cmp oprs on s390"); + Assembler::branch_condition acond = Assembler::bcondEqual, ncond = Assembler::bcondNotEqual; switch (condition) { case lir_cond_equal: acond = Assembler::bcondEqual; ncond = Assembler::bcondNotEqual; break; diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index eaeeae235f0..9619a7711e9 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -2010,7 +2010,10 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { } } -void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) { +void LIR_Assembler::cmove(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type, + LIR_Opr cmp_opr1, LIR_Opr cmp_opr2) { + assert(cmp_opr1 == LIR_OprFact::illegalOpr && cmp_opr2 == LIR_OprFact::illegalOpr, "unnecessary cmp oprs on x86"); + Assembler::Condition acond, ncond; switch (condition) { case lir_cond_equal: acond = Assembler::equal; ncond = Assembler::notEqual; break; diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index f2ecca92c82..cba539caf42 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -2496,6 +2496,8 @@ void os::get_summary_cpu_info(char* cpuinfo, size_t length) { strncpy(cpuinfo, "IA64", length); #elif defined(PPC) strncpy(cpuinfo, "PPC64", length); +#elif defined(RISCV) + strncpy(cpuinfo, "RISCV64", length); #elif defined(S390) strncpy(cpuinfo, "S390", length); #elif defined(SPARC) diff --git a/src/hotspot/os_cpu/linux_riscv/assembler_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/assembler_linux_riscv.cpp new file mode 100644 index 00000000000..f2610af6cdd --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/assembler_linux_riscv.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +// nothing required here diff --git a/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp new file mode 100644 index 00000000000..761da5d743e --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/atomic_linux_riscv.hpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_ATOMIC_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_ATOMIC_LINUX_RISCV_HPP + +#include "runtime/vm_version.hpp" + +// Implementation of class atomic + +// Note that memory_order_conservative requires a full barrier after atomic stores. +// See https://patchwork.kernel.org/patch/3575821/ + +template +struct Atomic::PlatformAdd { + template + D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const { + D res = __atomic_add_fetch(dest, add_value, __ATOMIC_RELEASE); + FULL_MEM_BARRIER; + return res; + } + + template + D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const { + return add_and_fetch(dest, add_value, order) - add_value; + } +}; + +template +template +inline T Atomic::PlatformXchg::operator()(T volatile* dest, + T exchange_value, + atomic_memory_order order) const { + STATIC_ASSERT(byte_size == sizeof(T)); + T res = __atomic_exchange_n(dest, exchange_value, __ATOMIC_RELEASE); + FULL_MEM_BARRIER; + return res; +} + +// __attribute__((unused)) on dest is to get rid of spurious GCC warnings. +template +template +inline T Atomic::PlatformCmpxchg::operator()(T volatile* dest __attribute__((unused)), + T compare_value, + T exchange_value, + atomic_memory_order order) const { + STATIC_ASSERT(byte_size == sizeof(T)); + T value = compare_value; + if (order != memory_order_relaxed) { + FULL_MEM_BARRIER; + } + + __atomic_compare_exchange(dest, &value, &exchange_value, /* weak */ false, + __ATOMIC_RELAXED, __ATOMIC_RELAXED); + + if (order != memory_order_relaxed) { + FULL_MEM_BARRIER; + } + return value; +} + +template<> +template +inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest __attribute__((unused)), + T compare_value, + T exchange_value, + atomic_memory_order order) const { + STATIC_ASSERT(4 == sizeof(T)); + if (order != memory_order_relaxed) { + FULL_MEM_BARRIER; + } + T rv; + int tmp; + __asm volatile( + "1:\n\t" + " addiw %[tmp], %[cv], 0\n\t" // make sure compare_value signed_extend + " lr.w.aq %[rv], (%[dest])\n\t" + " bne %[rv], %[tmp], 2f\n\t" + " sc.w.rl %[tmp], %[ev], (%[dest])\n\t" + " bnez %[tmp], 1b\n\t" + "2:\n\t" + : [rv] "=&r" (rv), [tmp] "=&r" (tmp) + : [ev] "r" (exchange_value), [dest] "r" (dest), [cv] "r" (compare_value) + : "memory"); + if (order != memory_order_relaxed) { + FULL_MEM_BARRIER; + } + return rv; +} + +template +struct Atomic::PlatformOrderedLoad +{ + template + T operator()(const volatile T* p) const { T data; __atomic_load(const_cast(p), &data, __ATOMIC_ACQUIRE); return data; } +}; + +template +struct Atomic::PlatformOrderedStore +{ + template + void operator()(volatile T* p, T v) const { __atomic_store(const_cast(p), &v, __ATOMIC_RELEASE); } +}; + +template +struct Atomic::PlatformOrderedStore +{ + template + void operator()(volatile T* p, T v) const { release_store(p, v); OrderAccess::fence(); } +}; + +#endif // OS_CPU_LINUX_RISCV_ATOMIC_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/bytes_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/bytes_linux_riscv.hpp new file mode 100644 index 00000000000..28868c76406 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/bytes_linux_riscv.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_BYTES_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_BYTES_LINUX_RISCV_HPP + +#include + +// Efficient swapping of data bytes from Java byte +// ordering to native byte ordering and vice versa. +inline u2 Bytes::swap_u2(u2 x) { + return bswap_16(x); +} + +inline u4 Bytes::swap_u4(u4 x) { + return bswap_32(x); +} + +inline u8 Bytes::swap_u8(u8 x) { + return bswap_64(x); +} + +#endif // OS_CPU_LINUX_RISCV_BYTES_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/copy_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/copy_linux_riscv.hpp new file mode 100644 index 00000000000..147cfdf3c10 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/copy_linux_riscv.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_VM_COPY_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_VM_COPY_LINUX_RISCV_HPP + +// Empty for build system + +#endif // OS_CPU_LINUX_RISCV_VM_COPY_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/gc/z/zSyscall_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/gc/z/zSyscall_linux_riscv.hpp new file mode 100644 index 00000000000..1aa58f27871 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/gc/z/zSyscall_linux_riscv.hpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_GC_Z_ZSYSCALL_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_GC_Z_ZSYSCALL_LINUX_RISCV_HPP + +#include + +// +// Support for building on older Linux systems +// + +#ifndef SYS_memfd_create +#define SYS_memfd_create 279 +#endif +#ifndef SYS_fallocate +#define SYS_fallocate 47 +#endif + +#endif // OS_CPU_LINUX_RISCV_GC_Z_ZSYSCALL_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/globals_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/globals_linux_riscv.hpp new file mode 100644 index 00000000000..297414bfcd5 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/globals_linux_riscv.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_VM_GLOBALS_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_VM_GLOBALS_LINUX_RISCV_HPP + +// Sets the default values for platform dependent flags used by the runtime system. +// (see globals.hpp) + +define_pd_global(bool, DontYieldALot, false); +define_pd_global(intx, ThreadStackSize, 2048); // 0 => use system default +define_pd_global(intx, VMThreadStackSize, 2048); + +define_pd_global(intx, CompilerThreadStackSize, 2048); + +define_pd_global(uintx, JVMInvokeMethodSlack, 8192); + +// Used on 64 bit platforms for UseCompressedOops base address +define_pd_global(uintx, HeapBaseMinAddress, 2 * G); + +#endif // OS_CPU_LINUX_RISCV_VM_GLOBALS_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp new file mode 100644 index 00000000000..1c33dc1e87f --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_ORDERACCESS_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_ORDERACCESS_LINUX_RISCV_HPP + +// Included in orderAccess.hpp header file. + +#include "runtime/vm_version.hpp" + +// Implementation of class OrderAccess. + +inline void OrderAccess::loadload() { acquire(); } +inline void OrderAccess::storestore() { release(); } +inline void OrderAccess::loadstore() { acquire(); } +inline void OrderAccess::storeload() { fence(); } + +#define FULL_MEM_BARRIER __sync_synchronize() +#define READ_MEM_BARRIER __atomic_thread_fence(__ATOMIC_ACQUIRE); +#define WRITE_MEM_BARRIER __atomic_thread_fence(__ATOMIC_RELEASE); + +inline void OrderAccess::acquire() { + READ_MEM_BARRIER; +} + +inline void OrderAccess::release() { + WRITE_MEM_BARRIER; +} + +inline void OrderAccess::fence() { + FULL_MEM_BARRIER; +} + +inline void OrderAccess::cross_modify_fence_impl() { + asm volatile("fence.i" : : : "memory"); + if (UseConservativeFence) { + asm volatile("fence ir, ir" : : : "memory"); + } +} + +#endif // OS_CPU_LINUX_RISCV_ORDERACCESS_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp new file mode 100644 index 00000000000..1f46bbab0a2 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp @@ -0,0 +1,466 @@ +/* + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +// no precompiled headers +#include "asm/macroAssembler.hpp" +#include "classfile/vmSymbols.hpp" +#include "code/codeCache.hpp" +#include "code/icBuffer.hpp" +#include "code/nativeInst.hpp" +#include "code/vtableStubs.hpp" +#include "interpreter/interpreter.hpp" +#include "jvm.h" +#include "memory/allocation.inline.hpp" +#include "os_share_linux.hpp" +#include "prims/jniFastGetField.hpp" +#include "prims/jvm_misc.hpp" +#include "runtime/arguments.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/java.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/mutexLocker.hpp" +#include "runtime/osThread.hpp" +#include "runtime/safepointMechanism.hpp" +#include "runtime/sharedRuntime.hpp" +#include "runtime/stubRoutines.hpp" +#include "runtime/thread.inline.hpp" +#include "runtime/timer.hpp" +#include "signals_posix.hpp" +#include "utilities/debug.hpp" +#include "utilities/events.hpp" +#include "utilities/vmError.hpp" + +// put OS-includes here +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +#define REG_LR 1 +#define REG_FP 8 + +NOINLINE address os::current_stack_pointer() { + return (address)__builtin_frame_address(0); +} + +char* os::non_memory_address_word() { + // Must never look like an address returned by reserve_memory, + return (char*) -1; +} + +address os::Posix::ucontext_get_pc(const ucontext_t * uc) { + return (address)uc->uc_mcontext.__gregs[REG_PC]; +} + +void os::Posix::ucontext_set_pc(ucontext_t * uc, address pc) { + uc->uc_mcontext.__gregs[REG_PC] = (intptr_t)pc; +} + +intptr_t* os::Linux::ucontext_get_sp(const ucontext_t * uc) { + return (intptr_t*)uc->uc_mcontext.__gregs[REG_SP]; +} + +intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) { + return (intptr_t*)uc->uc_mcontext.__gregs[REG_FP]; +} + +address os::fetch_frame_from_context(const void* ucVoid, + intptr_t** ret_sp, intptr_t** ret_fp) { + address epc; + const ucontext_t* uc = (const ucontext_t*)ucVoid; + + if (uc != NULL) { + epc = os::Posix::ucontext_get_pc(uc); + if (ret_sp != NULL) { + *ret_sp = os::Linux::ucontext_get_sp(uc); + } + if (ret_fp != NULL) { + *ret_fp = os::Linux::ucontext_get_fp(uc); + } + } else { + epc = NULL; + if (ret_sp != NULL) { + *ret_sp = (intptr_t *)NULL; + } + if (ret_fp != NULL) { + *ret_fp = (intptr_t *)NULL; + } + } + + return epc; +} + +frame os::fetch_compiled_frame_from_context(const void* ucVoid) { + const ucontext_t* uc = (const ucontext_t*)ucVoid; + // In compiled code, the stack banging is performed before RA + // has been saved in the frame. RA is live, and SP and FP + // belong to the caller. + intptr_t* frame_fp = os::Linux::ucontext_get_fp(uc); + intptr_t* frame_sp = os::Linux::ucontext_get_sp(uc); + address frame_pc = (address)(uc->uc_mcontext.__gregs[REG_LR] + - NativeInstruction::instruction_size); + return frame(frame_sp, frame_fp, frame_pc); +} + +frame os::fetch_frame_from_context(const void* ucVoid) { + intptr_t* frame_sp = NULL; + intptr_t* frame_fp = NULL; + address epc = fetch_frame_from_context(ucVoid, &frame_sp, &frame_fp); + return frame(frame_sp, frame_fp, epc); +} + +// By default, gcc always saves frame pointer rfp on this stack. This +// may get turned off by -fomit-frame-pointer. +frame os::get_sender_for_C_frame(frame* fr) { + return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); +} + +NOINLINE frame os::current_frame() { + intptr_t **sender_sp = (intptr_t **)__builtin_frame_address(0); + if (sender_sp != NULL) { + frame myframe((intptr_t*)os::current_stack_pointer(), + sender_sp[frame::link_offset], + CAST_FROM_FN_PTR(address, os::current_frame)); + if (os::is_first_C_frame(&myframe)) { + // stack is not walkable + return frame(); + } else { + return os::get_sender_for_C_frame(&myframe); + } + } else { + ShouldNotReachHere(); + return frame(); + } +} + +// Utility functions +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { + + // decide if this trap can be handled by a stub + address stub = NULL; + + address pc = NULL; + + //%note os_trap_1 + if (info != NULL && uc != NULL && thread != NULL) { + pc = (address) os::Posix::ucontext_get_pc(uc); + + address addr = (address) info->si_addr; + + // Make sure the high order byte is sign extended, as it may be masked away by the hardware. + if ((uintptr_t(addr) & (uintptr_t(1) << 55)) != 0) { + addr = address(uintptr_t(addr) | (uintptr_t(0xFF) << 56)); + } + + // Handle ALL stack overflow variations here + if (sig == SIGSEGV) { + // check if fault address is within thread stack + if (thread->is_in_full_stack(addr)) { + if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { + return true; // continue + } + } + } + + if (thread->thread_state() == _thread_in_Java) { + // Java thread running in Java code => find exception handler if any + // a fault inside compiled code, the interpreter, or a stub + + // Handle signal from NativeJump::patch_verified_entry(). + if ((sig == SIGILL || sig == SIGTRAP) + && nativeInstruction_at(pc)->is_sigill_zombie_not_entrant()) { + if (TraceTraps) { + tty->print_cr("trap: zombie_not_entrant (%s)", (sig == SIGTRAP) ? "SIGTRAP" : "SIGILL"); + } + stub = SharedRuntime::get_handle_wrong_method_stub(); + } else if (sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) { + stub = SharedRuntime::get_poll_stub(pc); + } else if (sig == SIGBUS /* && info->si_code == BUS_OBJERR */) { + // BugId 4454115: A read from a MappedByteBuffer can fault + // here if the underlying file has been truncated. + // Do not crash the VM in such a case. + CodeBlob* cb = CodeCache::find_blob_unsafe(pc); + CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL; + bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); + if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) { + address next_pc = pc + NativeCall::instruction_size; + if (is_unsafe_arraycopy) { + next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); + } + stub = SharedRuntime::handle_unsafe_access(thread, next_pc); + } + } else if (sig == SIGILL && nativeInstruction_at(pc)->is_stop()) { + // Pull a pointer to the error message out of the instruction + // stream. + const uint64_t *detail_msg_ptr + = (uint64_t*)(pc + NativeInstruction::instruction_size); + const char *detail_msg = (const char *)*detail_msg_ptr; + const char *msg = "stop"; + if (TraceTraps) { + tty->print_cr("trap: %s: (SIGILL)", msg); + } + + // End life with a fatal error, message and detail message and the context. + // Note: no need to do any post-processing here (e.g. signal chaining) + va_list va_dummy; + VMError::report_and_die(thread, uc, NULL, 0, msg, detail_msg, va_dummy); + va_end(va_dummy); + + ShouldNotReachHere(); + } else if (sig == SIGFPE && + (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) { + stub = + SharedRuntime:: + continuation_for_implicit_exception(thread, + pc, + SharedRuntime:: + IMPLICIT_DIVIDE_BY_ZERO); + } else if (sig == SIGSEGV && + MacroAssembler::uses_implicit_null_check((void*)addr)) { + // Determination of interpreter/vtable stub/compiled code null exception + stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); + } + } else if ((thread->thread_state() == _thread_in_vm || + thread->thread_state() == _thread_in_native) && + sig == SIGBUS && /* info->si_code == BUS_OBJERR && */ + thread->doing_unsafe_access()) { + address next_pc = pc + NativeCall::instruction_size; + if (UnsafeCopyMemory::contains_pc(pc)) { + next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); + } + stub = SharedRuntime::handle_unsafe_access(thread, next_pc); + } + + // jni_fast_GetField can trap at certain pc's if a GC kicks in + // and the heap gets shrunk before the field access. + if ((sig == SIGSEGV) || (sig == SIGBUS)) { + address addr_slow = JNI_FastGetField::find_slowcase_pc(pc); + if (addr_slow != (address)-1) { + stub = addr_slow; + } + } + } + + if (stub != NULL) { + // save all thread context in case we need to restore it + if (thread != NULL) { + thread->set_saved_exception_pc(pc); + } + + os::Posix::ucontext_set_pc(uc, stub); + return true; + } + + return false; // Mute compiler +} + +void os::Linux::init_thread_fpu_state(void) { +} + +int os::Linux::get_fpu_control_word(void) { + return 0; +} + +void os::Linux::set_fpu_control_word(int fpu_control) { +} + +//////////////////////////////////////////////////////////////////////////////// +// thread stack + +// Minimum usable stack sizes required to get to user code. Space for +// HotSpot guard pages is added later. +size_t os::Posix::_compiler_thread_min_stack_allowed = 72 * K; +size_t os::Posix::_java_thread_min_stack_allowed = 72 * K; +size_t os::Posix::_vm_internal_thread_min_stack_allowed = 72 * K; + +// return default stack size for thr_type +size_t os::Posix::default_stack_size(os::ThreadType thr_type) { + // default stack size (compiler thread needs larger stack) + size_t s = (thr_type == os::compiler_thread ? 4 * M : 1 * M); + return s; +} + +///////////////////////////////////////////////////////////////////////////// +// helper functions for fatal error handler + +static const char* reg_abi_names[] = { + "pc", + "x1(ra)", "x2(sp)", "x3(gp)", "x4(tp)", + "x5(t0)", "x6(t1)", "x7(t2)", + "x8(s0)", "x9(s1)", + "x10(a0)", "x11(a1)", "x12(a2)", "x13(a3)", "x14(a4)", "x15(a5)", "x16(a6)", "x17(a7)", + "x18(s2)", "x19(s3)", "x20(s4)", "x21(s5)", "x22(s6)", "x23(s7)", "x24(s8)", "x25(s9)", "x26(s10)", "x27(s11)", + "x28(t3)", "x29(t4)","x30(t5)", "x31(t6)" +}; + +void os::print_context(outputStream *st, const void *context) { + if (context == NULL) { + return; + } + + const ucontext_t *uc = (const ucontext_t*)context; + st->print_cr("Registers:"); + for (int r = 0; r < 32; r++) { + st->print("%-*.*s=", 8, 8, reg_abi_names[r]); + print_location(st, uc->uc_mcontext.__gregs[r]); + } + st->cr(); + + intptr_t *frame_sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); + st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", p2i(frame_sp)); + print_hex_dump(st, (address)frame_sp, (address)(frame_sp + 64), sizeof(intptr_t)); + st->cr(); + + // Note: it may be unsafe to inspect memory near pc. For example, pc may + // point to garbage if entry point in an nmethod is corrupted. Leave + // this at the end, and hope for the best. + address pc = os::Posix::ucontext_get_pc(uc); + print_instructions(st, pc, sizeof(char)); + st->cr(); +} + +void os::print_register_info(outputStream *st, const void *context) { + if (context == NULL) { + return; + } + + const ucontext_t *uc = (const ucontext_t*)context; + + st->print_cr("Register to memory mapping:"); + st->cr(); + + // this is horrendously verbose but the layout of the registers in the + // context does not match how we defined our abstract Register set, so + // we can't just iterate through the gregs area + + // this is only for the "general purpose" registers + + for (int r = 0; r < 32; r++) + st->print_cr("%-*.*s=" INTPTR_FORMAT, 8, 8, reg_abi_names[r], (uintptr_t)uc->uc_mcontext.__gregs[r]); + st->cr(); +} + +void os::setup_fpu() { +} + +#ifndef PRODUCT +void os::verify_stack_alignment() { + assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); +} +#endif + +int os::extra_bang_size_in_bytes() { + return 0; +} + +extern "C" { + int SpinPause() { + return 0; + } + + void _Copy_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) { + if (from > to) { + const jshort *end = from + count; + while (from < end) { + *(to++) = *(from++); + } + } else if (from < to) { + const jshort *end = from; + from += count - 1; + to += count - 1; + while (from >= end) { + *(to--) = *(from--); + } + } + } + void _Copy_conjoint_jints_atomic(const jint* from, jint* to, size_t count) { + if (from > to) { + const jint *end = from + count; + while (from < end) { + *(to++) = *(from++); + } + } else if (from < to) { + const jint *end = from; + from += count - 1; + to += count - 1; + while (from >= end) { + *(to--) = *(from--); + } + } + } + void _Copy_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) { + if (from > to) { + const jlong *end = from + count; + while (from < end) { + os::atomic_copy64(from++, to++); + } + } else if (from < to) { + const jlong *end = from; + from += count - 1; + to += count - 1; + while (from >= end) { + os::atomic_copy64(from--, to--); + } + } + } + + void _Copy_arrayof_conjoint_bytes(const HeapWord* from, + HeapWord* to, + size_t count) { + memmove(to, from, count); + } + void _Copy_arrayof_conjoint_jshorts(const HeapWord* from, + HeapWord* to, + size_t count) { + memmove(to, from, count * 2); + } + void _Copy_arrayof_conjoint_jints(const HeapWord* from, + HeapWord* to, + size_t count) { + memmove(to, from, count * 4); + } + void _Copy_arrayof_conjoint_jlongs(const HeapWord* from, + HeapWord* to, + size_t count) { + memmove(to, from, count * 8); + } +}; diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.hpp new file mode 100644 index 00000000000..6d415630661 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.hpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_VM_OS_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_VM_OS_LINUX_RISCV_HPP + + static void setup_fpu(); + + // Used to register dynamic code cache area with the OS + // Note: Currently only used in 64 bit Windows implementations + static bool register_code_area(char *low, char *high) { return true; } + + // Atomically copy 64 bits of data + static void atomic_copy64(const volatile void *src, volatile void *dst) { + *(jlong *) dst = *(const jlong *) src; + } + + // SYSCALL_RISCV_FLUSH_ICACHE is used to flush instruction cache. The "fence.i" instruction + // only work on the current hart, so kernel provides the icache flush syscall to flush icache + // on each hart. You can pass a flag to determine a global or local icache flush. + static void icache_flush(long int start, long int end) + { + const int SYSCALL_RISCV_FLUSH_ICACHE = 259; + register long int __a7 asm ("a7") = SYSCALL_RISCV_FLUSH_ICACHE; + register long int __a0 asm ("a0") = start; + register long int __a1 asm ("a1") = end; + // the flush can be applied to either all threads or only the current. + // 0 means a global icache flush, and the icache flush will be applied + // to other harts concurrently executing. + register long int __a2 asm ("a2") = 0; + __asm__ volatile ("ecall\n\t" + : "+r" (__a0) + : "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a7) + : "memory"); + } + +#endif // OS_CPU_LINUX_RISCV_VM_OS_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/prefetch_linux_riscv.inline.hpp b/src/hotspot/os_cpu/linux_riscv/prefetch_linux_riscv.inline.hpp new file mode 100644 index 00000000000..a6432c84ec7 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/prefetch_linux_riscv.inline.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_VM_PREFETCH_LINUX_RISCV_INLINE_HPP +#define OS_CPU_LINUX_RISCV_VM_PREFETCH_LINUX_RISCV_INLINE_HPP + +#include "runtime/prefetch.hpp" + + +inline void Prefetch::read (const void *loc, intx interval) { +} + +inline void Prefetch::write(void *loc, intx interval) { +} + +#endif // OS_CPU_LINUX_RISCV_VM_PREFETCH_LINUX_RISCV_INLINE_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/thread_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/thread_linux_riscv.cpp new file mode 100644 index 00000000000..3100572e9fd --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/thread_linux_riscv.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "runtime/frame.inline.hpp" +#include "runtime/thread.inline.hpp" + +frame JavaThread::pd_last_frame() { + assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); + return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); +} + +// For Forte Analyzer AsyncGetCallTrace profiling support - thread is +// currently interrupted by SIGPROF +bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, + void* ucontext, bool isInJava) { + + assert(Thread::current() == this, "caller must be current thread"); + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} + +bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava) { + return pd_get_top_frame(fr_addr, ucontext, isInJava); +} + +bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) { + // If we have a last_Java_frame, then we should use it even if + // isInJava == true. It should be more reliable than ucontext info. + if (has_last_Java_frame() && frame_anchor()->walkable()) { + *fr_addr = pd_last_frame(); + return true; + } + + // At this point, we don't have a last_Java_frame, so + // we try to glean some information out of the ucontext + // if we were running Java code when SIGPROF came in. + if (isInJava) { + ucontext_t* uc = (ucontext_t*) ucontext; + + intptr_t* ret_fp = NULL; + intptr_t* ret_sp = NULL; + address addr = os::fetch_frame_from_context(uc, &ret_sp, &ret_fp); + if (addr == NULL || ret_sp == NULL ) { + // ucontext wasn't useful + return false; + } + + frame ret_frame(ret_sp, ret_fp, addr); + if (!ret_frame.safe_for_sender(this)) { +#ifdef COMPILER2 + frame ret_frame2(ret_sp, NULL, addr); + if (!ret_frame2.safe_for_sender(this)) { + // nothing else to try if the frame isn't good + return false; + } + ret_frame = ret_frame2; +#else + // nothing else to try if the frame isn't good + return false; +#endif /* COMPILER2 */ + } + *fr_addr = ret_frame; + return true; + } + + // nothing else to try + return false; +} + +void JavaThread::cache_global_variables() { } diff --git a/src/hotspot/os_cpu/linux_riscv/thread_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/thread_linux_riscv.hpp new file mode 100644 index 00000000000..61e2cf85b63 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/thread_linux_riscv.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_THREAD_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_THREAD_LINUX_RISCV_HPP + + private: + void pd_initialize() { + _anchor.clear(); + } + + frame pd_last_frame(); + + public: + static ByteSize last_Java_fp_offset() { + return byte_offset_of(JavaThread, _anchor) + JavaFrameAnchor::last_Java_fp_offset(); + } + + bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, + bool isInJava); + + bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, bool isInJava); +private: + bool pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava); + +#endif // OS_CPU_LINUX_RISCV_THREAD_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp new file mode 100644 index 00000000000..6cf7683a586 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/vmStructs_linux_riscv.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#ifndef OS_CPU_LINUX_RISCV_VM_VMSTRUCTS_LINUX_RISCV_HPP +#define OS_CPU_LINUX_RISCV_VM_VMSTRUCTS_LINUX_RISCV_HPP + +// These are the OS and CPU-specific fields, types and integer +// constants required by the Serviceability Agent. This file is +// referenced by vmStructs.cpp. + +#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ + \ + /******************************/ \ + /* Threads (NOTE: incomplete) */ \ + /******************************/ \ + nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \ + nonstatic_field(OSThread, _pthread_id, pthread_t) + + +#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ + \ + /**********************/ \ + /* Posix Thread IDs */ \ + /**********************/ \ + \ + declare_integer_type(OSThread::thread_id_t) \ + declare_unsigned_integer_type(pthread_t) + +#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) + +#endif // OS_CPU_LINUX_RISCV_VM_VMSTRUCTS_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp new file mode 100644 index 00000000000..4623dbfad42 --- /dev/null +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +#include "precompiled.hpp" +#include "asm/register.hpp" +#include "runtime/os.hpp" +#include "runtime/os.inline.hpp" +#include "runtime/vm_version.hpp" + +#include +#include + +#ifndef HWCAP_ISA_I +#define HWCAP_ISA_I (1 << ('I' - 'A')) +#endif + +#ifndef HWCAP_ISA_M +#define HWCAP_ISA_M (1 << ('M' - 'A')) +#endif + +#ifndef HWCAP_ISA_A +#define HWCAP_ISA_A (1 << ('A' - 'A')) +#endif + +#ifndef HWCAP_ISA_F +#define HWCAP_ISA_F (1 << ('F' - 'A')) +#endif + +#ifndef HWCAP_ISA_D +#define HWCAP_ISA_D (1 << ('D' - 'A')) +#endif + +#ifndef HWCAP_ISA_C +#define HWCAP_ISA_C (1 << ('C' - 'A')) +#endif + +#ifndef HWCAP_ISA_V +#define HWCAP_ISA_V (1 << ('V' - 'A')) +#endif + +#ifndef HWCAP_ISA_B +#define HWCAP_ISA_B (1 << ('B' - 'A')) +#endif + +#define read_csr(csr) \ +({ \ + register unsigned long __v; \ + __asm__ __volatile__ ("csrr %0, %1" \ + : "=r" (__v) \ + : "i" (csr) \ + : "memory"); \ + __v; \ +}) + +uint32_t VM_Version::get_current_vector_length() { + assert(_features & CPU_V, "should not call this"); + return (uint32_t)read_csr(CSR_VLENB); +} + +void VM_Version::get_os_cpu_info() { + + uint64_t auxv = getauxval(AT_HWCAP); + + static_assert(CPU_I == HWCAP_ISA_I, "Flag CPU_I must follow Linux HWCAP"); + static_assert(CPU_M == HWCAP_ISA_M, "Flag CPU_M must follow Linux HWCAP"); + static_assert(CPU_A == HWCAP_ISA_A, "Flag CPU_A must follow Linux HWCAP"); + static_assert(CPU_F == HWCAP_ISA_F, "Flag CPU_F must follow Linux HWCAP"); + static_assert(CPU_D == HWCAP_ISA_D, "Flag CPU_D must follow Linux HWCAP"); + static_assert(CPU_C == HWCAP_ISA_C, "Flag CPU_C must follow Linux HWCAP"); + static_assert(CPU_V == HWCAP_ISA_V, "Flag CPU_V must follow Linux HWCAP"); + static_assert(CPU_B == HWCAP_ISA_B, "Flag CPU_B must follow Linux HWCAP"); + _features = auxv & ( + HWCAP_ISA_I | + HWCAP_ISA_M | + HWCAP_ISA_A | + HWCAP_ISA_F | + HWCAP_ISA_D | + HWCAP_ISA_C | + HWCAP_ISA_V | + HWCAP_ISA_B); + + if (FILE *f = fopen("/proc/cpuinfo", "r")) { + char buf[512], *p; + while (fgets(buf, sizeof (buf), f) != NULL) { + if ((p = strchr(buf, ':')) != NULL) { + if (strncmp(buf, "uarch", sizeof "uarch" - 1) == 0) { + char* uarch = os::strdup(p + 2); + uarch[strcspn(uarch, "\n")] = '\0'; + _uarch = uarch; + break; + } + } + } + fclose(f); + } +} diff --git a/src/hotspot/share/c1/c1_LIR.cpp b/src/hotspot/share/c1/c1_LIR.cpp index d27b9175c9d..33f0a59c758 100644 --- a/src/hotspot/share/c1/c1_LIR.cpp +++ b/src/hotspot/share/c1/c1_LIR.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -186,7 +186,6 @@ bool LIR_Opr::is_oop() const { void LIR_Op2::verify() const { #ifdef ASSERT switch (code()) { - case lir_cmove: case lir_xchg: break; @@ -237,8 +236,7 @@ void LIR_Op2::verify() const { LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, BlockBegin* block) - : LIR_Op(lir_branch, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL) - , _cond(cond) + : LIR_Op2(lir_branch, cond, LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL) , _label(block->label()) , _block(block) , _ublock(NULL) @@ -246,8 +244,7 @@ LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, BlockBegin* block) } LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, CodeStub* stub) : - LIR_Op(lir_branch, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL) - , _cond(cond) + LIR_Op2(lir_branch, cond, LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL) , _label(stub->entry()) , _block(NULL) , _ublock(NULL) @@ -255,8 +252,7 @@ LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, CodeStub* stub) : } LIR_OpBranch::LIR_OpBranch(LIR_Condition cond, BlockBegin* block, BlockBegin* ublock) - : LIR_Op(lir_cond_float_branch, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL) - , _cond(cond) + : LIR_Op2(lir_cond_float_branch, cond, LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr, (CodeEmitInfo*)NULL) , _label(block->label()) , _block(block) , _ublock(ublock) @@ -278,13 +274,13 @@ void LIR_OpBranch::change_ublock(BlockBegin* b) { } void LIR_OpBranch::negate_cond() { - switch (_cond) { - case lir_cond_equal: _cond = lir_cond_notEqual; break; - case lir_cond_notEqual: _cond = lir_cond_equal; break; - case lir_cond_less: _cond = lir_cond_greaterEqual; break; - case lir_cond_lessEqual: _cond = lir_cond_greater; break; - case lir_cond_greaterEqual: _cond = lir_cond_less; break; - case lir_cond_greater: _cond = lir_cond_lessEqual; break; + switch (cond()) { + case lir_cond_equal: set_cond(lir_cond_notEqual); break; + case lir_cond_notEqual: set_cond(lir_cond_equal); break; + case lir_cond_less: set_cond(lir_cond_greaterEqual); break; + case lir_cond_lessEqual: set_cond(lir_cond_greater); break; + case lir_cond_greaterEqual: set_cond(lir_cond_less); break; + case lir_cond_greater: set_cond(lir_cond_lessEqual); break; default: ShouldNotReachHere(); } } @@ -507,6 +503,13 @@ void LIR_OpVisitState::visit(LIR_Op* op) { assert(op->as_OpBranch() != NULL, "must be"); LIR_OpBranch* opBranch = (LIR_OpBranch*)op; + assert(opBranch->_tmp1->is_illegal() && opBranch->_tmp2->is_illegal() && + opBranch->_tmp3->is_illegal() && opBranch->_tmp4->is_illegal() && + opBranch->_tmp5->is_illegal(), "not used"); + + if (opBranch->_opr1->is_valid()) do_input(opBranch->_opr1); + if (opBranch->_opr2->is_valid()) do_input(opBranch->_opr2); + if (opBranch->_info != NULL) do_info(opBranch->_info); assert(opBranch->_result->is_illegal(), "not used"); if (opBranch->_stub != NULL) opBranch->stub()->visit(this); @@ -595,17 +598,19 @@ void LIR_OpVisitState::visit(LIR_Op* op) { // to the result operand, otherwise the backend fails case lir_cmove: { - assert(op->as_Op2() != NULL, "must be"); - LIR_Op2* op2 = (LIR_Op2*)op; + assert(op->as_Op4() != NULL, "must be"); + LIR_Op4* op4 = (LIR_Op4*)op; - assert(op2->_info == NULL && op2->_tmp1->is_illegal() && op2->_tmp2->is_illegal() && - op2->_tmp3->is_illegal() && op2->_tmp4->is_illegal() && op2->_tmp5->is_illegal(), "not used"); - assert(op2->_opr1->is_valid() && op2->_opr2->is_valid() && op2->_result->is_valid(), "used"); + assert(op4->_info == NULL && op4->_tmp1->is_illegal() && op4->_tmp2->is_illegal() && + op4->_tmp3->is_illegal() && op4->_tmp4->is_illegal() && op4->_tmp5->is_illegal(), "not used"); + assert(op4->_opr1->is_valid() && op4->_opr2->is_valid() && op4->_result->is_valid(), "used"); - do_input(op2->_opr1); - do_input(op2->_opr2); - do_temp(op2->_opr2); - do_output(op2->_result); + do_input(op4->_opr1); + do_input(op4->_opr2); + if (op4->_opr3->is_valid()) do_input(op4->_opr3); + if (op4->_opr4->is_valid()) do_input(op4->_opr4); + do_temp(op4->_opr2); + do_output(op4->_result); break; } @@ -1049,6 +1054,10 @@ void LIR_Op3::emit_code(LIR_Assembler* masm) { masm->emit_op3(this); } +void LIR_Op4::emit_code(LIR_Assembler* masm) { + masm->emit_op4(this); +} + void LIR_OpLock::emit_code(LIR_Assembler* masm) { masm->emit_lock(this); if (stub()) { @@ -1089,6 +1098,10 @@ LIR_List::LIR_List(Compilation* compilation, BlockBegin* block) , _file(NULL) , _line(0) #endif +#ifdef RISCV + , _cmp_opr1(LIR_OprFact::illegalOpr) + , _cmp_opr2(LIR_OprFact::illegalOpr) +#endif { } @@ -1106,6 +1119,38 @@ void LIR_List::set_file_and_line(const char * file, int line) { } #endif +#ifdef RISCV +void LIR_List::set_cmp_oprs(LIR_Op* op) { + switch (op->code()) { + case lir_cmp: + _cmp_opr1 = op->as_Op2()->in_opr1(); + _cmp_opr2 = op->as_Op2()->in_opr2(); + break; + case lir_branch: // fall through + case lir_cond_float_branch: + assert(op->as_OpBranch()->cond() == lir_cond_always || + (_cmp_opr1 != LIR_OprFact::illegalOpr && _cmp_opr2 != LIR_OprFact::illegalOpr), + "conditional branches must have legal operands"); + if (op->as_OpBranch()->cond() != lir_cond_always) { + op->as_Op2()->set_in_opr1(_cmp_opr1); + op->as_Op2()->set_in_opr2(_cmp_opr2); + } + break; + case lir_cmove: + op->as_Op4()->set_in_opr3(_cmp_opr1); + op->as_Op4()->set_in_opr4(_cmp_opr2); + break; +#if INCLUDE_ZGC + case lir_zloadbarrier_test: + _cmp_opr1 = FrameMap::as_opr(t1); + _cmp_opr2 = LIR_OprFact::intConst(0); + break; +#endif + default: + break; + } +} +#endif void LIR_List::append(LIR_InsertionBuffer* buffer) { assert(this == buffer->lir_list(), "wrong lir list"); @@ -1677,7 +1722,6 @@ const char * LIR_Op::name() const { case lir_cmp_l2i: s = "cmp_l2i"; break; case lir_ucmp_fd2i: s = "ucomp_fd2i"; break; case lir_cmp_fd2i: s = "comp_fd2i"; break; - case lir_cmove: s = "cmove"; break; case lir_add: s = "add"; break; case lir_sub: s = "sub"; break; case lir_mul: s = "mul"; break; @@ -1700,6 +1744,8 @@ const char * LIR_Op::name() const { case lir_irem: s = "irem"; break; case lir_fmad: s = "fmad"; break; case lir_fmaf: s = "fmaf"; break; + // LIR_Op4 + case lir_cmove: s = "cmove"; break; // LIR_OpJavaCall case lir_static_call: s = "static"; break; case lir_optvirtual_call: s = "optvirtual"; break; @@ -1833,6 +1879,8 @@ void LIR_Op1::print_patch_code(outputStream* out, LIR_PatchCode code) { // LIR_OpBranch void LIR_OpBranch::print_instr(outputStream* out) const { print_condition(out, cond()); out->print(" "); + in_opr1()->print(out); out->print(" "); + in_opr2()->print(out); out->print(" "); if (block() != NULL) { out->print("[B%d] ", block()->block_id()); } else if (stub() != NULL) { @@ -1913,7 +1961,7 @@ void LIR_OpRoundFP::print_instr(outputStream* out) const { // LIR_Op2 void LIR_Op2::print_instr(outputStream* out) const { - if (code() == lir_cmove || code() == lir_cmp) { + if (code() == lir_cmp || code() == lir_branch || code() == lir_cond_float_branch) { print_condition(out, condition()); out->print(" "); } in_opr1()->print(out); out->print(" "); @@ -1964,6 +2012,15 @@ void LIR_Op3::print_instr(outputStream* out) const { result_opr()->print(out); } +// LIR_Op4 +void LIR_Op4::print_instr(outputStream* out) const { + print_condition(out, condition()); out->print(" "); + in_opr1()->print(out); out->print(" "); + in_opr2()->print(out); out->print(" "); + in_opr3()->print(out); out->print(" "); + in_opr4()->print(out); out->print(" "); + result_opr()->print(out); +} void LIR_OpLock::print_instr(outputStream* out) const { hdr_opr()->print(out); out->print(" "); diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index c4504b7b8b5..c3afd5553a1 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -887,6 +887,7 @@ class LIR_Op2; class LIR_OpDelay; class LIR_Op3; class LIR_OpAllocArray; +class LIR_Op4; class LIR_OpCall; class LIR_OpJavaCall; class LIR_OpRTCall; @@ -931,8 +932,6 @@ enum LIR_Code { , lir_null_check , lir_return , lir_leal - , lir_branch - , lir_cond_float_branch , lir_move , lir_convert , lir_alloc_object @@ -943,11 +942,12 @@ enum LIR_Code { , lir_load_klass , end_op1 , begin_op2 + , lir_branch + , lir_cond_float_branch , lir_cmp , lir_cmp_l2i , lir_ucmp_fd2i , lir_cmp_fd2i - , lir_cmove , lir_add , lir_sub , lir_mul @@ -975,6 +975,9 @@ enum LIR_Code { , lir_fmad , lir_fmaf , end_op3 + , begin_op4 + , lir_cmove + , end_op4 , begin_opJavaCall , lir_static_call , lir_optvirtual_call @@ -1011,6 +1014,11 @@ enum LIR_Code { , begin_opAssert , lir_assert , end_opAssert +#ifdef INCLUDE_ZGC + , begin_opZLoadBarrierTest + , lir_zloadbarrier_test + , end_opZLoadBarrierTest +#endif }; @@ -1146,6 +1154,7 @@ class LIR_Op: public CompilationResourceObj { virtual LIR_Op1* as_Op1() { return NULL; } virtual LIR_Op2* as_Op2() { return NULL; } virtual LIR_Op3* as_Op3() { return NULL; } + virtual LIR_Op4* as_Op4() { return NULL; } virtual LIR_OpArrayCopy* as_OpArrayCopy() { return NULL; } virtual LIR_OpUpdateCRC32* as_OpUpdateCRC32() { return NULL; } virtual LIR_OpTypeCheck* as_OpTypeCheck() { return NULL; } @@ -1419,45 +1428,6 @@ class LIR_OpRTCall: public LIR_OpCall { }; -class LIR_OpBranch: public LIR_Op { - friend class LIR_OpVisitState; - - private: - LIR_Condition _cond; - Label* _label; - BlockBegin* _block; // if this is a branch to a block, this is the block - BlockBegin* _ublock; // if this is a float-branch, this is the unorderd block - CodeStub* _stub; // if this is a branch to a stub, this is the stub - - public: - LIR_OpBranch(LIR_Condition cond, Label* lbl) - : LIR_Op(lir_branch, LIR_OprFact::illegalOpr, (CodeEmitInfo*) NULL) - , _cond(cond) - , _label(lbl) - , _block(NULL) - , _ublock(NULL) - , _stub(NULL) { } - - LIR_OpBranch(LIR_Condition cond, BlockBegin* block); - LIR_OpBranch(LIR_Condition cond, CodeStub* stub); - - // for unordered comparisons - LIR_OpBranch(LIR_Condition cond, BlockBegin* block, BlockBegin* ublock); - - LIR_Condition cond() const { return _cond; } - Label* label() const { return _label; } - BlockBegin* block() const { return _block; } - BlockBegin* ublock() const { return _ublock; } - CodeStub* stub() const { return _stub; } - - void change_block(BlockBegin* b); - void change_ublock(BlockBegin* b); - void negate_cond(); - - virtual void emit_code(LIR_Assembler* masm); - virtual LIR_OpBranch* as_OpBranch() { return this; } - virtual void print_instr(outputStream* out) const PRODUCT_RETURN; -}; class LIR_OpReturn: public LIR_Op1 { friend class LIR_OpVisitState; @@ -1631,19 +1601,19 @@ class LIR_Op2: public LIR_Op { void verify() const; public: - LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, CodeEmitInfo* info = NULL) + LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, CodeEmitInfo* info = NULL, BasicType type = T_ILLEGAL) : LIR_Op(code, LIR_OprFact::illegalOpr, info) , _fpu_stack_size(0) , _opr1(opr1) , _opr2(opr2) - , _type(T_ILLEGAL) + , _type(type) , _tmp1(LIR_OprFact::illegalOpr) , _tmp2(LIR_OprFact::illegalOpr) , _tmp3(LIR_OprFact::illegalOpr) , _tmp4(LIR_OprFact::illegalOpr) , _tmp5(LIR_OprFact::illegalOpr) , _condition(condition) { - assert(code == lir_cmp || code == lir_assert, "code check"); + assert(code == lir_cmp || code == lir_branch || code == lir_cond_float_branch || code == lir_assert, "code check"); } LIR_Op2(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, BasicType type) @@ -1675,7 +1645,7 @@ class LIR_Op2: public LIR_Op { , _tmp4(LIR_OprFact::illegalOpr) , _tmp5(LIR_OprFact::illegalOpr) , _condition(lir_cond_unknown) { - assert(code != lir_cmp && is_in_range(code, begin_op2, end_op2), "code check"); + assert(code != lir_cmp && code != lir_branch && code != lir_cond_float_branch && is_in_range(code, begin_op2, end_op2), "code check"); } LIR_Op2(LIR_Code code, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2 = LIR_OprFact::illegalOpr, @@ -1691,7 +1661,7 @@ class LIR_Op2: public LIR_Op { , _tmp4(tmp4) , _tmp5(tmp5) , _condition(lir_cond_unknown) { - assert(code != lir_cmp && is_in_range(code, begin_op2, end_op2), "code check"); + assert(code != lir_cmp && code != lir_branch && code != lir_cond_float_branch && is_in_range(code, begin_op2, end_op2), "code check"); } LIR_Opr in_opr1() const { return _opr1; } @@ -1703,10 +1673,10 @@ class LIR_Op2: public LIR_Op { LIR_Opr tmp4_opr() const { return _tmp4; } LIR_Opr tmp5_opr() const { return _tmp5; } LIR_Condition condition() const { - assert(code() == lir_cmp || code() == lir_cmove || code() == lir_assert, "only valid for cmp and cmove and assert"); return _condition; + assert(code() == lir_cmp || code() == lir_branch || code() == lir_cond_float_branch || code() == lir_assert, "only valid for branch and assert"); return _condition; } void set_condition(LIR_Condition condition) { - assert(code() == lir_cmp || code() == lir_cmove, "only valid for cmp and cmove"); _condition = condition; + assert(code() == lir_cmp || code() == lir_branch || code() == lir_cond_float_branch, "only valid for branch"); _condition = condition; } void set_fpu_stack_size(int size) { _fpu_stack_size = size; } @@ -1720,6 +1690,51 @@ class LIR_Op2: public LIR_Op { virtual void print_instr(outputStream* out) const PRODUCT_RETURN; }; +class LIR_OpBranch: public LIR_Op2 { + friend class LIR_OpVisitState; + + private: + Label* _label; + BlockBegin* _block; // if this is a branch to a block, this is the block + BlockBegin* _ublock; // if this is a float-branch, this is the unorderd block + CodeStub* _stub; // if this is a branch to a stub, this is the stub + + public: + LIR_OpBranch(LIR_Condition cond, Label* lbl) + : LIR_Op2(lir_branch, cond, LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr, (CodeEmitInfo*) NULL) + , _label(lbl) + , _block(NULL) + , _ublock(NULL) + , _stub(NULL) { } + + LIR_OpBranch(LIR_Condition cond, BlockBegin* block); + LIR_OpBranch(LIR_Condition cond, CodeStub* stub); + + // for unordered comparisons + LIR_OpBranch(LIR_Condition cond, BlockBegin* block, BlockBegin* ublock); + + LIR_Condition cond() const { + return condition(); + } + + void set_cond(LIR_Condition cond) { + set_condition(cond); + } + + Label* label() const { return _label; } + BlockBegin* block() const { return _block; } + BlockBegin* ublock() const { return _ublock; } + CodeStub* stub() const { return _stub; } + + void change_block(BlockBegin* b); + void change_ublock(BlockBegin* b); + void negate_cond(); + + virtual void emit_code(LIR_Assembler* masm); + virtual LIR_OpBranch* as_OpBranch() { return this; } + virtual void print_instr(outputStream* out) const PRODUCT_RETURN; +}; + class LIR_OpAllocArray : public LIR_Op { friend class LIR_OpVisitState; @@ -1783,6 +1798,63 @@ class LIR_Op3: public LIR_Op { virtual void print_instr(outputStream* out) const PRODUCT_RETURN; }; +class LIR_Op4: public LIR_Op { + friend class LIR_OpVisitState; + protected: + LIR_Opr _opr1; + LIR_Opr _opr2; + LIR_Opr _opr3; + LIR_Opr _opr4; + BasicType _type; + LIR_Opr _tmp1; + LIR_Opr _tmp2; + LIR_Opr _tmp3; + LIR_Opr _tmp4; + LIR_Opr _tmp5; + LIR_Condition _condition; + + public: + LIR_Op4(LIR_Code code, LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2, LIR_Opr opr3, LIR_Opr opr4, + LIR_Opr result, BasicType type) + : LIR_Op(code, result, NULL) + , _opr1(opr1) + , _opr2(opr2) + , _opr3(opr3) + , _opr4(opr4) + , _type(type) + , _tmp1(LIR_OprFact::illegalOpr) + , _tmp2(LIR_OprFact::illegalOpr) + , _tmp3(LIR_OprFact::illegalOpr) + , _tmp4(LIR_OprFact::illegalOpr) + , _tmp5(LIR_OprFact::illegalOpr) + , _condition(condition) { + assert(code == lir_cmove, "code check"); + assert(type != T_ILLEGAL, "cmove should have type"); + } + + LIR_Opr in_opr1() const { return _opr1; } + LIR_Opr in_opr2() const { return _opr2; } + LIR_Opr in_opr3() const { return _opr3; } + LIR_Opr in_opr4() const { return _opr4; } + BasicType type() const { return _type; } + LIR_Opr tmp1_opr() const { return _tmp1; } + LIR_Opr tmp2_opr() const { return _tmp2; } + LIR_Opr tmp3_opr() const { return _tmp3; } + LIR_Opr tmp4_opr() const { return _tmp4; } + LIR_Opr tmp5_opr() const { return _tmp5; } + + LIR_Condition condition() const { return _condition; } + void set_condition(LIR_Condition condition) { _condition = condition; } + + void set_in_opr1(LIR_Opr opr) { _opr1 = opr; } + void set_in_opr2(LIR_Opr opr) { _opr2 = opr; } + void set_in_opr3(LIR_Opr opr) { _opr3 = opr; } + void set_in_opr4(LIR_Opr opr) { _opr4 = opr; } + virtual void emit_code(LIR_Assembler* masm); + virtual LIR_Op4* as_Op4() { return this; } + + virtual void print_instr(outputStream* out) const PRODUCT_RETURN; +}; //-------------------------------- class LabelObj: public CompilationResourceObj { @@ -2022,6 +2094,10 @@ class LIR_List: public CompilationResourceObj { const char * _file; int _line; #endif +#ifdef RISCV + LIR_Opr _cmp_opr1; + LIR_Opr _cmp_opr2; +#endif public: void append(LIR_Op* op) { @@ -2034,6 +2110,12 @@ class LIR_List: public CompilationResourceObj { } #endif // PRODUCT +#ifdef RISCV + set_cmp_oprs(op); + // lir_cmp set cmp oprs only on riscv + if (op->code() == lir_cmp) return; +#endif + _operations.append(op); #ifdef ASSERT @@ -2050,6 +2132,10 @@ class LIR_List: public CompilationResourceObj { void set_file_and_line(const char * file, int line); #endif +#ifdef RISCV + void set_cmp_oprs(LIR_Op* op); +#endif + //---------- accessors --------------- LIR_OpList* instructions_list() { return &_operations; } int length() const { return _operations.length(); } @@ -2166,8 +2252,9 @@ class LIR_List: public CompilationResourceObj { void cmp_mem_int(LIR_Condition condition, LIR_Opr base, int disp, int c, CodeEmitInfo* info); void cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Address* addr, CodeEmitInfo* info); - void cmove(LIR_Condition condition, LIR_Opr src1, LIR_Opr src2, LIR_Opr dst, BasicType type) { - append(new LIR_Op2(lir_cmove, condition, src1, src2, dst, type)); + void cmove(LIR_Condition condition, LIR_Opr src1, LIR_Opr src2, LIR_Opr dst, BasicType type, + LIR_Opr cmp_opr1 = LIR_OprFact::illegalOpr, LIR_Opr cmp_opr2 = LIR_OprFact::illegalOpr) { + append(new LIR_Op4(lir_cmove, condition, src1, src2, cmp_opr1, cmp_opr2, dst, type)); } void cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value, diff --git a/src/hotspot/share/c1/c1_LIRAssembler.cpp b/src/hotspot/share/c1/c1_LIRAssembler.cpp index 1c4e0d09306..331db648756 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.cpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp @@ -689,10 +689,6 @@ void LIR_Assembler::emit_op2(LIR_Op2* op) { comp_fl2i(op->code(), op->in_opr1(), op->in_opr2(), op->result_opr(), op); break; - case lir_cmove: - cmove(op->condition(), op->in_opr1(), op->in_opr2(), op->result_opr(), op->type()); - break; - case lir_shl: case lir_shr: case lir_ushr: @@ -754,6 +750,17 @@ void LIR_Assembler::emit_op2(LIR_Op2* op) { } } +void LIR_Assembler::emit_op4(LIR_Op4* op) { + switch(op->code()) { + case lir_cmove: + cmove(op->condition(), op->in_opr1(), op->in_opr2(), op->result_opr(), op->type(), op->in_opr3(), op->in_opr4()); + break; + + default: + Unimplemented(); + break; + } +} void LIR_Assembler::build_frame() { _masm->build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes()); diff --git a/src/hotspot/share/c1/c1_LIRAssembler.hpp b/src/hotspot/share/c1/c1_LIRAssembler.hpp index 1d873b9638d..8a50667c88a 100644 --- a/src/hotspot/share/c1/c1_LIRAssembler.hpp +++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp @@ -184,6 +184,7 @@ class LIR_Assembler: public CompilationResourceObj { void emit_op1(LIR_Op1* op); void emit_op2(LIR_Op2* op); void emit_op3(LIR_Op3* op); + void emit_op4(LIR_Op4* op); void emit_opBranch(LIR_OpBranch* op); void emit_opLabel(LIR_OpLabel* op); void emit_arraycopy(LIR_OpArrayCopy* op); @@ -217,8 +218,8 @@ class LIR_Assembler: public CompilationResourceObj { void volatile_move_op(LIR_Opr src, LIR_Opr result, BasicType type, CodeEmitInfo* info); void comp_mem_op(LIR_Opr src, LIR_Opr result, BasicType type, CodeEmitInfo* info); // info set for null exceptions void comp_fl2i(LIR_Code code, LIR_Opr left, LIR_Opr right, LIR_Opr result, LIR_Op2* op); - void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result, BasicType type); - + void cmove(LIR_Condition code, LIR_Opr left, LIR_Opr right, LIR_Opr result, BasicType type, + LIR_Opr cmp_opr1 = LIR_OprFact::illegalOpr, LIR_Opr cmp_opr2 = LIR_OprFact::illegalOpr); void call( LIR_OpJavaCall* op, relocInfo::relocType rtype); void ic_call( LIR_OpJavaCall* op); void vtable_call( LIR_OpJavaCall* op); diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp index d2386d7cbb6..9f0d264f2fa 100644 --- a/src/hotspot/share/c1/c1_LinearScan.cpp +++ b/src/hotspot/share/c1/c1_LinearScan.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -1240,11 +1240,11 @@ void LinearScan::add_register_hints(LIR_Op* op) { break; } case lir_cmove: { - assert(op->as_Op2() != NULL, "lir_cmove must be LIR_Op2"); - LIR_Op2* cmove = (LIR_Op2*)op; + assert(op->as_Op4() != NULL, "lir_cmove must be LIR_Op4"); + LIR_Op4* cmove = (LIR_Op4*)op; LIR_Opr move_from = cmove->in_opr1(); - LIR_Opr move_to = cmove->result_opr(); + LIR_Opr move_to = cmove->result_opr(); if (move_to->is_register() && move_from->is_register()) { Interval* from = interval_at(reg_num(move_from)); @@ -3131,6 +3131,9 @@ void LinearScan::do_linear_scan() { } } +#ifndef RISCV + // Disable these optimizations on riscv temporarily, because it does not + // work when the comparison operands are bound to branches or cmoves. { TIME_LINEAR_SCAN(timer_optimize_lir); EdgeMoveOptimizer::optimize(ir()->code()); @@ -3138,6 +3141,7 @@ void LinearScan::do_linear_scan() { // check that cfg is still correct after optimizations ir()->verify(); } +#endif NOT_PRODUCT(print_lir(1, "Before Code Generation", false)); NOT_PRODUCT(LinearScanStatistic::compute(this, _stat_final)); @@ -6361,14 +6365,14 @@ void ControlFlowOptimizer::delete_unnecessary_jumps(BlockList* code) { // There might be a cmove inserted for profiling which depends on the same // compare. If we change the condition of the respective compare, we have // to take care of this cmove as well. - LIR_Op2* prev_cmove = NULL; + LIR_Op4* prev_cmove = NULL; for(int j = instructions->length() - 3; j >= 0 && prev_cmp == NULL; j--) { prev_op = instructions->at(j); // check for the cmove if (prev_op->code() == lir_cmove) { - assert(prev_op->as_Op2() != NULL, "cmove must be of type LIR_Op2"); - prev_cmove = (LIR_Op2*)prev_op; + assert(prev_op->as_Op4() != NULL, "cmove must be of type LIR_Op4"); + prev_cmove = (LIR_Op4*)prev_op; assert(prev_branch->cond() == prev_cmove->condition(), "should be the same"); } if (prev_op->code() == lir_cmp) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index c7e0c9b0cd9..7d31ff02e1a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Red Hat, Inc. All rights reserved. + * Copyright (c) 2018, 2022, Red Hat, Inc. 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 @@ -35,7 +35,7 @@ #include "utilities/defaultStream.hpp" void ShenandoahArguments::initialize() { -#if !(defined AARCH64 || defined AMD64 || defined IA32 || defined PPC64) +#if !(defined AARCH64 || defined AMD64 || defined IA32 || defined PPC64 || defined RISCV64) vm_exit_during_initialization("Shenandoah GC is not supported on this platform."); #endif diff --git a/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp b/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp index 4f2e36a8304..705d498399a 100644 --- a/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp +++ b/src/hotspot/share/gc/z/c1/zBarrierSetC1.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -94,7 +94,7 @@ private: public: LIR_OpZLoadBarrierTest(LIR_Opr opr) : - LIR_Op(), + LIR_Op(lir_zloadbarrier_test, LIR_OprFact::illegalOpr, NULL), _opr(opr) {} virtual void visit(LIR_OpVisitState* state) { diff --git a/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp b/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp index b2e641269e0..15ae3046721 100644 --- a/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp +++ b/src/hotspot/share/jfr/utilities/jfrBigEndian.hpp @@ -102,7 +102,7 @@ inline T JfrBigEndian::read_unaligned(const address location) { inline bool JfrBigEndian::platform_supports_unaligned_reads(void) { #if defined(IA32) || defined(AMD64) || defined(PPC) || defined(S390) return true; -#elif defined(ARM) || defined(AARCH64) +#elif defined(ARM) || defined(AARCH64) || defined(RISCV) return false; #else #warning "Unconfigured platform" diff --git a/src/hotspot/share/opto/regmask.hpp b/src/hotspot/share/opto/regmask.hpp index 1694367554d..233dd0da2d7 100644 --- a/src/hotspot/share/opto/regmask.hpp +++ b/src/hotspot/share/opto/regmask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -99,7 +99,7 @@ class RegMask { // requirement is internal to the allocator, and independent of any // particular platform. enum { SlotsPerLong = 2, - SlotsPerVecA = 8, + SlotsPerVecA = RISCV_ONLY(4) NOT_RISCV(8), SlotsPerVecS = 1, SlotsPerVecD = 2, SlotsPerVecX = 4, diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp index 319f1eba26b..41fada6988b 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.cpp +++ b/src/hotspot/share/runtime/abstract_vm_version.cpp @@ -183,7 +183,8 @@ const char* Abstract_VM_Version::jre_release_version() { AMD64_ONLY("amd64") \ IA32_ONLY("x86") \ IA64_ONLY("ia64") \ - S390_ONLY("s390") + S390_ONLY("s390") \ + RISCV64_ONLY("riscv64") #endif // !ZERO #endif // !CPU diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 1d7fb5f983a..3a75c0d0804 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -2085,7 +2085,7 @@ bool Arguments::check_vm_args_consistency() { } #endif -#if !defined(X86) && !defined(AARCH64) && !defined(PPC64) +#if !defined(X86) && !defined(AARCH64) && !defined(PPC64) && !defined(RISCV64) if (UseHeavyMonitors) { jio_fprintf(defaultStream::error_stream(), "UseHeavyMonitors is not fully implemented on this architecture"); diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index d4234575fc0..b7fc180ee44 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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 @@ -452,7 +452,7 @@ void ObjectSynchronizer::handle_sync_on_value_based_class(Handle obj, JavaThread } static bool useHeavyMonitors() { -#if defined(X86) || defined(AARCH64) || defined(PPC64) +#if defined(X86) || defined(AARCH64) || defined(PPC64) || defined(RISCV64) return UseHeavyMonitors; #else return false; diff --git a/src/hotspot/share/runtime/thread.inline.hpp b/src/hotspot/share/runtime/thread.inline.hpp index cdb8d9abb23..92dfdfa3dbe 100644 --- a/src/hotspot/share/runtime/thread.inline.hpp +++ b/src/hotspot/share/runtime/thread.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -150,7 +150,7 @@ inline JavaThread::NoAsyncExceptionDeliveryMark::~NoAsyncExceptionDeliveryMark() } inline JavaThreadState JavaThread::thread_state() const { -#if defined(PPC64) || defined (AARCH64) +#if defined(PPC64) || defined (AARCH64) || defined(RISCV64) // Use membars when accessing volatile _thread_state. See // Threads::create_vm() for size checks. return (JavaThreadState) Atomic::load_acquire((volatile jint*)&_thread_state); diff --git a/src/hotspot/share/utilities/macros.hpp b/src/hotspot/share/utilities/macros.hpp index 8dea1a754fa..bf647fbf65b 100644 --- a/src/hotspot/share/utilities/macros.hpp +++ b/src/hotspot/share/utilities/macros.hpp @@ -545,6 +545,32 @@ #define MACOS_AARCH64_ONLY(x) MACOS_ONLY(AARCH64_ONLY(x)) +#if defined(RISCV32) || defined(RISCV64) +#define RISCV +#define RISCV_ONLY(code) code +#define NOT_RISCV(code) +#else +#undef RISCV +#define RISCV_ONLY(code) +#define NOT_RISCV(code) code +#endif + +#ifdef RISCV32 +#define RISCV32_ONLY(code) code +#define NOT_RISCV32(code) +#else +#define RISCV32_ONLY(code) +#define NOT_RISCV32(code) code +#endif + +#ifdef RISCV64 +#define RISCV64_ONLY(code) code +#define NOT_RISCV64(code) +#else +#define RISCV64_ONLY(code) +#define NOT_RISCV64(code) code +#endif + #ifdef VM_LITTLE_ENDIAN #define LITTLE_ENDIAN_ONLY(code) code #define BIG_ENDIAN_ONLY(code) diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp index b7a2c6dde8f..9accba375a2 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/LinuxDebuggerLocal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2021, NTT DATA. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -60,6 +60,10 @@ #include "sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext.h" #endif +#ifdef riscv64 +#include "sun_jvm_hotspot_debugger_riscv64_RISCV64ThreadContext.h" +#endif + class AutoJavaString { JNIEnv* m_env; jstring m_str; @@ -408,7 +412,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo return (err == PS_OK)? array : 0; } -#if defined(i586) || defined(amd64) || defined(ppc64) || defined(ppc64le) || defined(aarch64) +#if defined(i586) || defined(amd64) || defined(ppc64) || defined(ppc64le) || defined(aarch64) || defined(riscv64) extern "C" JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_getThreadIntegerRegisterSet0 (JNIEnv *env, jobject this_obj, jint lwp_id) { @@ -440,6 +444,9 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo #ifdef aarch64 #define NPRGREG sun_jvm_hotspot_debugger_aarch64_AARCH64ThreadContext_NPRGREG #endif +#ifdef riscv64 +#define NPRGREG sun_jvm_hotspot_debugger_riscv64_RISCV64ThreadContext_NPRGREG +#endif #if defined(ppc64) || defined(ppc64le) #define NPRGREG sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_NPRGREG #endif @@ -516,6 +523,44 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLo } #endif /* aarch64 */ +#if defined(riscv64) +#define REG_INDEX(reg) sun_jvm_hotspot_debugger_riscv64_RISCV64ThreadContext_##reg + + regs[REG_INDEX(PC)] = gregs.pc; + regs[REG_INDEX(LR)] = gregs.ra; + regs[REG_INDEX(SP)] = gregs.sp; + regs[REG_INDEX(R3)] = gregs.gp; + regs[REG_INDEX(R4)] = gregs.tp; + regs[REG_INDEX(R5)] = gregs.t0; + regs[REG_INDEX(R6)] = gregs.t1; + regs[REG_INDEX(R7)] = gregs.t2; + regs[REG_INDEX(R8)] = gregs.s0; + regs[REG_INDEX(R9)] = gregs.s1; + regs[REG_INDEX(R10)] = gregs.a0; + regs[REG_INDEX(R11)] = gregs.a1; + regs[REG_INDEX(R12)] = gregs.a2; + regs[REG_INDEX(R13)] = gregs.a3; + regs[REG_INDEX(R14)] = gregs.a4; + regs[REG_INDEX(R15)] = gregs.a5; + regs[REG_INDEX(R16)] = gregs.a6; + regs[REG_INDEX(R17)] = gregs.a7; + regs[REG_INDEX(R18)] = gregs.s2; + regs[REG_INDEX(R19)] = gregs.s3; + regs[REG_INDEX(R20)] = gregs.s4; + regs[REG_INDEX(R21)] = gregs.s5; + regs[REG_INDEX(R22)] = gregs.s6; + regs[REG_INDEX(R23)] = gregs.s7; + regs[REG_INDEX(R24)] = gregs.s8; + regs[REG_INDEX(R25)] = gregs.s9; + regs[REG_INDEX(R26)] = gregs.s10; + regs[REG_INDEX(R27)] = gregs.s11; + regs[REG_INDEX(R28)] = gregs.t3; + regs[REG_INDEX(R29)] = gregs.t4; + regs[REG_INDEX(R30)] = gregs.t5; + regs[REG_INDEX(R31)] = gregs.t6; + +#endif /* riscv64 */ + #if defined(ppc64) || defined(ppc64le) #define REG_INDEX(reg) sun_jvm_hotspot_debugger_ppc64_PPC64ThreadContext_##reg diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h index b0fcfb1e4d5..a69496e77a4 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/libproc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -43,6 +43,8 @@ #elif defined(arm) #include #define user_regs_struct pt_regs +#elif defined(riscv64) +#include #endif // This C bool type must be int for compatibility with Linux calls and diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java index 04db854c84d..0890dcf8893 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java @@ -36,6 +36,7 @@ import sun.jvm.hotspot.debugger.MachineDescription; import sun.jvm.hotspot.debugger.MachineDescriptionAMD64; import sun.jvm.hotspot.debugger.MachineDescriptionPPC64; import sun.jvm.hotspot.debugger.MachineDescriptionAArch64; +import sun.jvm.hotspot.debugger.MachineDescriptionRISCV64; import sun.jvm.hotspot.debugger.MachineDescriptionIntelX86; import sun.jvm.hotspot.debugger.NoSuchSymbolException; import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal; @@ -558,6 +559,8 @@ public class HotSpotAgent { machDesc = new MachineDescriptionPPC64(); } else if (cpu.equals("aarch64")) { machDesc = new MachineDescriptionAArch64(); + } else if (cpu.equals("riscv64")) { + machDesc = new MachineDescriptionRISCV64(); } else { try { machDesc = (MachineDescription) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionRISCV64.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionRISCV64.java new file mode 100644 index 00000000000..a972516dee3 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/MachineDescriptionRISCV64.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger; + +public class MachineDescriptionRISCV64 extends MachineDescriptionTwosComplement implements MachineDescription { + public long getAddressSize() { + return 8; + } + + public boolean isLP64() { + return true; + } + + public boolean isBigEndian() { + return false; + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java index 491e3d5dc2c..469bb6e0665 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxCDebugger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, Red Hat Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -33,11 +33,13 @@ import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.x86.*; import sun.jvm.hotspot.debugger.amd64.*; import sun.jvm.hotspot.debugger.aarch64.*; +import sun.jvm.hotspot.debugger.riscv64.*; import sun.jvm.hotspot.debugger.ppc64.*; import sun.jvm.hotspot.debugger.linux.x86.*; import sun.jvm.hotspot.debugger.linux.amd64.*; import sun.jvm.hotspot.debugger.linux.ppc64.*; import sun.jvm.hotspot.debugger.linux.aarch64.*; +import sun.jvm.hotspot.debugger.linux.riscv64.*; import sun.jvm.hotspot.utilities.*; class LinuxCDebugger implements CDebugger { @@ -105,7 +107,14 @@ class LinuxCDebugger implements CDebugger { Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC); if (pc == null) return null; return new LinuxAARCH64CFrame(dbg, fp, pc); - } else { + } else if (cpu.equals("riscv64")) { + RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext(); + Address fp = context.getRegisterAsAddress(RISCV64ThreadContext.FP); + if (fp == null) return null; + Address pc = context.getRegisterAsAddress(RISCV64ThreadContext.PC); + if (pc == null) return null; + return new LinuxRISCV64CFrame(dbg, fp, pc); + } else { // Runtime exception thrown by LinuxThreadContextFactory if unknown cpu ThreadContext context = (ThreadContext) thread.getContext(); return context.getTopFrame(dbg); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java new file mode 100644 index 00000000000..f06da24bd0e --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64CFrame.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.linux.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.riscv64.*; +import sun.jvm.hotspot.debugger.linux.*; +import sun.jvm.hotspot.debugger.cdbg.*; +import sun.jvm.hotspot.debugger.cdbg.basic.*; + +public final class LinuxRISCV64CFrame extends BasicCFrame { + private static final int C_FRAME_LINK_OFFSET = -2; + private static final int C_FRAME_RETURN_ADDR_OFFSET = -1; + + public LinuxRISCV64CFrame(LinuxDebugger dbg, Address fp, Address pc) { + super(dbg.getCDebugger()); + this.fp = fp; + this.pc = pc; + this.dbg = dbg; + } + + // override base class impl to avoid ELF parsing + public ClosestSymbol closestSymbolToPC() { + // try native lookup in debugger. + return dbg.lookup(dbg.getAddressValue(pc())); + } + + public Address pc() { + return pc; + } + + public Address localVariableBase() { + return fp; + } + + public CFrame sender(ThreadProxy thread) { + RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext(); + Address rsp = context.getRegisterAsAddress(RISCV64ThreadContext.SP); + + if ((fp == null) || fp.lessThan(rsp)) { + return null; + } + + // Check alignment of fp + if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) { + return null; + } + + Address nextFP = fp.getAddressAt(C_FRAME_LINK_OFFSET * ADDRESS_SIZE); + if (nextFP == null || nextFP.lessThanOrEqual(fp)) { + return null; + } + Address nextPC = fp.getAddressAt(C_FRAME_RETURN_ADDR_OFFSET * ADDRESS_SIZE); + if (nextPC == null) { + return null; + } + return new LinuxRISCV64CFrame(dbg, nextFP, nextPC); + } + + // package/class internals only + private static final int ADDRESS_SIZE = 8; + private Address pc; + private Address sp; + private Address fp; + private LinuxDebugger dbg; +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64ThreadContext.java new file mode 100644 index 00000000000..fdb841ccf3d --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/riscv64/LinuxRISCV64ThreadContext.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.linux.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.riscv64.*; +import sun.jvm.hotspot.debugger.linux.*; + +public class LinuxRISCV64ThreadContext extends RISCV64ThreadContext { + private LinuxDebugger debugger; + + public LinuxRISCV64ThreadContext(LinuxDebugger debugger) { + super(); + this.debugger = debugger; + } + + public void setRegisterAsAddress(int index, Address value) { + setRegister(index, debugger.getAddressValue(value)); + } + + public Address getRegisterAsAddress(int index) { + return debugger.newAddress(getRegister(index)); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64Thread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64Thread.java new file mode 100644 index 00000000000..96d5dee47ce --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64Thread.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.proc.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.riscv64.*; +import sun.jvm.hotspot.debugger.proc.*; +import sun.jvm.hotspot.utilities.*; + +public class ProcRISCV64Thread implements ThreadProxy { + private ProcDebugger debugger; + private int id; + + public ProcRISCV64Thread(ProcDebugger debugger, Address addr) { + this.debugger = debugger; + + // FIXME: the size here should be configurable. However, making it + // so would produce a dependency on the "types" package from the + // debugger package, which is not desired. + this.id = (int) addr.getCIntegerAt(0, 4, true); + } + + public ProcRISCV64Thread(ProcDebugger debugger, long id) { + this.debugger = debugger; + this.id = (int) id; + } + + public ThreadContext getContext() throws IllegalThreadStateException { + ProcRISCV64ThreadContext context = new ProcRISCV64ThreadContext(debugger); + long[] regs = debugger.getThreadIntegerRegisterSet(id); + if (Assert.ASSERTS_ENABLED) { + Assert.that(regs.length == RISCV64ThreadContext.NPRGREG, "size mismatch"); + } + for (int i = 0; i < regs.length; i++) { + context.setRegister(i, regs[i]); + } + return context; + } + + public boolean canSetContext() throws DebuggerException { + return false; + } + + public void setContext(ThreadContext context) + throws IllegalThreadStateException, DebuggerException { + throw new DebuggerException("Unimplemented"); + } + + public String toString() { + return "t@" + id; + } + + public boolean equals(Object obj) { + if ((obj == null) || !(obj instanceof ProcRISCV64Thread)) { + return false; + } + + return (((ProcRISCV64Thread) obj).id == id); + } + + public int hashCode() { + return id; + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64ThreadContext.java new file mode 100644 index 00000000000..f2aa845e665 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64ThreadContext.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.proc.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.riscv64.*; +import sun.jvm.hotspot.debugger.proc.*; + +public class ProcRISCV64ThreadContext extends RISCV64ThreadContext { + private ProcDebugger debugger; + + public ProcRISCV64ThreadContext(ProcDebugger debugger) { + super(); + this.debugger = debugger; + } + + public void setRegisterAsAddress(int index, Address value) { + setRegister(index, debugger.getAddressValue(value)); + } + + public Address getRegisterAsAddress(int index) { + return debugger.newAddress(getRegister(index)); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64ThreadFactory.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64ThreadFactory.java new file mode 100644 index 00000000000..19f64b8ce2d --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/riscv64/ProcRISCV64ThreadFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.proc.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.proc.*; + +public class ProcRISCV64ThreadFactory implements ProcThreadFactory { + private ProcDebugger debugger; + + public ProcRISCV64ThreadFactory(ProcDebugger debugger) { + this.debugger = debugger; + } + + public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) { + return new ProcRISCV64Thread(debugger, threadIdentifierAddr); + } + + public ThreadProxy createThreadWrapper(long id) { + return new ProcRISCV64Thread(debugger, id); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64Thread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64Thread.java new file mode 100644 index 00000000000..aecbda59023 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64Thread.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.remote.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.riscv64.*; +import sun.jvm.hotspot.debugger.remote.*; +import sun.jvm.hotspot.utilities.*; + +public class RemoteRISCV64Thread extends RemoteThread { + public RemoteRISCV64Thread(RemoteDebuggerClient debugger, Address addr) { + super(debugger, addr); + } + + public RemoteRISCV64Thread(RemoteDebuggerClient debugger, long id) { + super(debugger, id); + } + + public ThreadContext getContext() throws IllegalThreadStateException { + RemoteRISCV64ThreadContext context = new RemoteRISCV64ThreadContext(debugger); + long[] regs = (addr != null)? debugger.getThreadIntegerRegisterSet(addr) : + debugger.getThreadIntegerRegisterSet(id); + if (Assert.ASSERTS_ENABLED) { + Assert.that(regs.length == RISCV64ThreadContext.NPRGREG, "size of register set must match"); + } + for (int i = 0; i < regs.length; i++) { + context.setRegister(i, regs[i]); + } + return context; + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64ThreadContext.java new file mode 100644 index 00000000000..1d3da6be5af --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64ThreadContext.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.remote.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.riscv64.*; +import sun.jvm.hotspot.debugger.remote.*; + +public class RemoteRISCV64ThreadContext extends RISCV64ThreadContext { + private RemoteDebuggerClient debugger; + + public RemoteRISCV64ThreadContext(RemoteDebuggerClient debugger) { + super(); + this.debugger = debugger; + } + + public void setRegisterAsAddress(int index, Address value) { + setRegister(index, debugger.getAddressValue(value)); + } + + public Address getRegisterAsAddress(int index) { + return debugger.newAddress(getRegister(index)); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64ThreadFactory.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64ThreadFactory.java new file mode 100644 index 00000000000..725b94e25a3 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/remote/riscv64/RemoteRISCV64ThreadFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.remote.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.remote.*; + +public class RemoteRISCV64ThreadFactory implements RemoteThreadFactory { + private RemoteDebuggerClient debugger; + + public RemoteRISCV64ThreadFactory(RemoteDebuggerClient debugger) { + this.debugger = debugger; + } + + public ThreadProxy createThreadWrapper(Address threadIdentifierAddr) { + return new RemoteRISCV64Thread(debugger, threadIdentifierAddr); + } + + public ThreadProxy createThreadWrapper(long id) { + return new RemoteRISCV64Thread(debugger, id); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/risv64/RISCV64ThreadContext.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/risv64/RISCV64ThreadContext.java new file mode 100644 index 00000000000..fb60a70427a --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/risv64/RISCV64ThreadContext.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.debugger.riscv64; + +import java.lang.annotation.Native; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.cdbg.*; + +/** Specifies the thread context on riscv64 platforms; only a sub-portion + * of the context is guaranteed to be present on all operating + * systems. */ + +public abstract class RISCV64ThreadContext implements ThreadContext { + // Taken from /usr/include/asm/sigcontext.h on Linux/RISCV64. + + // /* + // * Signal context structure - contains all info to do with the state + // * before the signal handler was invoked. + // */ + // struct sigcontext { + // struct user_regs_struct sc_regs; + // union __riscv_fp_state sc_fpregs; + // }; + // + // struct user_regs_struct { + // unsigned long pc; + // unsigned long ra; + // unsigned long sp; + // unsigned long gp; + // unsigned long tp; + // unsigned long t0; + // unsigned long t1; + // unsigned long t2; + // unsigned long s0; + // unsigned long s1; + // unsigned long a0; + // unsigned long a1; + // unsigned long a2; + // unsigned long a3; + // unsigned long a4; + // unsigned long a5; + // unsigned long a6; + // unsigned long a7; + // unsigned long s2; + // unsigned long s3; + // unsigned long s4; + // unsigned long s5; + // unsigned long s6; + // unsigned long s7; + // unsigned long s8; + // unsigned long s9; + // unsigned long s10; + // unsigned long s11; + // unsigned long t3; + // unsigned long t4; + // unsigned long t5; + // unsigned long t6; + // }; + + // NOTE: the indices for the various registers must be maintained as + // listed across various operating systems. However, only a small + // subset of the registers' values are guaranteed to be present (and + // must be present for the SA's stack walking to work) + + // One instance of the Native annotation is enough to trigger header generation + // for this file. + @Native + public static final int R0 = 0; + public static final int R1 = 1; + public static final int R2 = 2; + public static final int R3 = 3; + public static final int R4 = 4; + public static final int R5 = 5; + public static final int R6 = 6; + public static final int R7 = 7; + public static final int R8 = 8; + public static final int R9 = 9; + public static final int R10 = 10; + public static final int R11 = 11; + public static final int R12 = 12; + public static final int R13 = 13; + public static final int R14 = 14; + public static final int R15 = 15; + public static final int R16 = 16; + public static final int R17 = 17; + public static final int R18 = 18; + public static final int R19 = 19; + public static final int R20 = 20; + public static final int R21 = 21; + public static final int R22 = 22; + public static final int R23 = 23; + public static final int R24 = 24; + public static final int R25 = 25; + public static final int R26 = 26; + public static final int R27 = 27; + public static final int R28 = 28; + public static final int R29 = 29; + public static final int R30 = 30; + public static final int R31 = 31; + + public static final int NPRGREG = 32; + + public static final int PC = R0; + public static final int LR = R1; + public static final int SP = R2; + public static final int FP = R8; + + private long[] data; + + public RISCV64ThreadContext() { + data = new long[NPRGREG]; + } + + public int getNumRegisters() { + return NPRGREG; + } + + public String getRegisterName(int index) { + switch (index) { + case LR: return "lr"; + case SP: return "sp"; + case PC: return "pc"; + default: + return "r" + index; + } + } + + public void setRegister(int index, long value) { + data[index] = value; + } + + public long getRegister(int index) { + return data[index]; + } + + public CFrame getTopFrame(Debugger dbg) { + return null; + } + + /** This can't be implemented in this class since we would have to + * tie the implementation to, for example, the debugging system */ + public abstract void setRegisterAsAddress(int index, Address value); + + /** This can't be implemented in this class since we would have to + * tie the implementation to, for example, the debugging system */ + public abstract Address getRegisterAsAddress(int index); +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java index 4a2fa691d3f..d16ac8aae51 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -34,6 +34,7 @@ import sun.jvm.hotspot.runtime.win32_aarch64.Win32AARCH64JavaThreadPDAccess; import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess; import sun.jvm.hotspot.runtime.linux_amd64.LinuxAMD64JavaThreadPDAccess; import sun.jvm.hotspot.runtime.linux_aarch64.LinuxAARCH64JavaThreadPDAccess; +import sun.jvm.hotspot.runtime.linux_riscv64.LinuxRISCV64JavaThreadPDAccess; import sun.jvm.hotspot.runtime.linux_ppc64.LinuxPPC64JavaThreadPDAccess; import sun.jvm.hotspot.runtime.bsd_x86.BsdX86JavaThreadPDAccess; import sun.jvm.hotspot.runtime.bsd_amd64.BsdAMD64JavaThreadPDAccess; @@ -113,6 +114,8 @@ public class Threads { access = new LinuxPPC64JavaThreadPDAccess(); } else if (cpu.equals("aarch64")) { access = new LinuxAARCH64JavaThreadPDAccess(); + } else if (cpu.equals("riscv64")) { + access = new LinuxRISCV64JavaThreadPDAccess(); } else { try { access = (JavaThreadPDAccess) diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_riscv64/LinuxRISCV64JavaThreadPDAccess.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_riscv64/LinuxRISCV64JavaThreadPDAccess.java new file mode 100644 index 00000000000..f2e224f28ee --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/linux_riscv64/LinuxRISCV64JavaThreadPDAccess.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.runtime.linux_riscv64; + +import java.io.*; +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.riscv64.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.riscv64.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; +import sun.jvm.hotspot.utilities.Observable; +import sun.jvm.hotspot.utilities.Observer; + +public class LinuxRISCV64JavaThreadPDAccess implements JavaThreadPDAccess { + private static AddressField lastJavaFPField; + private static AddressField osThreadField; + + // Field from OSThread + private static CIntegerField osThreadThreadIDField; + + // This is currently unneeded but is being kept in case we change + // the currentFrameGuess algorithm + private static final long GUESS_SCAN_RANGE = 128 * 1024; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("JavaThread"); + osThreadField = type.getAddressField("_osthread"); + + Type anchorType = db.lookupType("JavaFrameAnchor"); + lastJavaFPField = anchorType.getAddressField("_last_Java_fp"); + + Type osThreadType = db.lookupType("OSThread"); + osThreadThreadIDField = osThreadType.getCIntegerField("_thread_id"); + } + + public Address getLastJavaFP(Address addr) { + return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset())); + } + + public Address getLastJavaPC(Address addr) { + return null; + } + + public Address getBaseOfStackPointer(Address addr) { + return null; + } + + public Frame getLastFramePD(JavaThread thread, Address addr) { + Address fp = thread.getLastJavaFP(); + if (fp == null) { + return null; // no information + } + return new RISCV64Frame(thread.getLastJavaSP(), fp); + } + + public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) { + return new RISCV64RegisterMap(thread, updateMap); + } + + public Frame getCurrentFrameGuess(JavaThread thread, Address addr) { + ThreadProxy t = getThreadProxy(addr); + RISCV64ThreadContext context = (RISCV64ThreadContext) t.getContext(); + RISCV64CurrentFrameGuess guesser = new RISCV64CurrentFrameGuess(context, thread); + if (!guesser.run(GUESS_SCAN_RANGE)) { + return null; + } + if (guesser.getPC() == null) { + return new RISCV64Frame(guesser.getSP(), guesser.getFP()); + } else { + return new RISCV64Frame(guesser.getSP(), guesser.getFP(), guesser.getPC()); + } + } + + public void printThreadIDOn(Address addr, PrintStream tty) { + tty.print(getThreadProxy(addr)); + } + + public void printInfoOn(Address threadAddr, PrintStream tty) { + tty.print("Thread id: "); + printThreadIDOn(threadAddr, tty); + } + + public Address getLastSP(Address addr) { + ThreadProxy t = getThreadProxy(addr); + RISCV64ThreadContext context = (RISCV64ThreadContext) t.getContext(); + return context.getRegisterAsAddress(RISCV64ThreadContext.SP); + } + + public ThreadProxy getThreadProxy(Address addr) { + // Addr is the address of the JavaThread. + // Fetch the OSThread (for now and for simplicity, not making a + // separate "OSThread" class in this package) + Address osThreadAddr = osThreadField.getValue(addr); + // Get the address of the _thread_id from the OSThread + Address threadIdAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset()); + + JVMDebugger debugger = VM.getVM().getDebugger(); + return debugger.getThreadForIdentifierAddress(threadIdAddr); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64CurrentFrameGuess.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64CurrentFrameGuess.java new file mode 100644 index 00000000000..34701c6922f --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64CurrentFrameGuess.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.runtime.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.riscv64.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.interpreter.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.riscv64.*; + +/**

      Should be able to be used on all riscv64 platforms we support + (Linux/riscv64) to implement JavaThread's "currentFrameGuess()" + functionality. Input is an RISCV64ThreadContext; output is SP, FP, + and PC for an RISCV64Frame. Instantiation of the RISCV64Frame is + left to the caller, since we may need to subclass RISCV64Frame to + support signal handler frames on Unix platforms.

      + +

      Algorithm is to walk up the stack within a given range (say, + 512K at most) looking for a plausible PC and SP for a Java frame, + also considering those coming in from the context. If we find a PC + that belongs to the VM (i.e., in generated code like the + interpreter or CodeCache) then we try to find an associated FP. + We repeat this until we either find a complete frame or run out of + stack to look at.

      */ + +public class RISCV64CurrentFrameGuess { + private RISCV64ThreadContext context; + private JavaThread thread; + private Address spFound; + private Address fpFound; + private Address pcFound; + + private static final boolean DEBUG = System.getProperty("sun.jvm.hotspot.runtime.riscv64.RISCV64Frame.DEBUG") + != null; + + public RISCV64CurrentFrameGuess(RISCV64ThreadContext context, + JavaThread thread) { + this.context = context; + this.thread = thread; + } + + /** Returns false if not able to find a frame within a reasonable range. */ + public boolean run(long regionInBytesToSearch) { + Address sp = context.getRegisterAsAddress(RISCV64ThreadContext.SP); + Address pc = context.getRegisterAsAddress(RISCV64ThreadContext.PC); + Address fp = context.getRegisterAsAddress(RISCV64ThreadContext.FP); + if (sp == null) { + // Bail out if no last java frame either + if (thread.getLastJavaSP() != null) { + setValues(thread.getLastJavaSP(), thread.getLastJavaFP(), null); + return true; + } + return false; + } + Address end = sp.addOffsetTo(regionInBytesToSearch); + VM vm = VM.getVM(); + + setValues(null, null, null); // Assume we're not going to find anything + + if (vm.isJavaPCDbg(pc)) { + if (vm.isClientCompiler()) { + // If the topmost frame is a Java frame, we are (pretty much) + // guaranteed to have a viable FP. We should be more robust + // than this (we have the potential for losing entire threads' + // stack traces) but need to see how much work we really have + // to do here. Searching the stack for an (SP, FP) pair is + // hard since it's easy to misinterpret inter-frame stack + // pointers as base-of-frame pointers; we also don't know the + // sizes of C1 frames (not registered in the nmethod) so can't + // derive them from SP. + + setValues(sp, fp, pc); + return true; + } else { + if (vm.getInterpreter().contains(pc)) { + if (DEBUG) { + System.out.println("CurrentFrameGuess: choosing interpreter frame: sp = " + + sp + ", fp = " + fp + ", pc = " + pc); + } + setValues(sp, fp, pc); + return true; + } + + // For the server compiler, FP is not guaranteed to be valid + // for compiled code. In addition, an earlier attempt at a + // non-searching algorithm (see below) failed because the + // stack pointer from the thread context was pointing + // (considerably) beyond the ostensible end of the stack, into + // garbage; walking from the topmost frame back caused a crash. + // + // This algorithm takes the current PC as a given and tries to + // find the correct corresponding SP by walking up the stack + // and repeatedly performing stackwalks (very inefficient). + // + // FIXME: there is something wrong with stackwalking across + // adapter frames...this is likely to be the root cause of the + // failure with the simpler algorithm below. + + for (long offset = 0; + offset < regionInBytesToSearch; + offset += vm.getAddressSize()) { + try { + Address curSP = sp.addOffsetTo(offset); + Frame frame = new RISCV64Frame(curSP, null, pc); + RegisterMap map = thread.newRegisterMap(false); + while (frame != null) { + if (frame.isEntryFrame() && frame.entryFrameIsFirst()) { + // We were able to traverse all the way to the + // bottommost Java frame. + // This sp looks good. Keep it. + if (DEBUG) { + System.out.println("CurrentFrameGuess: Choosing sp = " + curSP + ", pc = " + pc); + } + setValues(curSP, null, pc); + return true; + } + frame = frame.sender(map); + } + } catch (Exception e) { + if (DEBUG) { + System.out.println("CurrentFrameGuess: Exception " + e + " at offset " + offset); + } + // Bad SP. Try another. + } + } + + // Were not able to find a plausible SP to go with this PC. + // Bail out. + return false; + } + } else { + // If the current program counter was not known to us as a Java + // PC, we currently assume that we are in the run-time system + // and attempt to look to thread-local storage for saved SP and + // FP. Note that if these are null (because we were, in fact, + // in Java code, i.e., vtable stubs or similar, and the SA + // didn't have enough insight into the target VM to understand + // that) then we are going to lose the entire stack trace for + // the thread, which is sub-optimal. FIXME. + + if (DEBUG) { + System.out.println("CurrentFrameGuess: choosing last Java frame: sp = " + + thread.getLastJavaSP() + ", fp = " + thread.getLastJavaFP()); + } + if (thread.getLastJavaSP() == null) { + return false; // No known Java frames on stack + } + + // The runtime has a nasty habit of not saving fp in the frame + // anchor, leaving us to grovel about in the stack to find a + // plausible address. Fortunately, this only happens in + // compiled code; there we always have a valid PC, and we always + // push LR and FP onto the stack as a pair, with FP at the lower + // address. + pc = thread.getLastJavaPC(); + fp = thread.getLastJavaFP(); + sp = thread.getLastJavaSP(); + + if (fp == null) { + CodeCache cc = vm.getCodeCache(); + if (cc.contains(pc)) { + CodeBlob cb = cc.findBlob(pc); + if (DEBUG) { + System.out.println("FP is null. Found blob frame size " + cb.getFrameSize()); + } + // See if we can derive a frame pointer from SP and PC + long link_offset = cb.getFrameSize() - 2 * VM.getVM().getAddressSize(); + if (link_offset >= 0) { + fp = sp.addOffsetTo(link_offset); + } + } + } + + // We found a PC in the frame anchor. Check that it's plausible, and + // if it is, use it. + if (vm.isJavaPCDbg(pc)) { + setValues(sp, fp, pc); + } else { + setValues(sp, fp, null); + } + + return true; + } + } + + public Address getSP() { return spFound; } + public Address getFP() { return fpFound; } + /** May be null if getting values from thread-local storage; take + care to call the correct RISCV64Frame constructor to recover this if + necessary */ + public Address getPC() { return pcFound; } + + private void setValues(Address sp, Address fp, Address pc) { + spFound = sp; + fpFound = fp; + pcFound = pc; + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java new file mode 100644 index 00000000000..df280005d72 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64Frame.java @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, Red Hat Inc. + * Copyright (c) 2021, 2022, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.runtime.riscv64; + +import java.util.*; +import sun.jvm.hotspot.code.*; +import sun.jvm.hotspot.compiler.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.oops.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; +import sun.jvm.hotspot.utilities.Observable; +import sun.jvm.hotspot.utilities.Observer; + +/** Specialization of and implementation of abstract methods of the + Frame class for the riscv64 family of CPUs. */ + +public class RISCV64Frame extends Frame { + private static final boolean DEBUG; + static { + DEBUG = System.getProperty("sun.jvm.hotspot.runtime.RISCV64.RISCV64Frame.DEBUG") != null; + } + + // Java frames + private static final int LINK_OFFSET = -2; + private static final int RETURN_ADDR_OFFSET = -1; + private static final int SENDER_SP_OFFSET = 0; + + // Interpreter frames + private static final int INTERPRETER_FRAME_SENDER_SP_OFFSET = -3; + private static final int INTERPRETER_FRAME_LAST_SP_OFFSET = INTERPRETER_FRAME_SENDER_SP_OFFSET - 1; + private static final int INTERPRETER_FRAME_METHOD_OFFSET = INTERPRETER_FRAME_LAST_SP_OFFSET - 1; + private static int INTERPRETER_FRAME_MDX_OFFSET; // Non-core builds only + private static int INTERPRETER_FRAME_PADDING_OFFSET; + private static int INTERPRETER_FRAME_MIRROR_OFFSET; + private static int INTERPRETER_FRAME_CACHE_OFFSET; + private static int INTERPRETER_FRAME_LOCALS_OFFSET; + private static int INTERPRETER_FRAME_BCX_OFFSET; + private static int INTERPRETER_FRAME_INITIAL_SP_OFFSET; + private static int INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET; + private static int INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET; + + // Entry frames + private static int ENTRY_FRAME_CALL_WRAPPER_OFFSET = -10; + + // Native frames + private static final int NATIVE_FRAME_INITIAL_PARAM_OFFSET = 2; + + private static VMReg fp = new VMReg(8); + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + INTERPRETER_FRAME_MDX_OFFSET = INTERPRETER_FRAME_METHOD_OFFSET - 1; + INTERPRETER_FRAME_PADDING_OFFSET = INTERPRETER_FRAME_MDX_OFFSET - 1; + INTERPRETER_FRAME_MIRROR_OFFSET = INTERPRETER_FRAME_PADDING_OFFSET - 1; + INTERPRETER_FRAME_CACHE_OFFSET = INTERPRETER_FRAME_MIRROR_OFFSET - 1; + INTERPRETER_FRAME_LOCALS_OFFSET = INTERPRETER_FRAME_CACHE_OFFSET - 1; + INTERPRETER_FRAME_BCX_OFFSET = INTERPRETER_FRAME_LOCALS_OFFSET - 1; + INTERPRETER_FRAME_INITIAL_SP_OFFSET = INTERPRETER_FRAME_BCX_OFFSET - 1; + INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET; + INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET = INTERPRETER_FRAME_INITIAL_SP_OFFSET; + } + + + // an additional field beyond sp and pc: + Address raw_fp; // frame pointer + private Address raw_unextendedSP; + + private RISCV64Frame() { + } + + private void adjustForDeopt() { + if ( pc != null) { + // Look for a deopt pc and if it is deopted convert to original pc + CodeBlob cb = VM.getVM().getCodeCache().findBlob(pc); + if (cb != null && cb.isJavaMethod()) { + NMethod nm = (NMethod) cb; + if (pc.equals(nm.deoptHandlerBegin())) { + if (Assert.ASSERTS_ENABLED) { + Assert.that(this.getUnextendedSP() != null, "null SP in Java frame"); + } + // adjust pc if frame is deoptimized. + pc = this.getUnextendedSP().getAddressAt(nm.origPCOffset()); + deoptimized = true; + } + } + } + } + + public RISCV64Frame(Address raw_sp, Address raw_fp, Address pc) { + this.raw_sp = raw_sp; + this.raw_unextendedSP = raw_sp; + this.raw_fp = raw_fp; + this.pc = pc; + adjustUnextendedSP(); + + // Frame must be fully constructed before this call + adjustForDeopt(); + + if (DEBUG) { + System.out.println("RISCV64Frame(sp, fp, pc): " + this); + dumpStack(); + } + } + + public RISCV64Frame(Address raw_sp, Address raw_fp) { + this.raw_sp = raw_sp; + this.raw_unextendedSP = raw_sp; + this.raw_fp = raw_fp; + + // We cannot assume SP[-1] always contains a valid return PC (e.g. if + // the callee is a C/C++ compiled frame). If the PC is not known to + // Java then this.pc is null. + Address savedPC = raw_sp.getAddressAt(-1 * VM.getVM().getAddressSize()); + if (VM.getVM().isJavaPCDbg(savedPC)) { + this.pc = savedPC; + } + + adjustUnextendedSP(); + + // Frame must be fully constructed before this call + adjustForDeopt(); + + if (DEBUG) { + System.out.println("RISCV64Frame(sp, fp): " + this); + dumpStack(); + } + } + + public RISCV64Frame(Address raw_sp, Address raw_unextendedSp, Address raw_fp, Address pc) { + this.raw_sp = raw_sp; + this.raw_unextendedSP = raw_unextendedSp; + this.raw_fp = raw_fp; + this.pc = pc; + adjustUnextendedSP(); + + // Frame must be fully constructed before this call + adjustForDeopt(); + + if (DEBUG) { + System.out.println("RISCV64Frame(sp, unextendedSP, fp, pc): " + this); + dumpStack(); + } + + } + + public Object clone() { + RISCV64Frame frame = new RISCV64Frame(); + frame.raw_sp = raw_sp; + frame.raw_unextendedSP = raw_unextendedSP; + frame.raw_fp = raw_fp; + frame.pc = pc; + frame.deoptimized = deoptimized; + return frame; + } + + public boolean equals(Object arg) { + if (arg == null) { + return false; + } + + if (!(arg instanceof RISCV64Frame)) { + return false; + } + + RISCV64Frame other = (RISCV64Frame) arg; + + return (AddressOps.equal(getSP(), other.getSP()) && + AddressOps.equal(getUnextendedSP(), other.getUnextendedSP()) && + AddressOps.equal(getFP(), other.getFP()) && + AddressOps.equal(getPC(), other.getPC())); + } + + public int hashCode() { + if (raw_sp == null) { + return 0; + } + + return raw_sp.hashCode(); + } + + public String toString() { + return "sp: " + (getSP() == null? "null" : getSP().toString()) + + ", unextendedSP: " + (getUnextendedSP() == null? "null" : getUnextendedSP().toString()) + + ", fp: " + (getFP() == null? "null" : getFP().toString()) + + ", pc: " + (pc == null? "null" : pc.toString()); + } + + // accessors for the instance variables + public Address getFP() { return raw_fp; } + public Address getSP() { return raw_sp; } + public Address getID() { return raw_sp; } + + // FIXME: not implemented yet + public boolean isSignalHandlerFrameDbg() { return false; } + public int getSignalNumberDbg() { return 0; } + public String getSignalNameDbg() { return null; } + + public boolean isInterpretedFrameValid() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(isInterpretedFrame(), "Not an interpreted frame"); + } + + // These are reasonable sanity checks + if (getFP() == null || getFP().andWithMask(0x3) != null) { + return false; + } + + if (getSP() == null || getSP().andWithMask(0x3) != null) { + return false; + } + + if (getFP().addOffsetTo(INTERPRETER_FRAME_INITIAL_SP_OFFSET * VM.getVM().getAddressSize()).lessThan(getSP())) { + return false; + } + + // These are hacks to keep us out of trouble. + // The problem with these is that they mask other problems + if (getFP().lessThanOrEqual(getSP())) { + // this attempts to deal with unsigned comparison above + return false; + } + + if (getFP().minus(getSP()) > 4096 * VM.getVM().getAddressSize()) { + // stack frames shouldn't be large. + return false; + } + + return true; + } + + public Frame sender(RegisterMap regMap, CodeBlob cb) { + RISCV64RegisterMap map = (RISCV64RegisterMap) regMap; + + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + // Default is we done have to follow them. The sender_for_xxx will + // update it accordingly + map.setIncludeArgumentOops(false); + + if (isEntryFrame()) return senderForEntryFrame(map); + if (isInterpretedFrame()) return senderForInterpreterFrame(map); + + if(cb == null) { + cb = VM.getVM().getCodeCache().findBlob(getPC()); + } else { + if (Assert.ASSERTS_ENABLED) { + Assert.that(cb.equals(VM.getVM().getCodeCache().findBlob(getPC())), "Must be the same"); + } + } + + if (cb != null) { + return senderForCompiledFrame(map, cb); + } + + // Must be native-compiled frame, i.e. the marshaling code for native + // methods that exists in the core system. + return new RISCV64Frame(getSenderSP(), getLink(), getSenderPC()); + } + + private Frame senderForEntryFrame(RISCV64RegisterMap map) { + if (DEBUG) { + System.out.println("senderForEntryFrame"); + } + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + // Java frame called from C; skip all C frames and return top C + // frame of that chunk as the sender + RISCV64JavaCallWrapper jcw = (RISCV64JavaCallWrapper) getEntryFrameCallWrapper(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(!entryFrameIsFirst(), "next Java fp must be non zero"); + Assert.that(jcw.getLastJavaSP().greaterThan(getSP()), "must be above this frame on stack"); + } + RISCV64Frame fr; + if (jcw.getLastJavaPC() != null) { + fr = new RISCV64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP(), jcw.getLastJavaPC()); + } else { + fr = new RISCV64Frame(jcw.getLastJavaSP(), jcw.getLastJavaFP()); + } + map.clear(); + if (Assert.ASSERTS_ENABLED) { + Assert.that(map.getIncludeArgumentOops(), "should be set by clear"); + } + return fr; + } + + //------------------------------------------------------------------------------ + // frame::adjust_unextended_sp + private void adjustUnextendedSP() { + // If we are returning to a compiled MethodHandle call site, the + // saved_fp will in fact be a saved value of the unextended SP. The + // simplest way to tell whether we are returning to such a call site + // is as follows: + + CodeBlob cb = cb(); + NMethod senderNm = (cb == null) ? null : cb.asNMethodOrNull(); + if (senderNm != null) { + // If the sender PC is a deoptimization point, get the original + // PC. For MethodHandle call site the unextended_sp is stored in + // saved_fp. + if (senderNm.isDeoptMhEntry(getPC())) { + raw_unextendedSP = getFP(); + } + else if (senderNm.isDeoptEntry(getPC())) { + } + else if (senderNm.isMethodHandleReturn(getPC())) { + raw_unextendedSP = getFP(); + } + } + } + + private Frame senderForInterpreterFrame(RISCV64RegisterMap map) { + if (DEBUG) { + System.out.println("senderForInterpreterFrame"); + } + Address unextendedSP = addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0); + Address sp = addressOfStackSlot(SENDER_SP_OFFSET); + // We do not need to update the callee-save register mapping because above + // us is either another interpreter frame or a converter-frame, but never + // directly a compiled frame. + // 11/24/04 SFG. With the removal of adapter frames this is no longer true. + // However c2 no longer uses callee save register for java calls so there + // are no callee register to find. + + if (map.getUpdateMap()) + updateMapWithSavedLink(map, addressOfStackSlot(LINK_OFFSET)); + + return new RISCV64Frame(sp, unextendedSP, getLink(), getSenderPC()); + } + + private void updateMapWithSavedLink(RegisterMap map, Address savedFPAddr) { + map.setLocation(fp, savedFPAddr); + } + + private Frame senderForCompiledFrame(RISCV64RegisterMap map, CodeBlob cb) { + if (DEBUG) { + System.out.println("senderForCompiledFrame"); + } + + // + // NOTE: some of this code is (unfortunately) duplicated RISCV64CurrentFrameGuess + // + + if (Assert.ASSERTS_ENABLED) { + Assert.that(map != null, "map must be set"); + } + + // frame owned by optimizing compiler + if (Assert.ASSERTS_ENABLED) { + Assert.that(cb.getFrameSize() >= 0, "must have non-zero frame size"); + } + Address senderSP = getUnextendedSP().addOffsetTo(cb.getFrameSize()); + + // The return_address is always the word on the stack + Address senderPC = senderSP.getAddressAt(-1 * VM.getVM().getAddressSize()); + + // This is the saved value of FP which may or may not really be an FP. + // It is only an FP if the sender is an interpreter frame. + Address savedFPAddr = senderSP.addOffsetTo(-2 * VM.getVM().getAddressSize()); + + if (map.getUpdateMap()) { + // Tell GC to use argument oopmaps for some runtime stubs that need it. + // For C1, the runtime stub might not have oop maps, so set this flag + // outside of update_register_map. + map.setIncludeArgumentOops(cb.callerMustGCArguments()); + + if (cb.getOopMaps() != null) { + ImmutableOopMapSet.updateRegisterMap(this, cb, map, true); + } + + // Since the prolog does the save and restore of FP there is no oopmap + // for it so we must fill in its location as if there was an oopmap entry + // since if our caller was compiled code there could be live jvm state in it. + updateMapWithSavedLink(map, savedFPAddr); + } + + return new RISCV64Frame(senderSP, savedFPAddr.getAddressAt(0), senderPC); + } + + protected boolean hasSenderPD() { + return true; + } + + public long frameSize() { + return (getSenderSP().minus(getSP()) / VM.getVM().getAddressSize()); + } + + public Address getLink() { + try { + if (DEBUG) { + System.out.println("Reading link at " + addressOfStackSlot(LINK_OFFSET) + + " = " + addressOfStackSlot(LINK_OFFSET).getAddressAt(0)); + } + return addressOfStackSlot(LINK_OFFSET).getAddressAt(0); + } catch (Exception e) { + if (DEBUG) + System.out.println("Returning null"); + return null; + } + } + + public Address getUnextendedSP() { return raw_unextendedSP; } + + // Return address: + public Address getSenderPCAddr() { return addressOfStackSlot(RETURN_ADDR_OFFSET); } + public Address getSenderPC() { return getSenderPCAddr().getAddressAt(0); } + + // return address of param, zero origin index. + public Address getNativeParamAddr(int idx) { + return addressOfStackSlot(NATIVE_FRAME_INITIAL_PARAM_OFFSET + idx); + } + + public Address getSenderSP() { return addressOfStackSlot(SENDER_SP_OFFSET); } + + public Address addressOfInterpreterFrameLocals() { + return addressOfStackSlot(INTERPRETER_FRAME_LOCALS_OFFSET); + } + + private Address addressOfInterpreterFrameBCX() { + return addressOfStackSlot(INTERPRETER_FRAME_BCX_OFFSET); + } + + public int getInterpreterFrameBCI() { + // FIXME: this is not atomic with respect to GC and is unsuitable + // for use in a non-debugging, or reflective, system. Need to + // figure out how to express this. + Address bcp = addressOfInterpreterFrameBCX().getAddressAt(0); + Address methodHandle = addressOfInterpreterFrameMethod().getAddressAt(0); + Method method = (Method)Metadata.instantiateWrapperFor(methodHandle); + return bcpToBci(bcp, method); + } + + public Address addressOfInterpreterFrameMDX() { + return addressOfStackSlot(INTERPRETER_FRAME_MDX_OFFSET); + } + + // expression stack + // (the max_stack arguments are used by the GC; see class FrameClosure) + + public Address addressOfInterpreterFrameExpressionStack() { + Address monitorEnd = interpreterFrameMonitorEnd().address(); + return monitorEnd.addOffsetTo(-1 * VM.getVM().getAddressSize()); + } + + public int getInterpreterFrameExpressionStackDirection() { return -1; } + + // top of expression stack + public Address addressOfInterpreterFrameTOS() { + return getSP(); + } + + /** Expression stack from top down */ + public Address addressOfInterpreterFrameTOSAt(int slot) { + return addressOfInterpreterFrameTOS().addOffsetTo(slot * VM.getVM().getAddressSize()); + } + + public Address getInterpreterFrameSenderSP() { + if (Assert.ASSERTS_ENABLED) { + Assert.that(isInterpretedFrame(), "interpreted frame expected"); + } + return addressOfStackSlot(INTERPRETER_FRAME_SENDER_SP_OFFSET).getAddressAt(0); + } + + // Monitors + public BasicObjectLock interpreterFrameMonitorBegin() { + return new BasicObjectLock(addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_BOTTOM_OFFSET)); + } + + public BasicObjectLock interpreterFrameMonitorEnd() { + Address result = addressOfStackSlot(INTERPRETER_FRAME_MONITOR_BLOCK_TOP_OFFSET).getAddressAt(0); + if (Assert.ASSERTS_ENABLED) { + // make sure the pointer points inside the frame + Assert.that(AddressOps.gt(getFP(), result), "result must < than frame pointer"); + Assert.that(AddressOps.lte(getSP(), result), "result must >= than stack pointer"); + } + return new BasicObjectLock(result); + } + + public int interpreterFrameMonitorSize() { + return BasicObjectLock.size(); + } + + // Method + public Address addressOfInterpreterFrameMethod() { + return addressOfStackSlot(INTERPRETER_FRAME_METHOD_OFFSET); + } + + // Constant pool cache + public Address addressOfInterpreterFrameCPCache() { + return addressOfStackSlot(INTERPRETER_FRAME_CACHE_OFFSET); + } + + // Entry frames + public JavaCallWrapper getEntryFrameCallWrapper() { + return new RISCV64JavaCallWrapper(addressOfStackSlot(ENTRY_FRAME_CALL_WRAPPER_OFFSET).getAddressAt(0)); + } + + protected Address addressOfSavedOopResult() { + // offset is 2 for compiler2 and 3 for compiler1 + return getSP().addOffsetTo((VM.getVM().isClientCompiler() ? 2 : 3) * + VM.getVM().getAddressSize()); + } + + protected Address addressOfSavedReceiver() { + return getSP().addOffsetTo(-4 * VM.getVM().getAddressSize()); + } + + private void dumpStack() { + for (Address addr = getSP().addOffsetTo(-4 * VM.getVM().getAddressSize()); + AddressOps.lt(addr, getSP()); + addr = addr.addOffsetTo(VM.getVM().getAddressSize())) { + System.out.println(addr + ": " + addr.getAddressAt(0)); + } + System.out.println("-----------------------"); + for (Address addr = getSP(); + AddressOps.lte(addr, getSP().addOffsetTo(20 * VM.getVM().getAddressSize())); + addr = addr.addOffsetTo(VM.getVM().getAddressSize())) { + System.out.println(addr + ": " + addr.getAddressAt(0)); + } + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64JavaCallWrapper.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64JavaCallWrapper.java new file mode 100644 index 00000000000..d0ad2b559a6 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64JavaCallWrapper.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.runtime.riscv64; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.utilities.*; +import sun.jvm.hotspot.utilities.Observable; +import sun.jvm.hotspot.utilities.Observer; + +public class RISCV64JavaCallWrapper extends JavaCallWrapper { + private static AddressField lastJavaFPField; + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("JavaFrameAnchor"); + + lastJavaFPField = type.getAddressField("_last_Java_fp"); + } + + public RISCV64JavaCallWrapper(Address addr) { + super(addr); + } + + public Address getLastJavaFP() { + return lastJavaFPField.getValue(addr.addOffsetTo(anchorField.getOffset())); + } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64RegisterMap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64RegisterMap.java new file mode 100644 index 00000000000..4aeb1c6f557 --- /dev/null +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/riscv64/RISCV64RegisterMap.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Red Hat Inc. + * Copyright (c) 2021, Huawei Technologies Co., Ltd. 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. + * + */ + +package sun.jvm.hotspot.runtime.riscv64; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.runtime.*; + +public class RISCV64RegisterMap extends RegisterMap { + + /** This is the only public constructor */ + public RISCV64RegisterMap(JavaThread thread, boolean updateMap) { + super(thread, updateMap); + } + + protected RISCV64RegisterMap(RegisterMap map) { + super(map); + } + + public Object clone() { + RISCV64RegisterMap retval = new RISCV64RegisterMap(this); + return retval; + } + + // no PD state to clear or copy: + protected void clearPD() {} + protected void initializePD() {} + protected void initializeFromPD(RegisterMap map) {} + protected Address getLocationPD(VMReg reg) { return null; } +} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java index 3e66e24700b..f4cd4873207 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -50,7 +50,7 @@ public class PlatformInfo { public static boolean knownCPU(String cpu) { final String[] KNOWN = - new String[] {"i386", "x86", "x86_64", "amd64", "ppc64", "ppc64le", "aarch64"}; + new String[] {"i386", "x86", "x86_64", "amd64", "ppc64", "ppc64le", "aarch64", "riscv64"}; for(String s : KNOWN) { if(s.equals(cpu)) diff --git a/test/hotspot/jtreg/compiler/c2/TestBit.java b/test/hotspot/jtreg/compiler/c2/TestBit.java index f8af537a62f..02596b7ee55 100644 --- a/test/hotspot/jtreg/compiler/c2/TestBit.java +++ b/test/hotspot/jtreg/compiler/c2/TestBit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -33,7 +33,7 @@ import jdk.test.lib.process.ProcessTools; * @library /test/lib / * * @requires vm.flagless - * @requires os.arch=="aarch64" | os.arch=="amd64" | os.arch == "ppc64le" + * @requires os.arch=="aarch64" | os.arch=="amd64" | os.arch == "ppc64le" | os.arch == "riscv64" * @requires vm.debug == true & vm.compiler2.enabled * * @run driver compiler.c2.TestBit @@ -55,7 +55,8 @@ public class TestBit { String expectedTestBitInstruction = "ppc64le".equals(System.getProperty("os.arch")) ? "ANDI" : "aarch64".equals(System.getProperty("os.arch")) ? "tb" : - "amd64".equals(System.getProperty("os.arch")) ? "test" : null; + "amd64".equals(System.getProperty("os.arch")) ? "test" : + "riscv64".equals(System.getProperty("os.arch")) ? "andi" : null; if (expectedTestBitInstruction != null) { output.shouldContain(expectedTestBitInstruction); diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnUnsupportedCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnUnsupportedCPU.java index 6329ed74e9e..50294e068cb 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnUnsupportedCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA1IntrinsicsOptionOnUnsupportedCPU.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -39,6 +39,7 @@ package compiler.intrinsics.sha.cli; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForOtherCPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedAArch64CPU; +import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedRISCV64CPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedX86CPU; import compiler.intrinsics.sha.cli.testcases.UseSHAIntrinsicsSpecificTestCaseForUnsupportedCPU; @@ -49,6 +50,8 @@ public class TestUseSHA1IntrinsicsOptionOnUnsupportedCPU { DigestOptionsBase.USE_SHA1_INTRINSICS_OPTION), new GenericTestCaseForUnsupportedAArch64CPU( DigestOptionsBase.USE_SHA1_INTRINSICS_OPTION), + new GenericTestCaseForUnsupportedRISCV64CPU( + DigestOptionsBase.USE_SHA1_INTRINSICS_OPTION), new UseSHAIntrinsicsSpecificTestCaseForUnsupportedCPU( DigestOptionsBase.USE_SHA1_INTRINSICS_OPTION), new GenericTestCaseForOtherCPU( diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnUnsupportedCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnUnsupportedCPU.java index dbc938d2b54..9ce909185f2 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnUnsupportedCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA256IntrinsicsOptionOnUnsupportedCPU.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -39,6 +39,7 @@ package compiler.intrinsics.sha.cli; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForOtherCPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedAArch64CPU; +import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedRISCV64CPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedX86CPU; import compiler.intrinsics.sha.cli.testcases.UseSHAIntrinsicsSpecificTestCaseForUnsupportedCPU; @@ -49,6 +50,8 @@ public class TestUseSHA256IntrinsicsOptionOnUnsupportedCPU { DigestOptionsBase.USE_SHA256_INTRINSICS_OPTION), new GenericTestCaseForUnsupportedAArch64CPU( DigestOptionsBase.USE_SHA256_INTRINSICS_OPTION), + new GenericTestCaseForUnsupportedRISCV64CPU( + DigestOptionsBase.USE_SHA256_INTRINSICS_OPTION), new UseSHAIntrinsicsSpecificTestCaseForUnsupportedCPU( DigestOptionsBase.USE_SHA256_INTRINSICS_OPTION), new GenericTestCaseForOtherCPU( diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnUnsupportedCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnUnsupportedCPU.java index eef34f01d84..1ab05caca4e 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnUnsupportedCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHA512IntrinsicsOptionOnUnsupportedCPU.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -39,6 +39,7 @@ package compiler.intrinsics.sha.cli; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForOtherCPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedAArch64CPU; +import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedRISCV64CPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedX86CPU; import compiler.intrinsics.sha.cli.testcases.UseSHAIntrinsicsSpecificTestCaseForUnsupportedCPU; @@ -49,6 +50,8 @@ public class TestUseSHA512IntrinsicsOptionOnUnsupportedCPU { DigestOptionsBase.USE_SHA512_INTRINSICS_OPTION), new GenericTestCaseForUnsupportedAArch64CPU( DigestOptionsBase.USE_SHA512_INTRINSICS_OPTION), + new GenericTestCaseForUnsupportedRISCV64CPU( + DigestOptionsBase.USE_SHA512_INTRINSICS_OPTION), new UseSHAIntrinsicsSpecificTestCaseForUnsupportedCPU( DigestOptionsBase.USE_SHA512_INTRINSICS_OPTION), new GenericTestCaseForOtherCPU( diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHAOptionOnUnsupportedCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHAOptionOnUnsupportedCPU.java index df471c4bf03..e6131d6c0ae 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHAOptionOnUnsupportedCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/TestUseSHAOptionOnUnsupportedCPU.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -39,6 +39,7 @@ package compiler.intrinsics.sha.cli; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForOtherCPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedAArch64CPU; +import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedRISCV64CPU; import compiler.intrinsics.sha.cli.testcases.GenericTestCaseForUnsupportedX86CPU; import compiler.intrinsics.sha.cli.testcases.UseSHASpecificTestCaseForUnsupportedCPU; @@ -49,6 +50,8 @@ public class TestUseSHAOptionOnUnsupportedCPU { DigestOptionsBase.USE_SHA_OPTION), new GenericTestCaseForUnsupportedAArch64CPU( DigestOptionsBase.USE_SHA_OPTION), + new GenericTestCaseForUnsupportedRISCV64CPU( + DigestOptionsBase.USE_SHA_OPTION), new UseSHASpecificTestCaseForUnsupportedCPU( DigestOptionsBase.USE_SHA_OPTION), new GenericTestCaseForOtherCPU( diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java index 2b8d143dd68..468cd83d7a2 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForOtherCPU.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -32,7 +32,7 @@ import jdk.test.lib.cli.predicate.OrPredicate; /** * Generic test case for SHA-related options targeted to any CPU except - * AArch64, PPC, S390x, and X86. + * AArch64, RISCV64, PPC, S390x, and X86. */ public class GenericTestCaseForOtherCPU extends DigestOptionsBase.TestCase { @@ -44,13 +44,14 @@ public class GenericTestCaseForOtherCPU extends } public GenericTestCaseForOtherCPU(String optionName, boolean checkUseSHA) { - // Execute the test case on any CPU except AArch64, PPC, S390x, and X86. + // Execute the test case on any CPU except AArch64, RISCV64, PPC, S390x, and X86. super(optionName, new NotPredicate( new OrPredicate(Platform::isAArch64, + new OrPredicate(Platform::isRISCV64, new OrPredicate(Platform::isS390x, new OrPredicate(Platform::isPPC, new OrPredicate(Platform::isX64, - Platform::isX86)))))); + Platform::isX86))))))); this.checkUseSHA = checkUseSHA; } @@ -59,7 +60,7 @@ public class GenericTestCaseForOtherCPU extends protected void verifyWarnings() throws Throwable { String shouldPassMessage = String.format("JVM should start with " + "option '%s' without any warnings", optionName); - // Verify that on non-x86 and non-AArch64 CPU usage of SHA-related + // Verify that on non-x86, non-RISCV64 and non-AArch64 CPU usage of SHA-related // options will not cause any warnings. CommandLineOptionTest.verifySameJVMStartup(null, new String[] { ".*" + optionName + ".*" }, shouldPassMessage, diff --git a/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForUnsupportedRISCV64CPU.java b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForUnsupportedRISCV64CPU.java new file mode 100644 index 00000000000..2ecfec07a4c --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/sha/cli/testcases/GenericTestCaseForUnsupportedRISCV64CPU.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2021, Huawei Technologies Co., Ltd. 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. + */ + +package compiler.intrinsics.sha.cli.testcases; + +import compiler.intrinsics.sha.cli.DigestOptionsBase; +import jdk.test.lib.process.ExitCode; +import jdk.test.lib.Platform; +import jdk.test.lib.cli.CommandLineOptionTest; +import jdk.test.lib.cli.predicate.AndPredicate; +import jdk.test.lib.cli.predicate.NotPredicate; + +/** + * Generic test case for SHA-related options targeted to RISCV64 CPUs + * which don't support instruction required by the tested option. + */ +public class GenericTestCaseForUnsupportedRISCV64CPU extends + DigestOptionsBase.TestCase { + + final private boolean checkUseSHA; + + public GenericTestCaseForUnsupportedRISCV64CPU(String optionName) { + this(optionName, true); + } + + public GenericTestCaseForUnsupportedRISCV64CPU(String optionName, boolean checkUseSHA) { + super(optionName, new AndPredicate(Platform::isRISCV64, + new NotPredicate(DigestOptionsBase.getPredicateForOption( + optionName)))); + + this.checkUseSHA = checkUseSHA; + } + + @Override + protected void verifyWarnings() throws Throwable { + String shouldPassMessage = String.format("JVM startup should pass with" + + "option '-XX:-%s' without any warnings", optionName); + //Verify that option could be disabled without any warnings. + CommandLineOptionTest.verifySameJVMStartup(null, new String[] { + DigestOptionsBase.getWarningForUnsupportedCPU(optionName) + }, shouldPassMessage, shouldPassMessage, ExitCode.OK, + DigestOptionsBase.UNLOCK_DIAGNOSTIC_VM_OPTIONS, + CommandLineOptionTest.prepareBooleanFlag(optionName, false)); + + if (checkUseSHA) { + shouldPassMessage = String.format("If JVM is started with '-XX:-" + + "%s' '-XX:+%s', output should contain warning.", + DigestOptionsBase.USE_SHA_OPTION, optionName); + + // Verify that when the tested option is enabled, then + // a warning will occur in VM output if UseSHA is disabled. + if (!optionName.equals(DigestOptionsBase.USE_SHA_OPTION)) { + CommandLineOptionTest.verifySameJVMStartup( + new String[] { DigestOptionsBase.getWarningForUnsupportedCPU(optionName) }, + null, + shouldPassMessage, + shouldPassMessage, + ExitCode.OK, + DigestOptionsBase.UNLOCK_DIAGNOSTIC_VM_OPTIONS, + CommandLineOptionTest.prepareBooleanFlag(DigestOptionsBase.USE_SHA_OPTION, false), + CommandLineOptionTest.prepareBooleanFlag(optionName, true)); + } + } + } + + @Override + protected void verifyOptionValues() throws Throwable { + // Verify that option is disabled by default. + CommandLineOptionTest.verifyOptionValueForSameVM(optionName, "false", + String.format("Option '%s' should be disabled by default", + optionName), + DigestOptionsBase.UNLOCK_DIAGNOSTIC_VM_OPTIONS); + + if (checkUseSHA) { + // Verify that option is disabled even if it was explicitly enabled + // using CLI options. + CommandLineOptionTest.verifyOptionValueForSameVM(optionName, "false", + String.format("Option '%s' should be off on unsupported " + + "RISCV64CPU even if set to true directly", optionName), + DigestOptionsBase.UNLOCK_DIAGNOSTIC_VM_OPTIONS, + CommandLineOptionTest.prepareBooleanFlag(optionName, true)); + + // Verify that option is disabled when +UseSHA was passed to JVM. + CommandLineOptionTest.verifyOptionValueForSameVM(optionName, "false", + String.format("Option '%s' should be off on unsupported " + + "RISCV64CPU even if %s flag set to JVM", + optionName, CommandLineOptionTest.prepareBooleanFlag( + DigestOptionsBase.USE_SHA_OPTION, true)), + DigestOptionsBase.UNLOCK_DIAGNOSTIC_VM_OPTIONS, + CommandLineOptionTest.prepareBooleanFlag( + DigestOptionsBase.USE_SHA_OPTION, true)); + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java index 2e3e2717a65..7be8af6d035 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Double.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java index 0e06a9e4327..797927b42bf 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Float.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : float test - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java index c3cdbf37464..be8f7d586c2 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ProdRed_Int.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : int test - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java b/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java index d33bd411f16..d96d5e29c00 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/ReductionPerf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8074981 * @summary Add C2 x86 Superword support for scalar product reduction optimizations : int test - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions * -XX:LoopUnrollLimit=250 -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java index 992fa4b5161..b09c873d05d 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Double.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8138583 * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : double abs & neg test - * @requires os.arch=="aarch64" + * @requires os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java index 3e79b3528b7..fe40ed6f98d 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedAbsNeg_Float.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8138583 * @summary Add C2 AArch64 Superword support for scalar sum reduction optimizations : float abs & neg test - * @requires os.arch=="aarch64" + * @requires os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java index 6603dd224ef..51631910493 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRedSqrt_Double.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8135028 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double sqrt test - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java index d9a0c988004..d999ae423cf 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Double.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : double test - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java index 722db95aed3..65912a5c7fa 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Float.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : float test - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java index f58f21feb23..fffdc2f7565 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/SumRed_Int.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -25,7 +25,7 @@ * @test * @bug 8074981 * @summary Add C2 x86 Superword support for scalar sum reduction optimizations : int test - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64" * * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:LoopUnrollLimit=250 * -XX:CompileThresholdScaling=0.1 diff --git a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java index 782ab6b9b46..e922c5b8853 100644 --- a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java +++ b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -68,14 +68,16 @@ public class IntrinsicPredicates { public static final BooleanSupplier SHA1_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha1" }, null), + new OrPredicate(new CPUSpecificPredicate("riscv64.*", new String[] { "sha1" }, null), new OrPredicate(new CPUSpecificPredicate("s390.*", new String[] { "sha1" }, null), // x86 variants new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("i386.*", new String[] { "sha" }, null), - new CPUSpecificPredicate("x86.*", new String[] { "sha" }, null))))); + new CPUSpecificPredicate("x86.*", new String[] { "sha" }, null)))))); public static final BooleanSupplier SHA256_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha256" }, null), + new OrPredicate(new CPUSpecificPredicate("riscv64.*", new String[] { "sha256" }, null), new OrPredicate(new CPUSpecificPredicate("s390.*", new String[] { "sha256" }, null), new OrPredicate(new CPUSpecificPredicate("ppc64.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("ppc64le.*", new String[] { "sha" }, null), @@ -84,10 +86,11 @@ public class IntrinsicPredicates { new OrPredicate(new CPUSpecificPredicate("i386.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("x86.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "avx2", "bmi2" }, null), - new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null))))))))); + new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null)))))))))); public static final BooleanSupplier SHA512_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha512" }, null), + new OrPredicate(new CPUSpecificPredicate("riscv64.*", new String[] { "sha512" }, null), new OrPredicate(new CPUSpecificPredicate("s390.*", new String[] { "sha512" }, null), new OrPredicate(new CPUSpecificPredicate("ppc64.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("ppc64le.*", new String[] { "sha" }, null), @@ -96,7 +99,7 @@ public class IntrinsicPredicates { new OrPredicate(new CPUSpecificPredicate("i386.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("x86.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("amd64.*", new String[] { "avx2", "bmi2" }, null), - new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null))))))))); + new CPUSpecificPredicate("x86_64", new String[] { "avx2", "bmi2" }, null)))))))))); public static final BooleanSupplier SHA3_INSTRUCTION_AVAILABLE // sha3 is only implemented on aarch64 for now diff --git a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java index dfc84241beb..b96e3a80aba 100644 --- a/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java +++ b/test/hotspot/jtreg/runtime/NMT/CheckForProperDetailStackTrace.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, 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 @@ -133,7 +133,7 @@ public class CheckForProperDetailStackTrace { // It's ok for ARM not to have symbols, because it does not support NMT detail // when targeting thumb2. It's also ok for Windows not to have symbols, because // they are only available if the symbols file is included with the build. - if (Platform.isWindows() || Platform.isARM()) { + if (Platform.isWindows() || Platform.isARM() || Platform.isRISCV64()) { return; // we are done } output.reportDiagnosticSummary(); diff --git a/test/hotspot/jtreg/runtime/ReservedStack/ReservedStackTest.java b/test/hotspot/jtreg/runtime/ReservedStack/ReservedStackTest.java index c11472a0918..36f74d01b54 100644 --- a/test/hotspot/jtreg/runtime/ReservedStack/ReservedStackTest.java +++ b/test/hotspot/jtreg/runtime/ReservedStack/ReservedStackTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -240,7 +240,7 @@ public class ReservedStackTest { return Platform.isAix() || (Platform.isLinux() && (Platform.isPPC() || Platform.isS390x() || Platform.isX64() || - Platform.isX86() || Platform.isAArch64())) || + Platform.isX86() || Platform.isAArch64() || Platform.isRISCV64())) || Platform.isOSX(); } diff --git a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java index 5653b735273..5c41565db8d 100644 --- a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java +++ b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Google and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,7 +29,7 @@ package MyPackage; * @summary Verifies that AsyncGetCallTrace is call-able and provides sane information. * @compile ASGCTBaseTest.java * @requires os.family == "linux" - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="arm" | os.arch=="aarch64" | os.arch=="ppc64" | os.arch=="s390" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="arm" | os.arch=="aarch64" | os.arch=="ppc64" | os.arch=="s390" | os.arch=="riscv64" * @requires vm.jvmti * @run main/othervm/native -agentlib:AsyncGetCallTraceTest MyPackage.ASGCTBaseTest */ diff --git a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java index 922b18836dd..c078acbaff8 100644 --- a/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java +++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/MapLoops.java @@ -48,7 +48,7 @@ /* * @test * @summary Exercise multithreaded maps, using only heavy monitors. - * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch == "ppc64" | os.arch == "ppc64le" + * @requires os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch == "ppc64" | os.arch == "ppc64le" | os.arch == "riscv64" * @library /test/lib * @run main/othervm/timeout=1600 -XX:+IgnoreUnrecognizedVMOptions -XX:+UseHeavyMonitors -XX:+VerifyHeavyMonitors MapLoops */ diff --git a/test/jdk/jdk/jfr/event/os/TestCPUInformation.java b/test/jdk/jdk/jfr/event/os/TestCPUInformation.java index a4b5169ca4a..c5166580010 100644 --- a/test/jdk/jdk/jfr/event/os/TestCPUInformation.java +++ b/test/jdk/jdk/jfr/event/os/TestCPUInformation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2022, 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 @@ -52,8 +52,8 @@ public class TestCPUInformation { Events.assertField(event, "hwThreads").atLeast(1); Events.assertField(event, "cores").atLeast(1); Events.assertField(event, "sockets").atLeast(1); - Events.assertField(event, "cpu").containsAny("Intel", "AMD", "Unknown x86", "ARM", "PPC", "PowerPC", "AArch64", "s390"); - Events.assertField(event, "description").containsAny("Intel", "AMD", "Unknown x86", "ARM", "PPC", "PowerPC", "AArch64", "s390"); + Events.assertField(event, "cpu").containsAny("Intel", "AMD", "Unknown x86", "ARM", "PPC", "PowerPC", "AArch64", "RISCV64", "s390"); + Events.assertField(event, "description").containsAny("Intel", "AMD", "Unknown x86", "ARM", "PPC", "PowerPC", "AArch64", "RISCV64", "s390"); } } } diff --git a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java index 3ca1de653a4..219d3797453 100644 --- a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java +++ b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java @@ -45,7 +45,7 @@ import java.util.Set; */ public class TestMutuallyExclusivePlatformPredicates { private static enum MethodGroup { - ARCH("isAArch64", "isARM", "isPPC", "isS390x", "isX64", "isX86"), + ARCH("isAArch64", "isARM", "isRISCV64", "isPPC", "isS390x", "isX64", "isX86"), BITNESS("is32bit", "is64bit"), OS("isAix", "isLinux", "isOSX", "isWindows"), VM_TYPE("isClient", "isServer", "isMinimal", "isZero", "isEmbedded"), diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index a8405c93722..3084634018b 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -197,6 +197,10 @@ public class Platform { return isArch("arm.*"); } + public static boolean isRISCV64() { + return isArch("riscv64"); + } + public static boolean isPPC() { return isArch("ppc.*"); } -- GitLab From 2c43ecb43fa3c94b69478039f1cd70ed4a577768 Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Thu, 24 Mar 2022 09:49:33 +0000 Subject: [PATCH 152/237] 8283323: libharfbuzz optimization level results in extreme build times Reviewed-by: erikj, prr --- make/modules/java.desktop/lib/Awt2dLibraries.gmk | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index 3cf8ca8a820..c410e390fc9 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -470,7 +470,6 @@ else endif - LIBFONTMANAGER_EXTRA_HEADER_DIRS := \ libharfbuzz \ common/awt \ @@ -485,6 +484,14 @@ BUILD_LIBFONTMANAGER_FONTLIB += $(LIBFREETYPE_LIBS) LIBFONTMANAGER_OPTIMIZATION := HIGHEST +ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), ) + # gcc (and to an extent clang) is particularly bad at optimizing these files, + # causing a massive spike in compile time. We don't care about these + # particular files anyway, so lower optimization level. + BUILD_LIBFONTMANAGER_hb-subset.cc_OPTIMIZATION := SIZE + BUILD_LIBFONTMANAGER_hb-subset-plan.cc_OPTIMIZATION := SIZE +endif + ifeq ($(call isTargetOs, windows), true) LIBFONTMANAGER_EXCLUDE_FILES += X11FontScaler.c \ X11TextRenderer.c -- GitLab From 1c4f5fcb88892e6c76074eac87b63d81d53647b2 Mon Sep 17 00:00:00 2001 From: Erik Joelsson Date: Thu, 24 Mar 2022 12:48:12 +0000 Subject: [PATCH 153/237] 8283575: Check for GNU time fails for version >1.7 Reviewed-by: shade, ihse --- make/autoconf/basic_tools.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4 index 1611e9fd531..953f29bddd5 100644 --- a/make/autoconf/basic_tools.m4 +++ b/make/autoconf/basic_tools.m4 @@ -348,7 +348,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS], UTIL_LOOKUP_PROGS(DTRACE, dtrace, $PATH:/usr/sbin) UTIL_LOOKUP_PROGS(PATCH, gpatch patch) # Check if it's GNU time - IS_GNU_TIME=`$TIME --version 2>&1 | $GREP 'GNU time'` + [ IS_GNU_TIME=`$TIME --version 2>&1 | $GREP 'GNU [Tt]ime'` ] if test "x$IS_GNU_TIME" != x; then IS_GNU_TIME=yes else -- GitLab From 14c20bc0e0ee32b82ffe653ae9e4a0be52d578cb Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Thu, 24 Mar 2022 12:53:44 +0000 Subject: [PATCH 154/237] 8283187: C2: loop candidate for superword not always unrolled fully if superword fails Reviewed-by: thartmann, chagedorn --- src/hotspot/share/opto/loopnode.cpp | 9 +- src/hotspot/share/opto/superword.cpp | 92 ++++++++++--------- src/hotspot/share/opto/superword.hpp | 6 +- .../irTests/TestSuperwordFailsUnrolling.java | 66 +++++++++++++ .../compiler/lib/ir_framework/IRNode.java | 1 + 5 files changed, 129 insertions(+), 45 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/TestSuperwordFailsUnrolling.java diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index f08b1d46b1c..28ed035b82b 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -4568,7 +4568,14 @@ void PhaseIdealLoop::build_and_optimize() { sw.transform_loop(lpt, true); } } else if (cl->is_main_loop()) { - sw.transform_loop(lpt, true); + if (!sw.transform_loop(lpt, true)) { + // Instigate more unrolling for optimization when vectorization fails. + if (cl->has_passed_slp()) { + C->set_major_progress(); + cl->set_notpassed_slp(); + cl->mark_do_unroll_only(); + } + } } } } diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index 1bf4c7a3282..8a116212783 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -95,38 +95,48 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) : static const bool _do_vector_loop_experimental = false; // Experimental vectorization which uses data from loop unrolling. //------------------------------transform_loop--------------------------- -void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { +bool SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { assert(UseSuperWord, "should be"); // SuperWord only works with power of two vector sizes. int vector_width = Matcher::vector_width_in_bytes(T_BYTE); if (vector_width < 2 || !is_power_of_2(vector_width)) { - return; + return false; } assert(lpt->_head->is_CountedLoop(), "must be"); CountedLoopNode *cl = lpt->_head->as_CountedLoop(); - if (!cl->is_valid_counted_loop(T_INT)) return; // skip malformed counted loop + if (!cl->is_valid_counted_loop(T_INT)) { + return false; // skip malformed counted loop + } bool post_loop_allowed = (PostLoopMultiversioning && Matcher::has_predicated_vectors() && cl->is_post_loop()); if (post_loop_allowed) { - if (cl->is_reduction_loop()) return; // no predication mapping + if (cl->is_reduction_loop()) { + return false; // no predication mapping + } Node *limit = cl->limit(); - if (limit->is_Con()) return; // non constant limits only + if (limit->is_Con()) { + return false; // non constant limits only + } // Now check the limit for expressions we do not handle if (limit->is_Add()) { Node *in2 = limit->in(2); if (in2->is_Con()) { int val = in2->get_int(); // should not try to program these cases - if (val < 0) return; + if (val < 0) { + return false; + } } } } // skip any loop that has not been assigned max unroll by analysis if (do_optimization) { - if (SuperWordLoopUnrollAnalysis && cl->slp_max_unroll() == 0) return; + if (SuperWordLoopUnrollAnalysis && cl->slp_max_unroll() == 0) { + return false; + } } // Check for no control flow in body (other than exit) @@ -141,28 +151,32 @@ void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { lpt->dump_head(); } #endif - return; + return false; } // Make sure the are no extra control users of the loop backedge if (cl->back_control()->outcnt() != 1) { - return; + return false; } // Skip any loops already optimized by slp - if (cl->is_vectorized_loop()) return; + if (cl->is_vectorized_loop()) { + return false; + } - if (cl->is_unroll_only()) return; + if (cl->is_unroll_only()) { + return false; + } if (cl->is_main_loop()) { // Check for pre-loop ending with CountedLoopEnd(Bool(Cmp(x,Opaque1(limit)))) CountedLoopEndNode* pre_end = find_pre_loop_end(cl); if (pre_end == NULL) { - return; + return false; } Node* pre_opaq1 = pre_end->limit(); if (pre_opaq1->Opcode() != Op_Opaque1) { - return; + return false; } set_pre_loop_end(pre_end); } @@ -175,9 +189,10 @@ void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { // For now, define one block which is the entire loop body set_bb(cl); + bool success = true; if (do_optimization) { assert(_packset.length() == 0, "packset must be empty"); - SLP_extract(); + success = SLP_extract(); if (PostLoopMultiversioning && Matcher::has_predicated_vectors()) { if (cl->is_vectorized_loop() && cl->is_main_loop() && !cl->is_reduction_loop()) { IdealLoopTree *lpt_next = lpt->_next; @@ -192,6 +207,7 @@ void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { } } } + return success; } //------------------------------early unrolling analysis------------------------------ @@ -451,7 +467,7 @@ void SuperWord::unrolling_analysis(int &local_loop_unroll_factor) { // inserting scalar promotion, vector creation from multiple scalars, and // extraction of scalar values from vectors. // -void SuperWord::SLP_extract() { +bool SuperWord::SLP_extract() { #ifndef PRODUCT if (_do_vector_loop && TraceSuperWord) { @@ -466,7 +482,7 @@ void SuperWord::SLP_extract() { #endif // Ready the block if (!construct_bb()) { - return; // Exit if no interesting nodes or complex graph. + return false; // Exit if no interesting nodes or complex graph. } // build _dg, _disjoint_ptrs @@ -483,7 +499,7 @@ void SuperWord::SLP_extract() { hoist_loads_in_graph(); // this only rebuild the graph; all basic structs need rebuild explicitly if (!construct_bb()) { - return; // Exit if no interesting nodes or complex graph. + return false; // Exit if no interesting nodes or complex graph. } dependence_graph(); compute_max_depth(); @@ -511,7 +527,7 @@ void SuperWord::SLP_extract() { find_adjacent_refs(); if (align_to_ref() == NULL) { - return; // Did not find memory reference to align vectors + return false; // Did not find memory reference to align vectors } extend_packlist(); @@ -563,15 +579,15 @@ void SuperWord::SLP_extract() { // map base types for vector usage compute_vector_element_type(); } else { - return; + return false; } } else { // for some reason we could not map the slp analysis state of the vectorized loop - return; + return false; } } - output(); + return output(); } //------------------------------find_adjacent_refs--------------------------- @@ -2385,17 +2401,11 @@ void SuperWord::print_loop(bool whole) { //------------------------------output--------------------------- // Convert packs into vector node operations -void SuperWord::output() { +bool SuperWord::output() { CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); Compile* C = _phase->C; if (_packset.length() == 0) { - if (cl->is_main_loop()) { - // Instigate more unrolling for optimization when vectorization fails. - C->set_major_progress(); - cl->set_notpassed_slp(); - cl->mark_do_unroll_only(); - } - return; + return false; } #ifndef PRODUCT @@ -2429,7 +2439,7 @@ void SuperWord::output() { if (do_reserve_copy() && !make_reversable.has_reserved()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: loop was not reserved correctly, exiting SuperWord");}) - return; + return false; } for (int i = 0; i < _block.length(); i++) { @@ -2474,7 +2484,7 @@ void SuperWord::output() { if (val == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: val should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2518,7 +2528,7 @@ void SuperWord::output() { if (in1 == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: in1 should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2527,7 +2537,7 @@ void SuperWord::output() { if (in2 == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: in2 should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2569,7 +2579,7 @@ void SuperWord::output() { } else if (is_cmov_pack(p)) { if (can_process_post_loop) { // do not refactor of flow in post loop context - return; + return false; } if (!n->is_CMove()) { continue; @@ -2586,7 +2596,7 @@ void SuperWord::output() { if (!bol->is_Bool()) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: expected %d bool node, exiting SuperWord", bol->_idx); bol->dump();}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2602,7 +2612,7 @@ void SuperWord::output() { if (src1 == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: src1 should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2610,7 +2620,7 @@ void SuperWord::output() { if (src2 == NULL) { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: src2 should not be NULL, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2634,7 +2644,7 @@ void SuperWord::output() { } else { if (do_reserve_copy()) { NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: ShouldNotReachHere, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2643,7 +2653,7 @@ void SuperWord::output() { if (vn == NULL) { if (do_reserve_copy()){ NOT_PRODUCT(if(is_trace_loop_reverse() || TraceLoopOpts) {tty->print_cr("SWPointer::output: got NULL node, cannot proceed, exiting SuperWord");}) - return; //and reverse to backup IG + return false; //and reverse to backup IG } ShouldNotReachHere(); } @@ -2661,7 +2671,7 @@ void SuperWord::output() { // first check if the vector size if the maximum vector which we can use on the machine, // other vector size have reduced values for predicated data mapping. if (vlen_in_bytes != (uint)MaxVectorSize) { - return; + return false; } } @@ -2734,7 +2744,7 @@ void SuperWord::output() { make_reversable.use_new(); } NOT_PRODUCT(if(is_trace_loop_reverse()) {tty->print_cr("\n Final loop after SuperWord"); print_loop(true);}) - return; + return true; } //------------------------------vector_opd--------------------------- diff --git a/src/hotspot/share/opto/superword.hpp b/src/hotspot/share/opto/superword.hpp index ddddfc83663..9c92365865a 100644 --- a/src/hotspot/share/opto/superword.hpp +++ b/src/hotspot/share/opto/superword.hpp @@ -286,7 +286,7 @@ class SuperWord : public ResourceObj { public: SuperWord(PhaseIdealLoop* phase); - void transform_loop(IdealLoopTree* lpt, bool do_optimization); + bool transform_loop(IdealLoopTree* lpt, bool do_optimization); void unrolling_analysis(int &local_loop_unroll_factor); @@ -422,7 +422,7 @@ class SuperWord : public ResourceObj { // methods // Extract the superword level parallelism - void SLP_extract(); + bool SLP_extract(); // Find the adjacent memory references and create pack pairs for them. void find_adjacent_refs(); // Tracing support @@ -509,7 +509,7 @@ class SuperWord : public ResourceObj { Node* find_last_mem_state(Node_List* pk, Node* first_mem); // Convert packs into vector node operations - void output(); + bool output(); // Create a vector operand for the nodes in pack p for operand: in(opd_idx) Node* vector_opd(Node_List* p, int opd_idx); // Can code be generated for pack p? diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestSuperwordFailsUnrolling.java b/test/hotspot/jtreg/compiler/c2/irTests/TestSuperwordFailsUnrolling.java new file mode 100644 index 00000000000..2ba5e4e7340 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestSuperwordFailsUnrolling.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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. + */ + +package compiler.c2.irTests; + +import compiler.lib.ir_framework.*; +import sun.hotspot.WhiteBox; + +/* + * @test + * @bug 8283187 + * @summary C2: loop candidate for superword not always unrolled fully if superword fails + * @library /test/lib / + * @build sun.hotspot.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -DSkipWhiteBoxInstall=true -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI compiler.c2.irTests.TestSuperwordFailsUnrolling + */ + +public class TestSuperwordFailsUnrolling { + private static int v = 0; + private final static WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String[] args) { + Object avx = wb.getVMFlag("UseAVX"); + if (avx != null && ((Long)avx) > 2) { + TestFramework.runWithFlags("-XX:UseAVX=2", "-XX:LoopMaxUnroll=8"); + } + TestFramework.runWithFlags("-XX:LoopMaxUnroll=8"); + } + + @Test + @IR(applyIf = { "UsePopCountInstruction", "true" }, counts = { IRNode.POPCOUNT_L, "10" }) + private static int test(long[] array1, long[] array2) { + v = 0; + for (int i = 0; i < array1.length; i++) { + v += Long.bitCount(array1[i]); + } + return v; + } + + @Run(test = "test") + void test_runner() { + long[] array = new long[1000]; + test(array, array); + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 033ed28d2e5..de91a0054b2 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -173,6 +173,7 @@ public class IRNode { public static final String DIV_L = START + "DivL" + MID + END; public static final String CONV_I2L = START + "ConvI2L" + MID + END; public static final String CONV_L2I = START + "ConvL2I" + MID + END; + public static final String POPCOUNT_L = START + "PopCountL" + MID + END; public static final String VECTOR_CAST_B2X = START + "VectorCastB2X" + MID + END; public static final String VECTOR_CAST_S2X = START + "VectorCastS2X" + MID + END; -- GitLab From 929b6a3556ce6f6ffb1a5ae14b7f87d21598eb21 Mon Sep 17 00:00:00 2001 From: Aleksei Efimov Date: Thu, 24 Mar 2022 13:50:50 +0000 Subject: [PATCH 155/237] 8282917: Remove InetAddressImplFactory from InetAddress Reviewed-by: dfuchs, jpai --- .../share/classes/java/net/InetAddress.java | 19 ++------ .../share/native/libnet/InetAddress.c | 13 +++++- .../native/libnet/InetAddressImplFactory.c | 46 ------------------- .../native/libnet/InetAddressImplFactory.c | 46 ------------------- 4 files changed, 17 insertions(+), 107 deletions(-) delete mode 100644 src/java.base/unix/native/libnet/InetAddressImplFactory.c delete mode 100644 src/java.base/windows/native/libnet/InetAddressImplFactory.c diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index 3bad2755978..2ff3d3375a3 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -412,6 +412,9 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In // Native method to check if IPv4 is available private static native boolean isIPv4Available(); + // Native method to check if IPv6 is available + private static native boolean isIPv6Supported(); + /** * The {@code RuntimePermission("inetAddressResolverProvider")} is * necessary to subclass and instantiate the {@code InetAddressResolverProvider} @@ -1270,7 +1273,8 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In static { // create the impl - impl = InetAddressImplFactory.create(); + impl = isIPv6Supported() ? + new Inet6AddressImpl() : new Inet4AddressImpl(); // impl must be initialized before calling this method PLATFORM_LOOKUP_POLICY = initializePlatformLookupPolicy(); @@ -1826,16 +1830,3 @@ public sealed class InetAddress implements Serializable permits Inet4Address, In s.writeFields(); } } - -/* - * Simple factory to create the impl - */ -class InetAddressImplFactory { - - static InetAddressImpl create() { - return isIPv6Supported() ? - new Inet6AddressImpl() : new Inet4AddressImpl(); - } - - static native boolean isIPv6Supported(); -} diff --git a/src/java.base/share/native/libnet/InetAddress.c b/src/java.base/share/native/libnet/InetAddress.c index 39b419d600e..e759a064d25 100644 --- a/src/java.base/share/native/libnet/InetAddress.c +++ b/src/java.base/share/native/libnet/InetAddress.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -76,8 +76,19 @@ Java_java_net_InetAddress_init(JNIEnv *env, jclass cls) { /* * Class: java_net_InetAddress * Method: isIPv4Available + * Signature: ()Z */ JNIEXPORT jboolean JNICALL Java_java_net_InetAddress_isIPv4Available(JNIEnv *env, jclass clazz) { return ipv4_available(); } + +/* + * Class: java_net_InetAddress + * Method: isIPv6Supported + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL +Java_java_net_InetAddress_isIPv6Supported(JNIEnv *env, jclass clazz) { + return ipv6_available(); +} diff --git a/src/java.base/unix/native/libnet/InetAddressImplFactory.c b/src/java.base/unix/native/libnet/InetAddressImplFactory.c deleted file mode 100644 index 2c799feb105..00000000000 --- a/src/java.base/unix/native/libnet/InetAddressImplFactory.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 1997, 2016, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -#include "java_net_InetAddressImplFactory.h" - -#include "net_util.h" - -/************************************************************************ - * InetAddressImplFactory - */ - -/* - * Class: java_net_InetAddressImplFactory - * Method: isIPv6Supported - * Signature: ()I - */ -JNIEXPORT jboolean JNICALL -Java_java_net_InetAddressImplFactory_isIPv6Supported(JNIEnv *env, jclass cls) { - if (ipv6_available()) { - return JNI_TRUE; - } else { - return JNI_FALSE; - } -} diff --git a/src/java.base/windows/native/libnet/InetAddressImplFactory.c b/src/java.base/windows/native/libnet/InetAddressImplFactory.c deleted file mode 100644 index 9d76762ca6c..00000000000 --- a/src/java.base/windows/native/libnet/InetAddressImplFactory.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 1997, 2003, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ -#include "java_net_InetAddressImplFactory.h" -#include "net_util.h" - -/* - * InetAddressImplFactory - */ - - -/* - * Class: java_net_InetAddressImplFactory - * Method: isIPv6Supported - * Signature: ()Z - */ -JNIEXPORT jboolean JNICALL -Java_java_net_InetAddressImplFactory_isIPv6Supported(JNIEnv *env, jobject this) -{ - if (ipv6_available()) { - return JNI_TRUE; - } else { - return JNI_FALSE; - } -} -- GitLab From 19f01ab70133d244422684f63f118249178bce4a Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Thu, 24 Mar 2022 14:35:39 +0000 Subject: [PATCH 156/237] 8283555: G1: Concurrent mark accesses uninitialized BOT of closed archive regions Reviewed-by: ayang, iwalulya --- src/hotspot/share/cds/filemap.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index b8e28f30b72..3879f933613 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2330,6 +2330,11 @@ void FileMapInfo::fixup_mapped_heap_regions() { "Null closed_heap_regions array with non-zero count"); G1CollectedHeap::heap()->fill_archive_regions(closed_heap_regions, num_closed_heap_regions); + // G1 marking uses the BOT for object chunking during marking in + // G1CMObjArrayProcessor::process_slice(); for this reason we need to + // initialize the BOT for closed archive regions too. + G1CollectedHeap::heap()->populate_archive_regions_bot_part(closed_heap_regions, + num_closed_heap_regions); } // do the same for mapped open archive heap regions @@ -2342,11 +2347,6 @@ void FileMapInfo::fixup_mapped_heap_regions() { // fast G1BlockOffsetTablePart::block_start operations for any given address // within the open archive regions when trying to find start of an object // (e.g. during card table scanning). - // - // This is only needed for open archive regions but not the closed archive - // regions, because objects in closed archive regions never reference objects - // outside the closed archive regions and they are immutable. So we never - // need their BOT during garbage collection. G1CollectedHeap::heap()->populate_archive_regions_bot_part(open_heap_regions, num_open_heap_regions); } -- GitLab From b36cf35ad938f9bab7cbb9752c0b15c49bd50407 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Thu, 24 Mar 2022 16:11:57 +0000 Subject: [PATCH 157/237] 8283417: Update java.nio buffers to use sealed classes Reviewed-by: rriggs, darcy, iris, alanb --- src/java.base/share/classes/java/nio/Buffer.java | 6 ++++-- .../java/nio/ByteBufferAs-X-Buffer.java.template | 10 +++++++++- .../classes/java/nio/Direct-X-Buffer.java.template | 10 +++++++++- .../classes/java/nio/Heap-X-Buffer.java.template | 8 ++++++++ .../share/classes/java/nio/MappedByteBuffer.java | 3 ++- .../share/classes/java/nio/StringCharBuffer.java | 2 +- .../share/classes/java/nio/X-Buffer.java.template | 14 ++++++++++++-- 7 files changed, 45 insertions(+), 8 deletions(-) diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java index a452b1a28dd..4df2f620611 100644 --- a/src/java.base/share/classes/java/nio/Buffer.java +++ b/src/java.base/share/classes/java/nio/Buffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -191,7 +191,9 @@ import java.util.Spliterator; * @since 1.4 */ -public abstract class Buffer { +public abstract sealed class Buffer + permits ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, + LongBuffer, ShortBuffer { // Cached unsafe-access object static final Unsafe UNSAFE = Unsafe.getUnsafe(); diff --git a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template index 12788a2b998..6040ac79411 100644 --- a/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/ByteBufferAs-X-Buffer.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -31,8 +31,16 @@ import java.util.Objects; import jdk.internal.access.foreign.MemorySegmentProxy; import jdk.internal.misc.Unsafe; +#if[rw] +sealed +#else[rw] +final +#end[rw] class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private extends {#if[ro]?ByteBufferAs}$Type$Buffer{#if[ro]?$BO$} +#if[rw] + permits ByteBufferAs$Type$BufferR$BO$ +#end[rw] { #if[rw] diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template index c227cec8e15..38697b39480 100644 --- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -37,6 +37,11 @@ import jdk.internal.ref.Cleaner; import sun.nio.ch.DirectBuffer; +#if[rw] +sealed +#else[rw] +final +#end[rw] class Direct$Type$Buffer$RW$$BO$ #if[rw] extends {#if[byte]?Mapped$Type$Buffer:$Type$Buffer} @@ -44,6 +49,9 @@ class Direct$Type$Buffer$RW$$BO$ extends Direct$Type$Buffer$BO$ #end[rw] implements DirectBuffer +#if[rw] + permits Direct$Type$BufferR$BO$ +#end[rw] { #if[rw] diff --git a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template index 38e18ac625b..541dbd6c8f8 100644 --- a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template @@ -40,8 +40,16 @@ import jdk.internal.access.foreign.MemorySegmentProxy; * instance of this class rather than of the superclass. #end[rw] */ +#if[rw] +sealed +#else[rw] +final +#end[rw] class Heap$Type$Buffer$RW$ extends {#if[ro]?Heap}$Type$Buffer +#if[rw] + permits Heap$Type$BufferR +#end[rw] { #if[rw] // Cached array base offset diff --git a/src/java.base/share/classes/java/nio/MappedByteBuffer.java b/src/java.base/share/classes/java/nio/MappedByteBuffer.java index 54fb6c869e0..8f9ca9f8fe6 100644 --- a/src/java.base/share/classes/java/nio/MappedByteBuffer.java +++ b/src/java.base/share/classes/java/nio/MappedByteBuffer.java @@ -70,8 +70,9 @@ import jdk.internal.misc.Unsafe; * @since 1.4 */ -public abstract class MappedByteBuffer +public abstract sealed class MappedByteBuffer extends ByteBuffer + permits DirectByteBuffer { // This is a little bit backwards: By rights MappedByteBuffer should be a diff --git a/src/java.base/share/classes/java/nio/StringCharBuffer.java b/src/java.base/share/classes/java/nio/StringCharBuffer.java index 40d807a6532..a62e8023363 100644 --- a/src/java.base/share/classes/java/nio/StringCharBuffer.java +++ b/src/java.base/share/classes/java/nio/StringCharBuffer.java @@ -29,7 +29,7 @@ import java.util.Objects; // ## If the sequence is a string, use reflection to share its array -class StringCharBuffer // package-private +final class StringCharBuffer // package-private extends CharBuffer { CharSequence str; diff --git a/src/java.base/share/classes/java/nio/X-Buffer.java.template b/src/java.base/share/classes/java/nio/X-Buffer.java.template index cfedf970f43..e559b46f37c 100644 --- a/src/java.base/share/classes/java/nio/X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -264,9 +264,19 @@ import jdk.internal.util.ArraysSupport; * @since 1.4 */ -public abstract class $Type$Buffer +public abstract sealed class $Type$Buffer extends Buffer implements Comparable<$Type$Buffer>{#if[char]?, Appendable, CharSequence, Readable} + permits +#if[byte] + Heap$Type$Buffer, MappedByteBuffer +#else[byte] +#if[char] + StringCharBuffer, +#end[char] + Heap$Type$Buffer, Direct$Type$BufferS, Direct$Type$BufferU, + ByteBufferAs$Type$BufferB, ByteBufferAs$Type$BufferL +#end[byte] { // Cached array base offset private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset($type$[].class); -- GitLab From a7e988343c7fda5b0f37e477f29cb172b908394d Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Thu, 24 Mar 2022 17:06:35 +0000 Subject: [PATCH 158/237] 8283467: runtime/Thread/StopAtExit.java needs updating Reviewed-by: dholmes, pchilanomate --- .../jtreg/runtime/Thread/StopAtExit.java | 50 ++++++++++---- .../jtreg/runtime/Thread/libStopAtExit.cpp | 68 +++++++++++++++++++ 2 files changed, 106 insertions(+), 12 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/Thread/libStopAtExit.cpp diff --git a/test/hotspot/jtreg/runtime/Thread/StopAtExit.java b/test/hotspot/jtreg/runtime/Thread/StopAtExit.java index b997890e347..86771cf9496 100644 --- a/test/hotspot/jtreg/runtime/Thread/StopAtExit.java +++ b/test/hotspot/jtreg/runtime/Thread/StopAtExit.java @@ -23,10 +23,11 @@ /** * @test - * @bug 8167108 8266130 8282704 - * @summary Stress test java.lang.Thread.stop() at thread exit. + * @bug 8167108 8266130 8282704 8283467 + * @summary Stress test JVM/TI StopThread() at thread exit. + * @requires vm.jvmti * @modules java.base/java.lang:open - * @run main/othervm StopAtExit + * @run main/othervm/native -agentlib:StopAtExit StopAtExit */ import java.lang.reflect.Method; @@ -36,10 +37,13 @@ import java.util.concurrent.TimeUnit; public class StopAtExit extends Thread { private final static int DEF_TIME_MAX = 30; // default max # secs to test private final static String PROG_NAME = "StopAtExit"; + private final static int JVMTI_ERROR_THREAD_NOT_ALIVE = 15; public CountDownLatch exitSyncObj = new CountDownLatch(1); public CountDownLatch startSyncObj = new CountDownLatch(1); + native static int stopThread(StopAtExit thr, Throwable exception); + public StopAtExit(ThreadGroup group, Runnable target) { super(group, target); } @@ -56,9 +60,9 @@ public class StopAtExit extends Thread { throw new RuntimeException("Unexpected: " + e); } } catch (ThreadDeath td) { - // ignore because we're testing Thread.stop() which throws it + // ignore because we're testing JVM/TI StopThread() which throws it } catch (NoClassDefFoundError ncdfe) { - // ignore because we're testing Thread.stop() which can cause it + // ignore because we're testing JVM/TI StopThread() which can cause it } } @@ -89,19 +93,32 @@ public class StopAtExit extends Thread { // the thread is terminated. ThreadGroup myTG = new ThreadGroup("myTG-" + count); myTG.setDaemon(true); + Throwable myException = new ThreadDeath(); + int retCode; StopAtExit thread = new StopAtExit(myTG, null); thread.start(); try { // Wait for the worker thread to get going. thread.startSyncObj.await(); // Tell the worker thread to race to the exit and the - // Thread.stop() calls will come in during thread exit. + // JVM/TI StopThread() calls will come in during thread exit. thread.exitSyncObj.countDown(); while (true) { - thread.stop(); + retCode = stopThread(thread, myException); + + if (retCode == JVMTI_ERROR_THREAD_NOT_ALIVE) { + // Done with JVM/TI StopThread() calls since + // thread is not alive. + break; + } else if (retCode != 0) { + throw new RuntimeException("thread " + thread.getName() + + ": stopThread() " + + "retCode=" + retCode + + ": unexpected value."); + } if (!thread.isAlive()) { - // Done with Thread.stop() calls since + // Done with JVM/TI StopThread() calls since // thread is not alive. break; } @@ -109,7 +126,7 @@ public class StopAtExit extends Thread { } catch (InterruptedException e) { throw new Error("Unexpected: " + e); } catch (NoClassDefFoundError ncdfe) { - // Ignore because we're testing Thread.stop() which can + // Ignore because we're testing JVM/TI StopThread() which can // cause it. Yes, a NoClassDefFoundError that happens // in a worker thread can subsequently be seen in the // main thread. @@ -120,9 +137,18 @@ public class StopAtExit extends Thread { } catch (InterruptedException e) { throw new Error("Unexpected: " + e); } - // This stop() call happens after the join() so it should do - // nothing, but let's make sure. - thread.stop(); + // This JVM/TI StopThread() happens after the join() so it + // should do nothing, but let's make sure. + retCode = stopThread(thread, myException); + + if (retCode != JVMTI_ERROR_THREAD_NOT_ALIVE) { + throw new RuntimeException("thread " + thread.getName() + + ": stopThread() " + + "retCode=" + retCode + + ": unexpected value; " + + "expected JVMTI_ERROR_THREAD_NOT_ALIVE(" + + JVMTI_ERROR_THREAD_NOT_ALIVE + ")."); + } if (myTG.activeCount() != 0) { // If the ThreadGroup still has a count, then the thread diff --git a/test/hotspot/jtreg/runtime/Thread/libStopAtExit.cpp b/test/hotspot/jtreg/runtime/Thread/libStopAtExit.cpp new file mode 100644 index 00000000000..1204915050b --- /dev/null +++ b/test/hotspot/jtreg/runtime/Thread/libStopAtExit.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022, 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. + */ + +#include +#include "jvmti.h" + +extern "C" { + +static jvmtiEnv* jvmti = NULL; + +#define LOG(...) \ + do { \ + printf(__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) + +JNIEXPORT jint JNICALL +Java_StopAtExit_stopThread(JNIEnv *jni, jclass cls, jthread thr, jobject exception) { + return jvmti->StopThread(thr, exception); +} + + +/** Agent library initialization. */ + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + LOG("\nAgent_OnLoad started"); + + // create JVMTI environment + if (jvm->GetEnv((void **) (&jvmti), JVMTI_VERSION) != JNI_OK) { + return JNI_ERR; + } + + // add specific capabilities for stoping thread + jvmtiCapabilities stopCaps; + memset(&stopCaps, 0, sizeof(stopCaps)); + stopCaps.can_signal_thread = 1; + + jvmtiError err = jvmti->AddCapabilities(&stopCaps); + if (err != JVMTI_ERROR_NONE) { + return JNI_ERR; + } + LOG("Agent_OnLoad finished\n"); + return JNI_OK; +} + +} -- GitLab From 90750decb47772420eaf127b19efa9b5cdacccfe Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Thu, 24 Mar 2022 18:35:13 +0000 Subject: [PATCH 159/237] 8272477: Additional cleanup of test/jdk/java/nio/file/spi/SetDefaultProvider.java Reviewed-by: bpb --- .../java/nio/file/spi/SetDefaultProvider.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/test/jdk/java/nio/file/spi/SetDefaultProvider.java b/test/jdk/java/nio/file/spi/SetDefaultProvider.java index 0c012b24bf8..5af47da4f19 100644 --- a/test/jdk/java/nio/file/spi/SetDefaultProvider.java +++ b/test/jdk/java/nio/file/spi/SetDefaultProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -40,7 +40,6 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.spi.ToolProvider; -import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.test.lib.process.ProcessTools; @@ -51,7 +50,7 @@ import static org.testng.Assert.*; @Test public class SetDefaultProvider { - private static String SET_DEFAULT_FSP = + private static final String SET_DEFAULT_FSP = "-Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider"; private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar") @@ -73,7 +72,7 @@ public class SetDefaultProvider { String testClasses = System.getProperty("test.classes"); String classpath = moduleClasses + File.pathSeparator + testClasses; int exitValue = exec(SET_DEFAULT_FSP, "-cp", classpath, "p.Main"); - assertTrue(exitValue == 0); + assertEquals(exitValue, 0); } /** @@ -88,7 +87,7 @@ public class SetDefaultProvider { String classpath = jar + File.pathSeparator + testClasses + File.separator + "modules" + File.separator + "m"; int exitValue = exec(SET_DEFAULT_FSP, "-cp", classpath, "p.Main"); - assertTrue(exitValue == 0); + assertEquals(exitValue, 0); } /** @@ -112,7 +111,7 @@ public class SetDefaultProvider { } } int ret = JAR_TOOL.run(System.out, System.out, args.toArray(new String[0])); - assertTrue(ret == 0); + assertEquals(ret, 0); } /** @@ -128,7 +127,7 @@ public class SetDefaultProvider { int exitValue = exec(SET_DEFAULT_FSP, "-cp", classpath, "-Dtest.classes=" + testClasses, "-Djava.security.manager", "-Djava.security.policy==" + policyFile, "p.Main"); - assertTrue(exitValue == 0); + assertEquals(exitValue, 0); } /** @@ -138,7 +137,7 @@ public class SetDefaultProvider { public void testExplodedModule() throws Exception { String modulePath = System.getProperty("jdk.module.path"); int exitValue = exec(SET_DEFAULT_FSP, "-p", modulePath, "-m", "m/p.Main"); - assertTrue(exitValue == 0); + assertEquals(exitValue, 0); } /** @@ -148,7 +147,7 @@ public class SetDefaultProvider { public void testModularJar() throws Exception { String jarFile = createModularJar(); int exitValue = exec(SET_DEFAULT_FSP, "-p", jarFile, "-m", "m/p.Main"); - assertTrue(exitValue == 0); + assertEquals(exitValue, 0); } /** @@ -162,7 +161,7 @@ public class SetDefaultProvider { "--patch-module", "m=" + patchdir, "-p", modulePath, "-m", "m/p.Main"); - assertTrue(exitValue == 0); + assertEquals(exitValue, 0); } /** @@ -178,7 +177,7 @@ public class SetDefaultProvider { "--patch-module", "m=" + patch, "-p", modulePath, "-m", "m/p.Main"); - assertTrue(exitValue == 0); + assertEquals(exitValue, 0); } /** @@ -190,7 +189,7 @@ public class SetDefaultProvider { Path m = Paths.get(dir, "m"); if (Files.exists(m)) return m.toString(); } - assertFalse(true); + fail(); return null; } @@ -210,7 +209,7 @@ public class SetDefaultProvider { Path jar = createTempDirectory("tmp").resolve("m.jar"); String[] args = { "--create", "--file=" + jar, "-C", dir.toString(), "." }; int ret = JAR_TOOL.run(System.out, System.out, args); - assertTrue(ret == 0); + assertEquals(ret, 0); return jar; } -- GitLab From f16244509df7659572bfd23e55a62bb9a891000a Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Thu, 24 Mar 2022 19:08:23 +0000 Subject: [PATCH 160/237] 8283416: Update java.lang.invoke.MethodHandle to use sealed classes Reviewed-by: sundar, mchung --- .../java/lang/invoke/BoundMethodHandle.java | 4 ++-- .../java/lang/invoke/DelegatingMethodHandle.java | 8 ++++++-- .../java/lang/invoke/DirectMethodHandle.java | 14 +++++++------- .../classes/java/lang/invoke/MethodHandle.java | 4 +++- .../classes/java/lang/invoke/MethodHandleImpl.java | 6 +++--- .../java/lang/invoke/NativeMethodHandle.java | 4 ++-- 6 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java index 9a4393eea27..bb15f3cfbf3 100644 --- a/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/BoundMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -49,7 +49,7 @@ import static java.lang.invoke.MethodHandleStatics.uncaughtException; * All bound arguments are encapsulated in dedicated species. */ /*non-public*/ -abstract class BoundMethodHandle extends MethodHandle { +abstract non-sealed class BoundMethodHandle extends MethodHandle { /*non-public*/ BoundMethodHandle(MethodType type, LambdaForm form) { diff --git a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java index 458810f3c10..d3986a38dab 100644 --- a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -37,7 +37,11 @@ import static java.lang.invoke.MethodHandleStatics.*; * @author jrose */ /*non-public*/ -abstract class DelegatingMethodHandle extends MethodHandle { +abstract sealed class DelegatingMethodHandle extends MethodHandle + permits MethodHandleImpl.AsVarargsCollector, + MethodHandleImpl.WrappedMember, + MethodHandleImpl.IntrinsicMethodHandle, + MethodHandleImpl.CountingWrapper { protected DelegatingMethodHandle(MethodHandle target) { this(target.type(), target); } diff --git a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java index d760e6e64c0..e2106883e5a 100644 --- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2022, 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 @@ -49,7 +49,7 @@ import static java.lang.invoke.MethodTypeForm.*; * to a class member. * @author jrose */ -class DirectMethodHandle extends MethodHandle { +sealed class DirectMethodHandle extends MethodHandle { final MemberName member; final boolean crackable; @@ -395,7 +395,7 @@ class DirectMethodHandle extends MethodHandle { } /** This subclass represents invokespecial instructions. */ - static class Special extends DirectMethodHandle { + static final class Special extends DirectMethodHandle { private final Class caller; private Special(MethodType mtype, LambdaForm form, MemberName member, boolean crackable, Class caller) { super(mtype, form, member, crackable); @@ -425,7 +425,7 @@ class DirectMethodHandle extends MethodHandle { } /** This subclass represents invokeinterface instructions. */ - static class Interface extends DirectMethodHandle { + static final class Interface extends DirectMethodHandle { private final Class refc; private Interface(MethodType mtype, LambdaForm form, MemberName member, boolean crackable, Class refc) { super(mtype, form, member, crackable); @@ -458,7 +458,7 @@ class DirectMethodHandle extends MethodHandle { } /** This subclass handles constructor references. */ - static class Constructor extends DirectMethodHandle { + static final class Constructor extends DirectMethodHandle { final MemberName initMethod; final Class instanceClass; @@ -493,7 +493,7 @@ class DirectMethodHandle extends MethodHandle { } /** This subclass handles non-static field references. */ - static class Accessor extends DirectMethodHandle { + static final class Accessor extends DirectMethodHandle { final Class fieldType; final int fieldOffset; private Accessor(MethodType mtype, LambdaForm form, MemberName member, @@ -539,7 +539,7 @@ class DirectMethodHandle extends MethodHandle { } /** This subclass handles static field references. */ - static class StaticAccessor extends DirectMethodHandle { + static final class StaticAccessor extends DirectMethodHandle { private final Class fieldType; private final Object staticBase; private final long staticOffset; diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index fb7ef0afbac..812f26f58cc 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -440,7 +440,9 @@ mh.invokeExact(System.out, "Hello, world."); * @author John Rose, JSR 292 EG * @since 1.7 */ -public abstract class MethodHandle implements Constable { +public abstract sealed class MethodHandle implements Constable + permits NativeMethodHandle, DirectMethodHandle, + DelegatingMethodHandle, BoundMethodHandle { /** * Internal marker interface which distinguishes (to the Java compiler) diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java index 404782c047e..cdbc26200a1 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -448,7 +448,7 @@ abstract class MethodHandleImpl { return new AsVarargsCollector(target, arrayType); } - private static final class AsVarargsCollector extends DelegatingMethodHandle { + static final class AsVarargsCollector extends DelegatingMethodHandle { private final MethodHandle target; private final Class arrayType; private @Stable MethodHandle asCollectorCache; @@ -705,7 +705,7 @@ abstract class MethodHandleImpl { * Behavior in counting and non-counting states is determined by lambda forms produced by * countingFormProducer & nonCountingFormProducer respectively. */ - static class CountingWrapper extends DelegatingMethodHandle { + static final class CountingWrapper extends DelegatingMethodHandle { private final MethodHandle target; private int count; private Function countingFormProducer; @@ -1299,7 +1299,7 @@ abstract class MethodHandleImpl { } /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ - private static final class WrappedMember extends DelegatingMethodHandle { + static final class WrappedMember extends DelegatingMethodHandle { private final MethodHandle target; private final MemberName member; private final Class callerClass; diff --git a/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java b/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java index 4c4cd474e19..11acea6e508 100644 --- a/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/NativeMethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -39,7 +39,7 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError; * or whether a native transition is required) and a fallback method handle, which can be used * when intrinsification of this method handle is not possible. */ -/*non-public*/ class NativeMethodHandle extends MethodHandle { +/*non-public*/ final class NativeMethodHandle extends MethodHandle { final NativeEntryPoint nep; final MethodHandle fallback; -- GitLab From dc5a65ab378f0780f7760965f2b52cbbd7c62aad Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 24 Mar 2022 19:52:16 +0000 Subject: [PATCH 161/237] 8283426: Fix 'exeption' typo Reviewed-by: xuelei, iris, dholmes, wetmore, aivanov --- src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp | 6 +++--- src/hotspot/os_cpu/windows_x86/assembler_windows_x86.cpp | 4 ++-- src/hotspot/share/code/exceptionHandlerTable.cpp | 4 ++-- src/hotspot/share/jfr/dcmd/jfrDcmds.cpp | 4 ++-- src/java.base/share/classes/javax/crypto/Cipher.java | 4 ++-- src/java.base/share/classes/jdk/internal/misc/CDS.java | 5 ++--- .../classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java | 5 ++--- .../share/classes/sun/security/krb5/KrbCryptoException.java | 4 ++-- .../jdi/ThreadReference/ownedMonitors/ownedmonitors001.java | 4 ++-- .../vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001.java | 4 ++-- .../hotspot/jtreg/vmTestbase/vm/mlvm/share/MlvmOOMTest.java | 4 ++-- .../jaxp/javax/xml/jaxp/unittest/validation/Bug4987574.java | 4 ++-- test/jdk/java/awt/Window/AlwaysOnTop/AutoTestOnTop.java | 6 +++--- .../java/awt/dnd/ImageDecoratedDnDNegative/DnDSource.java | 4 ++-- test/jdk/java/lang/Throwable/StackTraceSerialization.java | 4 ++-- test/jdk/java/text/BreakIterator/Bug7104012.java | 4 ++-- .../testng/test/rowset/serial/SerialJavaObjectTests.java | 4 ++-- 17 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index 53b017d2217..26ec71d258a 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -304,7 +304,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, CodeBlob* cb = CodeCache::find_blob_unsafe(pc); CompiledMethod* nm = (cb != NULL) ? cb->as_compiled_method_or_null() : NULL; if (nm != NULL && nm->has_unsafe_access()) { - // We don't really need a stub here! Just set the pending exeption and + // We don't really need a stub here! Just set the pending exception and // continue at the next instruction after the faulting read. Returning // garbage from this read is ok. thread->set_pending_unsafe_access_error(); @@ -329,7 +329,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, } else if ((thread->thread_state() == _thread_in_vm || thread->thread_state() == _thread_in_native) && sig == SIGBUS && thread->doing_unsafe_access()) { - // We don't really need a stub here! Just set the pending exeption and + // We don't really need a stub here! Just set the pending exception and // continue at the next instruction after the faulting read. Returning // garbage from this read is ok. thread->set_pending_unsafe_access_error(); diff --git a/src/hotspot/os_cpu/windows_x86/assembler_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/assembler_windows_x86.cpp index 8045f792b76..3cc0003cd4c 100644 --- a/src/hotspot/os_cpu/windows_x86/assembler_windows_x86.cpp +++ b/src/hotspot/os_cpu/windows_x86/assembler_windows_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, 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 @@ -47,7 +47,7 @@ void MacroAssembler::int3() { // Warning: This mechanism assumes that we only attempt to get the // thread when we are nested below a call wrapper. // -// movl reg, fs:[0] Get exeception pointer +// movl reg, fs:[0] Get exception pointer // movl reg, [reg + thread_ptr_offset] Load thread // void MacroAssembler::get_thread(Register thread) { diff --git a/src/hotspot/share/code/exceptionHandlerTable.cpp b/src/hotspot/share/code/exceptionHandlerTable.cpp index f3c2a787044..d43d18e4b2b 100644 --- a/src/hotspot/share/code/exceptionHandlerTable.cpp +++ b/src/hotspot/share/code/exceptionHandlerTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2022, 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 @@ -68,7 +68,7 @@ ExceptionHandlerTable::ExceptionHandlerTable(int initial_size) { ExceptionHandlerTable::ExceptionHandlerTable(const CompiledMethod* cm) { _table = (HandlerTableEntry*)cm->handler_table_begin(); _length = cm->handler_table_size() / sizeof(HandlerTableEntry); - _size = 0; // no space allocated by ExeptionHandlerTable! + _size = 0; // no space allocated by ExceptionHandlerTable! } diff --git a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp index 9b295536657..4790506bf97 100644 --- a/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp +++ b/src/hotspot/share/jfr/dcmd/jfrDcmds.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -132,7 +132,7 @@ static void handle_dcmd_result(outputStream* output, const bool startup = DCmd_Source_Internal == source; if (HAS_PENDING_EXCEPTION) { handle_pending_exception(output, startup, PENDING_EXCEPTION); - // Don't clear excption on startup, JVM should fail initialization. + // Don't clear exception on startup, JVM should fail initialization. if (!startup) { CLEAR_PENDING_EXCEPTION; } diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index a6751e886bd..e1cb75d5493 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2022, 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 @@ -1174,7 +1174,7 @@ public class Cipher { } // check if opmode is one of the defined constants - // throw InvalidParameterExeption if not + // throw InvalidParameterException if not private static void checkOpmode(int opmode) { if ((opmode < ENCRYPT_MODE) || (opmode > UNWRAP_MODE)) { throw new InvalidParameterException("Invalid operation mode"); diff --git a/src/java.base/share/classes/jdk/internal/misc/CDS.java b/src/java.base/share/classes/jdk/internal/misc/CDS.java index 370086612cd..29b6a3cbce7 100644 --- a/src/java.base/share/classes/jdk/internal/misc/CDS.java +++ b/src/java.base/share/classes/jdk/internal/misc/CDS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -38,7 +38,6 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Stream; -import jdk.internal.access.JavaLangInvokeAccess; import jdk.internal.access.SharedSecrets; public class CDS { @@ -224,7 +223,7 @@ public class CDS { prt.println(line); } } catch (IOException e) { - throw new RuntimeException("IOExeption happens during drain stream to file " + + throw new RuntimeException("IOException happens during drain stream to file " + fileName + ": " + e.getMessage()); }}).start(); return fileName; diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java index 6a8076ee118..8570ecaa97a 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, 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 @@ -32,7 +32,6 @@ import sun.awt.CGraphicsDevice; import sun.java2d.SurfaceData; import sun.java2d.metal.MTLLayer; import sun.java2d.opengl.CGLLayer; -import sun.lwawt.macosx.CFLayer; import sun.lwawt.LWWindowPeer; import sun.lwawt.PlatformWindow; import sun.util.logging.PlatformLogger; @@ -199,7 +198,7 @@ public class CPlatformEmbeddedFrame implements PlatformWindow { /* * The method could not be implemented due to CALayer restrictions. - * The exeption enforce clients not to use it. + * The exception enforces clients not to use it. */ @Override public boolean isUnderMouse() { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/KrbCryptoException.java b/src/java.security.jgss/share/classes/sun/security/krb5/KrbCryptoException.java index 28522e8316d..eda5fcec397 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/KrbCryptoException.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/KrbCryptoException.java @@ -31,7 +31,7 @@ package sun.security.krb5; /** - * KrbCryptoExceptoin is a wrapper exception for exceptions thrown by JCE. + * KrbCryptoException is a wrapper exception for exceptions thrown by JCE. * * @author Yanni Zhang */ @@ -39,7 +39,7 @@ public class KrbCryptoException extends KrbException { private static final long serialVersionUID = -1657367919979982250L; - public KrbCryptoException (String s) { + public KrbCryptoException(String s) { super(s); } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/ownedMonitors/ownedmonitors001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/ownedMonitors/ownedmonitors001.java index f5c721cfac7..608d3410639 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/ownedMonitors/ownedmonitors001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadReference/ownedMonitors/ownedmonitors001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -281,7 +281,7 @@ public class ownedmonitors001 { Value value = debuggeeRef.getValue(field); expMonitors.add((ObjectReference)value); } catch (Exception e) { - log3("Unexpected excption while getting ObjectReference for monitors"); + log3("Unexpected exception while getting ObjectReference for monitors"); testExitCode = FAILED; } } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001.java index 4a482ab2164..2092256ef6c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdwp/Event/EXCEPTION/exception001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -267,7 +267,7 @@ public class exception001 { JDWP.SuspendPolicy.ALL); log.display(" ... breakpoint reached with threadID: " + testedThreadID); - // get excepion objectID value for static field + // get exception objectID value for static field log.display("Getting exception objectID from static field: " + EXCEPTION_FIELD_NAME); JDWP.Value value = debugee.getStaticFieldValue(testedClassID, EXCEPTION_FIELD_NAME, JDWP.Tag.OBJECT); exceptionObjectID = ((Long)value.getValue()).longValue(); diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/MlvmOOMTest.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/MlvmOOMTest.java index eb3cc9f89d6..fb44a54b825 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/MlvmOOMTest.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/share/MlvmOOMTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2022, 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 @@ -69,7 +69,7 @@ public abstract class MlvmOOMTest extends MlvmTest { /** * Checks the OOME type is expected. - * Method just exits if OOME is expected and throws an exeption if not. + * Method just exits if OOME is expected and throws an exception if not. * @param oome thrown by {@link #eatMemory(List)} */ protected abstract void checkOOME(OutOfMemoryError oome); diff --git a/test/jaxp/javax/xml/jaxp/unittest/validation/Bug4987574.java b/test/jaxp/javax/xml/jaxp/unittest/validation/Bug4987574.java index 10f9157eef7..9f360c38cec 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/validation/Bug4987574.java +++ b/test/jaxp/javax/xml/jaxp/unittest/validation/Bug4987574.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -41,7 +41,7 @@ import org.testng.annotations.Test; * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm -DrunSecMngr=true -Djava.security.manager=allow validation.Bug4987574 * @run testng/othervm validation.Bug4987574 - * @summary Test schemaFactory.newSchema doesn't throw NullPointerExceptio for empty schema. + * @summary Test schemaFactory.newSchema doesn't throw NullPointerException for empty schema. */ @Listeners({jaxp.library.FilePolicy.class}) public class Bug4987574 { diff --git a/test/jdk/java/awt/Window/AlwaysOnTop/AutoTestOnTop.java b/test/jdk/java/awt/Window/AlwaysOnTop/AutoTestOnTop.java index fcec97d7fb1..aada6d7af8a 100644 --- a/test/jdk/java/awt/Window/AlwaysOnTop/AutoTestOnTop.java +++ b/test/jdk/java/awt/Window/AlwaysOnTop/AutoTestOnTop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -672,7 +672,7 @@ public class AutoTestOnTop { } catch (Exception e) { error("Test failed: stage#" + stageNum + "action #" + actNum + ": " + msgCase + ": " + msgAction + ": setAlwaysOnTop(" + value + ") called at state " + msgVisibility + - " threw exeption " + e); + " threw exception " + e); } } @@ -685,7 +685,7 @@ public class AutoTestOnTop { } catch (Exception e) { error("Test failed: stage #" + stageNum + ", action # " + actNum + ": " + msgCase + ": " + msgAction + ": isAlwaysOnTop() called at state " + msgVisibility + - " threw exeption " + e); + " threw exception " + e); } return result; } diff --git a/test/jdk/java/awt/dnd/ImageDecoratedDnDNegative/DnDSource.java b/test/jdk/java/awt/dnd/ImageDecoratedDnDNegative/DnDSource.java index c1548966ab5..750448c562d 100644 --- a/test/jdk/java/awt/dnd/ImageDecoratedDnDNegative/DnDSource.java +++ b/test/jdk/java/awt/dnd/ImageDecoratedDnDNegative/DnDSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2022, 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 @@ -76,7 +76,7 @@ class DnDSource extends Button implements Transferable, * a Drag gesture has been recognized */ int iProblem = 0; - String[] problem = {"unready", "throw exeption", "good"}; + String[] problem = {"unready", "throw exception", "good"}; public void dragGestureRecognized(DragGestureEvent dge) { System.out.println("starting Drag"); if( !DragSource.isDragImageSupported() ) { diff --git a/test/jdk/java/lang/Throwable/StackTraceSerialization.java b/test/jdk/java/lang/Throwable/StackTraceSerialization.java index 29a4d2a8c13..015c39b202d 100644 --- a/test/jdk/java/lang/Throwable/StackTraceSerialization.java +++ b/test/jdk/java/lang/Throwable/StackTraceSerialization.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2022, 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 @@ -126,7 +126,7 @@ public class StackTraceSerialization { * Returns true if e1 and e2 have equal stack traces and their * causes are recursively equal (by the same definition) and their * suppressed exception information is equals. Returns false or - * throws NullPointerExeption otherwise. + * throws NullPointerException otherwise. */ private static boolean equal(Throwable t1, Throwable t2) { return t1==t2 || diff --git a/test/jdk/java/text/BreakIterator/Bug7104012.java b/test/jdk/java/text/BreakIterator/Bug7104012.java index ced84b9edb7..8d5ac2969a3 100644 --- a/test/jdk/java/text/BreakIterator/Bug7104012.java +++ b/test/jdk/java/text/BreakIterator/Bug7104012.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -71,7 +71,7 @@ public class Bug7104012 { } if (err) { - throw new RuntimeException("Unexpected exeption."); + throw new RuntimeException("Unexpected exception."); } } diff --git a/test/jdk/javax/sql/testng/test/rowset/serial/SerialJavaObjectTests.java b/test/jdk/javax/sql/testng/test/rowset/serial/SerialJavaObjectTests.java index cc2d184298d..c2fcf2fa48f 100644 --- a/test/jdk/javax/sql/testng/test/rowset/serial/SerialJavaObjectTests.java +++ b/test/jdk/javax/sql/testng/test/rowset/serial/SerialJavaObjectTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 @@ -43,7 +43,7 @@ public class SerialJavaObjectTests extends BaseTest { } /* - * Validate that an SerialExcepion is thrown when the object specified + * Validate that a SerialException is thrown when the object specified * contains public static fields */ @Test(expectedExceptions = SerialException.class, enabled = false) -- GitLab From c1048021fe57b78bb1f300b977588e1a93a284b6 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Thu, 24 Mar 2022 21:42:35 +0000 Subject: [PATCH 162/237] 8283641: Large value for CompileThresholdScaling causes assert Reviewed-by: kvn --- src/hotspot/share/compiler/compilerDefinitions.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/hotspot/share/compiler/compilerDefinitions.cpp b/src/hotspot/share/compiler/compilerDefinitions.cpp index aa8dd0a1be8..1bbff8fb77b 100644 --- a/src/hotspot/share/compiler/compilerDefinitions.cpp +++ b/src/hotspot/share/compiler/compilerDefinitions.cpp @@ -124,10 +124,17 @@ intx CompilerConfig::scaled_freq_log(intx freq_log) { // Returns threshold scaled with the value of scale. // If scale < 0.0, threshold is returned without scaling. intx CompilerConfig::scaled_compile_threshold(intx threshold, double scale) { + assert(threshold >= 0, "must be"); if (scale == 1.0 || scale < 0.0) { return threshold; } else { - return (intx)(threshold * scale); + double v = threshold * scale; + assert(v >= 0, "must be"); + if (v > max_intx) { + return max_intx; + } else { + return (intx)(v); + } } } -- GitLab From 313bc7f64f69d8f352d495d2c35bea62aca910e4 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Thu, 24 Mar 2022 22:50:26 +0000 Subject: [PATCH 163/237] 8267319: Use larger default key sizes and algorithms based on CNSA Reviewed-by: weijun, xuelei --- .../sun/crypto/provider/AESKeyGenerator.java | 7 +- .../sun/security/tools/keytool/Main.java | 2 + .../util/SecurityProviderConstants.java | 45 ++++++-- .../sun/security/util/SignatureUtil.java | 46 ++++---- .../sun/security/pkcs11/P11KeyGenerator.java | 6 +- .../security/pkcs11/P11KeyPairGenerator.java | 40 ++++--- .../jdk/security/jarsigner/JarSigner.java | 21 ++-- .../KeyAgreement/TestExponentSize.java | 13 ++- .../provider/KeyGenerator/Test4628062.java | 7 +- .../jdk/security/jarsigner/Properties.java | 11 +- test/jdk/jdk/security/jarsigner/Spec.java | 11 +- .../security/pkcs11/KeyGenerator/TestAES.java | 90 ++++++++++++++++ .../KeyPairGenerator/TestDefaultSize.java | 101 ++++++++++++++++++ .../tools/jarsigner/CheckSignerCertChain.java | 25 +++-- .../tools/jarsigner/DefaultSigalg.java | 33 ++++-- .../security/tools/jarsigner/NewSize7.java | 14 ++- .../PreserveRawManifestEntryAndDigest.java | 40 +++---- .../SectionNameContinuedVsLineBreak.java | 20 ++-- .../security/tools/jarsigner/SignedAgain.java | 18 ++-- .../tools/jarsigner/TimestampCheck.java | 27 ++++- .../compatibility/Compatibility.java | 8 +- .../jarsigner/compatibility/SignTwice.java | 17 ++- .../tools/keytool/GenKeyPairSigner.java | 14 +-- .../security/tools/keytool/GenerateAll.java | 12 +-- .../sun/security/tools/keytool/GroupName.java | 9 +- .../sun/security/tools/keytool/KeyAlg.java | 8 +- .../sun/security/tools/keytool/NewSize7.java | 13 +-- .../fakegen/DefaultSignatureAlgorithm.java | 8 +- .../security/tools/keytool/fakegen/PSS.java | 8 +- 29 files changed, 496 insertions(+), 178 deletions(-) create mode 100644 test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java create mode 100644 test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java diff --git a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java index 6ca4d929acb..2672807aadd 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/AESKeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2022, 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 @@ -34,7 +34,7 @@ import java.util.Arrays; import javax.crypto.KeyGeneratorSpi; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; - +import sun.security.util.SecurityProviderConstants; /** * This class generates a AES key. @@ -46,7 +46,8 @@ import javax.crypto.spec.SecretKeySpec; public final class AESKeyGenerator extends KeyGeneratorSpi { private SecureRandom random = null; - private int keySize = 16; // default keysize (in number of bytes) + // default keysize (in number of bytes) + private int keySize = SecurityProviderConstants.getDefAESKeySize() >> 3; /** * Empty constructor. diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 462606c7f84..0a1b889db6d 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1917,6 +1917,8 @@ public final class Main { keysize = SecurityProviderConstants.DEF_EC_KEY_SIZE; } else if ("RSA".equalsIgnoreCase(keyAlgName)) { keysize = SecurityProviderConstants.DEF_RSA_KEY_SIZE; + } else if ("RSASSA-PSS".equalsIgnoreCase(keyAlgName)) { + keysize = SecurityProviderConstants.DEF_RSASSA_PSS_KEY_SIZE; } else if ("DSA".equalsIgnoreCase(keyAlgName)) { keysize = SecurityProviderConstants.DEF_DSA_KEY_SIZE; } else if ("EdDSA".equalsIgnoreCase(keyAlgName)) { diff --git a/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java b/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java index 166c4a5130f..c358cc66354 100644 --- a/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java +++ b/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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 @@ -27,9 +27,12 @@ package sun.security.util; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.PatternSyntaxException; import java.security.InvalidParameterException; import java.security.ProviderException; +import java.security.NoSuchAlgorithmException; +import javax.crypto.Cipher; import sun.security.action.GetPropertyAction; /** @@ -43,11 +46,11 @@ public final class SecurityProviderConstants { private static final Debug debug = Debug.getInstance("jca", "ProviderConfig"); - // cache for provider aliases; key is the standard algorithm name + // Cache for provider aliases; key is the standard algorithm name // value is the associated aliases List private static final ConcurrentHashMap> aliasesMap; - // utility method for generating aliases list using the supplied + // Utility method for generating aliases list using the supplied // 'oid' and 'extraAliases', then store into "aliasesMap" cache under the // key 'stdName' private static List store(String stdName, KnownOIDs oid, @@ -75,7 +78,7 @@ public final class SecurityProviderConstants { return value; } - // returns an aliases List for the specified algorithm name o + // Return an aliases List for the specified algorithm name o // NOTE: exception is thrown if no aliases nor oid found, so // only call this method if aliases are expected public static List getAliases(String o) { @@ -105,6 +108,25 @@ public final class SecurityProviderConstants { } } + public static final int getDefAESKeySize() { + int currVal = DEF_AES_KEY_SIZE.get(); + if (currVal == -1) { + int v = 256; // default AES key size + try { + // adjust if crypto policy only allows a smaller value + int max = Cipher.getMaxAllowedKeyLength("AES"); + if (v > max) { + v = max; + } + } catch (NoSuchAlgorithmException ne) { + // should never happen; ignore and use the default + } + DEF_AES_KEY_SIZE.compareAndSet(-1, v); + currVal = v; + } + return currVal; + } + public static final int DEF_DSA_KEY_SIZE; public static final int DEF_RSA_KEY_SIZE; public static final int DEF_RSASSA_PSS_KEY_SIZE; @@ -112,6 +134,11 @@ public final class SecurityProviderConstants { public static final int DEF_EC_KEY_SIZE; public static final int DEF_ED_KEY_SIZE; public static final int DEF_XEC_KEY_SIZE; + // The logic for finding the max allowable value in getDefAESKeySize() + // interferes with provider loading logic and may lead to deadlocks if + // called inside a static block. So, it is deferred to a later time when + // DEF_AES_KEY_SIZE is actually used/needed. + private static final AtomicInteger DEF_AES_KEY_SIZE; private static final String KEY_LENGTH_PROP = "jdk.security.defaultKeySize"; @@ -120,12 +147,13 @@ public final class SecurityProviderConstants { String keyLengthStr = GetPropertyAction.privilegedGetProperty (KEY_LENGTH_PROP); int dsaKeySize = 2048; - int rsaKeySize = 2048; + int rsaKeySize = 3072; int rsaSsaPssKeySize = rsaKeySize; // default to same value as RSA - int dhKeySize = 2048; - int ecKeySize = 256; + int dhKeySize = 3072; + int ecKeySize = 384; int edKeySize = 255; int xecKeySize = 255; + int aesKeySize = -1; // needs to check crypto policy if (keyLengthStr != null) { try { @@ -167,6 +195,8 @@ public final class SecurityProviderConstants { edKeySize = value; } else if (algoName.equals("XDH")) { xecKeySize = value; + } else if (algoName.equals("AES")) { + aesKeySize = value; } else { if (debug != null) { debug.println("Ignoring unsupported algo in " + @@ -195,6 +225,7 @@ public final class SecurityProviderConstants { DEF_EC_KEY_SIZE = ecKeySize; DEF_ED_KEY_SIZE = edKeySize; DEF_XEC_KEY_SIZE = xecKeySize; + DEF_AES_KEY_SIZE = new AtomicInteger(aesKeySize); // Set up aliases with default mappings // This is needed when the mapping contains non-oid diff --git a/src/java.base/share/classes/sun/security/util/SignatureUtil.java b/src/java.base/share/classes/sun/security/util/SignatureUtil.java index ec86df854fc..8fe2d4deebe 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java +++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java @@ -60,13 +60,11 @@ public class SignatureUtil { if (algName.startsWith("OID.")) { algName = algName.substring(4); } - KnownOIDs ko = KnownOIDs.findMatch(algName); if (ko != null) { return ko.stdName().toUpperCase(Locale.ENGLISH); } } - return algName; } @@ -491,12 +489,11 @@ public class SignatureUtil { * @return the default alg, might be null if unsupported */ public static String getDefaultSigAlgForKey(PrivateKey k) { - String kAlg = k.getAlgorithm(); - return switch (kAlg.toUpperCase(Locale.ENGLISH)) { - case "DSA", "RSA" -> ifcFfcStrength(KeyUtil.getKeySize(k)) - + "with" + kAlg; - case "EC" -> ecStrength(KeyUtil.getKeySize(k)) - + "withECDSA"; + String kAlg = k.getAlgorithm().toUpperCase(Locale.ENGLISH); + return switch (kAlg) { + case "DSA" -> "SHA256withDSA"; + case "RSA" -> ifcFfcStrength(KeyUtil.getKeySize(k)) + "withRSA"; + case "EC" -> ecStrength(KeyUtil.getKeySize(k)) + "withECDSA"; case "EDDSA" -> k instanceof EdECPrivateKey ? ((EdECPrivateKey) k).getParams().getName() : kAlg; @@ -521,11 +518,16 @@ public class SignatureUtil { 64, PSSParameterSpec.TRAILER_FIELD_BC); } - // The following values are from SP800-57 part 1 rev 4 tables 2 and 3 + // SP800-57 part 1 rev5 table 2 "Comparable security strengths of + // symmetric block cipher and asymmetric-key algorithms", and table 3 + // "Maximum security strengths for hash and hash-based functions" + // define security strength for various algorithms. + // Besides matching the security strength, the default algorithms may + // also be chosen based on various recommendations such as NIST CNSA. /** - * Return the default message digest algorithm with the same security - * strength as the specified EC key size. + * Return the default message digest algorithm based on the specified + * EC key size. * * Attention: sync with the @implNote inside * {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm}. @@ -533,27 +535,27 @@ public class SignatureUtil { private static String ecStrength (int bitLength) { if (bitLength >= 512) { // 256 bits of strength return "SHA512"; - } else if (bitLength >= 384) { // 192 bits of strength + } else { + // per CNSA, use SHA-384 return "SHA384"; - } else { // 128 bits of strength and less - return "SHA256"; } } /** - * Return the default message digest algorithm with the same security - * strength as the specified IFC/FFC key size. + * Return the default message digest algorithm based on both the + * security strength of the specified IFC/FFC key size, i.e. RSA, + * RSASSA-PSS, and the recommendation from NIST CNSA, e.g. use SHA-384 + * and min 3072-bit. * * Attention: sync with the @implNote inside * {@link jdk.security.jarsigner.JarSigner.Builder#getDefaultSignatureAlgorithm}. */ - private static String ifcFfcStrength (int bitLength) { - if (bitLength > 7680) { // 256 bits + private static String ifcFfcStrength(int bitLength) { + if (bitLength > 7680) { // 256 bits security strength return "SHA512"; - } else if (bitLength > 3072) { // 192 bits - return "SHA384"; - } else { // 128 bits and less - return "SHA256"; + } else { + // per CNSA, use SHA-384 unless keysize is too small + return (bitLength >= 624 ? "SHA384" : "SHA256"); } } } diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java index c7552402509..012eb25392c 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -30,6 +30,7 @@ import java.security.spec.AlgorithmParameterSpec; import javax.crypto.*; +import sun.security.util.SecurityProviderConstants;; import static sun.security.pkcs11.TemplateManager.*; import sun.security.pkcs11.wrapper.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; @@ -225,7 +226,8 @@ final class P11KeyGenerator extends KeyGeneratorSpi { significantKeySize = 168; break; case (int)CKM_AES_KEY_GEN: - keySize = adjustKeySize(128, range); + keySize = adjustKeySize + (SecurityProviderConstants.getDefAESKeySize(), range); keyType = CKK_AES; break; case (int)CKM_RC4_KEY_GEN: diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java index f13ae3cd67d..ba99d0bcb5c 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -99,29 +99,35 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi { // set default key sizes and apply our own algorithm-specific limits // override lower limit to disallow unsecure keys being generated // override upper limit to deter DOS attack - if (algorithm.equals("EC")) { - keySize = DEF_EC_KEY_SIZE; - if (minKeyLen < 112) { - minKeyLen = 112; - } - if (maxKeyLen > 2048) { - maxKeyLen = 2048; + int jdkMinKeyLen = 512; + int jdkMaxKeyLen = Integer.MAX_VALUE; + switch (algorithm) { + case "EC" -> { + keySize = DEF_EC_KEY_SIZE; + jdkMinKeyLen = 112; + jdkMaxKeyLen = 2048; } - } else { - if (algorithm.equals("DSA")) { + case "DSA" -> { keySize = DEF_DSA_KEY_SIZE; - } else if (algorithm.equals("RSA")) { + } + case "RSA" -> { keySize = DEF_RSA_KEY_SIZE; - if (maxKeyLen > 64 * 1024) { - maxKeyLen = 64 * 1024; - } - } else { + jdkMaxKeyLen = 64 * 1024; + } + case "DH" -> { keySize = DEF_DH_KEY_SIZE; } - if (minKeyLen < 512) { - minKeyLen = 512; + default -> { + throw new ProviderException + ("Unrecognized algorithm for checking key size"); } } + if (minKeyLen < jdkMinKeyLen) { + minKeyLen = jdkMinKeyLen; + } + if (maxKeyLen > jdkMaxKeyLen) { + maxKeyLen = jdkMaxKeyLen; + } // auto-adjust default keysize in case it's out-of-range if (keySize < minKeyLen) { diff --git a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java index 08fad553cc9..74c687912fe 100644 --- a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java +++ b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -417,29 +417,30 @@ public final class JarSigner { /** * Gets the default digest algorithm. * - * @implNote This implementation returns "SHA-256". The value may + * @implNote This implementation returns "SHA-384". The value may * change in the future. * * @return the default digest algorithm. */ public static String getDefaultDigestAlgorithm() { - return "SHA-256"; + return "SHA-384"; } /** * Gets the default signature algorithm for a private key. - * For example, SHA256withRSA for a 2048-bit RSA key, and + * For example, SHA384withRSA for a 2048-bit RSA key, and * SHA384withECDSA for a 384-bit EC key. * * @implNote This implementation makes use of comparable strengths - * as defined in Tables 2 and 3 of NIST SP 800-57 Part 1-Rev.4. - * Specifically, if a DSA or RSA key with a key size greater than 7680 + * as defined in Tables 2 and 3 of NIST SP 800-57 Part 1-Rev.5 as + * well as NIST recommendations as appropriate. + * Specifically, if an RSA key with a key size greater than 7680 * bits, or an EC key with a key size greater than or equal to 512 bits, * SHA-512 will be used as the hash function for the signature. - * If a DSA or RSA key has a key size greater than 3072 bits, or an - * EC key has a key size greater than or equal to 384 bits, SHA-384 will - * be used. Otherwise, SHA-256 will be used. The value may - * change in the future. + * Otherwise, SHA-384 will be used unless the key size is too small + * for resulting signature algorithm. As for DSA keys, the SHA256withDSA + * signature algorithm is returned regardless of key size. + * The value may change in the future. * * @param key the private key. * @return the default signature algorithm. Returns null if a default diff --git a/test/jdk/com/sun/crypto/provider/KeyAgreement/TestExponentSize.java b/test/jdk/com/sun/crypto/provider/KeyAgreement/TestExponentSize.java index b304121fa0c..2367c361d57 100644 --- a/test/jdk/com/sun/crypto/provider/KeyAgreement/TestExponentSize.java +++ b/test/jdk/com/sun/crypto/provider/KeyAgreement/TestExponentSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 6330287 6331386 7044060 + * @bug 6330287 6331386 7044060 8267319 * @summary verify that DHKeyPairGenerator returns keys of the expected size * (modulus and exponent) * -and- @@ -58,7 +58,7 @@ public class TestExponentSize { */ private enum Sizes { two56(256), three84(384), five12(512), seven68(768), ten24(1024), - twenty48(2048); + fifteen36(1536), twenty48(2048), thirty72(3072); private final int intSize; private final BigInteger bigIntValue; @@ -83,11 +83,14 @@ public class TestExponentSize { KeyPair kp; KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", "SunJCE"); - // Sun's default uses a default psize of 2048 and + // Sun's default uses a default psize of 3072 and // lsize of (pSize / 2) but at least 384 bits kp = kpg.generateKeyPair(); - checkKeyPair(kp, Sizes.twenty48, Sizes.ten24); + checkKeyPair(kp, Sizes.thirty72, Sizes.fifteen36); + kpg.initialize(Sizes.twenty48.getIntSize()); + kp = kpg.generateKeyPair(); + checkKeyPair(kp, Sizes.twenty48, Sizes.ten24); DHPublicKey publicKey = (DHPublicKey)kp.getPublic(); BigInteger p = publicKey.getParams().getP(); BigInteger g = publicKey.getParams().getG(); diff --git a/test/jdk/com/sun/crypto/provider/KeyGenerator/Test4628062.java b/test/jdk/com/sun/crypto/provider/KeyGenerator/Test4628062.java index 3e93874a88a..10cb29b6db2 100644 --- a/test/jdk/com/sun/crypto/provider/KeyGenerator/Test4628062.java +++ b/test/jdk/com/sun/crypto/provider/KeyGenerator/Test4628062.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2022, 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 4628062 4963723 + * @bug 4628062 4963723 8267319 * @summary Verify that AES KeyGenerator supports default initialization * when init is not called * @author Valerie Peng @@ -34,7 +34,8 @@ import java.util.*; public class Test4628062 { - private static final int[] AES_SIZES = { 16, 24, 32 }; // in bytes + // first value is the default key size + private static final int[] AES_SIZES = { 32, 16, 24 }; // in bytes private static final int[] HMACSHA224_SIZES = { 28 }; private static final int[] HMACSHA256_SIZES = { 32 }; private static final int[] HMACSHA384_SIZES = { 48 }; diff --git a/test/jdk/jdk/security/jarsigner/Properties.java b/test/jdk/jdk/security/jarsigner/Properties.java index 05c50c16979..9de99759798 100644 --- a/test/jdk/jdk/security/jarsigner/Properties.java +++ b/test/jdk/jdk/security/jarsigner/Properties.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 8242068 + * @bug 8242068 8267319 * @summary test the properties * @library /test/lib * @modules java.base/sun.security.tools.keytool @@ -50,6 +50,9 @@ import java.util.zip.ZipFile; public class Properties { + private static final String DEF_DIGEST_STR = + JarSigner.Builder.getDefaultDigestAlgorithm() + "-Digest-Manifest:"; + public static void main(String[] args) throws Exception { Files.writeString(Path.of("anything"), "anything"); @@ -82,12 +85,12 @@ public class Properties { // Has a hash for the whole manifest byte[] s0 = sign(jsb.setProperty("sectionsonly", "false")); sf = new String(DerUtils.innerDerValue(s0, "10210").getOctetString()); - Asserts.assertTrue(sf.contains("SHA-256-Digest-Manifest:")); + Asserts.assertTrue(sf.contains(DEF_DIGEST_STR)); // Has no hash for the whole manifest byte[] s1 = sign(jsb.setProperty("sectionsonly", "true")); sf = new String(DerUtils.innerDerValue(s1, "10210").getOctetString()); - Asserts.assertFalse(sf.contains("SHA-256-Digest-Manifest:")); + Asserts.assertFalse(sf.contains(DEF_DIGEST_STR)); } // Sign and returns the content of the PKCS7 signature block inside diff --git a/test/jdk/jdk/security/jarsigner/Spec.java b/test/jdk/jdk/security/jarsigner/Spec.java index b089f4af929..0b41cc94be6 100644 --- a/test/jdk/jdk/security/jarsigner/Spec.java +++ b/test/jdk/jdk/security/jarsigner/Spec.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 8056174 8242068 8255536 + * @bug 8056174 8242068 8255536 8267319 * @summary Make sure JarSigner impl conforms to spec * @library /test/lib * @modules java.base/sun.security.tools.keytool @@ -178,14 +178,15 @@ public class Spec { assertTrue(js3.getProperty("altsigner").equals("MyContentSigner")); assertTrue(js3.getProperty("altsignerpath") == null); - assertTrue(JarSigner.Builder.getDefaultDigestAlgorithm().equals("SHA-256")); + assertTrue(JarSigner.Builder.getDefaultDigestAlgorithm() + .equals("SHA-384")); // Calculating large DSA and RSA keys are too slow. KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); kpg.initialize(1024); assertTrue(JarSigner.Builder .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) - .equals("SHA256withRSA")); + .equals("SHA384withRSA")); kpg = KeyPairGenerator.getInstance("DSA"); kpg.initialize(1024); @@ -197,7 +198,7 @@ public class Spec { kpg.initialize(256); assertTrue(JarSigner.Builder .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) - .equals("SHA256withECDSA")); + .equals("SHA384withECDSA")); kpg.initialize(384); assertTrue(JarSigner.Builder .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java new file mode 100644 index 00000000000..e74007a65e3 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestAES.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022, 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 8267319 + * @modules java.base/sun.security.util + * jdk.crypto.cryptoki + * @summary Check AES key generator. + * @library /test/lib .. + * @run main TestAES + */ +import java.security.Provider; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import static sun.security.util.SecurityProviderConstants.*; + +public class TestAES extends PKCS11Test { + + private static final String ALGO = "AES"; + + public static void main(String[] args) throws Exception { + main(new TestAES(), args); + } + + @Override + public void main(Provider p) throws Exception { + System.out.println("Testing " + p.getName()); + KeyGenerator kg; + try { + kg = KeyGenerator.getInstance(ALGO, p); + } catch (NoSuchAlgorithmException nsae) { + System.out.println("Skip; no support for " + ALGO); + return; + } + + // first try w/o setting a key length and check if the generated key + // length matches + SecretKey key = kg.generateKey(); + byte[] keyValue = key.getEncoded(); + if (key.getEncoded().length != getDefAESKeySize() >> 3) { + throw new RuntimeException("Default AES key length should be " + + getDefAESKeySize()); + } + + for (int keySize : new int[] { 16, 32, 64, 128, 256, 512, 1024 }) { + boolean isValid = (keySize == 128 || keySize == 192 || + keySize == 256); + try { + kg.init(keySize); + if (!isValid) { + throw new RuntimeException(keySize + " is invalid keysize"); + } + key = kg.generateKey(); + if (key.getEncoded().length != keySize >> 3) { + throw new RuntimeException("Generated key len mismatch!"); + } + } catch (InvalidParameterException e) { + if (isValid) { + throw new RuntimeException("IPE thrown for valid keySize"); + } else { + System.out.println("Expected IPE thrown for " + keySize); + } + } + } + } +} diff --git a/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java new file mode 100644 index 00000000000..a359ff7a13c --- /dev/null +++ b/test/jdk/sun/security/pkcs11/KeyPairGenerator/TestDefaultSize.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022, 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 8267319 + * @summary Ensure that DSA/RSA/DH/EC KPG in PKCS11 provider uses the + * same default key length + * @library /test/lib .. + * @modules java.base/sun.security.util + * jdk.crypto.cryptoki + * @run main TestDefaultSize + */ + +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Provider; +import java.security.PrivateKey; +import java.security.interfaces.*; +import javax.crypto.interfaces.DHKey; + +import static sun.security.util.SecurityProviderConstants.*; + +public class TestDefaultSize extends PKCS11Test { + + @Override + public void main(Provider p) throws Exception { + System.out.println("Testing " + p.getName()); + + String[] ALGOS = { "DSA", "RSA", "DH", "EC" }; + + for (String algo : ALGOS) { + if (p.getService("KeyPairGenerator", algo) == null) { + System.out.println("Skip, no support for KPG: " + algo); + return; + } + + KeyPairGenerator kpg = KeyPairGenerator.getInstance(algo, p); + KeyPair kp = kpg.generateKeyPair(); + PrivateKey priv = kp.getPrivate(); + int actualSize = -1; + int expectedSize; + if (algo == "DSA") { + expectedSize = DEF_DSA_KEY_SIZE; + if (priv instanceof DSAKey) { + actualSize = ((DSAKey) priv).getParams().getP().bitLength(); + } + } else if (algo == "RSA") { + expectedSize = DEF_RSA_KEY_SIZE; + if (priv instanceof RSAKey) { + actualSize = ((RSAKey) priv).getModulus().bitLength(); + } + } else if (algo == "DH") { + expectedSize = DEF_DH_KEY_SIZE; + if (priv instanceof DHKey) { + actualSize = ((DHKey) priv).getParams().getP().bitLength(); + } + } else if (algo == "EC") { + expectedSize = DEF_EC_KEY_SIZE; + if (priv instanceof ECKey) { + actualSize = ((ECKey) priv).getParams().getCurve() + .getField().getFieldSize(); + } + } else { + throw new RuntimeException("Error: Unrecognized algo " + + algo + " or opaque private key object " + priv); + } + if (actualSize != expectedSize) { + throw new RuntimeException("key size check failed, got " + + actualSize); + } else { + System.out.println(algo + ": passed, " + actualSize); + } + } + } + + public static void main(String[] args) throws Exception { + main(new TestDefaultSize(), args); + } +} diff --git a/test/jdk/sun/security/tools/jarsigner/CheckSignerCertChain.java b/test/jdk/sun/security/tools/jarsigner/CheckSignerCertChain.java index 8465f36261b..da409612efe 100644 --- a/test/jdk/sun/security/tools/jarsigner/CheckSignerCertChain.java +++ b/test/jdk/sun/security/tools/jarsigner/CheckSignerCertChain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, 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 8259401 8266225 + * @bug 8259401 8266225 8267319 * @summary Check certificates in signer's cert chain to see if warning emitted * @library /test/lib */ @@ -40,6 +40,8 @@ public class CheckSignerCertChain { private static final String JAVA_SECURITY_FILE = "java.security"; + private static final String keysizeOpt = "-keysize 2048"; + static OutputAnalyzer kt(String cmd, String ks) throws Exception { return SecurityTools.keytool("-storepass changeit " + cmd + " -keystore " + ks); @@ -57,8 +59,11 @@ public class CheckSignerCertChain { System.out.println("Generating a root cert using SHA1withRSA and 1024-bit key"); kt("-genkeypair -keyalg rsa -alias ca -dname CN=CA -ext bc:c " + "-keysize 1024 -sigalg SHA1withRSA", "ks"); - kt("-genkeypair -keyalg rsa -alias ca1 -dname CN=CA1", "ks"); - kt("-genkeypair -keyalg rsa -alias e1 -dname CN=E1", "ks"); + + kt("-genkeypair -keyalg rsa -alias ca1 -dname CN=CA1 " + keysizeOpt, + "ks"); + kt("-genkeypair -keyalg rsa -alias e1 -dname CN=E1 " + keysizeOpt, + "ks"); // intermediate certificate using SHA1withRSA and 2048-bit key System.out.println("Generating an intermediate cert using SHA1withRSA and 2048-bit key"); @@ -97,8 +102,10 @@ public class CheckSignerCertChain { * Generate a non-self-signed certificate using MD5withRSA as its signature * algorithm to sign a JAR file. */ - kt("-genkeypair -keyalg rsa -alias cacert -dname CN=CACERT -ext bc:c ", "ks"); - kt("-genkeypair -keyalg rsa -alias ee -dname CN=EE -ext bc:c ", "ks"); + kt("-genkeypair -keyalg rsa -alias cacert -dname CN=CACERT -ext bc:c " + + keysizeOpt, "ks"); + kt("-genkeypair -keyalg rsa -alias ee -dname CN=EE -ext bc:c " + + keysizeOpt, "ks"); gencert("ee", "-alias cacert -ext san=dns:ee -sigalg MD5withRSA"); Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), @@ -112,7 +119,7 @@ public class CheckSignerCertChain { JAVA_SECURITY_FILE + " a.jar ee") .shouldNotContain("Signature algorithm: MD5withRSA (disabled), 2048-bit key") - .shouldContain("Signature algorithm: SHA256withRSA, 2048-bit key") + .shouldContain("Signature algorithm: SHA384withRSA, 2048-bit key") .shouldNotContain("Invalid certificate chain: Algorithm constraints check failed on signature algorithm: MD5withRSA") .shouldHaveExitValue(0); @@ -128,7 +135,7 @@ public class CheckSignerCertChain { JAVA_SECURITY_FILE + " a.jar ee") .shouldContain("Signature algorithm: MD5withRSA (disabled), 2048-bit key") - .shouldContain("Signature algorithm: SHA256withRSA, 2048-bit key") + .shouldContain("Signature algorithm: SHA384withRSA, 2048-bit key") .shouldContain("Invalid certificate chain: Algorithm constraints check failed on disabled algorithm: MD5 used with certificate: CN=EE") .shouldHaveExitValue(0); @@ -138,7 +145,7 @@ public class CheckSignerCertChain { SecurityTools.jarsigner("-verify -certs signeda.jar " + "-keystore caks1 -storepass changeit -verbose -debug") .shouldContain("Signature algorithm: MD5withRSA (disabled), 2048-bit key") - .shouldContain("Signature algorithm: SHA256withRSA, 2048-bit key") + .shouldContain("Signature algorithm: SHA384withRSA, 2048-bit key") .shouldContain("Invalid certificate chain: Algorithm constraints check failed on disabled algorithm: MD5 used with certificate: CN=EE") .shouldHaveExitValue(0); } diff --git a/test/jdk/sun/security/tools/jarsigner/DefaultSigalg.java b/test/jdk/sun/security/tools/jarsigner/DefaultSigalg.java index 1d8919934d5..6880a95a503 100644 --- a/test/jdk/sun/security/tools/jarsigner/DefaultSigalg.java +++ b/test/jdk/sun/security/tools/jarsigner/DefaultSigalg.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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,8 +23,8 @@ /** * @test - * @bug 8057810 - * @summary New defaults for DSA keys in jarsigner and keytool + * @bug 8057810 8267319 + * @summary New defaults for DSA, RSA, EC keys in jarsigner and keytool * @modules java.base/sun.security.pkcs * java.base/sun.security.tools.keytool * java.base/sun.security.util @@ -42,20 +42,22 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyStore; import java.security.cert.X509Certificate; -import java.util.jar.JarFile; +import java.util.jar.*; +import java.util.Enumeration; public class DefaultSigalg { public static void main(String[] args) throws Exception { // Three test cases - String[] keyalgs = {"DSA", "RSA", "EC"}; + String[] keyalgs = {"DSA", "RSA", "EC", "RSASSA-PSS"}; // Expected default keytool sigalg - String[] sigalgs = {"SHA256withDSA", "SHA256withRSA", "SHA256withECDSA"}; + String[] sigalgs = {"SHA256withDSA", "SHA384withRSA", + "SHA384withECDSA", "RSASSA-PSS"}; // Expected keysizes - int[] keysizes = {2048, 2048, 256}; + int[] keysizes = {2048, 3072, 384, 3072}; // Expected jarsigner digest alg used in signature - String[] digestalgs = {"SHA-256", "SHA-256", "SHA-256"}; + String[] digestalgs = {"SHA-256", "SHA-384", "SHA-384", "SHA-384"}; // Create a jar file sun.tools.jar.Main m = @@ -96,7 +98,20 @@ public class DefaultSigalg { "keytool keysize for " + keyalg + " is " + keysize); } // jarsigner - String bk = "META-INF/" + keyalg + "." + keyalg; + // truncated to the first 8 chars if alias name is longer + String jeName = (keyalg.equals("RSASSA-PSS")? "RSASSA-P.RSA" : + keyalg + "." + keyalg); + String bk = "META-INF/" + jeName; + if (jf.getEntry(bk) == null) { + System.out.println("JarFile entries:"); + Enumeration entries = jf.entries(); + while (entries.hasMoreElements()) { + System.out.println("je: " + + entries.nextElement().getRealName()); + } + throw new Exception("Expected jarfile entry name " + + jeName + " not found"); + } try (InputStream is = jf.getInputStream(jf.getEntry(bk))) { String digestalg = new PKCS7(is).getSignerInfos()[0] .getDigestAlgorithmId().toString(); diff --git a/test/jdk/sun/security/tools/jarsigner/NewSize7.java b/test/jdk/sun/security/tools/jarsigner/NewSize7.java index 8dbf15f4a38..1b75e08807a 100644 --- a/test/jdk/sun/security/tools/jarsigner/NewSize7.java +++ b/test/jdk/sun/security/tools/jarsigner/NewSize7.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2022, 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,8 @@ /* * @test - * @bug 6561126 + * @bug 6561126 8267319 + * @modules jdk.jartool/jdk.security.jarsigner * @summary keytool should use larger default keysize for keypairs * @library /test/lib */ @@ -37,8 +38,13 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.jar.JarFile; import java.util.jar.Manifest; +import jdk.security.jarsigner.JarSigner; public class NewSize7 { + + private static final String DEF_DIGEST_ALGO = + JarSigner.Builder.getDefaultDigestAlgorithm(); + public static void main(String[] args) throws Exception { String common = "-storepass changeit -keypass changeit -keystore ks "; SecurityTools.keytool(common @@ -53,13 +59,13 @@ public class NewSize7 { jf.getEntry("META-INF/MANIFEST.MF"))) { Asserts.assertTrue(new Manifest(is).getAttributes("ns7.txt") .keySet().stream() - .anyMatch(s -> s.toString().contains("SHA-256"))); + .anyMatch(s -> s.toString().contains(DEF_DIGEST_ALGO))); } try (InputStream is = jf.getInputStream( jf.getEntry("META-INF/ME.SF"))) { Asserts.assertTrue(new Manifest(is).getAttributes("ns7.txt") .keySet().stream() - .anyMatch(s -> s.toString().contains("SHA-256"))); + .anyMatch(s -> s.toString().contains(DEF_DIGEST_ALGO))); } } } diff --git a/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java b/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java index 85f185ebd0c..ed47231e004 100644 --- a/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java +++ b/test/jdk/sun/security/tools/jarsigner/PreserveRawManifestEntryAndDigest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -44,6 +44,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.zip.ZipFile; import java.util.zip.ZipEntry; +import jdk.security.jarsigner.JarSigner; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Platform; import jdk.test.lib.SecurityTools; @@ -57,7 +58,7 @@ import static org.testng.Assert.*; /** * @test - * @bug 8217375 + * @bug 8217375 8267319 * @library /test/lib * @modules jdk.jartool/sun.security.tools.jarsigner * @run testng/timeout=1200 PreserveRawManifestEntryAndDigest @@ -87,6 +88,8 @@ public class PreserveRawManifestEntryAndDigest { static final String KEYSTORE_FILENAME = "test.jks"; static final String FILENAME_INITIAL_CONTENTS = "initial-contents"; static final String FILENAME_UPDATED_CONTENTS = "updated-contents"; + private static final String DEF_DIGEST_STR = + JarSigner.Builder.getDefaultDigestAlgorithm() + "-Digest"; /** * @see sun.security.tools.jarsigner.Main#run @@ -373,9 +376,9 @@ public class PreserveRawManifestEntryAndDigest { ZipEntry eb = zip.getEntry("META-INF/B.SF"); Manifest sfb = new Manifest(zip.getInputStream(eb)); if (assertMainAttrsDigestsUnchanged) { - String mainAttrsDigKey = - (digestalg != null ? digestalg : "SHA-256") + - "-Digest-Manifest-Main-Attributes"; + String mainAttrsDigKey = (digestalg != null ? + (digestalg + "-Digest") : DEF_DIGEST_STR) + + "-Manifest-Main-Attributes"; assertEquals(sfa.getMainAttributes().getValue(mainAttrsDigKey), sfb.getMainAttributes().getValue(mainAttrsDigKey)); } @@ -418,8 +421,9 @@ public class PreserveRawManifestEntryAndDigest { "Name: " + FILENAME_INITIAL_CONTENTS.substring(0, 1) + "\r\n" + " " + FILENAME_INITIAL_CONTENTS.substring(1, 8) + "\r\n" + " " + FILENAME_INITIAL_CONTENTS.substring(8) + "\r\n" + - "SHA-256-Digest: " + m.getAttributes(FILENAME_INITIAL_CONTENTS) - .getValue("SHA-256-Digest") + "\r\n" + + DEF_DIGEST_STR + ": " + + m.getAttributes(FILENAME_INITIAL_CONTENTS) + .getValue(DEF_DIGEST_STR) + "\r\n" + "\r\n" ).getBytes(UTF_8); }); @@ -442,7 +446,7 @@ public class PreserveRawManifestEntryAndDigest { public void arbitraryLineBreaksHeader() throws Exception { test("arbitraryLineBreaksHeader", m -> { String digest = m.getAttributes(FILENAME_INITIAL_CONTENTS) - .getValue("SHA-256-Digest"); + .getValue(DEF_DIGEST_STR); return ( Name.MANIFEST_VERSION + ": 1.0\r\n" + "Created-By: " + @@ -455,7 +459,7 @@ public class PreserveRawManifestEntryAndDigest { " line breaks.\r\n" + "\r\n" + "Name: " + FILENAME_INITIAL_CONTENTS + "\r\n" + - "SHA-256-Digest: " + digest.substring(0, 11) + "\r\n" + + DEF_DIGEST_STR + ": " + digest.substring(0, 11) + "\r\n" + " " + digest.substring(11) + "\r\n" + "\r\n" ).getBytes(UTF_8); @@ -491,7 +495,7 @@ public class PreserveRawManifestEntryAndDigest { *
    • simulate a manifest as it would have been written by a JDK before 11 * by re-positioning line breaks at 70 bytes (which makes a difference by * digests that grow headers longer than 70 characters such as SHA-512 as - * opposed to default SHA-256, long file names, or manual editing)
    • + * opposed to default SHA-384, long file names, or manual editing) *
    • add a new file to the jar
    • *
    • sign the jar with a JDK 11 or 12 with a different signer
    • *

      → @@ -787,8 +791,8 @@ public class PreserveRawManifestEntryAndDigest { // with either digest or digestWorkaround has been checked by test // before. assertEquals(abSigFilesEqual(jarFilename, sf -> sf.getMainAttributes() - .getValue("SHA-256-Digest-Manifest-Main-Attributes")), - expectUnchangedDigests); + .getValue(DEF_DIGEST_STR + "-Manifest-Main-Attributes")), + expectUnchangedDigests); } /** @@ -817,7 +821,7 @@ public class PreserveRawManifestEntryAndDigest { replaceTrailingLineBreaksManipulation(trailingSeq)); assertTrue(abSigFilesEqual(jarFilename, sf -> sf.getAttributes( - FILENAME_INITIAL_CONTENTS).getValue("SHA-256-Digest"))); + FILENAME_INITIAL_CONTENTS).getValue(DEF_DIGEST_STR))); } /** @@ -857,7 +861,7 @@ public class PreserveRawManifestEntryAndDigest { }); assertTrue(abSigFilesEqual(jarFilename, sf -> sf.getAttributes( - FILENAME_INITIAL_CONTENTS).getValue("SHA-256-Digest"))); + FILENAME_INITIAL_CONTENTS).getValue(DEF_DIGEST_STR))); } /** @@ -886,7 +890,7 @@ public class PreserveRawManifestEntryAndDigest { }); assertTrue(abSigFilesEqual(jarFilename, sf -> sf.getAttributes( - FILENAME_INITIAL_CONTENTS).getValue("SHA-256-Digest"))); + FILENAME_INITIAL_CONTENTS).getValue(DEF_DIGEST_STR))); } /** @@ -917,7 +921,7 @@ public class PreserveRawManifestEntryAndDigest { null, true, true); assertTrue(abSigFilesEqual(jarFilename, sf -> sf.getAttributes( - FILENAME_INITIAL_CONTENTS).getValue("SHA-256-Digest"))); + FILENAME_INITIAL_CONTENTS).getValue(DEF_DIGEST_STR))); } /** @@ -957,7 +961,7 @@ public class PreserveRawManifestEntryAndDigest { }); assertTrue(abSigFilesEqual(jarFilename, sf -> sf.getAttributes( - FILENAME_INITIAL_CONTENTS).getValue("SHA-256-Digest"))); + FILENAME_INITIAL_CONTENTS).getValue(DEF_DIGEST_STR))); } /** @@ -993,7 +997,7 @@ public class PreserveRawManifestEntryAndDigest { }, null, true, true); assertTrue(abSigFilesEqual(jarFilename, sf -> sf.getAttributes( - FILENAME_INITIAL_CONTENTS).getValue("SHA-256-Digest"))); + FILENAME_INITIAL_CONTENTS).getValue(DEF_DIGEST_STR))); } String manifestToString(Manifest mf) { diff --git a/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java b/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java index c2beff2c317..4464314bf28 100644 --- a/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java +++ b/test/jdk/sun/security/tools/jarsigner/SectionNameContinuedVsLineBreak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -32,6 +32,7 @@ import java.util.jar.Manifest; import java.util.jar.JarFile; import jdk.test.lib.util.JarUtils; import jdk.test.lib.SecurityTools; +import jdk.security.jarsigner.JarSigner; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; @@ -39,8 +40,9 @@ import static java.nio.charset.StandardCharsets.UTF_8; /** * @test - * @bug 8217375 + * @bug 8217375 8267319 * @library /test/lib + * @modules jdk.jartool/jdk.security.jarsigner * @run testng SectionNameContinuedVsLineBreak * @summary Checks some specific line break character sequences in section name * continuation line breaks. @@ -48,6 +50,8 @@ import static java.nio.charset.StandardCharsets.UTF_8; public class SectionNameContinuedVsLineBreak { static final String KEYSTORE_FILENAME = "test.jks"; + private static final String DEF_DIGEST_STR = + JarSigner.Builder.getDefaultDigestAlgorithm() + "-Digest"; @BeforeTest public void prepareCertificate() throws Exception { @@ -107,12 +111,12 @@ public class SectionNameContinuedVsLineBreak { public void testContinueNameAfterCr() throws Exception { String filename = "abc"; test("testContinueNameAfterCr", m -> { - String digest = m.getAttributes("abc").getValue("SHA-256-Digest"); + String digest = m.getAttributes("abc").getValue(DEF_DIGEST_STR); m.getEntries().remove("abc"); return (manifestToString(m) + "Name: a\r" + " bc\r\n" - + "SHA-256-Digest: " + digest + "\r\n" + + DEF_DIGEST_STR + ": " + digest + "\r\n" + "\r\n").getBytes(UTF_8); }, filename); } @@ -126,13 +130,13 @@ public class SectionNameContinuedVsLineBreak { public void testContinueNameAfterCrOnContinuationLine() throws Exception { String filename = "abc"; test("testContinueNameAfterCr", m -> { - String digest = m.getAttributes("abc").getValue("SHA-256-Digest"); + String digest = m.getAttributes("abc").getValue(DEF_DIGEST_STR); m.getEntries().remove("abc"); return (manifestToString(m) + "Name: a\r\n" + " b\r" + " c\r\n" - + "SHA-256-Digest: " + digest + "\r\n" + + DEF_DIGEST_STR + ": " + digest + "\r\n" + "\r\n").getBytes(UTF_8); }, filename); } @@ -146,12 +150,12 @@ public class SectionNameContinuedVsLineBreak { public void testEndNameWithCrOnContinuationLine() throws Exception { String filename = "abc"; test("testContinueNameAfterCr", m -> { - String digest = m.getAttributes("abc").getValue("SHA-256-Digest"); + String digest = m.getAttributes("abc").getValue(DEF_DIGEST_STR); m.getEntries().remove("abc"); return (manifestToString(m) + "Name: a\r\n" + " bc\r" - + "SHA-256-Digest: " + digest + "\r\n" + + DEF_DIGEST_STR + ": " + digest + "\r\n" + "\r\n").getBytes(UTF_8); }, filename); } diff --git a/test/jdk/sun/security/tools/jarsigner/SignedAgain.java b/test/jdk/sun/security/tools/jarsigner/SignedAgain.java index 54cf52148c6..584712c90cc 100644 --- a/test/jdk/sun/security/tools/jarsigner/SignedAgain.java +++ b/test/jdk/sun/security/tools/jarsigner/SignedAgain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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,8 @@ /* * @test - * @bug 8215922 + * @bug 8215922 8267319 + * @modules jdk.jartool/jdk.security.jarsigner * @summary jar spec is not precise when describing jar file re-signing * @library /test/lib */ @@ -37,10 +38,15 @@ import java.util.Base64; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; +import jdk.security.jarsigner.JarSigner; import static jdk.test.lib.SecurityTools.*; public class SignedAgain { + + private static final String DEF_DIGEST = + JarSigner.Builder.getDefaultDigestAlgorithm(); + public static void main(String[] args) throws Exception { String opt = "-storepass changeit -keystore ks"; @@ -73,20 +79,20 @@ public class SignedAgain { // Hash of manifest for 2 signed JAR files String da = Base64.getEncoder().encodeToString(MessageDigest - .getInstance("SHA-256").digest(ma.readAllBytes())); + .getInstance(DEF_DIGEST).digest(ma.readAllBytes())); String db = Base64.getEncoder().encodeToString(MessageDigest - .getInstance("SHA-256").digest(mb.readAllBytes())); + .getInstance(DEF_DIGEST).digest(mb.readAllBytes())); // They are not the same Asserts.assertNotEquals(da, db); // Digest-Manifest in A.SF matches da Asserts.assertEQ(new Manifest(sa).getMainAttributes() - .getValue("SHA-256-Digest-Manifest"), da); + .getValue(DEF_DIGEST + "-Digest-Manifest"), da); // Digest-Manifest in B.SF matches db Asserts.assertEQ(new Manifest(sb).getMainAttributes() - .getValue("SHA-256-Digest-Manifest"), db); + .getValue(DEF_DIGEST + "-Digest-Manifest"), db); } } } diff --git a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java index e6794550b90..c4cf1ef6a98 100644 --- a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java +++ b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -47,6 +47,7 @@ import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.security.KeyStoreUtils; import jdk.test.lib.security.timestamp.*; import jdk.test.lib.util.JarUtils; +import jdk.security.jarsigner.JarSigner; import sun.security.pkcs.PKCS7; import sun.security.pkcs.PKCS9Attribute; import sun.security.pkcs.SignerInfo; @@ -55,13 +56,14 @@ import sun.security.timestamp.TimestampToken; /* * @test * @bug 6543842 6543440 6939248 8009636 8024302 8163304 8169911 8180289 8172404 - * 8247960 8242068 8269039 8275887 + * 8247960 8242068 8269039 8275887 8267319 * @summary checking response of timestamp * @modules java.base/sun.security.pkcs * java.base/sun.security.timestamp * java.base/sun.security.x509 * java.base/sun.security.util * java.base/sun.security.tools.keytool + * jdk.jartool/jdk.security.jarsigner * @library /lib/testlibrary * @library /test/lib * @build jdk.test.lib.util.JarUtils @@ -80,6 +82,18 @@ public class TimestampCheck { private static final String PASSWORD = "changeit"; private static final String defaultPolicyId = "2.3.4"; private static String host = null; + private static final String getDefaultSigAlg(String keyAlg) { + switch(keyAlg) { + case "DSA": + return "SHA256withDSA"; + case "RSA": + return "SHA384withRSA"; + case "EC": + return "SHA384withECDSA"; + default: + throw new RuntimeException("Error: unsupported algo " + keyAlg); + } + } private static class Interceptor implements RespInterceptor { @@ -291,7 +305,8 @@ public class TimestampCheck { sign("policy", "-tsapolicyid", "1.2.3") .shouldHaveExitValue(0); - checkTimestamp("policy.jar", "1.2.3", "SHA-256"); + checkTimestamp("policy.jar", "1.2.3", + JarSigner.Builder.getDefaultDigestAlgorithm()); sign("diffpolicy", "-tsapolicyid", "1.2.3") .shouldContain("TSAPolicyID changed in timestamp token") @@ -378,9 +393,11 @@ public class TimestampCheck { .shouldHaveExitValue(0) .shouldContain("Signature algorithm: SHA3-256withRSA") .shouldContain("Signature algorithm: RSASSA-PSS") - .shouldContain("Signature algorithm: SHA256withECDSA") + .shouldContain("Signature algorithm: " + + getDefaultSigAlg("EC")) .shouldContain("Signature algorithm: Ed25519") - .shouldContain("Signature algorithm: SHA256withDSA"); + .shouldContain("Signature algorithm: " + + getDefaultSigAlg("DSA")); // Disabled algorithms sign("tsweak", "-digestalg", "SHA1", diff --git a/test/jdk/sun/security/tools/jarsigner/compatibility/Compatibility.java b/test/jdk/sun/security/tools/jarsigner/compatibility/Compatibility.java index 4d5b28533f5..9b4b3cb785f 100644 --- a/test/jdk/sun/security/tools/jarsigner/compatibility/Compatibility.java +++ b/test/jdk/sun/security/tools/jarsigner/compatibility/Compatibility.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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 8217375 8260286 + * @bug 8217375 8260286 8267319 * @summary This test is used to verify the compatibility of jarsigner across * different JDK releases. It also can be used to check jar signing (w/ * and w/o TSA) and to verify some specific signing and digest algorithms. @@ -1192,9 +1192,9 @@ public class Compatibility { // defaults if (RSA.equals(keyAlgorithm) || DSA.equals(keyAlgorithm)) { - return 2048; + return 3072; } else if (EC.equals(keyAlgorithm)) { - return 256; + return 384; } else { throw new RuntimeException("problem determining key size"); } diff --git a/test/jdk/sun/security/tools/jarsigner/compatibility/SignTwice.java b/test/jdk/sun/security/tools/jarsigner/compatibility/SignTwice.java index e948eb6e8d3..0b4d0668edc 100644 --- a/test/jdk/sun/security/tools/jarsigner/compatibility/SignTwice.java +++ b/test/jdk/sun/security/tools/jarsigner/compatibility/SignTwice.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 @@ -22,7 +22,7 @@ */ /** - * @bug 8217375 + * @bug 8217375 8267319 * @summary This test runs those test cases of {@link Compatibility} test nearby * which can be executed within the currently built and tested JDK and without * TSA, with only one digest algorithm and with only one key (algorithm and @@ -47,6 +47,19 @@ * -DtestJarUpdate=true * -Dstrict=true * -DkeyAlgs=EC;0 + * -DdigestAlgs=SHA-384 + * SignTwice + * @run main/othervm/timeout=600 + * -Djava.security.properties=./java.security + * -Duser.language=en + * -Duser.country=US + * -DjdkList=TEST_JDK + * -DtsaList=notsa + * -Dexpired=false + * -DtestComprehensiveJarContents=true + * -DtestJarUpdate=true + * -Dstrict=true + * -DkeyAlgs=EC;0 * -DdigestAlgs=SHA-256 * SignTwice */ diff --git a/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java b/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java index 46a55e4d6fb..52ca1ead82c 100644 --- a/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java +++ b/test/jdk/sun/security/tools/keytool/GenKeyPairSigner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, 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 8260693 + * @bug 8260693 8267319 * @summary Test for keytool -genkeypair with -signer and -signerkeypass options * @library /test/lib * @modules java.base/sun.security.util @@ -186,7 +186,7 @@ public class GenKeyPairSigner { System.out.println("Generating a DH cert with -signer option"); SecurityTools.keytool("-keystore ks -storepass changeit " + "-genkeypair -keyalg DH -alias e3 -dname CN=E3 -signer ca3") - .shouldContain("Generating 2,048 bit DH key pair and a certificate (SHA256withDSA) issued by with a validity of 90 days") + .shouldContain("Generating 3,072 bit DH key pair and a certificate (SHA256withDSA) issued by with a validity of 90 days") .shouldContain("for: CN=E3") .shouldHaveExitValue(0); @@ -200,7 +200,7 @@ public class GenKeyPairSigner { pKey = cert.getPublicKey(); keyLen = KeyUtil.getKeySize(pKey); - if (keyLen != 2048) { + if (keyLen != 3072) { throw new Exception("Key size is in error"); } @@ -212,8 +212,8 @@ public class GenKeyPairSigner { SecurityTools.keytool("-keystore ks -storepass changeit " + "-list -v") .shouldContain("Alias name: e3") - .shouldContain("Signature algorithm name: SHA256withRSA") - .shouldContain("Subject Public Key Algorithm: 2048-bit DH key") + .shouldContain("Signature algorithm name: SHA384withRSA") + .shouldContain("Subject Public Key Algorithm: 3072-bit DH key") .shouldHaveExitValue(0); } @@ -239,7 +239,7 @@ public class GenKeyPairSigner { SecurityTools.keytool("-keystore ksjks -storepass changeit -storetype jks " + "-genkeypair -keyalg DSA -keysize 1024 -alias ca1 -dname CN=CA1 " + "-keypass ca1keypass -signer ca -signerkeypass cakeypass") - .shouldContain("Generating 1,024 bit DSA key pair and a certificate (SHA256withRSA) issued by with a validity of 90 days") + .shouldContain("Generating 1,024 bit DSA key pair and a certificate (SHA384withRSA) issued by with a validity of 90 days") .shouldContain("for: CN=CA1") .shouldContain("The generated certificate #1 of 2 uses a 1024-bit DSA key which is considered a security risk") .shouldContain("The generated certificate #2 of 2 uses a 1024-bit RSA key which is considered a security risk") diff --git a/test/jdk/sun/security/tools/keytool/GenerateAll.java b/test/jdk/sun/security/tools/keytool/GenerateAll.java index a9d05813f4b..5435372cdcf 100644 --- a/test/jdk/sun/security/tools/keytool/GenerateAll.java +++ b/test/jdk/sun/security/tools/keytool/GenerateAll.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 8242184 8242068 + * @bug 8242184 8242068 8267319 * @summary keytool and jarsigner for all algorithms * @library /test/lib * @modules java.base/sun.security.util @@ -117,11 +117,11 @@ public class GenerateAll { @DataProvider(name = "all") public Object[][] dataProvider() { return new Object[][]{ - {"rsa", "rsa", null, "RSA", SHA_256, SHA256withRSA}, + {"rsa", "rsa", null, "RSA", SHA_384, SHA384withRSA}, {"dsa", "dsa", null, "DSA", SHA_256, SHA256withDSA}, - {"r", "rsa", "rsassa-pss", "RSA", SHA_256, RSASSA_PSS}, - {"pss", "rsassa-pss", null, "RSA", SHA_256, RSASSA_PSS}, - {"ec", "ec", null, "EC", SHA_256, SHA256withECDSA}, + {"r", "rsa", "rsassa-pss", "RSA", SHA_384, RSASSA_PSS}, + {"pss", "rsassa-pss", null, "RSA", SHA_384, RSASSA_PSS}, + {"ec", "ec", null, "EC", SHA_384, SHA384withECDSA}, {"ed25519", "ed25519", null, "EC", SHA_512, Ed25519}, {"ed448", "ed448", null, "EC", SHAKE256_LEN, Ed448}, }; diff --git a/test/jdk/sun/security/tools/keytool/GroupName.java b/test/jdk/sun/security/tools/keytool/GroupName.java index 2251ca47fe9..938d28b6d8f 100644 --- a/test/jdk/sun/security/tools/keytool/GroupName.java +++ b/test/jdk/sun/security/tools/keytool/GroupName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -31,7 +31,7 @@ import java.security.interfaces.ECKey; /** * @test - * @bug 8213400 8214179 + * @bug 8213400 8214179 8267319 * @summary Support choosing group name in keytool keypair generation * @library /test/lib */ @@ -48,7 +48,7 @@ public class GroupName { gen("b", "-keyalg EC") .shouldHaveExitValue(0) .shouldNotContain("Specifying -keysize for generating EC keys is deprecated"); - checkCurveName("b", "secp256r1"); + checkCurveName("b", "secp384r1"); // default; if none specified gen("c", "-keyalg EC -keysize 256") .shouldHaveExitValue(0) @@ -67,7 +67,8 @@ public class GroupName { kt("-list -v") .shouldHaveExitValue(0) - .shouldContain("Subject Public Key Algorithm: 256-bit EC (secp256r1) key"); + .shouldContain("Subject Public Key Algorithm: 256-bit EC (secp256r1) key") + .shouldContain("Subject Public Key Algorithm: 384-bit EC (secp384r1) key"); } private static void checkCurveName(String a, String name) diff --git a/test/jdk/sun/security/tools/keytool/KeyAlg.java b/test/jdk/sun/security/tools/keytool/KeyAlg.java index 044568ca624..ed5061949bf 100644 --- a/test/jdk/sun/security/tools/keytool/KeyAlg.java +++ b/test/jdk/sun/security/tools/keytool/KeyAlg.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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 8029659 8214179 + * @bug 8029659 8214179 8267319 * @summary Keytool, print key algorithm of certificate or key entry * @library /test/lib */ @@ -41,9 +41,9 @@ public class KeyAlg { keytool("-printcert -file user.crt") .shouldMatch("Signature algorithm name:.*SHA1withECDSA") .shouldMatch("Subject Public Key Algorithm:.*1024.*RSA"); - keytool("-genkeypair -alias f -dname CN=f -keyalg EC") + keytool("-genkeypair -alias g -dname CN=g -keyalg EC -keysize 256") .shouldContain("Generating 256 bit EC (secp256r1) key pair"); - keytool("-genkeypair -alias g -dname CN=g -keyalg EC -keysize 384") + keytool("-genkeypair -alias f -dname CN=f -keyalg EC") .shouldContain("Generating 384 bit EC (secp384r1) key pair"); } diff --git a/test/jdk/sun/security/tools/keytool/NewSize7.java b/test/jdk/sun/security/tools/keytool/NewSize7.java index 5a7dcfa57d9..09c0f9a289a 100644 --- a/test/jdk/sun/security/tools/keytool/NewSize7.java +++ b/test/jdk/sun/security/tools/keytool/NewSize7.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2022, 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,10 +23,10 @@ /* * @test - * @bug 6561126 + * @bug 6561126 8267319 * @summary keytool should use larger default keysize for keypairs - * @modules java.base/sun.security.tools.keytool - * @compile -XDignore.symbol.file NewSize7.java + * @modules java.base/sun.security.util + * java.base/sun.security.tools.keytool * @run main NewSize7 */ @@ -37,6 +37,7 @@ import java.nio.file.Paths; import java.security.KeyStore; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; +import sun.security.util.SecurityProviderConstants; public class NewSize7 { public static void main(String[] args) throws Exception { @@ -52,11 +53,11 @@ public class NewSize7 { } Files.delete(Paths.get(FILE)); RSAPublicKey r = (RSAPublicKey)ks.getCertificate("a").getPublicKey(); - if (r.getModulus().bitLength() != 2048) { + if (r.getModulus().bitLength() != 3072) { throw new Exception("Bad keysize"); } X509Certificate x = (X509Certificate)ks.getCertificate("a"); - if (!x.getSigAlgName().equals("SHA256withRSA")) { + if (!x.getSigAlgName().equals("SHA384withRSA")) { throw new Exception("Bad sigalg"); } } diff --git a/test/jdk/sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java b/test/jdk/sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java index b4ae0e21c76..5f0822440fc 100644 --- a/test/jdk/sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java +++ b/test/jdk/sun/security/tools/keytool/fakegen/DefaultSignatureAlgorithm.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 8138766 8227059 8227595 + * @bug 8138766 8227059 8227595 8267319 * @summary New default -sigalg for keytool * @library /test/lib * @build java.base/sun.security.rsa.RSAKeyPairGenerator @@ -46,8 +46,8 @@ public class DefaultSignatureAlgorithm { static int pos = 0; public static void main(String[] args) throws Exception { - check("RSA", 1024, null, "SHA256withRSA"); - check("RSA", 3072, null, "SHA256withRSA"); + check("RSA", 1024, null, "SHA384withRSA"); + check("RSA", 3072, null, "SHA384withRSA"); check("RSA", 3073, null, "SHA384withRSA"); check("RSA", 7680, null, "SHA384withRSA"); check("RSA", 7681, null, "SHA512withRSA"); diff --git a/test/jdk/sun/security/tools/keytool/fakegen/PSS.java b/test/jdk/sun/security/tools/keytool/fakegen/PSS.java index 72f74526189..9e7de9b757d 100644 --- a/test/jdk/sun/security/tools/keytool/fakegen/PSS.java +++ b/test/jdk/sun/security/tools/keytool/fakegen/PSS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2022, 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 8215694 8222987 8225257 + * @bug 8215694 8222987 8225257 8267319 * @summary keytool cannot generate RSASSA-PSS certificates * @library /test/lib * @build java.base/sun.security.rsa.RSAKeyPairGenerator @@ -63,10 +63,10 @@ public class PSS { new File("ks"), "changeit".toCharArray()); check((X509Certificate)ks.getCertificate("p"), "RSASSA-PSS", - AlgorithmId.SHA256_oid); + AlgorithmId.SHA384_oid); check((X509Certificate)ks.getCertificate("a"), "RSA", - AlgorithmId.SHA256_oid); + AlgorithmId.SHA384_oid); check((X509Certificate)ks.getCertificate("b"), "RSA", AlgorithmId.SHA384_oid); -- GitLab From 6b59760da69ff769d30950cb4ec6ebf684d1bf50 Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Fri, 25 Mar 2022 05:18:26 +0000 Subject: [PATCH 164/237] 8283608: Refactor 2d, beans classes javadoc to use @throws instead of @exception Reviewed-by: iris, prr --- .../com/sun/media/sound/AiffFileReader.java | 2 +- .../com/sun/media/sound/AiffFileWriter.java | 2 +- .../com/sun/media/sound/SunFileReader.java | 4 ++-- .../com/sun/media/sound/SunFileWriter.java | 4 ++-- .../share/classes/java/beans/Beans.java | 16 ++++++++-------- .../classes/java/beans/EventSetDescriptor.java | 12 ++++++------ .../java/beans/IndexedPropertyDescriptor.java | 6 +++--- .../share/classes/java/beans/Introspector.java | 10 +++++----- .../classes/java/beans/PropertyDescriptor.java | 6 +++--- .../java/beans/PropertyEditorManager.java | 2 +- .../java/beans/VetoableChangeListener.java | 2 +- .../java/beans/VetoableChangeListenerProxy.java | 2 +- .../beancontext/BeanContextMembershipEvent.java | 2 +- .../share/classes/sun/awt/AppContext.java | 4 ++-- .../share/classes/sun/awt/im/InputContext.java | 14 +++++++------- .../classes/sun/awt/im/InputMethodAdapter.java | 2 +- .../share/classes/sun/awt/shell/ShellFolder.java | 3 +-- .../classes/sun/awt/util/IdentityArrayList.java | 2 +- .../share/classes/sun/java2d/SunGraphics2D.java | 2 +- .../share/classes/sun/print/PSPrinterJob.java | 2 +- .../share/classes/sun/print/PrintJob2D.java | 2 +- .../classes/sun/print/RasterPrinterJob.java | 10 +++++----- 22 files changed, 55 insertions(+), 56 deletions(-) diff --git a/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java b/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java index c8d9cd8d2db..6ef0695c70d 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/AiffFileReader.java @@ -172,7 +172,7 @@ public final class AiffFileReader extends SunFileReader { * Extended precision IEEE floating-point conversion routine. * @argument DataInputStream * @return double - * @exception IOException + * @throws IOException */ private double read_ieee_extended(DataInputStream dis) throws IOException { diff --git a/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java b/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java index d384bf279c4..3738a557aef 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/AiffFileWriter.java @@ -392,7 +392,7 @@ public final class AiffFileWriter extends SunFileWriter { * Extended precision IEEE floating-point conversion routine. * @argument DataOutputStream * @argument double - * @exception IOException + * @throws IOException */ private void write_ieee_extended(DataOutputStream dos, float f) throws IOException { /* The special cases NaN, Infinity and Zero are ignored, since diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java b/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java index ef995f81294..89323cfe3c3 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SunFileReader.java @@ -164,7 +164,7 @@ abstract class SunFileReader extends AudioFileReader { * Protected helper method to read 64 bits and changing the order of * each bytes. * @return 32 bits swapped value. - * @exception IOException + * @throws IOException */ final int rllong(DataInputStream dis) throws IOException { @@ -206,7 +206,7 @@ abstract class SunFileReader extends AudioFileReader { * rlshort * Protected helper method to read 16 bits value. Swap high with low byte. * @return the swapped value. - * @exception IOException + * @throws IOException */ final short rlshort(DataInputStream dis) throws IOException { diff --git a/src/java.desktop/share/classes/com/sun/media/sound/SunFileWriter.java b/src/java.desktop/share/classes/com/sun/media/sound/SunFileWriter.java index 1d54bcfe91c..8e85f1e743f 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/SunFileWriter.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/SunFileWriter.java @@ -70,7 +70,7 @@ abstract class SunFileWriter extends AudioFileWriter { * Protected helper method to read 64 bits and changing the order of * each bytes. * @return 32 bits swapped value. - * @exception IOException + * @throws IOException */ final int rllong(DataInputStream dis) throws IOException { @@ -112,7 +112,7 @@ abstract class SunFileWriter extends AudioFileWriter { * rlshort * Protected helper method to read 16 bits value. Swap high with low byte. * @return the swapped value. - * @exception IOException + * @throws IOException */ final short rlshort(DataInputStream dis) throws IOException { diff --git a/src/java.desktop/share/classes/java/beans/Beans.java b/src/java.desktop/share/classes/java/beans/Beans.java index dbe678b7092..36a424664de 100644 --- a/src/java.desktop/share/classes/java/beans/Beans.java +++ b/src/java.desktop/share/classes/java/beans/Beans.java @@ -75,9 +75,9 @@ public class Beans { * @param beanName the name of the bean within the class-loader. * For example "sun.beanbox.foobah" * - * @exception ClassNotFoundException if the class of a serialized + * @throws ClassNotFoundException if the class of a serialized * object could not be found. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. */ public static Object instantiate(ClassLoader cls, String beanName) throws IOException, ClassNotFoundException { @@ -97,9 +97,9 @@ public class Beans { * For example "sun.beanbox.foobah" * @param beanContext The BeanContext in which to nest the new bean * - * @exception ClassNotFoundException if the class of a serialized + * @throws ClassNotFoundException if the class of a serialized * object could not be found. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @since 1.2 */ @SuppressWarnings("deprecation") @@ -156,9 +156,9 @@ public class Beans { * @param beanContext The BeanContext in which to nest the new bean * @param initializer The AppletInitializer for the new bean * - * @exception ClassNotFoundException if the class of a serialized + * @throws ClassNotFoundException if the class of a serialized * object could not be found. - * @exception IOException if an I/O error occurs. + * @throws IOException if an I/O error occurs. * @since 1.2 * * @deprecated It is recommended to use @@ -432,7 +432,7 @@ public class Beans { * method is called. This could result in a SecurityException. * * @param isDesignTime True if we're in an application builder tool. - * @exception SecurityException if a security manager exists and its + * @throws SecurityException if a security manager exists and its * {@code checkPropertiesAccess} method doesn't allow setting * of system properties. * @see SecurityManager#checkPropertiesAccess @@ -459,7 +459,7 @@ public class Beans { * method is called. This could result in a SecurityException. * * @param isGuiAvailable True if GUI interaction is available. - * @exception SecurityException if a security manager exists and its + * @throws SecurityException if a security manager exists and its * {@code checkPropertiesAccess} method doesn't allow setting * of system properties. * @see SecurityManager#checkPropertiesAccess diff --git a/src/java.desktop/share/classes/java/beans/EventSetDescriptor.java b/src/java.desktop/share/classes/java/beans/EventSetDescriptor.java index 87fa860cf7c..8826ff27902 100644 --- a/src/java.desktop/share/classes/java/beans/EventSetDescriptor.java +++ b/src/java.desktop/share/classes/java/beans/EventSetDescriptor.java @@ -69,7 +69,7 @@ public class EventSetDescriptor extends FeatureDescriptor { * will get delivered to. * @param listenerMethodName The method that will get called when the event gets * delivered to its target listener interface. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public EventSetDescriptor(Class sourceClass, String eventSetName, @@ -114,7 +114,7 @@ public class EventSetDescriptor extends FeatureDescriptor { * that can be used to register an event listener object. * @param removeListenerMethodName The name of the method on the event source * that can be used to de-register an event listener object. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public EventSetDescriptor(Class sourceClass, @@ -146,7 +146,7 @@ public class EventSetDescriptor extends FeatureDescriptor { * that can be used to de-register an event listener object. * @param getListenerMethodName The method on the event source that * can be used to access the array of event listener objects. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. * @since 1.4 */ @@ -210,7 +210,7 @@ public class EventSetDescriptor extends FeatureDescriptor { * that can be used to register an event listener object. * @param removeListenerMethod The method on the event source * that can be used to de-register an event listener object. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public EventSetDescriptor(String eventSetName, @@ -237,7 +237,7 @@ public class EventSetDescriptor extends FeatureDescriptor { * that can be used to de-register an event listener object. * @param getListenerMethod The method on the event source * that can be used to access the array of event listener objects. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. * @since 1.4 */ @@ -280,7 +280,7 @@ public class EventSetDescriptor extends FeatureDescriptor { * that can be used to register an event listener object. * @param removeListenerMethod The method on the event source * that can be used to de-register an event listener object. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public EventSetDescriptor(String eventSetName, diff --git a/src/java.desktop/share/classes/java/beans/IndexedPropertyDescriptor.java b/src/java.desktop/share/classes/java/beans/IndexedPropertyDescriptor.java index b49b1cb07a9..a46c8ec9d6e 100644 --- a/src/java.desktop/share/classes/java/beans/IndexedPropertyDescriptor.java +++ b/src/java.desktop/share/classes/java/beans/IndexedPropertyDescriptor.java @@ -63,7 +63,7 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor { * * @param propertyName The programmatic name of the property. * @param beanClass The Class object for the target bean. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public IndexedPropertyDescriptor(String propertyName, Class beanClass) @@ -94,7 +94,7 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor { * @param indexedWriteMethodName The name of the method used for writing * an indexed property value. * May be null if the property is read-only. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public IndexedPropertyDescriptor(String propertyName, Class beanClass, @@ -129,7 +129,7 @@ public class IndexedPropertyDescriptor extends PropertyDescriptor { * May be null if the property is write-only. * @param indexedWriteMethod The method used for writing an indexed property value. * May be null if the property is read-only. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public IndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod, diff --git a/src/java.desktop/share/classes/java/beans/Introspector.java b/src/java.desktop/share/classes/java/beans/Introspector.java index f73444a54ef..88225ab01d4 100644 --- a/src/java.desktop/share/classes/java/beans/Introspector.java +++ b/src/java.desktop/share/classes/java/beans/Introspector.java @@ -178,7 +178,7 @@ public class Introspector { * * @param beanClass The bean class to be analyzed. * @return A BeanInfo object describing the target bean. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. * @see #flushCaches * @see #flushFromCaches @@ -216,7 +216,7 @@ public class Introspector { * associated with the specified beanClass or any of its * parent classes. * @return A BeanInfo object describing the target bean. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. * @since 1.2 */ @@ -237,7 +237,7 @@ public class Introspector { * @param stopClass The baseclass at which to stop the analysis. Any * methods/properties/events in the stopClass or in its baseclasses * will be ignored in the analysis. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public static BeanInfo getBeanInfo(Class beanClass, Class stopClass) @@ -269,7 +269,7 @@ public class Introspector { * @param stopClass the parent class at which to stop the analysis * @param flags flags to control the introspection * @return a BeanInfo object describing the target bean - * @exception IntrospectionException if an exception occurs during introspection + * @throws IntrospectionException if an exception occurs during introspection * * @since 1.7 */ @@ -339,7 +339,7 @@ public class Introspector { * method is called. This could result in a SecurityException. * * @param path Array of package names. - * @exception SecurityException if a security manager exists and its + * @throws SecurityException if a security manager exists and its * {@code checkPropertiesAccess} method doesn't allow setting * of system properties. * @see SecurityManager#checkPropertiesAccess diff --git a/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java b/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java index d63c446f373..ae4bb69c18c 100644 --- a/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java +++ b/src/java.desktop/share/classes/java/beans/PropertyDescriptor.java @@ -66,7 +66,7 @@ public class PropertyDescriptor extends FeatureDescriptor { * @param propertyName The programmatic name of the property. * @param beanClass The Class object for the target bean. For * example sun.beans.OurButton.class. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public PropertyDescriptor(String propertyName, Class beanClass) @@ -87,7 +87,7 @@ public class PropertyDescriptor extends FeatureDescriptor { * value. May be null if the property is write-only. * @param writeMethodName The name of the method used for writing the property * value. May be null if the property is read-only. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public PropertyDescriptor(String propertyName, Class beanClass, @@ -129,7 +129,7 @@ public class PropertyDescriptor extends FeatureDescriptor { * May be null if the property is write-only. * @param writeMethod The method used for writing the property value. * May be null if the property is read-only. - * @exception IntrospectionException if an exception occurs during + * @throws IntrospectionException if an exception occurs during * introspection. */ public PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod) diff --git a/src/java.desktop/share/classes/java/beans/PropertyEditorManager.java b/src/java.desktop/share/classes/java/beans/PropertyEditorManager.java index 3642c0c58be..a692c921421 100644 --- a/src/java.desktop/share/classes/java/beans/PropertyEditorManager.java +++ b/src/java.desktop/share/classes/java/beans/PropertyEditorManager.java @@ -118,7 +118,7 @@ public class PropertyEditorManager { * method is called. This could result in a SecurityException. * * @param path Array of package names. - * @exception SecurityException if a security manager exists and its + * @throws SecurityException if a security manager exists and its * {@code checkPropertiesAccess} method doesn't allow setting * of system properties. * @see SecurityManager#checkPropertiesAccess diff --git a/src/java.desktop/share/classes/java/beans/VetoableChangeListener.java b/src/java.desktop/share/classes/java/beans/VetoableChangeListener.java index ae473becad9..1c20a9926e5 100644 --- a/src/java.desktop/share/classes/java/beans/VetoableChangeListener.java +++ b/src/java.desktop/share/classes/java/beans/VetoableChangeListener.java @@ -37,7 +37,7 @@ public interface VetoableChangeListener extends java.util.EventListener { * * @param evt a {@code PropertyChangeEvent} object describing the * event source and the property that has changed. - * @exception PropertyVetoException if the recipient wishes the property + * @throws PropertyVetoException if the recipient wishes the property * change to be rolled back. */ void vetoableChange(PropertyChangeEvent evt) diff --git a/src/java.desktop/share/classes/java/beans/VetoableChangeListenerProxy.java b/src/java.desktop/share/classes/java/beans/VetoableChangeListenerProxy.java index 9a0438790c1..4e4ad96ebd8 100644 --- a/src/java.desktop/share/classes/java/beans/VetoableChangeListenerProxy.java +++ b/src/java.desktop/share/classes/java/beans/VetoableChangeListenerProxy.java @@ -66,7 +66,7 @@ public class VetoableChangeListenerProxy * * @param event the property change event * - * @exception PropertyVetoException if the recipient wishes the property + * @throws PropertyVetoException if the recipient wishes the property * change to be rolled back */ public void vetoableChange(PropertyChangeEvent event) throws PropertyVetoException{ diff --git a/src/java.desktop/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java b/src/java.desktop/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java index 13279894ce6..ecdd4794d38 100644 --- a/src/java.desktop/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java +++ b/src/java.desktop/share/classes/java/beans/beancontext/BeanContextMembershipEvent.java @@ -81,7 +81,7 @@ public class BeanContextMembershipEvent extends BeanContextEvent { * * @param bc The BeanContext source * @param changes The Children effected - * @exception NullPointerException if changes associated with this + * @throws NullPointerException if changes associated with this * event are null. */ diff --git a/src/java.desktop/share/classes/sun/awt/AppContext.java b/src/java.desktop/share/classes/sun/awt/AppContext.java index 6ed0b2b325e..741b52d8bae 100644 --- a/src/java.desktop/share/classes/sun/awt/AppContext.java +++ b/src/java.desktop/share/classes/sun/awt/AppContext.java @@ -391,7 +391,7 @@ public final class AppContext { * This method must be called from a Thread which is not contained * within this AppContext. * - * @exception IllegalThreadStateException if the current thread is + * @throws IllegalThreadStateException if the current thread is * contained within this AppContext * @since 1.2 */ @@ -660,7 +660,7 @@ public final class AppContext { * @param value the value. * @return the previous value of the specified key in this * AppContext, or {@code null} if it did not have one. - * @exception NullPointerException if the key or value is + * @throws NullPointerException if the key or value is * {@code null}. * @see #get(Object) * @since 1.2 diff --git a/src/java.desktop/share/classes/sun/awt/im/InputContext.java b/src/java.desktop/share/classes/sun/awt/im/InputContext.java index c35d17bfae3..237164a9d42 100644 --- a/src/java.desktop/share/classes/sun/awt/im/InputContext.java +++ b/src/java.desktop/share/classes/sun/awt/im/InputContext.java @@ -133,7 +133,7 @@ public class InputContext extends java.awt.im.InputContext /** * @see java.awt.im.InputContext#selectInputMethod - * @exception NullPointerException when the locale is null. + * @throws NullPointerException when the locale is null. */ public synchronized boolean selectInputMethod(Locale locale) { if (locale == null) { @@ -206,7 +206,7 @@ public class InputContext extends java.awt.im.InputContext /** * @see java.awt.im.InputContext#reconvert * @since 1.3 - * @exception UnsupportedOperationException when input method is null + * @throws UnsupportedOperationException when input method is null */ public synchronized void reconvert() { InputMethod inputMethod = getInputMethod(); @@ -610,7 +610,7 @@ public class InputContext extends java.awt.im.InputContext /** * @see java.awt.im.InputContext#removeNotify - * @exception NullPointerException when the component is null. + * @throws NullPointerException when the component is null. */ public synchronized void removeNotify(Component component) { if (component == null) { @@ -662,7 +662,7 @@ public class InputContext extends java.awt.im.InputContext /** * @see java.awt.im.InputContext#dispose - * @exception IllegalStateException when the currentClientComponent is not null + * @throws IllegalStateException when the currentClientComponent is not null */ public synchronized void dispose() { if (currentClientComponent != null) { @@ -723,7 +723,7 @@ public class InputContext extends java.awt.im.InputContext /** * @see java.awt.im.InputContext#setCompositionEnabled(boolean) - * @exception UnsupportedOperationException when input method is null + * @throws UnsupportedOperationException when input method is null */ public void setCompositionEnabled(boolean enable) { InputMethod inputMethod = getInputMethod(); @@ -736,7 +736,7 @@ public class InputContext extends java.awt.im.InputContext /** * @see java.awt.im.InputContext#isCompositionEnabled - * @exception UnsupportedOperationException when input method is null + * @throws UnsupportedOperationException when input method is null */ public boolean isCompositionEnabled() { InputMethod inputMethod = getInputMethod(); @@ -749,7 +749,7 @@ public class InputContext extends java.awt.im.InputContext /** * @return a string with information about the current input method. - * @exception UnsupportedOperationException when input method is null + * @throws UnsupportedOperationException when input method is null */ public String getInputMethodInfo() { InputMethod inputMethod = getInputMethod(); diff --git a/src/java.desktop/share/classes/sun/awt/im/InputMethodAdapter.java b/src/java.desktop/share/classes/sun/awt/im/InputMethodAdapter.java index dfc31799bfb..b70f5bbbf71 100644 --- a/src/java.desktop/share/classes/sun/awt/im/InputMethodAdapter.java +++ b/src/java.desktop/share/classes/sun/awt/im/InputMethodAdapter.java @@ -93,7 +93,7 @@ public abstract class InputMethodAdapter implements InputMethod { /** * Starts reconvertion. An implementing host adapter has to override * this method if it can support reconvert(). - * @exception UnsupportedOperationException when the adapter does not override + * @throws UnsupportedOperationException when the adapter does not override * the method. */ public void reconvert() { diff --git a/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java b/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java index 3aa91dcb600..1f95995a222 100644 --- a/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java +++ b/src/java.desktop/share/classes/sun/awt/shell/ShellFolder.java @@ -253,13 +253,12 @@ public abstract class ShellFolder extends File { /** * Return a shell folder from a file object - * @exception FileNotFoundException if file does not exist + * @throws FileNotFoundException if file does not exist */ public static ShellFolder getShellFolder(File file) throws FileNotFoundException { if (file instanceof ShellFolder) { return (ShellFolder)file; } - if (!Files.exists(Paths.get(file.getPath()), LinkOption.NOFOLLOW_LINKS)) { throw new FileNotFoundException(); } diff --git a/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java b/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java index 98f93cc3ec7..202a55a8135 100644 --- a/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java +++ b/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java @@ -113,7 +113,7 @@ public class IdentityArrayList extends AbstractList * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list - * @exception IllegalArgumentException if the specified initial capacity + * @throws IllegalArgumentException if the specified initial capacity * is negative */ public IdentityArrayList(int initialCapacity) { diff --git a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java index 193a8a38587..5c681b454b9 100644 --- a/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java +++ b/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java @@ -409,7 +409,7 @@ public final class SunGraphics2D * drawback of the workaround is that the resulting * clip and device origin cannot be "enforced". * - * @exception IllegalStateException If the Graphics + * @throws IllegalStateException If the Graphics * to be constrained has a complex transform. */ @Override diff --git a/src/java.desktop/share/classes/sun/print/PSPrinterJob.java b/src/java.desktop/share/classes/sun/print/PSPrinterJob.java index 61450e49553..01a24adfda4 100644 --- a/src/java.desktop/share/classes/sun/print/PSPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/PSPrinterJob.java @@ -418,7 +418,7 @@ public class PSPrinterJob extends RasterPrinterJob { * print job interactively. * @return false if the user cancels the dialog and * true otherwise. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ diff --git a/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/src/java.desktop/share/classes/sun/print/PrintJob2D.java index 9083bd3e269..7a238383ce8 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -966,7 +966,7 @@ public class PrintJob2D extends PrintJob implements Printable, Runnable { * @return PAGE_EXISTS if the page is rendered successfully * or NO_SUCH_PAGE if {@code pageIndex} specifies a * non-existent page. - * @exception java.awt.print.PrinterException + * @throws java.awt.print.PrinterException * thrown when the print job is terminated. */ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index 6ceeb48df85..ffdebb82d0b 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -714,7 +714,7 @@ public abstract class RasterPrinterJob extends PrinterJob { * is cancelled, or a new PageFormat object containing * the format indicated by the user if the dialog is * acknowledged - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 @@ -947,7 +947,7 @@ public abstract class RasterPrinterJob extends PrinterJob { * * @param attributes to store changed properties. * @return false if the user cancels the dialog and true otherwise. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -1100,7 +1100,7 @@ public abstract class RasterPrinterJob extends PrinterJob { * print job interactively. * @return false if the user cancels the dialog and * true otherwise. - * @exception HeadlessException if GraphicsEnvironment.isHeadless() + * @throws HeadlessException if GraphicsEnvironment.isHeadless() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ @@ -1183,7 +1183,7 @@ public abstract class RasterPrinterJob extends PrinterJob { * for the number of pages as well as the PageFormat and * Printable for each page. * @param document The document to be printed. It may not be null. - * @exception NullPointerException the Pageable passed in was null. + * @throws NullPointerException the Pageable passed in was null. * @see PageFormat * @see Printable */ @@ -1477,7 +1477,7 @@ public abstract class RasterPrinterJob extends PrinterJob { /** * Prints a set of pages. - * @exception java.awt.print.PrinterException an error in the print system + * @throws java.awt.print.PrinterException an error in the print system * caused the job to be aborted * @see java.awt.print.Book * @see java.awt.print.Pageable -- GitLab From 636225b8151d1bd53349a314fb50b682d6effcd2 Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 25 Mar 2022 08:17:45 +0000 Subject: [PATCH 165/237] 8283607: Rename KlassID to KlassKind Reviewed-by: dholmes, tschatzl --- src/hotspot/share/memory/iterator.inline.hpp | 40 ++++++++-------- src/hotspot/share/oops/arrayKlass.cpp | 4 +- src/hotspot/share/oops/arrayKlass.hpp | 2 +- .../share/oops/instanceClassLoaderKlass.hpp | 4 +- src/hotspot/share/oops/instanceKlass.cpp | 4 +- src/hotspot/share/oops/instanceKlass.hpp | 4 +- .../share/oops/instanceMirrorKlass.hpp | 4 +- src/hotspot/share/oops/instanceRefKlass.hpp | 4 +- src/hotspot/share/oops/klass.cpp | 2 +- src/hotspot/share/oops/klass.hpp | 46 ++++++++++--------- src/hotspot/share/oops/objArrayKlass.cpp | 2 +- src/hotspot/share/oops/objArrayKlass.hpp | 2 +- src/hotspot/share/oops/typeArrayKlass.cpp | 2 +- src/hotspot/share/oops/typeArrayKlass.hpp | 2 +- 14 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/hotspot/share/memory/iterator.inline.hpp b/src/hotspot/share/memory/iterator.inline.hpp index cc339f2213d..90d705ccab6 100644 --- a/src/hotspot/share/memory/iterator.inline.hpp +++ b/src/hotspot/share/memory/iterator.inline.hpp @@ -174,7 +174,7 @@ void Devirtualizer::do_cld(OopClosureType* closure, ClassLoaderData* cld) { // It allows for a single call to do a multi-dispatch to an optimized version // of oop_oop_iterate that statically know all these types: // - OopClosureType : static type give at call site -// - Klass* : dynamic to static type through Klass::id() -> table index +// - Klass* : dynamic to static type through Klass::kind() -> table index // - UseCompressedOops : dynamic to static value determined once // // when users call obj->oop_iterate(&cl). @@ -190,7 +190,7 @@ void Devirtualizer::do_cld(OopClosureType* closure, ClassLoaderData* cld) { // used when calling do_oop. // // Klass* : -// A table mapping from *Klass::ID to function is setup. This happens once +// A table mapping from *Klass::Kind to function is setup. This happens once // when the program starts, when the static _table instance is initialized for // the OopOopIterateDispatch specialized with the OopClosureType. // @@ -223,7 +223,7 @@ private: template void set_init_function() { - _function[KlassType::ID] = &init; + _function[KlassType::Kind] = &init; } template @@ -232,20 +232,20 @@ private: // when functions pointers are updated. STATIC_ASSERT(sizeof(_function[0]) == sizeof(void*)); if (UseCompressedOops) { - _function[KlassType::ID] = &oop_oop_iterate; + _function[KlassType::Kind] = &oop_oop_iterate; } else { - _function[KlassType::ID] = &oop_oop_iterate; + _function[KlassType::Kind] = &oop_oop_iterate; } } template void set_resolve_function_and_execute(OopClosureType* cl, oop obj, Klass* k) { set_resolve_function(); - _function[KlassType::ID](cl, obj, k); + _function[KlassType::Kind](cl, obj, k); } public: - FunctionType _function[KLASS_ID_COUNT]; + FunctionType _function[KLASS_KIND_COUNT]; Table(){ set_init_function(); @@ -261,7 +261,7 @@ private: public: static FunctionType function(Klass* klass) { - return _table._function[klass->id()]; + return _table._function[klass->kind()]; } }; @@ -288,26 +288,26 @@ private: template void set_init_function() { - _function[KlassType::ID] = &init; + _function[KlassType::Kind] = &init; } template void set_resolve_function() { if (UseCompressedOops) { - _function[KlassType::ID] = &oop_oop_iterate_bounded; + _function[KlassType::Kind] = &oop_oop_iterate_bounded; } else { - _function[KlassType::ID] = &oop_oop_iterate_bounded; + _function[KlassType::Kind] = &oop_oop_iterate_bounded; } } template void set_resolve_function_and_execute(OopClosureType* cl, oop obj, Klass* k, MemRegion mr) { set_resolve_function(); - _function[KlassType::ID](cl, obj, k, mr); + _function[KlassType::Kind](cl, obj, k, mr); } public: - FunctionType _function[KLASS_ID_COUNT]; + FunctionType _function[KLASS_KIND_COUNT]; Table(){ set_init_function(); @@ -323,7 +323,7 @@ private: public: static FunctionType function(Klass* klass) { - return _table._function[klass->id()]; + return _table._function[klass->kind()]; } }; @@ -350,26 +350,26 @@ private: template void set_init_function() { - _function[KlassType::ID] = &init; + _function[KlassType::Kind] = &init; } template void set_resolve_function() { if (UseCompressedOops) { - _function[KlassType::ID] = &oop_oop_iterate_backwards; + _function[KlassType::Kind] = &oop_oop_iterate_backwards; } else { - _function[KlassType::ID] = &oop_oop_iterate_backwards; + _function[KlassType::Kind] = &oop_oop_iterate_backwards; } } template void set_resolve_function_and_execute(OopClosureType* cl, oop obj, Klass* k) { set_resolve_function(); - _function[KlassType::ID](cl, obj, k); + _function[KlassType::Kind](cl, obj, k); } public: - FunctionType _function[KLASS_ID_COUNT]; + FunctionType _function[KLASS_KIND_COUNT]; Table(){ set_init_function(); @@ -385,7 +385,7 @@ private: public: static FunctionType function(Klass* klass) { - return _table._function[klass->id()]; + return _table._function[klass->kind()]; } }; diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp index c28ce0323b7..5a276fda3d6 100644 --- a/src/hotspot/share/oops/arrayKlass.cpp +++ b/src/hotspot/share/oops/arrayKlass.cpp @@ -83,8 +83,8 @@ Method* ArrayKlass::uncached_lookup_method(const Symbol* name, return super()->uncached_lookup_method(name, signature, OverpassLookupMode::skip, private_mode); } -ArrayKlass::ArrayKlass(Symbol* name, KlassID id) : - Klass(id), +ArrayKlass::ArrayKlass(Symbol* name, KlassKind kind) : + Klass(kind), _dimension(1), _higher_dimension(NULL), _lower_dimension(NULL) { diff --git a/src/hotspot/share/oops/arrayKlass.hpp b/src/hotspot/share/oops/arrayKlass.hpp index bed87db0d2a..62138ce862d 100644 --- a/src/hotspot/share/oops/arrayKlass.hpp +++ b/src/hotspot/share/oops/arrayKlass.hpp @@ -45,7 +45,7 @@ class ArrayKlass: public Klass { // Constructors // The constructor with the Symbol argument does the real array // initialization, the other is a dummy - ArrayKlass(Symbol* name, KlassID id); + ArrayKlass(Symbol* name, KlassKind kind); ArrayKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for cds"); } public: diff --git a/src/hotspot/share/oops/instanceClassLoaderKlass.hpp b/src/hotspot/share/oops/instanceClassLoaderKlass.hpp index e1a42ae3181..559878a1c67 100644 --- a/src/hotspot/share/oops/instanceClassLoaderKlass.hpp +++ b/src/hotspot/share/oops/instanceClassLoaderKlass.hpp @@ -40,10 +40,10 @@ class InstanceClassLoaderKlass: public InstanceKlass { friend class VMStructs; friend class InstanceKlass; public: - static const KlassID ID = InstanceClassLoaderKlassID; + static const KlassKind Kind = InstanceClassLoaderKlassKind; private: - InstanceClassLoaderKlass(const ClassFileParser& parser) : InstanceKlass(parser, ID) {} + InstanceClassLoaderKlass(const ClassFileParser& parser) : InstanceKlass(parser, Kind) {} public: InstanceClassLoaderKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index f5dcaebd96a..7e761c07f66 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -485,8 +485,8 @@ Array* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) { return vtable_indices; } -InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassID id) : - Klass(id), +InstanceKlass::InstanceKlass(const ClassFileParser& parser, KlassKind kind) : + Klass(kind), _nest_members(NULL), _nest_host(NULL), _permitted_subclasses(NULL), diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 623c3e24a95..91465272631 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -133,10 +133,10 @@ class InstanceKlass: public Klass { friend class CompileReplay; public: - static const KlassID ID = InstanceKlassID; + static const KlassKind Kind = InstanceKlassKind; protected: - InstanceKlass(const ClassFileParser& parser, KlassID id = ID); + InstanceKlass(const ClassFileParser& parser, KlassKind kind = Kind); public: InstanceKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } diff --git a/src/hotspot/share/oops/instanceMirrorKlass.hpp b/src/hotspot/share/oops/instanceMirrorKlass.hpp index 00258e13bc3..cb1ee2efba4 100644 --- a/src/hotspot/share/oops/instanceMirrorKlass.hpp +++ b/src/hotspot/share/oops/instanceMirrorKlass.hpp @@ -45,12 +45,12 @@ class InstanceMirrorKlass: public InstanceKlass { friend class InstanceKlass; public: - static const KlassID ID = InstanceMirrorKlassID; + static const KlassKind Kind = InstanceMirrorKlassKind; private: static int _offset_of_static_fields; - InstanceMirrorKlass(const ClassFileParser& parser) : InstanceKlass(parser, ID) {} + InstanceMirrorKlass(const ClassFileParser& parser) : InstanceKlass(parser, Kind) {} public: InstanceMirrorKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } diff --git a/src/hotspot/share/oops/instanceRefKlass.hpp b/src/hotspot/share/oops/instanceRefKlass.hpp index 5e271ebb762..5965e072a22 100644 --- a/src/hotspot/share/oops/instanceRefKlass.hpp +++ b/src/hotspot/share/oops/instanceRefKlass.hpp @@ -50,10 +50,10 @@ class ClassFileParser; class InstanceRefKlass: public InstanceKlass { friend class InstanceKlass; public: - static const KlassID ID = InstanceRefKlassID; + static const KlassKind Kind = InstanceRefKlassKind; private: - InstanceRefKlass(const ClassFileParser& parser) : InstanceKlass(parser, ID) {} + InstanceRefKlass(const ClassFileParser& parser) : InstanceKlass(parser, Kind) {} public: InstanceRefKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp index f431c2425d8..856669e44ca 100644 --- a/src/hotspot/share/oops/klass.cpp +++ b/src/hotspot/share/oops/klass.cpp @@ -201,7 +201,7 @@ void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word // which zeros out memory - calloc equivalent. // The constructor is also used from CppVtableCloner, // which doesn't zero out the memory before calling the constructor. -Klass::Klass(KlassID id) : _id(id), +Klass::Klass(KlassKind kind) : _kind(kind), _shared_class_path_index(-1) { CDS_ONLY(_shared_class_flags = 0;) CDS_JAVA_HEAP_ONLY(_archived_mirror_index = -1;) diff --git a/src/hotspot/share/oops/klass.hpp b/src/hotspot/share/oops/klass.hpp index f82ba4d9970..3d1d98c7037 100644 --- a/src/hotspot/share/oops/klass.hpp +++ b/src/hotspot/share/oops/klass.hpp @@ -37,17 +37,17 @@ #include "jfr/support/jfrTraceIdExtension.hpp" #endif -// Klass IDs for all subclasses of Klass -enum KlassID { - InstanceKlassID, - InstanceRefKlassID, - InstanceMirrorKlassID, - InstanceClassLoaderKlassID, - TypeArrayKlassID, - ObjArrayKlassID +// Klass Kinds for all subclasses of Klass +enum KlassKind { + InstanceKlassKind, + InstanceRefKlassKind, + InstanceMirrorKlassKind, + InstanceClassLoaderKlassKind, + TypeArrayKlassKind, + ObjArrayKlassKind }; -const uint KLASS_ID_COUNT = 6; +const uint KLASS_KIND_COUNT = ObjArrayKlassKind + 1; // // A Klass provides: @@ -114,8 +114,10 @@ class Klass : public Metadata { // because it is frequently queried. jint _layout_helper; - // Klass identifier used to implement devirtualized oop closure dispatching. - const KlassID _id; + // Klass kind used to resolve the runtime type of the instance. + // - Used to implement devirtualized oop closure dispatching. + // - Various type checking in the JVM + const KlassKind _kind; // Processed access flags, for use by Class.getModifiers. jint _modifier_flags; @@ -186,13 +188,13 @@ private: protected: // Constructor - Klass(KlassID id); - Klass() : _id(KlassID(-1)) { assert(DumpSharedSpaces || UseSharedSpaces, "only for cds"); } + Klass(KlassKind kind); + Klass() : _kind(KlassKind(-1)) { assert(DumpSharedSpaces || UseSharedSpaces, "only for cds"); } void* operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, TRAPS) throw(); public: - int id() { return _id; } + int kind() { return _kind; } enum class DefaultsLookupMode { find, skip }; enum class OverpassLookupMode { find, skip }; @@ -615,15 +617,15 @@ protected: public: #endif - bool is_instance_klass() const { return assert_same_query(_id <= InstanceClassLoaderKlassID, is_instance_klass_slow()); } + bool is_instance_klass() const { return assert_same_query(_kind <= InstanceClassLoaderKlassKind, is_instance_klass_slow()); } // Other is anything that is not one of the more specialized kinds of InstanceKlass. - bool is_other_instance_klass() const { return _id == InstanceKlassID; } - bool is_reference_instance_klass() const { return _id == InstanceRefKlassID; } - bool is_mirror_instance_klass() const { return _id == InstanceMirrorKlassID; } - bool is_class_loader_instance_klass() const { return _id == InstanceClassLoaderKlassID; } - bool is_array_klass() const { return assert_same_query( _id >= TypeArrayKlassID, is_array_klass_slow()); } - bool is_objArray_klass() const { return assert_same_query( _id == ObjArrayKlassID, is_objArray_klass_slow()); } - bool is_typeArray_klass() const { return assert_same_query( _id == TypeArrayKlassID, is_typeArray_klass_slow()); } + bool is_other_instance_klass() const { return _kind == InstanceKlassKind; } + bool is_reference_instance_klass() const { return _kind == InstanceRefKlassKind; } + bool is_mirror_instance_klass() const { return _kind == InstanceMirrorKlassKind; } + bool is_class_loader_instance_klass() const { return _kind == InstanceClassLoaderKlassKind; } + bool is_array_klass() const { return assert_same_query( _kind >= TypeArrayKlassKind, is_array_klass_slow()); } + bool is_objArray_klass() const { return assert_same_query( _kind == ObjArrayKlassKind, is_objArray_klass_slow()); } + bool is_typeArray_klass() const { return assert_same_query( _kind == TypeArrayKlassKind, is_typeArray_klass_slow()); } #undef assert_same_query // Access flags diff --git a/src/hotspot/share/oops/objArrayKlass.cpp b/src/hotspot/share/oops/objArrayKlass.cpp index fab9bd35487..a43816476e8 100644 --- a/src/hotspot/share/oops/objArrayKlass.cpp +++ b/src/hotspot/share/oops/objArrayKlass.cpp @@ -136,7 +136,7 @@ ObjArrayKlass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_da return oak; } -ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name) : ArrayKlass(name, ID) { +ObjArrayKlass::ObjArrayKlass(int n, Klass* element_klass, Symbol* name) : ArrayKlass(name, Kind) { set_dimension(n); set_element_klass(element_klass); diff --git a/src/hotspot/share/oops/objArrayKlass.hpp b/src/hotspot/share/oops/objArrayKlass.hpp index e4bd54b9ed1..0c031725e4c 100644 --- a/src/hotspot/share/oops/objArrayKlass.hpp +++ b/src/hotspot/share/oops/objArrayKlass.hpp @@ -37,7 +37,7 @@ class ObjArrayKlass : public ArrayKlass { friend class JVMCIVMStructs; public: - static const KlassID ID = ObjArrayKlassID; + static const KlassKind Kind = ObjArrayKlassKind; private: // If you add a new field that points to any metaspace object, you diff --git a/src/hotspot/share/oops/typeArrayKlass.cpp b/src/hotspot/share/oops/typeArrayKlass.cpp index c79cc61e39a..fa67b4876d9 100644 --- a/src/hotspot/share/oops/typeArrayKlass.cpp +++ b/src/hotspot/share/oops/typeArrayKlass.cpp @@ -75,7 +75,7 @@ TypeArrayKlass* TypeArrayKlass::allocate(ClassLoaderData* loader_data, BasicType return new (loader_data, size, THREAD) TypeArrayKlass(type, name); } -TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name, ID) { +TypeArrayKlass::TypeArrayKlass(BasicType type, Symbol* name) : ArrayKlass(name, Kind) { set_layout_helper(array_layout_helper(type)); assert(is_array_klass(), "sanity"); assert(is_typeArray_klass(), "sanity"); diff --git a/src/hotspot/share/oops/typeArrayKlass.hpp b/src/hotspot/share/oops/typeArrayKlass.hpp index 1ba4613adff..389c5ddbd74 100644 --- a/src/hotspot/share/oops/typeArrayKlass.hpp +++ b/src/hotspot/share/oops/typeArrayKlass.hpp @@ -36,7 +36,7 @@ class TypeArrayKlass : public ArrayKlass { friend class VMStructs; public: - static const KlassID ID = TypeArrayKlassID; + static const KlassKind Kind = TypeArrayKlassKind; private: jint _max_length; // maximum number of elements allowed in an array -- GitLab From 70648a6a153e5d321f78cf6445a9703f41083725 Mon Sep 17 00:00:00 2001 From: Ivan Walulya Date: Fri, 25 Mar 2022 09:41:20 +0000 Subject: [PATCH 166/237] 8283368: G1: Remove G1SegmentedArraySegment MEMFLAGS template parameter Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/g1/g1CardSetMemory.hpp | 10 +- src/hotspot/share/gc/g1/g1SegmentedArray.cpp | 246 ++++++++++++++++++ src/hotspot/share/gc/g1/g1SegmentedArray.hpp | 88 ++++--- .../share/gc/g1/g1SegmentedArray.inline.hpp | 232 +---------------- .../gc/g1/g1SegmentedArrayFreeMemoryTask.cpp | 6 +- .../gc/g1/g1SegmentedArrayFreeMemoryTask.hpp | 6 +- .../share/gc/g1/g1SegmentedArrayFreePool.cpp | 48 ++-- .../share/gc/g1/g1SegmentedArrayFreePool.hpp | 16 +- src/hotspot/share/gc/g1/heapRegionRemSet.cpp | 4 +- 9 files changed, 344 insertions(+), 312 deletions(-) create mode 100644 src/hotspot/share/gc/g1/g1SegmentedArray.cpp diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.hpp b/src/hotspot/share/gc/g1/g1CardSetMemory.hpp index c2663b41cf1..4b5638c3363 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.hpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.hpp @@ -50,7 +50,7 @@ public: static const uint SlotAlignment = 8; G1CardSetAllocOptions(uint slot_size, uint initial_num_slots = MinimumNumSlots, uint max_num_slots = MaximumNumSlots) : - G1SegmentedArrayAllocOptions(align_up(slot_size, SlotAlignment), initial_num_slots, max_num_slots, SlotAlignment) { + G1SegmentedArrayAllocOptions(mtGCCardSet, slot_size, initial_num_slots, max_num_slots, SlotAlignment) { } virtual uint next_num_slots(uint prev_num_slots) const override { @@ -58,16 +58,16 @@ public: } }; -typedef G1SegmentedArraySegment G1CardSetSegment; +using G1CardSetSegment = G1SegmentedArraySegment; -typedef G1SegmentedArrayFreeList G1CardSetFreeList; +using G1CardSetFreeList = G1SegmentedArrayFreeList; // Arena-like allocator for (card set) heap memory objects. // // Allocation occurs from an internal free list of objects first. If the free list is // empty then tries to allocate from the G1SegmentedArray. class G1CardSetAllocator { - G1SegmentedArray _segmented_array; + G1SegmentedArray _segmented_array; FreeListAllocator _free_slots_list; public: @@ -92,7 +92,7 @@ public: void print(outputStream* os); }; -typedef G1SegmentedArrayFreePool G1CardSetFreePool; +using G1CardSetFreePool = G1SegmentedArrayFreePool; class G1CardSetMemoryManager : public CHeapObj { G1CardSetConfiguration* _config; diff --git a/src/hotspot/share/gc/g1/g1SegmentedArray.cpp b/src/hotspot/share/gc/g1/g1SegmentedArray.cpp new file mode 100644 index 00000000000..5a77fab8a21 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1SegmentedArray.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2022, 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. + * + */ + +#include "precompiled.hpp" + +#include "gc/g1/g1SegmentedArray.inline.hpp" +#include "memory/allocation.hpp" +#include "runtime/atomic.hpp" +#include "utilities/globalCounter.inline.hpp" + +G1SegmentedArraySegment::G1SegmentedArraySegment(uint slot_size, uint num_slots, G1SegmentedArraySegment* next, MEMFLAGS flag) : + _slot_size(slot_size), + _num_slots(num_slots), + _mem_flag(flag), + _next(next), + _next_allocate(0) { + _bottom = ((char*) this) + header_size(); +} + +G1SegmentedArraySegment* G1SegmentedArraySegment::create_segment(uint slot_size, + uint num_slots, + G1SegmentedArraySegment* next, + MEMFLAGS mem_flag) { + size_t block_size = size_in_bytes(slot_size, num_slots); + char* alloc_block = NEW_C_HEAP_ARRAY(char, block_size, mem_flag); + return new (alloc_block) G1SegmentedArraySegment(slot_size, num_slots, next, mem_flag); +} + +void G1SegmentedArraySegment::delete_segment(G1SegmentedArraySegment* segment) { + segment->~G1SegmentedArraySegment(); + FREE_C_HEAP_ARRAY(_mem_flag, segment); +} + +void G1SegmentedArrayFreeList::bulk_add(G1SegmentedArraySegment& first, + G1SegmentedArraySegment& last, + size_t num, + size_t mem_size) { + _list.prepend(first, last); + Atomic::add(&_num_segments, num, memory_order_relaxed); + Atomic::add(&_mem_size, mem_size, memory_order_relaxed); +} + +void G1SegmentedArrayFreeList::print_on(outputStream* out, const char* prefix) { + out->print_cr("%s: segments %zu size %zu", + prefix, Atomic::load(&_num_segments), Atomic::load(&_mem_size)); +} + +G1SegmentedArraySegment* G1SegmentedArrayFreeList::get_all(size_t& num_segments, + size_t& mem_size) { + GlobalCounter::CriticalSection cs(Thread::current()); + + G1SegmentedArraySegment* result = _list.pop_all(); + num_segments = Atomic::load(&_num_segments); + mem_size = Atomic::load(&_mem_size); + + if (result != nullptr) { + Atomic::sub(&_num_segments, num_segments, memory_order_relaxed); + Atomic::sub(&_mem_size, mem_size, memory_order_relaxed); + } + return result; +} + +void G1SegmentedArrayFreeList::free_all() { + size_t num_freed = 0; + size_t mem_size_freed = 0; + G1SegmentedArraySegment* cur; + + while ((cur = _list.pop()) != nullptr) { + mem_size_freed += cur->mem_size(); + num_freed++; + G1SegmentedArraySegment::delete_segment(cur); + } + + Atomic::sub(&_num_segments, num_freed, memory_order_relaxed); + Atomic::sub(&_mem_size, mem_size_freed, memory_order_relaxed); +} + +G1SegmentedArraySegment* G1SegmentedArray::create_new_segment(G1SegmentedArraySegment* const prev) { + // Take an existing segment if available. + G1SegmentedArraySegment* next = _free_segment_list->get(); + if (next == nullptr) { + uint prev_num_slots = (prev != nullptr) ? prev->num_slots() : 0; + uint num_slots = _alloc_options->next_num_slots(prev_num_slots); + + next = G1SegmentedArraySegment::create_segment(slot_size(), num_slots, prev, _alloc_options->mem_flag()); + } else { + assert(slot_size() == next->slot_size() , + "Mismatch %d != %d", slot_size(), next->slot_size()); + next->reset(prev); + } + + // Install it as current allocation segment. + G1SegmentedArraySegment* old = Atomic::cmpxchg(&_first, prev, next); + if (old != prev) { + // Somebody else installed the segment, use that one. + G1SegmentedArraySegment::delete_segment(next); + return old; + } else { + // Did we install the first segment in the list? If so, this is also the last. + if (prev == nullptr) { + _last = next; + } + // Successfully installed the segment into the list. + Atomic::inc(&_num_segments, memory_order_relaxed); + Atomic::add(&_mem_size, next->mem_size(), memory_order_relaxed); + Atomic::add(&_num_available_slots, next->num_slots(), memory_order_relaxed); + return next; + } +} + +G1SegmentedArray::G1SegmentedArray(const G1SegmentedArrayAllocOptions* alloc_options, + G1SegmentedArrayFreeList* free_segment_list) : + _alloc_options(alloc_options), + _first(nullptr), + _last(nullptr), + _num_segments(0), + _mem_size(0), + _free_segment_list(free_segment_list), + _num_available_slots(0), + _num_allocated_slots(0) { + assert(_free_segment_list != nullptr, "precondition!"); +} + +G1SegmentedArray::~G1SegmentedArray() { + drop_all(); +} + +uint G1SegmentedArray::slot_size() const { + return _alloc_options->slot_size(); +} + +void G1SegmentedArray::drop_all() { + G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); + + if (cur != nullptr) { + assert(_last != nullptr, "If there is at least one segment, there must be a last one."); + + G1SegmentedArraySegment* first = cur; +#ifdef ASSERT + // Check list consistency. + G1SegmentedArraySegment* last = cur; + uint num_segments = 0; + size_t mem_size = 0; + while (cur != nullptr) { + mem_size += cur->mem_size(); + num_segments++; + + G1SegmentedArraySegment* next = cur->next(); + last = cur; + cur = next; + } +#endif + assert(num_segments == _num_segments, "Segment count inconsistent %u %u", num_segments, _num_segments); + assert(mem_size == _mem_size, "Memory size inconsistent"); + assert(last == _last, "Inconsistent last segment"); + + _free_segment_list->bulk_add(*first, *_last, _num_segments, _mem_size); + } + + _first = nullptr; + _last = nullptr; + _num_segments = 0; + _mem_size = 0; + _num_available_slots = 0; + _num_allocated_slots = 0; +} + +void* G1SegmentedArray::allocate() { + assert(slot_size() > 0, "instance size not set."); + + G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); + if (cur == nullptr) { + cur = create_new_segment(cur); + } + + while (true) { + void* slot = cur->get_new_slot(); + if (slot != nullptr) { + Atomic::inc(&_num_allocated_slots, memory_order_relaxed); + guarantee(is_aligned(slot, _alloc_options->slot_alignment()), + "result " PTR_FORMAT " not aligned at %u", p2i(slot), _alloc_options->slot_alignment()); + return slot; + } + // The segment is full. Next round. + assert(cur->is_full(), "must be"); + cur = create_new_segment(cur); + } +} + +uint G1SegmentedArray::num_segments() const { + return Atomic::load(&_num_segments); +} + +#ifdef ASSERT +class LengthClosure { + uint _total; +public: + LengthClosure() : _total(0) {} + void do_segment(G1SegmentedArraySegment* segment, uint limit) { + _total += limit; + } + uint length() const { + return _total; + } +}; + +uint G1SegmentedArray::calculate_length() const { + LengthClosure closure; + iterate_segments(closure); + return closure.length(); +} +#endif + +template +void G1SegmentedArray::iterate_segments(SegmentClosure& closure) const { + G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); + + assert((cur != nullptr) == (_last != nullptr), + "If there is at least one segment, there must be a last one"); + + while (cur != nullptr) { + closure.do_segment(cur, cur->length()); + cur = cur->next(); + } +} diff --git a/src/hotspot/share/gc/g1/g1SegmentedArray.hpp b/src/hotspot/share/gc/g1/g1SegmentedArray.hpp index 6c73e9855cc..6d1bcea9c90 100644 --- a/src/hotspot/share/gc/g1/g1SegmentedArray.hpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArray.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, Huawei Technologies Co. Ltd. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Huawei Technologies Co. Ltd. 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 @@ -28,28 +28,38 @@ #include "gc/shared/freeListAllocator.hpp" #include "memory/allocation.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/lockFreeStack.hpp" // A single segment/arena containing _num_slots blocks of memory of _slot_size. // G1SegmentedArraySegments can be linked together using a singly linked list. -template -class G1SegmentedArraySegment : public CHeapObj { +class G1SegmentedArraySegment { const uint _slot_size; const uint _num_slots; - + const MEMFLAGS _mem_flag; G1SegmentedArraySegment* volatile _next; - - char* _segment; // Actual data. - // Index into the next free slot to allocate into. Full if equal (or larger) // to _num_slots (can be larger because we atomically increment this value and // check only afterwards if the allocation has been successful). uint volatile _next_allocate; -public: - G1SegmentedArraySegment(uint slot_size, uint num_slots, G1SegmentedArraySegment* next); - ~G1SegmentedArraySegment(); + char* _bottom; // Actual data. + // Do not add class member variables beyond this point + + static size_t header_size() { return align_up(offset_of(G1SegmentedArraySegment, _bottom), DEFAULT_CACHE_LINE_SIZE); } + + static size_t payload_size(uint slot_size, uint num_slots) { + // The cast (size_t) is required to guard against overflow wrap around. + return (size_t)slot_size * num_slots; + } + + size_t payload_size() const { return payload_size(_slot_size, _num_slots); } + NONCOPYABLE(G1SegmentedArraySegment); + + G1SegmentedArraySegment(uint slot_size, uint num_slots, G1SegmentedArraySegment* next, MEMFLAGS flag); + ~G1SegmentedArraySegment() = default; +public: G1SegmentedArraySegment* volatile* next_addr() { return &_next; } void* get_new_slot(); @@ -67,12 +77,12 @@ public: _next_allocate = 0; assert(next != this, " loop condition"); set_next(next); - memset((void*)_segment, 0, (size_t)_num_slots * _slot_size); + memset((void*)_bottom, 0, payload_size()); } uint slot_size() const { return _slot_size; } - size_t mem_size() const { return sizeof(*this) + (size_t)_num_slots * _slot_size; } + size_t mem_size() const { return header_size() + payload_size(); } uint length() const { // _next_allocate might grow larger than _num_slots in multi-thread environments @@ -80,9 +90,16 @@ public: return MIN2(_next_allocate, _num_slots); } + static size_t size_in_bytes(uint slot_size, uint num_slots) { + return header_size() + payload_size(slot_size, num_slots); + } + + static G1SegmentedArraySegment* create_segment(uint slot_size, uint num_slots, G1SegmentedArraySegment* next, MEMFLAGS mem_flag); + static void delete_segment(G1SegmentedArraySegment* segment); + // Copies the (valid) contents of this segment into the destination. void copy_to(void* dest) const { - ::memcpy(dest, _segment, length() * _slot_size); + ::memcpy(dest, _bottom, length() * _slot_size); } bool is_full() const { return _next_allocate >= _num_slots; } @@ -92,12 +109,11 @@ public: // to it and removal of segments is strictly separate, but every action may be // performed by multiple threads at the same time. // Counts and memory usage are current on a best-effort basis if accessed concurrently. -template class G1SegmentedArrayFreeList { - static G1SegmentedArraySegment* volatile* next_ptr(G1SegmentedArraySegment& segment) { + static G1SegmentedArraySegment* volatile* next_ptr(G1SegmentedArraySegment& segment) { return segment.next_addr(); } - typedef LockFreeStack, &G1SegmentedArrayFreeList::next_ptr> SegmentStack; + using SegmentStack = LockFreeStack; SegmentStack _list; @@ -108,10 +124,10 @@ public: G1SegmentedArrayFreeList() : _list(), _num_segments(0), _mem_size(0) { } ~G1SegmentedArrayFreeList() { free_all(); } - void bulk_add(G1SegmentedArraySegment& first, G1SegmentedArraySegment& last, size_t num, size_t mem_size); + void bulk_add(G1SegmentedArraySegment& first, G1SegmentedArraySegment& last, size_t num, size_t mem_size); - G1SegmentedArraySegment* get(); - G1SegmentedArraySegment* get_all(size_t& num_segments, size_t& mem_size); + G1SegmentedArraySegment* get(); + G1SegmentedArraySegment* get_all(size_t& num_segments, size_t& mem_size); // Give back all memory to the OS. void free_all(); @@ -126,6 +142,7 @@ public: class G1SegmentedArrayAllocOptions { protected: + const MEMFLAGS _mem_flag; const uint _slot_size; const uint _initial_num_slots; // Defines a limit to the number of slots in the segment @@ -133,8 +150,9 @@ protected: const uint _slot_alignment; public: - G1SegmentedArrayAllocOptions(uint slot_size, uint initial_num_slots, uint max_num_slots, uint alignment) : - _slot_size(slot_size), + G1SegmentedArrayAllocOptions(MEMFLAGS mem_flag, uint slot_size, uint initial_num_slots, uint max_num_slots, uint alignment) : + _mem_flag(mem_flag), + _slot_size(align_up(slot_size, alignment)), _initial_num_slots(initial_num_slots), _max_num_slots(max_num_slots), _slot_alignment(alignment) { @@ -151,6 +169,8 @@ public: uint slot_size() const { return _slot_size; } uint slot_alignment() const { return _slot_alignment; } + + MEMFLAGS mem_flag() const {return _mem_flag; } }; // A segmented array where G1SegmentedArraySegment is the segment, and @@ -181,30 +201,30 @@ public: // The class also manages a few counters for statistics using atomic operations. // Their values are only consistent within each other with extra global // synchronization. -template + class G1SegmentedArray : public FreeListConfig { // G1SegmentedArrayAllocOptions provides parameters for allocation segment // sizing and expansion. const G1SegmentedArrayAllocOptions* _alloc_options; - G1SegmentedArraySegment* volatile _first; // The (start of the) list of all segments. - G1SegmentedArraySegment* _last; // The last segment of the list of all segments. - volatile uint _num_segments; // Number of assigned segments to this allocator. - volatile size_t _mem_size; // Memory used by all segments. + G1SegmentedArraySegment* volatile _first; // The (start of the) list of all segments. + G1SegmentedArraySegment* _last; // The last segment of the list of all segments. + volatile uint _num_segments; // Number of assigned segments to this allocator. + volatile size_t _mem_size; // Memory used by all segments. - G1SegmentedArrayFreeList* _free_segment_list; // The global free segment list to - // preferentially get new segments from. + G1SegmentedArrayFreeList* _free_segment_list; // The global free segment list to preferentially + // get new segments from. volatile uint _num_available_slots; // Number of slots available in all segments (allocated + free + pending + not yet used). volatile uint _num_allocated_slots; // Number of total slots allocated and in use. private: - inline G1SegmentedArraySegment* create_new_segment(G1SegmentedArraySegment* const prev); + inline G1SegmentedArraySegment* create_new_segment(G1SegmentedArraySegment* const prev); DEBUG_ONLY(uint calculate_length() const;) public: - const G1SegmentedArraySegment* first_array_segment() const { return Atomic::load(&_first); } + const G1SegmentedArraySegment* first_array_segment() const { return Atomic::load(&_first); } uint num_available_slots() const { return Atomic::load(&_num_available_slots); } uint num_allocated_slots() const { @@ -213,10 +233,10 @@ public: return allocated; } - inline uint slot_size() const; + uint slot_size() const; G1SegmentedArray(const G1SegmentedArrayAllocOptions* alloc_options, - G1SegmentedArrayFreeList* free_segment_list); + G1SegmentedArrayFreeList* free_segment_list); ~G1SegmentedArray(); // Deallocate all segments to the free segment list and reset this allocator. Must @@ -228,7 +248,7 @@ public: // We do not deallocate individual slots inline void deallocate(void* node) override { ShouldNotReachHere(); } - inline uint num_segments() const; + uint num_segments() const; template void iterate_segments(SegmentClosure& closure) const; diff --git a/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp b/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp index 69c3526e58d..1acb5060d4b 100644 --- a/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArray.inline.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2021, Huawei Technologies Co. Ltd. All rights reserved. + * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, Huawei Technologies Co. Ltd. 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 @@ -30,20 +30,7 @@ #include "runtime/atomic.hpp" #include "utilities/globalCounter.inline.hpp" -template -G1SegmentedArraySegment::G1SegmentedArraySegment(uint slot_size, uint num_slots, G1SegmentedArraySegment* next) : - _slot_size(slot_size), _num_slots(num_slots), _next(next), _next_allocate(0) { - - _segment = NEW_C_HEAP_ARRAY(char, (size_t)_num_slots * slot_size, flag); -} - -template -G1SegmentedArraySegment::~G1SegmentedArraySegment() { - FREE_C_HEAP_ARRAY(flag, _segment); -} - -template -void* G1SegmentedArraySegment::get_new_slot() { +inline void* G1SegmentedArraySegment::get_new_slot() { if (_next_allocate >= _num_slots) { return nullptr; } @@ -51,31 +38,14 @@ void* G1SegmentedArraySegment::get_new_slot() { if (result >= _num_slots) { return nullptr; } - void* r = _segment + (uint)result * _slot_size; + void* r = _bottom + (size_t)result * _slot_size; return r; } -template -void G1SegmentedArrayFreeList::bulk_add(G1SegmentedArraySegment& first, - G1SegmentedArraySegment& last, - size_t num, - size_t mem_size) { - _list.prepend(first, last); - Atomic::add(&_num_segments, num, memory_order_relaxed); - Atomic::add(&_mem_size, mem_size, memory_order_relaxed); -} - -template -void G1SegmentedArrayFreeList::print_on(outputStream* out, const char* prefix) { - out->print_cr("%s: segments %zu size %zu", - prefix, Atomic::load(&_num_segments), Atomic::load(&_mem_size)); -} - -template -G1SegmentedArraySegment* G1SegmentedArrayFreeList::get() { +inline G1SegmentedArraySegment* G1SegmentedArrayFreeList::get() { GlobalCounter::CriticalSection cs(Thread::current()); - G1SegmentedArraySegment* result = _list.pop(); + G1SegmentedArraySegment* result = _list.pop(); if (result != nullptr) { Atomic::dec(&_num_segments, memory_order_relaxed); Atomic::sub(&_mem_size, result->mem_size(), memory_order_relaxed); @@ -83,194 +53,4 @@ G1SegmentedArraySegment* G1SegmentedArrayFreeList::get() { return result; } -template -G1SegmentedArraySegment* G1SegmentedArrayFreeList::get_all(size_t& num_segments, - size_t& mem_size) { - GlobalCounter::CriticalSection cs(Thread::current()); - - G1SegmentedArraySegment* result = _list.pop_all(); - num_segments = Atomic::load(&_num_segments); - mem_size = Atomic::load(&_mem_size); - - if (result != nullptr) { - Atomic::sub(&_num_segments, num_segments, memory_order_relaxed); - Atomic::sub(&_mem_size, mem_size, memory_order_relaxed); - } - return result; -} - -template -void G1SegmentedArrayFreeList::free_all() { - size_t num_freed = 0; - size_t mem_size_freed = 0; - G1SegmentedArraySegment* cur; - - while ((cur = _list.pop()) != nullptr) { - mem_size_freed += cur->mem_size(); - num_freed++; - delete cur; - } - - Atomic::sub(&_num_segments, num_freed, memory_order_relaxed); - Atomic::sub(&_mem_size, mem_size_freed, memory_order_relaxed); -} - -template -G1SegmentedArraySegment* G1SegmentedArray::create_new_segment(G1SegmentedArraySegment* const prev) { - // Take an existing segment if available. - G1SegmentedArraySegment* next = _free_segment_list->get(); - if (next == nullptr) { - uint prev_num_slots = (prev != nullptr) ? prev->num_slots() : 0; - uint num_slots = _alloc_options->next_num_slots(prev_num_slots); - next = new G1SegmentedArraySegment(slot_size(), num_slots, prev); - } else { - assert(slot_size() == next->slot_size() , - "Mismatch %d != %d", slot_size(), next->slot_size()); - next->reset(prev); - } - - // Install it as current allocation segment. - G1SegmentedArraySegment* old = Atomic::cmpxchg(&_first, prev, next); - if (old != prev) { - // Somebody else installed the segment, use that one. - delete next; - return old; - } else { - // Did we install the first segment in the list? If so, this is also the last. - if (prev == nullptr) { - _last = next; - } - // Successfully installed the segment into the list. - Atomic::inc(&_num_segments, memory_order_relaxed); - Atomic::add(&_mem_size, next->mem_size(), memory_order_relaxed); - Atomic::add(&_num_available_slots, next->num_slots(), memory_order_relaxed); - return next; - } -} - -template -uint G1SegmentedArray::slot_size() const { - return _alloc_options->slot_size(); -} - -template -G1SegmentedArray::G1SegmentedArray(const G1SegmentedArrayAllocOptions* alloc_options, - G1SegmentedArrayFreeList* free_segment_list) : - _alloc_options(alloc_options), - _first(nullptr), - _last(nullptr), - _num_segments(0), - _mem_size(0), - _free_segment_list(free_segment_list), - _num_available_slots(0), - _num_allocated_slots(0) { - assert(_free_segment_list != nullptr, "precondition!"); -} - -template -G1SegmentedArray::~G1SegmentedArray() { - drop_all(); -} - -template -void G1SegmentedArray::drop_all() { - G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); - - if (cur != nullptr) { - assert(_last != nullptr, "If there is at least one segment, there must be a last one."); - - G1SegmentedArraySegment* first = cur; -#ifdef ASSERT - // Check list consistency. - G1SegmentedArraySegment* last = cur; - uint num_segments = 0; - size_t mem_size = 0; - while (cur != nullptr) { - mem_size += cur->mem_size(); - num_segments++; - - G1SegmentedArraySegment* next = cur->next(); - last = cur; - cur = next; - } -#endif - assert(num_segments == _num_segments, "Segment count inconsistent %u %u", num_segments, _num_segments); - assert(mem_size == _mem_size, "Memory size inconsistent"); - assert(last == _last, "Inconsistent last segment"); - - _free_segment_list->bulk_add(*first, *_last, _num_segments, _mem_size); - } - - _first = nullptr; - _last = nullptr; - _num_segments = 0; - _mem_size = 0; - _num_available_slots = 0; - _num_allocated_slots = 0; -} - -template -void* G1SegmentedArray::allocate() { - assert(slot_size() > 0, "instance size not set."); - - G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); - if (cur == nullptr) { - cur = create_new_segment(cur); - } - - while (true) { - void* slot = cur->get_new_slot(); - if (slot != nullptr) { - Atomic::inc(&_num_allocated_slots, memory_order_relaxed); - guarantee(is_aligned(slot, _alloc_options->slot_alignment()), - "result " PTR_FORMAT " not aligned at %u", p2i(slot), _alloc_options->slot_alignment()); - return slot; - } - // The segment is full. Next round. - assert(cur->is_full(), "must be"); - cur = create_new_segment(cur); - } -} - -template -inline uint G1SegmentedArray::num_segments() const { - return Atomic::load(&_num_segments); -} - -#ifdef ASSERT -template -class LengthClosure { - uint _total; -public: - LengthClosure() : _total(0) {} - void do_segment(G1SegmentedArraySegment* segment, uint limit) { - _total += limit; - } - uint length() const { - return _total; - } -}; - -template -uint G1SegmentedArray::calculate_length() const { - LengthClosure closure; - iterate_segments(closure); - return closure.length(); -} -#endif - -template -template -void G1SegmentedArray::iterate_segments(SegmentClosure& closure) const { - G1SegmentedArraySegment* cur = Atomic::load_acquire(&_first); - - assert((cur != nullptr) == (_last != nullptr), - "If there is at least one segment, there must be a last one"); - - while (cur != nullptr) { - closure.do_segment(cur, cur->length()); - cur = cur->next(); - } -} - #endif //SHARE_GC_G1_G1SEGMENTEDARRAY_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.cpp b/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.cpp index 4752adde74d..5bef0caca0b 100644 --- a/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.cpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -52,7 +52,7 @@ bool G1SegmentedArrayFreeMemoryTask::calculate_return_infos(jlong deadline) { // Ignore the deadline in this step as it is very short. G1SegmentedArrayMemoryStats used = _total_used; - G1SegmentedArrayMemoryStats free = G1SegmentedArrayFreePool::free_list_sizes(); + G1SegmentedArrayMemoryStats free = G1SegmentedArrayFreePool::free_list_sizes(); _return_info = new G1ReturnMemoryProcessorSet(used.num_pools()); for (uint i = 0; i < used.num_pools(); i++) { @@ -68,7 +68,7 @@ bool G1SegmentedArrayFreeMemoryTask::calculate_return_infos(jlong deadline) { _return_info->append(new G1ReturnMemoryProcessor(return_to_vm_size)); } - G1SegmentedArrayFreePool::update_unlink_processors(_return_info); + G1SegmentedArrayFreePool::update_unlink_processors(_return_info); return false; } diff --git a/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.hpp b/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.hpp index a4195cd424c..487f553ea7b 100644 --- a/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.hpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArrayFreeMemoryTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -56,8 +56,8 @@ class G1SegmentedArrayFreeMemoryTask : public G1ServiceTask { // Current total segmented array memory usage. G1SegmentedArrayMemoryStats _total_used; - typedef G1SegmentedArrayFreePool::G1ReturnMemoryProcessor G1ReturnMemoryProcessor; - typedef G1SegmentedArrayFreePool::G1ReturnMemoryProcessorSet G1ReturnMemoryProcessorSet; + using G1ReturnMemoryProcessor = G1SegmentedArrayFreePool::G1ReturnMemoryProcessor; + using G1ReturnMemoryProcessorSet = G1SegmentedArrayFreePool::G1ReturnMemoryProcessorSet; G1ReturnMemoryProcessorSet* _return_info; diff --git a/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.cpp b/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.cpp index 118638da75b..10f69405569 100644 --- a/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.cpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -43,8 +43,7 @@ void G1SegmentedArrayMemoryStats::clear() { } } -template -void G1SegmentedArrayFreePool::update_unlink_processors(G1ReturnMemoryProcessorSet* unlink_processor) { +void G1SegmentedArrayFreePool::update_unlink_processors(G1ReturnMemoryProcessorSet* unlink_processor) { uint num_free_lists = _freelist_pool.num_free_lists(); for (uint i = 0; i < num_free_lists; i++) { @@ -52,8 +51,7 @@ void G1SegmentedArrayFreePool::update_unlink_processors(G1ReturnMemoryProc } } -template -void G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::visit_free_list(G1SegmentedArrayFreeList* source) { +void G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::visit_free_list(G1SegmentedArrayFreeList* source) { assert(_source == nullptr, "already visited"); if (_return_to_vm_size > 0) { _source = source; @@ -75,16 +73,15 @@ void G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::visit_free_list(G1 } } -template -bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_vm(jlong deadline) { +bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_vm(jlong deadline) { assert(!finished_return_to_vm(), "already returned everything to the VM"); assert(_first != nullptr, "must have segment to return"); size_t keep_size = 0; size_t keep_num = 0; - G1SegmentedArraySegment* cur = _first; - G1SegmentedArraySegment* last = nullptr; + G1SegmentedArraySegment* cur = _first; + G1SegmentedArraySegment* last = nullptr; while (cur != nullptr && _return_to_vm_size > 0) { size_t cur_size = cur->mem_size(); @@ -125,8 +122,7 @@ bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_vm(jlong return _source != nullptr; } -template -bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_os(jlong deadline) { +bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_os(jlong deadline) { assert(finished_return_to_vm(), "not finished returning to VM"); assert(!finished_return_to_os(), "already returned everything to the OS"); @@ -135,10 +131,10 @@ bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_os(jlong size_t mem_size_deleted = 0; while (_first != nullptr) { - G1SegmentedArraySegment* next = _first->next(); + G1SegmentedArraySegment* next = _first->next(); num_delete++; mem_size_deleted += _first->mem_size(); - delete _first; + G1SegmentedArraySegment::delete_segment(_first); _first = next; // To ensure progress, perform the deadline check here. @@ -152,29 +148,25 @@ bool G1SegmentedArrayFreePool::G1ReturnMemoryProcessor::return_to_os(jlong return _first != nullptr; } -template -G1SegmentedArrayFreePool G1SegmentedArrayFreePool::_freelist_pool(G1CardSetConfiguration::num_mem_object_types()); +G1SegmentedArrayFreePool G1SegmentedArrayFreePool::_freelist_pool(G1CardSetConfiguration::num_mem_object_types()); -template -G1SegmentedArrayFreePool::G1SegmentedArrayFreePool(uint num_free_lists) : +G1SegmentedArrayFreePool::G1SegmentedArrayFreePool(uint num_free_lists) : _num_free_lists(num_free_lists) { - _free_lists = NEW_C_HEAP_ARRAY(G1SegmentedArrayFreeList < flag >, _num_free_lists, mtGC); + _free_lists = NEW_C_HEAP_ARRAY(G1SegmentedArrayFreeList, _num_free_lists, mtGC); for (uint i = 0; i < _num_free_lists; i++) { - new (&_free_lists[i]) G1SegmentedArrayFreeList(); + new (&_free_lists[i]) G1SegmentedArrayFreeList(); } } -template -G1SegmentedArrayFreePool::~G1SegmentedArrayFreePool() { +G1SegmentedArrayFreePool::~G1SegmentedArrayFreePool() { for (uint i = 0; i < _num_free_lists; i++) { - _free_lists[i].~G1SegmentedArrayFreeList(); + _free_lists[i].~G1SegmentedArrayFreeList(); } FREE_C_HEAP_ARRAY(mtGC, _free_lists); } -template -G1SegmentedArrayMemoryStats G1SegmentedArrayFreePool::memory_sizes() const { +G1SegmentedArrayMemoryStats G1SegmentedArrayFreePool::memory_sizes() const { G1SegmentedArrayMemoryStats free_list_stats; assert(free_list_stats.num_pools() == num_free_lists(), "must be"); for (uint i = 0; i < num_free_lists(); i++) { @@ -184,8 +176,7 @@ G1SegmentedArrayMemoryStats G1SegmentedArrayFreePool::memory_sizes() const return free_list_stats; } -template -size_t G1SegmentedArrayFreePool::mem_size() const { +size_t G1SegmentedArrayFreePool::mem_size() const { size_t result = 0; for (uint i = 0; i < _num_free_lists; i++) { result += _free_lists[i].mem_size(); @@ -193,13 +184,10 @@ size_t G1SegmentedArrayFreePool::mem_size() const { return result; } -template -void G1SegmentedArrayFreePool::print_on(outputStream* out) { +void G1SegmentedArrayFreePool::print_on(outputStream* out) { out->print_cr(" Free Pool: size %zu", free_list_pool()->mem_size()); for (uint i = 0; i < _num_free_lists; i++) { FormatBuffer<> fmt(" %s", G1CardSetConfiguration::mem_object_type_name_str(i)); _free_lists[i].print_on(out, fmt); } } - -template class G1SegmentedArrayFreePool; diff --git a/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.hpp b/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.hpp index ba1b952875c..23079c3853f 100644 --- a/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.hpp +++ b/src/hotspot/share/gc/g1/g1SegmentedArrayFreePool.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2022, 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 @@ -56,13 +56,12 @@ public: // A set of free lists holding freed segments for use by G1SegmentedArray, // e.g. G1CardSetAllocators::SegmentedArray -template class G1SegmentedArrayFreePool { // The global free pool. static G1SegmentedArrayFreePool _freelist_pool; const uint _num_free_lists; - G1SegmentedArrayFreeList* _free_lists; + G1SegmentedArrayFreeList* _free_lists; public: static G1SegmentedArrayFreePool* free_list_pool() { return &_freelist_pool; } @@ -76,7 +75,7 @@ public: explicit G1SegmentedArrayFreePool(uint num_free_lists); ~G1SegmentedArrayFreePool(); - G1SegmentedArrayFreeList* free_list(uint i) { + G1SegmentedArrayFreeList* free_list(uint i) { assert(i < _num_free_lists, "must be"); return &_free_lists[i]; } @@ -91,12 +90,11 @@ public: // Data structure containing current in-progress state for returning memory to the // operating system for a single G1SegmentedArrayFreeList. -template -class G1SegmentedArrayFreePool::G1ReturnMemoryProcessor : public CHeapObj { - G1SegmentedArrayFreeList* _source; +class G1SegmentedArrayFreePool::G1ReturnMemoryProcessor : public CHeapObj { + G1SegmentedArrayFreeList* _source; size_t _return_to_vm_size; - G1SegmentedArraySegment* _first; + G1SegmentedArraySegment* _first; size_t _unlinked_bytes; size_t _num_unlinked; @@ -108,7 +106,7 @@ public: // Updates the instance members about the given free list for // the purpose of giving back memory. Only necessary members are updated, // e.g. if there is nothing to return to the VM, do not set the source list. - void visit_free_list(G1SegmentedArrayFreeList* source); + void visit_free_list(G1SegmentedArrayFreeList* source); bool finished_return_to_vm() const { return _return_to_vm_size == 0; } bool finished_return_to_os() const { return _first == nullptr; } diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp index 9e6c31ffdc1..9b661768ae1 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2022, 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 @@ -81,7 +81,7 @@ HeapRegionRemSet::HeapRegionRemSet(HeapRegion* hr, G1CardSetConfiguration* config) : _m(Mutex::service - 1, FormatBuffer<128>("HeapRegionRemSet#%u_lock", hr->hrm_index())), _code_roots(), - _card_set_mm(config, G1SegmentedArrayFreePool::free_list_pool()), + _card_set_mm(config, G1SegmentedArrayFreePool::free_list_pool()), _card_set(config, &_card_set_mm), _hr(hr), _state(Untracked) { } -- GitLab From f8a164915fff5e9e8f3c9c1996b51e7e4fe5d68d Mon Sep 17 00:00:00 2001 From: Phil Race Date: Fri, 25 Mar 2022 15:07:44 +0000 Subject: [PATCH 167/237] 8274735: javax.imageio.IIOException: Unsupported Image Type while processing a valid JPEG image Reviewed-by: kizune, serb --- .../plugins/common/SimpleCMYKColorSpace.java | 2 +- .../imageio/plugins/jpeg/JPEGImageReader.java | 62 ++++++ .../imageio/plugins/jpeg/JPEGImageWriter.java | 21 ++ .../plugins/jpeg/CMYK/CMYKJPEGTest.java | 200 ++++++++++++++++++ .../imageio/plugins/jpeg/CMYK/black_cmyk.jpg | Bin 0 -> 220 bytes .../imageio/plugins/jpeg/CMYK/blue_cmyk.jpg | Bin 0 -> 220 bytes .../imageio/plugins/jpeg/CMYK/cyan_cmyk.jpg | Bin 0 -> 220 bytes .../imageio/plugins/jpeg/CMYK/gray_cmyk.jpg | Bin 0 -> 214 bytes .../imageio/plugins/jpeg/CMYK/green_cmyk.jpg | Bin 0 -> 220 bytes .../plugins/jpeg/CMYK/magenta_cmyk.jpg | Bin 0 -> 220 bytes .../imageio/plugins/jpeg/CMYK/red_cmyk.jpg | Bin 0 -> 220 bytes .../imageio/plugins/jpeg/CMYK/white_cmyk.jpg | Bin 0 -> 220 bytes .../imageio/plugins/jpeg/CMYK/yellow_cmyk.jpg | Bin 0 -> 220 bytes 13 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/CMYKJPEGTest.java create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/black_cmyk.jpg create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/blue_cmyk.jpg create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/cyan_cmyk.jpg create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/gray_cmyk.jpg create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/green_cmyk.jpg create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/magenta_cmyk.jpg create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/red_cmyk.jpg create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/white_cmyk.jpg create mode 100644 test/jdk/javax/imageio/plugins/jpeg/CMYK/yellow_cmyk.jpg diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java index 75586561598..a5c283e6c9c 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/common/SimpleCMYKColorSpace.java @@ -63,7 +63,7 @@ public final class SimpleCMYKColorSpace extends ColorSpace { } public int hashCode() { - return theInstance.hashCode(); + return System.identityHashCode(theInstance); } public float[] toRGB(float[] colorvalue) { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index dac1b79d4ea..e1839777480 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -35,6 +35,7 @@ import javax.imageio.stream.ImageInputStream; import javax.imageio.plugins.jpeg.JPEGImageReadParam; import javax.imageio.plugins.jpeg.JPEGQTable; import javax.imageio.plugins.jpeg.JPEGHuffmanTable; +import com.sun.imageio.plugins.common.SimpleCMYKColorSpace; import java.awt.Point; import java.awt.Rectangle; @@ -164,6 +165,12 @@ public class JPEGImageReader extends ImageReader { /** If we need to post-convert in Java, convert with this op */ private ColorConvertOp convert = null; + /** If reading CMYK as an Image, flip the bytes */ + private boolean invertCMYK = false; + + /** Whether to read as a raster */ + private boolean readAsRaster = false; + /** The image we are going to fill */ private BufferedImage image = null; @@ -938,6 +945,32 @@ public class JPEGImageReader extends ImageReader { ArrayList list = new ArrayList(1); switch (colorSpaceCode) { + case JPEG.JCS_YCCK: + case JPEG.JCS_CMYK: + // There's no standard CMYK ColorSpace in JDK so raw.getType() + // will return null so skip that. + // And we can't add RGB because the number of bands is different. + // So need to create our own special that is 4 channels and uses + // the iccCS ColorSpace based on profile data in the image, and + // if there is none, on the internal CMYKColorSpace class + if (iccCS == null) { + iccCS = SimpleCMYKColorSpace.getInstance(); + } + if (iccCS != null) { + list.add(new ImageTypeProducer(colorSpaceCode) { + @Override + protected ImageTypeSpecifier produce() { + int [] bands = {0, 1, 2, 3}; + return ImageTypeSpecifier.createInterleaved + (iccCS, + bands, + DataBuffer.TYPE_BYTE, + false, + false); + } + }); + } + break; case JPEG.JCS_GRAYSCALE: list.add(raw); list.add(getImageType(JPEG.JCS_RGB)); @@ -1019,6 +1052,8 @@ public class JPEGImageReader extends ImageReader { int csType = cs.getType(); convert = null; switch (outColorSpaceCode) { + case JPEG.JCS_CMYK: // Its CMYK in the file + break; case JPEG.JCS_GRAYSCALE: // Its gray in the file if (csType == ColorSpace.TYPE_RGB) { // We want RGB // IJG can do this for us more efficiently @@ -1144,6 +1179,8 @@ public class JPEGImageReader extends ImageReader { private Raster readInternal(int imageIndex, ImageReadParam param, boolean wantRaster) throws IOException { + + readAsRaster = wantRaster; readHeader(imageIndex, false); WritableRaster imRas = null; @@ -1186,6 +1223,16 @@ public class JPEGImageReader extends ImageReader { image = null; } + // Adobe seems to have decided that the bytes in CMYK JPEGs + // should be stored inverted. So we need some extra logic to + // flip them in that case. Don't flip for the raster case + // so code that is reading these as rasters today won't + // see a change in behaviour. + invertCMYK = + (!wantRaster && + ((colorSpaceCode == JPEG.JCS_YCCK) || + (colorSpaceCode == JPEG.JCS_CMYK))); + // Create an intermediate 1-line Raster that will hold the decoded, // subsampled, clipped, band-selected image data in a single // byte-interleaved buffer. The above transformations @@ -1363,6 +1410,21 @@ public class JPEGImageReader extends ImageReader { * After the copy, we notify update listeners. */ private void acceptPixels(int y, boolean progressive) { + + /* + * CMYK JPEGs seems to be universally inverted at the byte level. + * Fix this here before storing. + * For "compatibility" don't do this if the target is a raster. + * Need to do this here in case the application is listening + * for line-by-line updates to the image. + */ + if (invertCMYK) { + byte[] data = ((DataBufferByte)raster.getDataBuffer()).getData(); + for (int i = 0, len = data.length; i < len; i++) { + data[i] = (byte)(0x0ff - (data[i] & 0xff)); + } + } + if (convert != null) { convert.filter(raster, raster); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java index 31acae628a1..fcce8f60495 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java @@ -131,6 +131,7 @@ public class JPEGImageWriter extends ImageWriter { private int newAdobeTransform = JPEG.ADOBE_IMPOSSIBLE; // Change if needed private boolean writeDefaultJFIF = false; private boolean writeAdobe = false; + private boolean invertCMYK = false; private JPEGMetadata metadata = null; private boolean sequencePrepared = false; @@ -654,6 +655,7 @@ public class JPEGImageWriter extends ImageWriter { newAdobeTransform = JPEG.ADOBE_IMPOSSIBLE; // Change if needed writeDefaultJFIF = false; writeAdobe = false; + invertCMYK = false; // By default we'll do no conversion: int inCsType = JPEG.JCS_UNKNOWN; @@ -807,6 +809,14 @@ public class JPEGImageWriter extends ImageWriter { } } break; + case ColorSpace.TYPE_CMYK: + outCsType = JPEG.JCS_CMYK; + if (jfif != null) { + ignoreJFIF = true; + warningOccurred + (WARNING_IMAGE_METADATA_JFIF_MISMATCH); + } + break; } } } // else no dest, metadata, not an image. Defaults ok @@ -1013,6 +1023,11 @@ public class JPEGImageWriter extends ImageWriter { System.out.println("outCsType: " + outCsType); } + invertCMYK = + (!rasterOnly && + ((outCsType == JPEG.JCS_YCCK) || + (outCsType == JPEG.JCS_CMYK))); + // Note that getData disables acceleration on buffer, but it is // just a 1-line intermediate data transfer buffer that does not // affect the acceleration of the source image. @@ -1721,6 +1736,12 @@ public class JPEGImageWriter extends ImageWriter { srcBands); } raster.setRect(sourceLine); + if (invertCMYK) { + byte[] data = ((DataBufferByte)raster.getDataBuffer()).getData(); + for (int i = 0, len = data.length; i < len; i++) { + data[i] = (byte)(0x0ff - (data[i] & 0xff)); + } + } if ((y > 7) && (y%8 == 0)) { // Every 8 scanlines cbLock.lock(); try { diff --git a/test/jdk/javax/imageio/plugins/jpeg/CMYK/CMYKJPEGTest.java b/test/jdk/javax/imageio/plugins/jpeg/CMYK/CMYKJPEGTest.java new file mode 100644 index 00000000000..db4588d29c7 --- /dev/null +++ b/test/jdk/javax/imageio/plugins/jpeg/CMYK/CMYKJPEGTest.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * + * This test verifies that using the built-in ImageI/O JPEG plugin that JPEG images + * that are in a CMYK ColorSpace can be read into a BufferedImage using the convemience + * APIS and that and the colours are properly interpreted. + * Since there is no standard JDK CMYK ColorSpace, this requires that either the image + * contain an ICC_Profile which can be used by the plugin to create an ICC_ColorSpace + * or that the plugin provides a suitable default CMYK ColorSpace instance by some other means. + * + * The test further verifies that the resultant BufferedImage will be re-written as a CMYK + * BufferedImage. It can do this so long as the BufferedImage has that CMYK ColorSpace + * used by its ColorModel. + * + * The verification requires re-reading again the re-written image and checking the + * re-read image still has a CMYK ColorSpace and the same colours. + * + * Optionally - not for use in the test harness - the test can be passed a parameter + * -display to create a UI which renders all the images the test is + * verifying so it can be manually verified + */ + +/* + * @test + * @bug 8274735 + * @summary Verify CMYK JPEGs can be read and written + */ + +import java.awt.Color; +import static java.awt.Color.*; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +public class CMYKJPEGTest { + + static String[] fileNames = { + "black_cmyk.jpg", + "white_cmyk.jpg", + "gray_cmyk.jpg", + "red_cmyk.jpg", + "blue_cmyk.jpg", + "green_cmyk.jpg", + "cyan_cmyk.jpg", + "magenta_cmyk.jpg", + "yellow_cmyk.jpg", + }; + + static Color[] colors = { + black, + white, + gray, + red, + blue, + green, + cyan, + magenta, + yellow, + }; + + static boolean display; + + static BufferedImage[] readImages; + static BufferedImage[] writtenImages; + static int imageIndex = 0; + + public static void main(String[] args) throws Exception { + + if (args.length > 0) { + display = "-display".equals(args[0]); + } + + String sep = System.getProperty("file.separator"); + String dir = System.getProperty("test.src", "."); + String prefix = dir+sep; + + readImages = new BufferedImage[fileNames.length]; + writtenImages = new BufferedImage[fileNames.length]; + + for (String fileName : fileNames) { + String color = fileName.replace("_cmyk.jpg", ""); + test(prefix+fileName, color, imageIndex++); + } + if (display) { + SwingUtilities.invokeAndWait(() -> createUI()); + } + } + + static void test(String fileName, String color, int index) + throws IOException { + + readImages[index] = ImageIO.read(new File(fileName)); + verify(readImages[index], color, colors[index]); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(readImages[index], "jpg", baos); + ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + writtenImages[index] = ImageIO.read(bais); + verify(writtenImages[index], color, colors[index]); + } + + static void verify(BufferedImage img, String colorName, Color c) { + ColorModel cm = img.getColorModel(); + int tc = cm.getNumComponents(); + int cc = cm.getNumColorComponents(); + if (cc != 4 || tc != 4) { + throw new RuntimeException("Unexpected num comp for " + img); + } + + int rgb = img.getRGB(0,0); + int c_red = c.getRed(); + int c_green = c.getGreen(); + int c_blue = c.getBlue(); + int i_red = (rgb & 0x0ff0000) >> 16; + int i_green = (rgb & 0x000ff00) >> 8; + int i_blue = (rgb & 0x00000ff); + int tol = 16; + if ((Math.abs(i_red - c_red) > tol) || + (Math.abs(i_green - c_green) > tol) || + (Math.abs(i_blue - c_blue) > tol)) + { + System.err.println("red="+i_red+" green="+i_green+" blue="+i_blue); + throw new RuntimeException("Too different " + img + " " + colorName + " " + c); + } + } + + static class ImageComp extends JComponent { + + BufferedImage img; + + ImageComp(BufferedImage img) { + this.img = img; + } + + public Dimension getPreferredSize() { + return new Dimension(img.getWidth(), img.getHeight()); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public void paintComponent(Graphics g) { + super.paintComponent(g); + g.drawImage(img, 0, 0, null); + } + } + + static void createUI() { + JFrame f = new JFrame("CMYK JPEG Test"); + JPanel p = new JPanel(); + p.setLayout(new GridLayout(3, colors.length, 10, 10)); + for (String s : fileNames) { + p.add(new JLabel(s.replace("_cmyk.jpg", ""))); + } + for (BufferedImage i : readImages) { + p.add(new ImageComp(i)); + } + for (BufferedImage i : writtenImages) { + p.add(new ImageComp(i)); + } + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + f.add(p); + f.pack(); + f.setVisible(true); + } +} diff --git a/test/jdk/javax/imageio/plugins/jpeg/CMYK/black_cmyk.jpg b/test/jdk/javax/imageio/plugins/jpeg/CMYK/black_cmyk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1446f063bddf0c80a63a4a9da213b5560ad1d236 GIT binary patch literal 220 zcmZ9FO%8%E6odzR@LD?D2_M8A2NOeT35 zzVQoo*LE$UD8kkY{D#>~r^68w0{ldSco7I5dxR7LCFN3*(wY>JPV-bJCLzjPW^!wt z)oD={w)ENZ1(iaLS~L!W!|2dE@D(dR{GFMNd|lc97W{w_4F-(pfi=$E-rxN8oA~|# DH1{1W literal 0 HcmV?d00001 diff --git a/test/jdk/javax/imageio/plugins/jpeg/CMYK/blue_cmyk.jpg b/test/jdk/javax/imageio/plugins/jpeg/CMYK/blue_cmyk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74aa67622e47c65cfeafda3faca6c913be204b39 GIT binary patch literal 220 zcmZ9FOAdlC7=))%o3=n{0q?*qj3FT+VdsXe!L_Gx@7hzi@DM&Wp1>>owr+@ilT0R) zOondsg55N21I8HEUZ6M3YCP=r7!jZ+YDBX@@W{gj4@e>ALP@QaR7xjVqGJ;)mAceq z);g<`yvS|gv!x44i3%039eRhsp>v=s7XJ8qGnw*rY5!Z$1BTb=F`xsMIJVofK25XV GME4IkcpXjv literal 0 HcmV?d00001 diff --git a/test/jdk/javax/imageio/plugins/jpeg/CMYK/cyan_cmyk.jpg b/test/jdk/javax/imageio/plugins/jpeg/CMYK/cyan_cmyk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4e97acc33c29f5630927789afc21d3532d027f57 GIT binary patch literal 220 zcmZ9FOAdlC7=#C@O@mVaPgDpO9`B)papn=6FS!&-Ng<_*(^y41k}|Q0 zPK~if#aW)2++{--6apnmR#|iwy+vz5SFGIe_hvTf>cafDpa(Ro(4j{QtZ{0l^I@82 HzlrW2O;sKT literal 0 HcmV?d00001 diff --git a/test/jdk/javax/imageio/plugins/jpeg/CMYK/gray_cmyk.jpg b/test/jdk/javax/imageio/plugins/jpeg/CMYK/gray_cmyk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a519437e702e9b6d097595ced0e8410f2864908c GIT binary patch literal 214 zcmZXNO$x#=6oe->h9phXm$rxKEkp`MEj>WDQrBM5g@^EG;|aXNGjUb)8yJRRVED!_ z(4pV=5JF%V1%AVC=kxJ|83}%(L$*pJ&mvOEgjQ;;jJDQjW2`Hk&3$f65ei=t1+uQH tE2?8AzM#=)(aJ7h4449j0KTGu_`WPGwe;UU;AMvq69!B$LS` zlc5{EV4C_+BM1WQoj`Bs-FO;~7~!EODugSK_t3#O^9at@TneS6kW$5ItRfvrnb<_9 z##p1`EYD2tvY`tKff6OFEINzcqP3taHtzU)vzT;sVg6gt1DaLn(4z&mn3{Py&&%vL G(ftEXbRH4_ literal 0 HcmV?d00001 diff --git a/test/jdk/javax/imageio/plugins/jpeg/CMYK/magenta_cmyk.jpg b/test/jdk/javax/imageio/plugins/jpeg/CMYK/magenta_cmyk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9209e1f82b9d3ed1fcc17619bb13f4bee987b13e GIT binary patch literal 220 zcmZ9FOAdlC7=))%o3=n{0q?*qj3FT^VdsXe!G$Yt<$_bV@DM&Wp1>>owr+@ilT0R) zOondsg55To28=PRy+Ci6)o|J$Fd#rr)QDz*;E{(59*{!Jg_2q;sgzE#M8_spDs`#J ztaVl=d6C<~XG<595)~?5J9G}cL+e0SEd25JW-{gL(*C!g2Mn*#p+^fWF&=lLK2NjX GME4IrnjMJ% literal 0 HcmV?d00001 diff --git a/test/jdk/javax/imageio/plugins/jpeg/CMYK/red_cmyk.jpg b/test/jdk/javax/imageio/plugins/jpeg/CMYK/red_cmyk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..594f2ac082355fcf437a9799a40b71ac6522e208 GIT binary patch literal 220 zcmZ9FI|{-;7=$NgUH0F+c9VFA+(IM}G$EZ$T8Xu%vA6aV79PS!;|aXN@2*YIZ(tY( zhT$8(VA^KWAP54ioxpFTtMRbgV}ysFs1eRQ-b06w!lR^|OHx{sBGPdd>nM$g5}Tx% zG1llfFLG13Z1{pwp+Y5Ui{4_e=q&h(g**P>pExSqzFO$h6 zFT*!}!EW14izte)_5#0QR^xHE$A|zw(IB1$g2x^qMLy+bPjyQ!ViCECL>>0_P+%`U_^r+13F-d^Wo%gdiza$ F{{U0f9y|a5 literal 0 HcmV?d00001 diff --git a/test/jdk/javax/imageio/plugins/jpeg/CMYK/yellow_cmyk.jpg b/test/jdk/javax/imageio/plugins/jpeg/CMYK/yellow_cmyk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4a7a338b256997d8d84290a4418ac9ebd3862648 GIT binary patch literal 220 zcmZ9FOAdlC7=#C@O@mVaPgDpO9`B)papn=6FS!&-Ng<_*(^y41k}|Q0 zPK~if#aW)2++{--6apnmR#|iwy+vz5SFGIe_hvTf>cafDpa(Ro(4j{QtZ_a}r)HXG HzlrW2P4pfI literal 0 HcmV?d00001 -- GitLab From 656cba7af376d6460202591230ac95d2366de9f3 Mon Sep 17 00:00:00 2001 From: Brent Christian Date: Fri, 25 Mar 2022 17:08:25 +0000 Subject: [PATCH 168/237] 8283349: Robustness improvements to java/util/prefs/AddNodeChangeListener.jar Reviewed-by: dfuchs, naoto, lancea --- .../util/prefs/AddNodeChangeListener.java | 93 +++++++++++-------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/test/jdk/java/util/prefs/AddNodeChangeListener.java b/test/jdk/java/util/prefs/AddNodeChangeListener.java index d63ffed36b7..11a771f93e3 100644 --- a/test/jdk/java/util/prefs/AddNodeChangeListener.java +++ b/test/jdk/java/util/prefs/AddNodeChangeListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -34,75 +34,88 @@ import java.util.prefs.*; public class AddNodeChangeListener { private static final int SLEEP_ITRS = 10; + private static final String N2_STR = "N2"; private static boolean failed = false; private static Preferences userRoot, N2; private static NodeChangeListenerAdd ncla; public static void main(String[] args) throws BackingStoreException, InterruptedException { - userRoot = Preferences.userRoot(); - ncla = new NodeChangeListenerAdd(); - userRoot.addNodeChangeListener(ncla); - //Should initiate a node added event - addNode(); - // Should not initiate a node added event - addNode(); - //Should initate a child removed event - removeNode(); - - if (failed) { - throw new RuntimeException("Failed"); + try { + userRoot = Preferences.userRoot(); + // Make sure test node is not present before test + clearPrefs(); + + ncla = new NodeChangeListenerAdd(); + userRoot.addNodeChangeListener(ncla); + //Should initiate a node added event + addNode(); + // Should not initiate a node added event + addNode(); + //Should initate a child removed event + removeNode(); + + if (failed) { + throw new RuntimeException("Failed"); + } + } finally { + // Make sure test node is not present after the test + clearPrefs(); } } private static void addNode() throws BackingStoreException, InterruptedException { - N2 = userRoot.node("N2"); + N2 = userRoot.node(N2_STR); userRoot.flush(); - int passItr = -1; - - for (int i = 0; i < SLEEP_ITRS; i++) { - System.out.print("addNode sleep iteration " + i + "..."); - Thread.sleep(3000); - System.out.println("done."); - if (ncla.getAddNumber() == 1) { - passItr = i; - break; - } - } - checkPassItr(passItr, "addNode()"); + checkAndSleep(1, "addNode"); } private static void removeNode() throws BackingStoreException, InterruptedException { N2.removeNode(); userRoot.flush(); - int passItr = -1; + checkAndSleep(0, "removeNode"); + } + /* Check for the expected value in the listener (1 after addNode(), 0 after removeNode()). + * Sleep a few extra times in a loop, if needed, for debugging purposes, to + * see if the event gets delivered late. + */ + private static void checkAndSleep(int expectedListenerVal, String methodName) throws InterruptedException { + int expectedItr = -1; // iteration in which the expected value was retrieved from the listener, or -1 if never for (int i = 0; i < SLEEP_ITRS; i++) { - System.out.print("removeNode sleep iteration " + i + "..."); + System.out.print(methodName + " sleep iteration " + i + "..."); Thread.sleep(3000); System.out.println("done."); - if (ncla.getAddNumber() == 0) { - passItr = i; + if (ncla.getAddNumber() == expectedListenerVal) { + expectedItr = i; break; } } - checkPassItr(passItr, "removeNode()"); - } - /* If the listener wasn't notified on iteration 0, throw a RuntimeException - * with some contextual information - */ - private static void checkPassItr(int itr, String methodName) { - if (itr == 0) { + if (expectedItr == 0) { System.out.println(methodName + " test passed"); } else { failed = true; - if (itr == -1) { - throw new RuntimeException("Failed in " + methodName + " - change listener never notified"); + if (expectedItr == -1) { + System.out.println("Failed in " + methodName + " - change listener never notified"); } else { - throw new RuntimeException("Failed in " + methodName + " - listener notified on iteration " + itr); + System.out.println("Failed in " + methodName + " - listener notified on iteration " + expectedItr); + } + } + } + + /* Check if the node already exists in userRoot, and remove it if so. */ + private static void clearPrefs() throws BackingStoreException { + if (userRoot.nodeExists(N2_STR)) { + System.out.println("Node " + N2_STR + " already/still exists; clearing"); + Preferences clearNode = userRoot.node(N2_STR); + userRoot.flush(); + clearNode.removeNode(); + userRoot.flush(); + if (userRoot.nodeExists(N2_STR)) { + throw new RuntimeException("Unable to clear pre-existing node." + (failed ? " Also, the test failed" : "")); } } } -- GitLab From 3b5dfee939dda02e14498baa2b52b0150326b938 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 25 Mar 2022 17:10:59 +0000 Subject: [PATCH 169/237] 8283665: Two Jarsigner tests needs to be updated with JDK-8267319 Reviewed-by: xuelei, ascarpino, hchao, weijun --- .../security/tools/jarsigner/CheckAlgParams.java | 14 +++++++------- .../security/tools/jarsigner/DisableCurveTest.java | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/test/jdk/sun/security/tools/jarsigner/CheckAlgParams.java b/test/jdk/sun/security/tools/jarsigner/CheckAlgParams.java index d0a4338fee3..9f96511182e 100644 --- a/test/jdk/sun/security/tools/jarsigner/CheckAlgParams.java +++ b/test/jdk/sun/security/tools/jarsigner/CheckAlgParams.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8277474 + * @bug 8277474 8283665 * @summary jarsigner -verify should check if the algorithm parameters of * its signature algorithm use disabled or legacy algorithms * @library /test/lib @@ -56,29 +56,29 @@ public class CheckAlgParams { .shouldHaveExitValue(0); Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), - "jdk.jar.disabledAlgorithms=SHA256\n" + + "jdk.jar.disabledAlgorithms=SHA384\n" + "jdk.security.legacyAlgorithms=\n"); SecurityTools.jarsigner("-verify signeda.jar " + "-J-Djava.security.properties=" + JAVA_SECURITY_FILE + " -keystore ks -storepass changeit -verbose -debug") - .shouldMatch("Digest algorithm: SHA-256.*(disabled)") - .shouldMatch("Signature algorithm: RSASSA-PSS using PSSParameterSpec.*hashAlgorithm=SHA-256.*(disabled)") + .shouldMatch("Digest algorithm: SHA-384.*(disabled)") + .shouldMatch("Signature algorithm: RSASSA-PSS using PSSParameterSpec.*hashAlgorithm=SHA-384.*(disabled)") .shouldContain("The jar will be treated as unsigned") .shouldHaveExitValue(0); Files.deleteIfExists(Paths.get(JAVA_SECURITY_FILE)); Files.writeString(Files.createFile(Paths.get(JAVA_SECURITY_FILE)), "jdk.jar.disabledAlgorithms=\n" + - "jdk.security.legacyAlgorithms=SHA256\n"); + "jdk.security.legacyAlgorithms=SHA384\n"); SecurityTools.jarsigner("-verify signeda.jar " + "-J-Djava.security.properties=" + JAVA_SECURITY_FILE + " -keystore ks -storepass changeit -verbose -debug") - .shouldMatch("Digest algorithm: SHA-256.*(weak)") - .shouldMatch("Signature algorithm: RSASSA-PSS using PSSParameterSpec.*hashAlgorithm=SHA-256.*(weak)") + .shouldMatch("Digest algorithm: SHA-384.*(weak)") + .shouldMatch("Signature algorithm: RSASSA-PSS using PSSParameterSpec.*hashAlgorithm=SHA-384.*(weak)") .shouldNotContain("The jar will be treated as unsigned") .shouldHaveExitValue(0); } diff --git a/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java b/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java index 9270899182c..353f82ad4b2 100644 --- a/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java +++ b/test/jdk/sun/security/tools/jarsigner/DisableCurveTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8282633 + * @bug 8282633 8283665 * @summary jarsigner should display the named curve to better explain why * an EC key is disabled or will be disabled. * @library /test/lib @@ -42,7 +42,7 @@ public class DisableCurveTest { public static void main(String[] args) throws Exception{ SecurityTools.keytool("-keystore ks -storepass changeit " + - "-genkeypair -keyalg EC -alias ca -dname CN=CA " + + "-genkeypair -keyalg EC -keysize 256 -alias ca -dname CN=CA " + "-ext bc:c") .shouldHaveExitValue(0); @@ -58,7 +58,7 @@ public class DisableCurveTest { JAVA_SECURITY_FILE + " a.jar ca") .shouldContain(">>> Signer") - .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (disabled)") + .shouldContain("Signature algorithm: SHA384withECDSA, 256-bit EC (secp256r1) key (disabled)") .shouldContain("Warning:") .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk and is disabled") .shouldHaveExitValue(0); @@ -68,7 +68,7 @@ public class DisableCurveTest { JAVA_SECURITY_FILE + " -keystore ks -storepass changeit -verbose -debug") .shouldContain("- Signed by") - .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (disabled)") + .shouldContain("Signature algorithm: SHA384withECDSA, 256-bit EC (secp256r1) key (disabled)") .shouldContain("WARNING: The jar will be treated as unsigned") .shouldHaveExitValue(0); @@ -82,7 +82,7 @@ public class DisableCurveTest { JAVA_SECURITY_FILE + " a.jar ca") .shouldContain(">>> Signer") - .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (weak)") + .shouldContain("Signature algorithm: SHA384withECDSA, 256-bit EC (secp256r1) key (weak)") .shouldContain("Warning:") .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk. This key size will be disabled in a future update") .shouldHaveExitValue(0); @@ -92,7 +92,7 @@ public class DisableCurveTest { JAVA_SECURITY_FILE + " -keystore ks -storepass changeit -verbose -debug") .shouldContain("- Signed by") - .shouldContain("Signature algorithm: SHA256withECDSA, 256-bit EC (secp256r1) key (weak)") + .shouldContain("Signature algorithm: SHA384withECDSA, 256-bit EC (secp256r1) key (weak)") .shouldContain("jar verified") .shouldContain("The EC (secp256r1) signing key has a keysize of 256 which is considered a security risk. This key size will be disabled in a future update") .shouldHaveExitValue(0); -- GitLab From f4fd53d0aee67319bf2c7bcaa671c2e97e66383f Mon Sep 17 00:00:00 2001 From: Joe Wang Date: Fri, 25 Mar 2022 18:10:45 +0000 Subject: [PATCH 170/237] 8273370: Preferences.exportSubtree() generates invalid XML if value contains control char Reviewed-by: lancea, naoto --- .../xml/internal/serializer/ToStream.java | 23 ++- .../unittest/transform/OpenJDK100017Test.java | 14 +- .../unittest/transform/SerializationTest.java | 160 ++++++++++++++++++ .../jaxp/unittest/transform/preferences.xml | 12 ++ 4 files changed, 194 insertions(+), 15 deletions(-) create mode 100644 test/jaxp/javax/xml/jaxp/unittest/transform/SerializationTest.java create mode 100644 test/jaxp/javax/xml/jaxp/unittest/transform/preferences.xml diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java index 93a4dd8d301..126f5d15255 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -20,6 +20,7 @@ package com.sun.org.apache.xml.internal.serializer; +import com.sun.org.apache.xerces.internal.util.XMLChar; import com.sun.org.apache.xml.internal.serializer.dom3.DOMConstants; import com.sun.org.apache.xml.internal.serializer.utils.MsgKey; import com.sun.org.apache.xml.internal.serializer.utils.Utils; @@ -54,7 +55,7 @@ import org.xml.sax.SAXException; * serializers (xml, html, text ...) that write output to a stream. * * @xsl.usage internal - * @LastModified: June 2021 + * @LastModified: Mar 2022 */ abstract public class ToStream extends SerializerBase { @@ -1745,13 +1746,19 @@ abstract public class ToStream extends SerializerBase { } else { - /* This if check is added to support control characters in XML 1.1. - * If a character is a Control Character within C0 and C1 range, it is desirable - * to write it out as Numeric Character Reference(NCR) regardless of XML Version - * being used for output document. + /* + * The check was added to support control characters in XML 1.1. + * It previously wrote Control Characters within C0 and C1 range + * as Numeric Character Reference(NCR) regardless of XML Version, + * which was incorrect as Control Characters are invalid in XML 1.0. */ - if (isCharacterInC0orC1Range(ch) || - (XMLVERSION11.equals(getVersion()) && isNELorLSEPCharacter(ch))) + boolean isVer11 = XMLVERSION11.equals(getVersion()); + if (!isVer11 && XMLChar.isInvalid(ch)) { + throw new org.xml.sax.SAXException(Utils.messages.createMessage( + MsgKey.ER_WF_INVALID_CHARACTER_IN_TEXT, + new Object[]{Integer.toHexString(ch)})); + } + if (isCharacterInC0orC1Range(ch) || (isVer11 && isNELorLSEPCharacter(ch))) { writeCharRef(writer, ch); } diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/OpenJDK100017Test.java b/test/jaxp/javax/xml/jaxp/unittest/transform/OpenJDK100017Test.java index 425468ef26a..f3802ec5c46 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/transform/OpenJDK100017Test.java +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/OpenJDK100017Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2022, 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,6 +23,7 @@ package transform; +import com.sun.org.apache.xerces.internal.util.XMLChar; import java.io.IOException; import javax.xml.transform.TransformerConfigurationException; @@ -32,19 +33,16 @@ import javax.xml.transform.sax.TransformerHandler; import javax.xml.transform.stream.StreamResult; import org.testng.Assert; -import org.testng.annotations.Listeners; import org.testng.annotations.Test; import org.xml.sax.SAXException; /* * @test - * @bug 6883209 - * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest - * @run testng/othervm -DrunSecMngr=true -Djava.security.manager=allow transform.OpenJDK100017Test + * @bug 6883209 8273370 + * @modules java.xml/com.sun.org.apache.xerces.internal.util * @run testng/othervm transform.OpenJDK100017Test * @summary Test XSLT won't cause StackOverflow when it handle many characters. */ -@Listeners({jaxp.library.BasePolicy.class}) public class OpenJDK100017Test { @Test @@ -56,7 +54,9 @@ public class OpenJDK100017Test { StringBuilder sb = new StringBuilder(4096); for (int x = 4096; x > 0; x--) { - sb.append((char) x); + if (XMLChar.isValid(x)) { + sb.append((char)x); + } } ser.characters(sb.toString().toCharArray(), 0, sb.toString().toCharArray().length); ser.endDocument(); diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/SerializationTest.java b/test/jaxp/javax/xml/jaxp/unittest/transform/SerializationTest.java new file mode 100644 index 00000000000..b13a9a2c93b --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/SerializationTest.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2022, 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. + */ +package transform; + +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.prefs.InvalidPreferencesFormatException; +import java.util.prefs.Preferences; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.testng.Assert; +import org.testng.annotations.Test; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; + +/* + * @test + * @bug 8273370 + * @run testng transform.SerializationTest + * @summary Verifies that the characters are written correctly during serialization. + */ +public class SerializationTest { + + private static final String PREFS_DTD_URI + = "http://java.sun.com/dtd/preferences.dtd"; + private static String CLS_DIR = System.getProperty("test.classes", "."); + private static String SRC_DIR = System.getProperty("test.src"); + + /** + * Verifies that the XMLSupport for exportSubtree handles control characters + * correctly by reporting en error. + * + * Note: exportSubtree currently throws AssertionError. It would be more + * appropriate to throw InvalidPreferencesFormatException as the import + * method does. Since this is an edge case however, we'll keep it as is to + * avoid signature change. + * + * The following was the original test: + Preferences p = Preferences.userRoot().node("test"); + p.put("key", "[\u0018\u0019]"); + p.exportSubtree(new ByteArrayOutputStream()); + * + * The code however, hanged when running in JTReg. This test therefore replaced + * the above code with the process extracted from the exportSubtree routine. + * + * @throws Exception if the test fails + */ + @Test + public void testTrasformer() throws Exception { + Assert.assertThrows(AssertionError.class, + () -> export(new ByteArrayOutputStream())); + } + + private void export(OutputStream os) throws IOException { + Document doc = createPrefsDoc("preferences"); + Element preferences = doc.getDocumentElement(); + preferences.setAttribute("EXTERNAL_XML_VERSION", "1.0"); + Element xmlRoot = (Element) preferences.appendChild(doc.createElement("root")); + xmlRoot.setAttribute("type", "user"); + + Element e = xmlRoot; + + e.appendChild(doc.createElement("map")); + e = (Element) e.appendChild(doc.createElement("node")); + e.setAttribute("name", "test"); + + putPreferencesInXml(e, doc); + + writeDoc(doc, os); + } + + private static Document createPrefsDoc(String qname) { + try { + DOMImplementation di = DocumentBuilderFactory.newInstance(). + newDocumentBuilder().getDOMImplementation(); + DocumentType dt = di.createDocumentType(qname, null, PREFS_DTD_URI); + return di.createDocument(null, qname, dt); + } catch (ParserConfigurationException e) { + throw new AssertionError(e); + } + } + + private static void putPreferencesInXml(Element elt, Document doc) { + Element map = (Element) elt.appendChild(doc.createElement("map")); + Element entry = (Element) map.appendChild(doc.createElement("entry")); + entry.setAttribute("key", "key"); + entry.setAttribute("value", "[\u0018\u0019]"); + } + + private void writeDoc(Document doc, OutputStream out) + throws IOException { + try { + TransformerFactory tf = TransformerFactory.newInstance(); + tf.setAttribute("indent-number", 2); + Transformer t = tf.newTransformer(); + t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, doc.getDoctype().getSystemId()); + t.setOutputProperty(OutputKeys.INDENT, "yes"); + //Transformer resets the "indent" info if the "result" is a StreamResult with + //an OutputStream object embedded, creating a Writer object on top of that + //OutputStream object however works. + t.transform(new DOMSource(doc), + new StreamResult(new BufferedWriter(new OutputStreamWriter(out, "UTF-8")))); + } catch (TransformerException e) { + throw new AssertionError(e); + } + } + + /** + * Verifies that the XMLSupport for importPreferences handles control + * characters correctly by reporting en error. + * + * Note: this is the existing behavior. This test is here to match with the + * export method. + * + * "preferences.xml" was generated by calling the exportSubtree method + * before the patch. + * + * @throws Exception if the test fails + */ + @Test + public void testParser() throws Exception { + Assert.assertThrows(InvalidPreferencesFormatException.class, () -> { + Preferences.importPreferences( + new FileInputStream(new File(SRC_DIR + "/preferences.xml"))); + }); + } +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/preferences.xml b/test/jaxp/javax/xml/jaxp/unittest/transform/preferences.xml new file mode 100644 index 00000000000..f2ac3cf4860 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/preferences.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + -- GitLab From 36b36efa12876c592d9bf4b381887ecbf49bc2c9 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 25 Mar 2022 21:16:51 +0000 Subject: [PATCH 171/237] 8283661: Unexpected TypeElement in ANALYZE TaskEvent Reviewed-by: vromero, jlahoda --- .../sun/tools/javac/main/JavaCompiler.java | 24 ++- .../sun/tools/javac/model/JavacElements.java | 12 +- .../api/taskListeners/TestTypeElement.java | 168 ++++++++++++++++++ 3 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 test/langtools/tools/javac/api/taskListeners/TestTypeElement.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 1b8b7077ed8..fa849c08e97 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, 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 @@ -1305,7 +1305,7 @@ public class JavaCompiler { log.printVerbose("checking.attribution", env.enclClass.sym); if (!taskListener.isEmpty()) { - TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym); + TaskEvent e = newAnalyzeTaskEvent(env); taskListener.started(e); } @@ -1390,12 +1390,30 @@ public class JavaCompiler { } finally { if (!taskListener.isEmpty()) { - TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym); + TaskEvent e = newAnalyzeTaskEvent(env); taskListener.finished(e); } } } + private TaskEvent newAnalyzeTaskEvent(Env env) { + JCCompilationUnit toplevel = env.toplevel; + ClassSymbol sym; + if (env.enclClass.sym == syms.predefClass) { + if (TreeInfo.isModuleInfo(toplevel)) { + sym = toplevel.modle.module_info; + } else if (TreeInfo.isPackageInfo(toplevel)) { + sym = toplevel.packge.package_info; + } else { + throw new IllegalStateException("unknown env.toplevel"); + } + } else { + sym = env.enclClass.sym; + } + + return new TaskEvent(TaskEvent.Kind.ANALYZE, toplevel, sym); + } + /** * Prepare attributed parse trees, in conjunction with their attribution contexts, * for source or code generation. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java index ed909c8b80f..a691f44cdab 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -445,10 +445,8 @@ public class JavacElements implements Elements { @DefinedBy(Api.LANGUAGE_MODEL) public PackageElement getPackageOf(Element e) { - if (e.getKind() == ElementKind.MODULE) - return null; - else - return cast(Symbol.class, e).packge(); + Symbol sym = cast(Symbol.class, e); + return (sym.kind == MDL || sym.owner.kind == MDL) ? null : sym.packge(); } @DefinedBy(Api.LANGUAGE_MODEL) @@ -456,7 +454,9 @@ public class JavacElements implements Elements { Symbol sym = cast(Symbol.class, e); if (modules.getDefaultModule() == syms.noModule) return null; - return (sym.kind == MDL) ? ((ModuleElement) e) : sym.packge().modle; + return (sym.kind == MDL) ? ((ModuleElement) e) + : (sym.owner.kind == MDL) ? (ModuleElement) sym.owner + : sym.packge().modle; } @DefinedBy(Api.LANGUAGE_MODEL) diff --git a/test/langtools/tools/javac/api/taskListeners/TestTypeElement.java b/test/langtools/tools/javac/api/taskListeners/TestTypeElement.java new file mode 100644 index 00000000000..058cbecd628 --- /dev/null +++ b/test/langtools/tools/javac/api/taskListeners/TestTypeElement.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2022, 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 8283661 + * @summary Unexpected TypeElement in ANALYZE TaskEvent + * @modules jdk.compiler + * @run main TestTypeElement + */ + +import java.io.IOException; +import java.io.PrintStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +import javax.lang.model.element.TypeElement; +import javax.lang.model.util.Elements; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.ToolProvider; + +import com.sun.source.util.JavacTask; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; + +public class TestTypeElement { + public static void main(String... args) throws Exception { + new TestTypeElement().run(); + } + + private PrintStream log; + private Elements elements; + private int errors; + + void run() throws Exception { + log = System.err; + + List files = List.of( + createFileObject("module-info.java", "module m { }"), + createFileObject("p/package-info.java", "/** Comment. */ package p;"), + createFileObject("p/C.java", "package p; public class C { }") + ); + + JavaCompiler c = ToolProvider.getSystemJavaCompiler(); + JavacTask t = (JavacTask) c.getTask(null, null, null, List.of("-d", "classes"), null, files); + t.addTaskListener(new TaskListener() { + @Override + public void started(TaskEvent e) { + log.println("started: " + e); + checkTypeElement(e); + } + @Override + public void finished(TaskEvent e) { + log.println("finished: " + e); + checkTypeElement(e); + } + }); + elements = t.getElements(); + t.call(); + + if (errors > 0) { + log.println(errors + " errors occurred"); + throw new Exception(errors + " errors occurred"); + } + } + + private void checkTypeElement(TaskEvent e) { + TypeElement te = e.getTypeElement(); + + if (te != null) { + showTypeElement(e.getTypeElement()); + } + + switch (e.getKind()) { + case COMPILATION, PARSE, ENTER -> { + checkEqual(te, null); + } + + case ANALYZE, GENERATE -> { + if (te == null) { + error("type element is null"); + return; + } + + + switch (te.getQualifiedName().toString()) { + case "m.module-info" -> { + checkEqual(elements.getModuleOf(te), elements.getModuleElement("m")); + checkEqual(elements.getPackageOf(te), null); + } + case "p.package-info", "p.C" -> { + checkEqual(elements.getModuleOf(te), elements.getModuleElement("m")); + checkEqual(elements.getPackageOf(te), elements.getPackageElement("p")); + } + } + } + } + } + + private void showTypeElement(TypeElement e) { + log.println("type element: " + e); + + try { + log.println(" module element: " + elements.getModuleOf(e)); + } catch (Throwable t) { + log.println(" module element: " + t); + } + + try { + log.println(" package element: " + elements.getPackageOf(e)); + } catch (Throwable t) { + log.println(" package element: " + t); + } + } + + private void checkEqual(T found, T expected) { + if (found != expected) { + error("mismatch"); + log.println(" found: " + found); + log.println("expected: " + expected); + } + } + + private void error(String message) { + log.println("Error: " + message); + errors++; + } + + private JavaFileObject createFileObject(String name, String body) { + return createFileObject(name, JavaFileObject.Kind.SOURCE, body); + } + + private JavaFileObject createFileObject(String name, JavaFileObject.Kind kind, String body) { + try { + return new SimpleJavaFileObject(new URI("myfo:///" + name), kind) { + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return body; + } + }; + } catch (URISyntaxException e) { + throw new IllegalArgumentException(name, e); + } + } +} \ No newline at end of file -- GitLab From cb012a5b625a7707c429f1e95db59018a6dcb992 Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 25 Mar 2022 21:20:02 +0000 Subject: [PATCH 172/237] 8283648: Improve the snippet "file not found" message. Reviewed-by: prappo --- .../doclets/toolkit/resources/doclets.properties | 3 ++- .../doclets/toolkit/taglets/SnippetTaglet.java | 4 ++-- .../javadoc/doclet/testSnippetTag/TestSnippetTag.java | 10 +++++----- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties index c67865344ee..55ce24edd87 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclets.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2010, 2022, 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 @@ -52,6 +52,7 @@ Please file a bug against the javadoc tool via the Java bug reporting page\n\ (http://bugreport.java.com) after checking the Bug Database (http://bugs.java.com)\n\ for duplicates. Include error messages and the following diagnostic in your report. Thank you. doclet.File_not_found=File not found: {0} +doclet.snippet_file_not_found=file not found on source path or snippet path: {0} doclet.Copy_Overwrite_warning=File {0} not copied to {1} due to existing file with same name... doclet.Copy_Ignored_warning=File {0} not copied: invalid name doclet.Copy_snippet_to_clipboard=Copy diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SnippetTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SnippetTaglet.java index 3c13b194c22..a10f369c1b1 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SnippetTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SnippetTaglet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -240,7 +240,7 @@ public class SnippetTaglet extends BaseTaglet { if (fileObject == null) { // i.e. the file does not exist - throw new BadSnippetException(a, "doclet.File_not_found", v); + throw new BadSnippetException(a, "doclet.snippet_file_not_found", v); } try { diff --git a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java index 4b0dd06a2a2..9923a191a57 100644 --- a/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java +++ b/test/langtools/jdk/javadoc/doclet/testSnippetTag/TestSnippetTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -1079,11 +1079,11 @@ public class TestSnippetTag extends SnippetTester { checkExit(Exit.ERROR); checkOutput(Output.OUT, true, """ - A.java:4: error: File not found: %s""".formatted(fileName)); + A.java:4: error: file not found on source path or snippet path: %s""".formatted(fileName)); checkOutput("pkg/A.html", true, """

      invalid @snippet -
      File not found: text.txt
      +
      file not found on source path or snippet path: text.txt
      """); checkNoCrashes(); @@ -1140,7 +1140,7 @@ public class TestSnippetTag extends SnippetTester { checkExit(Exit.ERROR); checkOutput(Output.OUT, true, """ - A.java:4: error: File not found: %s""".formatted(fileName)); + A.java:4: error: file not found on source path or snippet path: %s""".formatted(fileName)); checkNoCrashes(); } @@ -1869,7 +1869,7 @@ public class TestSnippetTag extends SnippetTester { checkExit(Exit.ERROR); checkOutput(Output.OUT, true, """ - A.java:4: error: File not found: %s""".formatted(fileName)); + A.java:4: error: file not found on source path or snippet path: %s""".formatted(fileName)); checkNoCrashes(); } -- GitLab From e97cf157cf20aeaef4a8c16fed6f3bb2bc933819 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 25 Mar 2022 21:21:05 +0000 Subject: [PATCH 173/237] 8283691: Classes in java.security still reference deprecated classes in spec Reviewed-by: hchao, mullan, wetmore --- src/java.base/share/classes/java/security/Key.java | 2 -- src/java.base/share/classes/java/security/PrivateKey.java | 4 ++-- src/java.base/share/classes/java/security/PublicKey.java | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/security/Key.java b/src/java.base/share/classes/java/security/Key.java index 4ea5ae0887b..1c01095caf9 100644 --- a/src/java.base/share/classes/java/security/Key.java +++ b/src/java.base/share/classes/java/security/Key.java @@ -93,8 +93,6 @@ package java.security; * @see KeyFactory * @see KeyRep * @see java.security.spec.KeySpec - * @see Identity - * @see Signer * * @author Benjamin Renaud * @since 1.1 diff --git a/src/java.base/share/classes/java/security/PrivateKey.java b/src/java.base/share/classes/java/security/PrivateKey.java index 3402aa66c8b..2fb07ab816e 100644 --- a/src/java.base/share/classes/java/security/PrivateKey.java +++ b/src/java.base/share/classes/java/security/PrivateKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -46,7 +46,7 @@ package java.security; * * @see Key * @see PublicKey - * @see Certificate + * @see java.security.cert.Certificate * @see Signature#initVerify * @see java.security.interfaces.DSAPrivateKey * @see java.security.interfaces.RSAPrivateKey diff --git a/src/java.base/share/classes/java/security/PublicKey.java b/src/java.base/share/classes/java/security/PublicKey.java index dca5bece1bd..737273bdbbc 100644 --- a/src/java.base/share/classes/java/security/PublicKey.java +++ b/src/java.base/share/classes/java/security/PublicKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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 @@ -37,7 +37,7 @@ package java.security; * @since 1.1 * @see Key * @see PrivateKey - * @see Certificate + * @see java.security.cert.Certificate * @see Signature#initVerify * @see java.security.interfaces.DSAPublicKey * @see java.security.interfaces.RSAPublicKey -- GitLab From 2600f99fece951259fa3ef4deeb8da4aa2cc436e Mon Sep 17 00:00:00 2001 From: Calvin Cheung Date: Fri, 25 Mar 2022 21:31:21 +0000 Subject: [PATCH 174/237] 8282685: fileToEncodedURL_[name|signature] symbols are unused Reviewed-by: hseigel --- src/hotspot/share/classfile/vmSymbols.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index e0402392467..d962eda50a2 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -465,8 +465,6 @@ template(security_manager_signature, "Ljava/lang/SecurityManager;") \ template(defineOrCheckPackage_name, "defineOrCheckPackage") \ template(defineOrCheckPackage_signature, "(Ljava/lang/String;Ljava/util/jar/Manifest;Ljava/net/URL;)Ljava/lang/Package;") \ - template(fileToEncodedURL_name, "fileToEncodedURL") \ - template(fileToEncodedURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ template(getProtectionDomain_name, "getProtectionDomain") \ template(getProtectionDomain_signature, "(Ljava/security/CodeSource;)Ljava/security/ProtectionDomain;") \ template(java_lang_Integer_array_signature, "[Ljava/lang/Integer;") \ -- GitLab From 7bac0a878d918745ed036954cbbee590ce810c71 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Fri, 25 Mar 2022 22:37:55 +0000 Subject: [PATCH 175/237] 8283681: Improve ZonedDateTime offset handling Reviewed-by: scolebourne, naoto, rriggs --- .../share/classes/java/time/ZoneId.java | 5 + .../share/classes/java/time/ZoneOffset.java | 23 +++- .../share/classes/java/time/ZoneRegion.java | 5 + .../classes/java/time/ZonedDateTime.java | 6 +- .../openjdk/bench/java/time/GetYearBench.java | 121 ++++++++++++++++++ 5 files changed, 156 insertions(+), 4 deletions(-) create mode 100644 test/micro/org/openjdk/bench/java/time/GetYearBench.java diff --git a/src/java.base/share/classes/java/time/ZoneId.java b/src/java.base/share/classes/java/time/ZoneId.java index 829ed5f2fdf..14196c160fb 100644 --- a/src/java.base/share/classes/java/time/ZoneId.java +++ b/src/java.base/share/classes/java/time/ZoneId.java @@ -584,6 +584,11 @@ public abstract sealed class ZoneId implements Serializable permits ZoneOffset, return this; } + /** + * Get the effective offset for an instant at the given epochSecond. + */ + /* package-private */ abstract ZoneOffset getOffset(long epochSecond); + //----------------------------------------------------------------------- /** * Checks if this time-zone ID is equal to another time-zone ID. diff --git a/src/java.base/share/classes/java/time/ZoneOffset.java b/src/java.base/share/classes/java/time/ZoneOffset.java index f061040b9e2..9dd64789409 100644 --- a/src/java.base/share/classes/java/time/ZoneOffset.java +++ b/src/java.base/share/classes/java/time/ZoneOffset.java @@ -86,6 +86,8 @@ import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import jdk.internal.vm.annotation.Stable; + /** * A time-zone offset from Greenwich/UTC, such as {@code +02:00}. *

      @@ -168,6 +170,11 @@ public final class ZoneOffset * The string form of the time-zone offset. */ private final transient String id; + /** + * The zone rules for an offset will always return this offset. Cache it for efficiency. + */ + @Stable + private transient ZoneRules rules; //----------------------------------------------------------------------- /** @@ -504,7 +511,21 @@ public final class ZoneOffset */ @Override public ZoneRules getRules() { - return ZoneRules.of(this); + ZoneRules rules = this.rules; + if (rules == null) { + rules = this.rules = ZoneRules.of(this); + } + return rules; + } + + @Override + public ZoneId normalized() { + return this; + } + + @Override + /* package-private */ ZoneOffset getOffset(long epochSecond) { + return this; } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/ZoneRegion.java b/src/java.base/share/classes/java/time/ZoneRegion.java index aec8a2b108b..9a7e66f0943 100644 --- a/src/java.base/share/classes/java/time/ZoneRegion.java +++ b/src/java.base/share/classes/java/time/ZoneRegion.java @@ -178,6 +178,11 @@ final class ZoneRegion extends ZoneId implements Serializable { return (rules != null ? rules : ZoneRulesProvider.getRules(id, false)); } + @Override + /* package-private */ ZoneOffset getOffset(long epochSecond) { + return getRules().getOffset(Instant.ofEpochSecond(epochSecond)); + } + //----------------------------------------------------------------------- /** * Writes the object using a diff --git a/src/java.base/share/classes/java/time/ZonedDateTime.java b/src/java.base/share/classes/java/time/ZonedDateTime.java index acd68706b1c..555392cf513 100644 --- a/src/java.base/share/classes/java/time/ZonedDateTime.java +++ b/src/java.base/share/classes/java/time/ZonedDateTime.java @@ -452,9 +452,9 @@ public final class ZonedDateTime * @throws DateTimeException if the result exceeds the supported range */ private static ZonedDateTime create(long epochSecond, int nanoOfSecond, ZoneId zone) { - ZoneRules rules = zone.getRules(); - Instant instant = Instant.ofEpochSecond(epochSecond, nanoOfSecond); // TODO: rules should be queryable by epochSeconds - ZoneOffset offset = rules.getOffset(instant); + // nanoOfSecond is in a range that'll not affect epochSecond, validated + // by LocalDateTime.ofEpochSecond + ZoneOffset offset = zone.getOffset(epochSecond); LocalDateTime ldt = LocalDateTime.ofEpochSecond(epochSecond, nanoOfSecond, offset); return new ZonedDateTime(ldt, offset, zone); } diff --git a/test/micro/org/openjdk/bench/java/time/GetYearBench.java b/test/micro/org/openjdk/bench/java/time/GetYearBench.java new file mode 100644 index 00000000000..59d3b84a297 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/time/GetYearBench.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022, 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. + */ +package org.openjdk.bench.java.time; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + +import java.util.Locale; +import java.util.Random; +import java.util.TimeZone; +import java.util.concurrent.TimeUnit; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; +import org.openjdk.jmh.infra.Blackhole; + +/** + * Examine ability to perform escape analysis on expressions + * such as {@code Instant.ofEpochMilli(value).atZone(ZoneOffset.UTC).getYear()} + */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +@Fork(3) +@State(Scope.Benchmark) +public class GetYearBench { + + private TimeZone UTC = TimeZone.getTimeZone("UTC"); + + private TimeZone LONDON = TimeZone.getTimeZone("Europe/London"); + + private long[] INSTANT_MILLIS; + + private int[] YEARS; + + @Setup + public void createInstants() { + // Various instants during the same day + final Instant loInstant = Instant.EPOCH.plus(Duration.ofDays(365*50)); // 2020-01-01 + final Instant hiInstant = loInstant.plus(Duration.ofDays(1)); + final long maxOffsetNanos = Duration.between(loInstant, hiInstant).toNanos(); + final Random random = new Random(0); + INSTANT_MILLIS = IntStream + .range(0, 1_000) + .mapToObj(ignored -> { + final long offsetNanos = (long) Math.floor(random.nextDouble() * maxOffsetNanos); + return loInstant.plus(offsetNanos, ChronoUnit.NANOS); + }) + .mapToLong(instant -> instant.toEpochMilli()) + .toArray(); + YEARS = new int[INSTANT_MILLIS.length]; + } + + @Benchmark + public int[] getYearFromMillisZoneOffset() { + for (int i = 0; i < YEARS.length; i++) { + YEARS[i] = Instant.ofEpochMilli(INSTANT_MILLIS[i]).atZone(ZoneOffset.UTC).getYear(); + } + return YEARS; + } + + @Benchmark + public int[] getYearFromMillisZoneRegionUTC() { + for (int i = 0; i < YEARS.length; i++) { + YEARS[i] = Instant.ofEpochMilli(INSTANT_MILLIS[i]).atZone(UTC.toZoneId()).getYear(); + } + return YEARS; + } + + @Benchmark + public int[] getYearFromMillisZoneRegion() { + for (int i = 0; i < YEARS.length; i++) { + YEARS[i] = Instant.ofEpochMilli(INSTANT_MILLIS[i]).atZone(LONDON.toZoneId()).getYear(); + } + return YEARS; + } + + @Benchmark + public int[] getYearFromMillisZoneRegionNormalized() { + for (int i = 0; i < YEARS.length; i++) { + YEARS[i] = Instant.ofEpochMilli(INSTANT_MILLIS[i]).atZone(UTC.toZoneId().normalized()).getYear(); + } + return YEARS; + } +} -- GitLab From 5ca8b91898cfdcff1e44df3b7f3070a2111f770b Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Fri, 25 Mar 2022 23:21:08 +0000 Subject: [PATCH 176/237] 8283713: [BACKOUT] Unexpected TypeElement in ANALYZE TaskEvent Reviewed-by: prr --- .../sun/tools/javac/main/JavaCompiler.java | 24 +-- .../sun/tools/javac/model/JavacElements.java | 12 +- .../api/taskListeners/TestTypeElement.java | 168 ------------------ 3 files changed, 9 insertions(+), 195 deletions(-) delete mode 100644 test/langtools/tools/javac/api/taskListeners/TestTypeElement.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index fa849c08e97..1b8b7077ed8 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2021, 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 @@ -1305,7 +1305,7 @@ public class JavaCompiler { log.printVerbose("checking.attribution", env.enclClass.sym); if (!taskListener.isEmpty()) { - TaskEvent e = newAnalyzeTaskEvent(env); + TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym); taskListener.started(e); } @@ -1390,30 +1390,12 @@ public class JavaCompiler { } finally { if (!taskListener.isEmpty()) { - TaskEvent e = newAnalyzeTaskEvent(env); + TaskEvent e = new TaskEvent(TaskEvent.Kind.ANALYZE, env.toplevel, env.enclClass.sym); taskListener.finished(e); } } } - private TaskEvent newAnalyzeTaskEvent(Env env) { - JCCompilationUnit toplevel = env.toplevel; - ClassSymbol sym; - if (env.enclClass.sym == syms.predefClass) { - if (TreeInfo.isModuleInfo(toplevel)) { - sym = toplevel.modle.module_info; - } else if (TreeInfo.isPackageInfo(toplevel)) { - sym = toplevel.packge.package_info; - } else { - throw new IllegalStateException("unknown env.toplevel"); - } - } else { - sym = env.enclClass.sym; - } - - return new TaskEvent(TaskEvent.Kind.ANALYZE, toplevel, sym); - } - /** * Prepare attributed parse trees, in conjunction with their attribution contexts, * for source or code generation. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java index a691f44cdab..ed909c8b80f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2021, 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 @@ -445,8 +445,10 @@ public class JavacElements implements Elements { @DefinedBy(Api.LANGUAGE_MODEL) public PackageElement getPackageOf(Element e) { - Symbol sym = cast(Symbol.class, e); - return (sym.kind == MDL || sym.owner.kind == MDL) ? null : sym.packge(); + if (e.getKind() == ElementKind.MODULE) + return null; + else + return cast(Symbol.class, e).packge(); } @DefinedBy(Api.LANGUAGE_MODEL) @@ -454,9 +456,7 @@ public class JavacElements implements Elements { Symbol sym = cast(Symbol.class, e); if (modules.getDefaultModule() == syms.noModule) return null; - return (sym.kind == MDL) ? ((ModuleElement) e) - : (sym.owner.kind == MDL) ? (ModuleElement) sym.owner - : sym.packge().modle; + return (sym.kind == MDL) ? ((ModuleElement) e) : sym.packge().modle; } @DefinedBy(Api.LANGUAGE_MODEL) diff --git a/test/langtools/tools/javac/api/taskListeners/TestTypeElement.java b/test/langtools/tools/javac/api/taskListeners/TestTypeElement.java deleted file mode 100644 index 058cbecd628..00000000000 --- a/test/langtools/tools/javac/api/taskListeners/TestTypeElement.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2022, 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 8283661 - * @summary Unexpected TypeElement in ANALYZE TaskEvent - * @modules jdk.compiler - * @run main TestTypeElement - */ - -import java.io.IOException; -import java.io.PrintStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.List; - -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; -import javax.tools.JavaCompiler; -import javax.tools.JavaFileObject; -import javax.tools.SimpleJavaFileObject; -import javax.tools.ToolProvider; - -import com.sun.source.util.JavacTask; -import com.sun.source.util.TaskEvent; -import com.sun.source.util.TaskListener; - -public class TestTypeElement { - public static void main(String... args) throws Exception { - new TestTypeElement().run(); - } - - private PrintStream log; - private Elements elements; - private int errors; - - void run() throws Exception { - log = System.err; - - List files = List.of( - createFileObject("module-info.java", "module m { }"), - createFileObject("p/package-info.java", "/** Comment. */ package p;"), - createFileObject("p/C.java", "package p; public class C { }") - ); - - JavaCompiler c = ToolProvider.getSystemJavaCompiler(); - JavacTask t = (JavacTask) c.getTask(null, null, null, List.of("-d", "classes"), null, files); - t.addTaskListener(new TaskListener() { - @Override - public void started(TaskEvent e) { - log.println("started: " + e); - checkTypeElement(e); - } - @Override - public void finished(TaskEvent e) { - log.println("finished: " + e); - checkTypeElement(e); - } - }); - elements = t.getElements(); - t.call(); - - if (errors > 0) { - log.println(errors + " errors occurred"); - throw new Exception(errors + " errors occurred"); - } - } - - private void checkTypeElement(TaskEvent e) { - TypeElement te = e.getTypeElement(); - - if (te != null) { - showTypeElement(e.getTypeElement()); - } - - switch (e.getKind()) { - case COMPILATION, PARSE, ENTER -> { - checkEqual(te, null); - } - - case ANALYZE, GENERATE -> { - if (te == null) { - error("type element is null"); - return; - } - - - switch (te.getQualifiedName().toString()) { - case "m.module-info" -> { - checkEqual(elements.getModuleOf(te), elements.getModuleElement("m")); - checkEqual(elements.getPackageOf(te), null); - } - case "p.package-info", "p.C" -> { - checkEqual(elements.getModuleOf(te), elements.getModuleElement("m")); - checkEqual(elements.getPackageOf(te), elements.getPackageElement("p")); - } - } - } - } - } - - private void showTypeElement(TypeElement e) { - log.println("type element: " + e); - - try { - log.println(" module element: " + elements.getModuleOf(e)); - } catch (Throwable t) { - log.println(" module element: " + t); - } - - try { - log.println(" package element: " + elements.getPackageOf(e)); - } catch (Throwable t) { - log.println(" package element: " + t); - } - } - - private void checkEqual(T found, T expected) { - if (found != expected) { - error("mismatch"); - log.println(" found: " + found); - log.println("expected: " + expected); - } - } - - private void error(String message) { - log.println("Error: " + message); - errors++; - } - - private JavaFileObject createFileObject(String name, String body) { - return createFileObject(name, JavaFileObject.Kind.SOURCE, body); - } - - private JavaFileObject createFileObject(String name, JavaFileObject.Kind kind, String body) { - try { - return new SimpleJavaFileObject(new URI("myfo:///" + name), kind) { - @Override - public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - return body; - } - }; - } catch (URISyntaxException e) { - throw new IllegalArgumentException(name, e); - } - } -} \ No newline at end of file -- GitLab From f520b4f891b71c630bc13f5db4f305194ef227e5 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 25 Mar 2022 23:29:56 +0000 Subject: [PATCH 177/237] 8283668: Update IllegalFormatException to use sealed classes Reviewed-by: iris, jpai --- .../java/util/DuplicateFormatFlagsException.java | 4 ++-- .../FormatFlagsConversionMismatchException.java | 4 ++-- .../IllegalFormatArgumentIndexException.java | 4 ++-- .../util/IllegalFormatCodePointException.java | 4 ++-- .../util/IllegalFormatConversionException.java | 4 ++-- .../java/util/IllegalFormatException.java | 16 ++++++++++++++-- .../java/util/IllegalFormatFlagsException.java | 4 ++-- .../util/IllegalFormatPrecisionException.java | 4 ++-- .../java/util/IllegalFormatWidthException.java | 4 ++-- .../util/MissingFormatArgumentException.java | 4 ++-- .../java/util/MissingFormatWidthException.java | 4 ++-- .../util/UnknownFormatConversionException.java | 4 ++-- .../java/util/UnknownFormatFlagsException.java | 4 ++-- 13 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/java.base/share/classes/java/util/DuplicateFormatFlagsException.java b/src/java.base/share/classes/java/util/DuplicateFormatFlagsException.java index 356ea209c92..ebeb3d5c44c 100644 --- a/src/java.base/share/classes/java/util/DuplicateFormatFlagsException.java +++ b/src/java.base/share/classes/java/util/DuplicateFormatFlagsException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -35,7 +35,7 @@ package java.util; * * @since 1.5 */ -public class DuplicateFormatFlagsException extends IllegalFormatException { +public non-sealed class DuplicateFormatFlagsException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 18890531L; diff --git a/src/java.base/share/classes/java/util/FormatFlagsConversionMismatchException.java b/src/java.base/share/classes/java/util/FormatFlagsConversionMismatchException.java index 6f2464d4fb6..cca7b3eb553 100644 --- a/src/java.base/share/classes/java/util/FormatFlagsConversionMismatchException.java +++ b/src/java.base/share/classes/java/util/FormatFlagsConversionMismatchException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -34,7 +34,7 @@ package java.util; * * @since 1.5 */ -public class FormatFlagsConversionMismatchException +public non-sealed class FormatFlagsConversionMismatchException extends IllegalFormatException { @java.io.Serial diff --git a/src/java.base/share/classes/java/util/IllegalFormatArgumentIndexException.java b/src/java.base/share/classes/java/util/IllegalFormatArgumentIndexException.java index 02d5449098d..64b24411592 100644 --- a/src/java.base/share/classes/java/util/IllegalFormatArgumentIndexException.java +++ b/src/java.base/share/classes/java/util/IllegalFormatArgumentIndexException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2022, 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 @@ -33,7 +33,7 @@ package java.util; * * @since 16 */ -class IllegalFormatArgumentIndexException extends IllegalFormatException { +final class IllegalFormatArgumentIndexException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 4191767811181838112L; diff --git a/src/java.base/share/classes/java/util/IllegalFormatCodePointException.java b/src/java.base/share/classes/java/util/IllegalFormatCodePointException.java index 14ec9137f1e..2f1803d220e 100644 --- a/src/java.base/share/classes/java/util/IllegalFormatCodePointException.java +++ b/src/java.base/share/classes/java/util/IllegalFormatCodePointException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -36,7 +36,7 @@ package java.util; * * @since 1.5 */ -public class IllegalFormatCodePointException extends IllegalFormatException { +public non-sealed class IllegalFormatCodePointException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 19080630L; diff --git a/src/java.base/share/classes/java/util/IllegalFormatConversionException.java b/src/java.base/share/classes/java/util/IllegalFormatConversionException.java index 2dacf2094b4..67237f63cdf 100644 --- a/src/java.base/share/classes/java/util/IllegalFormatConversionException.java +++ b/src/java.base/share/classes/java/util/IllegalFormatConversionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -35,7 +35,7 @@ package java.util; * * @since 1.5 */ -public class IllegalFormatConversionException extends IllegalFormatException { +public non-sealed class IllegalFormatConversionException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 17000126L; diff --git a/src/java.base/share/classes/java/util/IllegalFormatException.java b/src/java.base/share/classes/java/util/IllegalFormatException.java index 97b85cc107e..f5be4ad268b 100644 --- a/src/java.base/share/classes/java/util/IllegalFormatException.java +++ b/src/java.base/share/classes/java/util/IllegalFormatException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -33,7 +33,19 @@ package java.util; * * @since 1.5 */ -public class IllegalFormatException extends IllegalArgumentException { +public sealed class IllegalFormatException extends IllegalArgumentException + permits DuplicateFormatFlagsException, + FormatFlagsConversionMismatchException, + IllegalFormatArgumentIndexException, + IllegalFormatCodePointException, + IllegalFormatConversionException, + IllegalFormatFlagsException, + IllegalFormatPrecisionException, + IllegalFormatWidthException, + MissingFormatArgumentException, + MissingFormatWidthException, + UnknownFormatConversionException, + UnknownFormatFlagsException { @java.io.Serial private static final long serialVersionUID = 18830826L; diff --git a/src/java.base/share/classes/java/util/IllegalFormatFlagsException.java b/src/java.base/share/classes/java/util/IllegalFormatFlagsException.java index 38e4e2d577e..408fa1efa5c 100644 --- a/src/java.base/share/classes/java/util/IllegalFormatFlagsException.java +++ b/src/java.base/share/classes/java/util/IllegalFormatFlagsException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -34,7 +34,7 @@ package java.util; * * @since 1.5 */ -public class IllegalFormatFlagsException extends IllegalFormatException { +public non-sealed class IllegalFormatFlagsException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 790824L; diff --git a/src/java.base/share/classes/java/util/IllegalFormatPrecisionException.java b/src/java.base/share/classes/java/util/IllegalFormatPrecisionException.java index bdf3de6f528..4527953790c 100644 --- a/src/java.base/share/classes/java/util/IllegalFormatPrecisionException.java +++ b/src/java.base/share/classes/java/util/IllegalFormatPrecisionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -34,7 +34,7 @@ package java.util; * * @since 1.5 */ -public class IllegalFormatPrecisionException extends IllegalFormatException { +public non-sealed class IllegalFormatPrecisionException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 18711008L; diff --git a/src/java.base/share/classes/java/util/IllegalFormatWidthException.java b/src/java.base/share/classes/java/util/IllegalFormatWidthException.java index e00ec01eee0..df8d59b9e81 100644 --- a/src/java.base/share/classes/java/util/IllegalFormatWidthException.java +++ b/src/java.base/share/classes/java/util/IllegalFormatWidthException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -33,7 +33,7 @@ package java.util; * * @since 1.5 */ -public class IllegalFormatWidthException extends IllegalFormatException { +public non-sealed class IllegalFormatWidthException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 16660902L; diff --git a/src/java.base/share/classes/java/util/MissingFormatArgumentException.java b/src/java.base/share/classes/java/util/MissingFormatArgumentException.java index dcb0847833b..6363566216b 100644 --- a/src/java.base/share/classes/java/util/MissingFormatArgumentException.java +++ b/src/java.base/share/classes/java/util/MissingFormatArgumentException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -36,7 +36,7 @@ package java.util; * * @since 1.5 */ -public class MissingFormatArgumentException extends IllegalFormatException { +public non-sealed class MissingFormatArgumentException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 19190115L; diff --git a/src/java.base/share/classes/java/util/MissingFormatWidthException.java b/src/java.base/share/classes/java/util/MissingFormatWidthException.java index 0ce9c3af83c..b553a3876ac 100644 --- a/src/java.base/share/classes/java/util/MissingFormatWidthException.java +++ b/src/java.base/share/classes/java/util/MissingFormatWidthException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -34,7 +34,7 @@ package java.util; * * @since 1.5 */ -public class MissingFormatWidthException extends IllegalFormatException { +public non-sealed class MissingFormatWidthException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 15560123L; diff --git a/src/java.base/share/classes/java/util/UnknownFormatConversionException.java b/src/java.base/share/classes/java/util/UnknownFormatConversionException.java index 07519ade170..13d428e0b60 100644 --- a/src/java.base/share/classes/java/util/UnknownFormatConversionException.java +++ b/src/java.base/share/classes/java/util/UnknownFormatConversionException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -34,7 +34,7 @@ package java.util; * * @since 1.5 */ -public class UnknownFormatConversionException extends IllegalFormatException { +public non-sealed class UnknownFormatConversionException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 19060418L; diff --git a/src/java.base/share/classes/java/util/UnknownFormatFlagsException.java b/src/java.base/share/classes/java/util/UnknownFormatFlagsException.java index c498711fa21..93eaf85b389 100644 --- a/src/java.base/share/classes/java/util/UnknownFormatFlagsException.java +++ b/src/java.base/share/classes/java/util/UnknownFormatFlagsException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, 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 @@ -34,7 +34,7 @@ package java.util; * * @since 1.5 */ -public class UnknownFormatFlagsException extends IllegalFormatException { +public non-sealed class UnknownFormatFlagsException extends IllegalFormatException { @java.io.Serial private static final long serialVersionUID = 19370506L; -- GitLab From d5f90590323613b8b572ab5097365e005ba4f5ca Mon Sep 17 00:00:00 2001 From: Tyler Steele Date: Sat, 26 Mar 2022 07:37:42 +0000 Subject: [PATCH 178/237] 8283695: [AIX] Build failure due to name conflict in test_arguments.cpp Reviewed-by: iklam, stuefe --- test/hotspot/gtest/runtime/test_arguments.cpp | 212 +++++++++--------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/test/hotspot/gtest/runtime/test_arguments.cpp b/test/hotspot/gtest/runtime/test_arguments.cpp index 234bb2a015b..0919df6e8dd 100644 --- a/test/hotspot/gtest/runtime/test_arguments.cpp +++ b/test/hotspot/gtest/runtime/test_arguments.cpp @@ -214,7 +214,7 @@ TEST_VM_F(ArgumentsTest, parse_xss) { } struct Dummy {}; -static Dummy BAD; +static Dummy BAD_INT; template struct NumericArgument { @@ -292,143 +292,143 @@ void check_numeric_flag(JVMFlag* flag, T getvalue(JVMFlag* flag), #define INTEGER_TEST_TABLE(f) \ /*input i32 u32 i64 u64 */ \ f("0", 0, 0, 0, 0 ) \ - f("-0", 0, BAD, 0, BAD ) \ - f("-1", -1, BAD, -1, BAD ) \ + f("-0", 0, BAD_INT, 0, BAD_INT ) \ + f("-1", -1, BAD_INT, -1, BAD_INT ) \ f("0x1", 1, 1, 1, 1 ) \ - f("-0x1", -1, BAD, -1, BAD ) \ + f("-0x1", -1, BAD_INT, -1, BAD_INT ) \ f("4711", 4711, 4711, 4711, 4711 ) \ f("1K", 1024, 1024, 1024, 1024 ) \ f("1k", 1024, 1024, 1024, 1024 ) \ f("2M", 2097152, 2097152, 2097152, 2097152 ) \ f("2m", 2097152, 2097152, 2097152, 2097152 ) \ f("1G", 1073741824, 1073741824, 1073741824, 1073741824 ) \ - f("2G", BAD, 0x80000000, 2147483648LL, 2147483648ULL ) \ - f("1T", BAD, BAD, 1099511627776LL, 1099511627776ULL ) \ - f("1t", BAD, BAD, 1099511627776LL, 1099511627776ULL ) \ - f("-1K", -1024, BAD, -1024, BAD ) \ + f("2G", BAD_INT, 0x80000000, 2147483648LL, 2147483648ULL ) \ + f("1T", BAD_INT, BAD_INT, 1099511627776LL, 1099511627776ULL ) \ + f("1t", BAD_INT, BAD_INT, 1099511627776LL, 1099511627776ULL ) \ + f("-1K", -1024, BAD_INT, -1024, BAD_INT ) \ f("0x1K", 1024, 1024, 1024, 1024 ) \ - f("-0x1K", -1024, BAD, -1024, BAD ) \ + f("-0x1K", -1024, BAD_INT, -1024, BAD_INT ) \ f("0K", 0, 0, 0, 0 ) \ - f("0x1000000k", BAD, BAD, 17179869184LL, 17179869184ULL ) \ - f("0x800000m", BAD, BAD, 0x80000000000LL, 0x80000000000ULL ) \ - f("0x8000g", BAD, BAD, 0x200000000000LL, 0x200000000000ULL ) \ - f("0x8000t", BAD, BAD, 0x80000000000000LL, 0x80000000000000ULL ) \ - f("-0x1000000k", BAD, BAD, -17179869184LL, BAD ) \ - f("-0x800000m", BAD, BAD, -0x80000000000LL, BAD ) \ - f("-0x8000g", BAD, BAD, -0x200000000000LL, BAD ) \ - f("-0x8000t", BAD, BAD, -0x80000000000000LL, BAD ) \ + f("0x1000000k", BAD_INT, BAD_INT, 17179869184LL, 17179869184ULL ) \ + f("0x800000m", BAD_INT, BAD_INT, 0x80000000000LL, 0x80000000000ULL ) \ + f("0x8000g", BAD_INT, BAD_INT, 0x200000000000LL, 0x200000000000ULL ) \ + f("0x8000t", BAD_INT, BAD_INT, 0x80000000000000LL, 0x80000000000000ULL ) \ + f("-0x1000000k", BAD_INT, BAD_INT, -17179869184LL, BAD_INT ) \ + f("-0x800000m", BAD_INT, BAD_INT, -0x80000000000LL, BAD_INT ) \ + f("-0x8000g", BAD_INT, BAD_INT, -0x200000000000LL, BAD_INT ) \ + f("-0x8000t", BAD_INT, BAD_INT, -0x80000000000000LL, BAD_INT ) \ f("0x7fffffff", 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff ) \ - f("0xffffffff", BAD, 0xffffffff, 0xffffffff, 0xffffffff ) \ - f("0x80000000", BAD, 0x80000000, 0x80000000, 0x80000000 ) \ - f("-0x7fffffff", -2147483647, BAD, -2147483647LL, BAD ) \ - f("-0x80000000", -2147483648, BAD, -2147483648LL, BAD ) \ - f("-0x80000001", BAD, BAD, -2147483649LL, BAD ) \ - f("0x100000000", BAD, BAD, 0x100000000LL, 0x100000000ULL ) \ - f("0xcafebabe", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ - f("0XCAFEBABE", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ - f("0XCAFEbabe", BAD, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ - f("0xcafebabe1", BAD, BAD, 0xcafebabe1, 0xcafebabe1 ) \ - f("0x7fffffffffffffff", BAD, BAD, max_jlong, 9223372036854775807ULL ) \ - f("0x8000000000000000", BAD, BAD, BAD, 9223372036854775808ULL ) \ - f("0xffffffffffffffff", BAD, BAD, BAD, max_julong ) \ - f("9223372036854775807", BAD, BAD, 9223372036854775807LL, 9223372036854775807ULL ) \ - f("9223372036854775808", BAD, BAD, BAD, 9223372036854775808ULL ) \ - f("-9223372036854775808", BAD, BAD, min_jlong, BAD ) \ - f("18446744073709551615", BAD, BAD, BAD, max_julong ) \ + f("0xffffffff", BAD_INT, 0xffffffff, 0xffffffff, 0xffffffff ) \ + f("0x80000000", BAD_INT, 0x80000000, 0x80000000, 0x80000000 ) \ + f("-0x7fffffff", -2147483647, BAD_INT, -2147483647LL, BAD_INT ) \ + f("-0x80000000", -2147483648, BAD_INT, -2147483648LL, BAD_INT ) \ + f("-0x80000001", BAD_INT, BAD_INT, -2147483649LL, BAD_INT ) \ + f("0x100000000", BAD_INT, BAD_INT, 0x100000000LL, 0x100000000ULL ) \ + f("0xcafebabe", BAD_INT, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0XCAFEBABE", BAD_INT, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0XCAFEbabe", BAD_INT, 0xcafebabe, 0xcafebabe, 0xcafebabe ) \ + f("0xcafebabe1", BAD_INT, BAD_INT, 0xcafebabe1, 0xcafebabe1 ) \ + f("0x7fffffffffffffff", BAD_INT, BAD_INT, max_jlong, 9223372036854775807ULL ) \ + f("0x8000000000000000", BAD_INT, BAD_INT, BAD_INT, 9223372036854775808ULL ) \ + f("0xffffffffffffffff", BAD_INT, BAD_INT, BAD_INT, max_julong ) \ + f("9223372036854775807", BAD_INT, BAD_INT, 9223372036854775807LL, 9223372036854775807ULL ) \ + f("9223372036854775808", BAD_INT, BAD_INT, BAD_INT, 9223372036854775808ULL ) \ + f("-9223372036854775808", BAD_INT, BAD_INT, min_jlong, BAD_INT ) \ + f("18446744073709551615", BAD_INT, BAD_INT, BAD_INT, max_julong ) \ \ /* All edge cases without a k/m/g/t suffix */ \ f("0x7ffffffe", max_jint-1, 0x7ffffffe, 0x7ffffffeLL, 0x7ffffffeULL ) \ f("0x7fffffff", max_jint, 0x7fffffff, 0x7fffffffLL, 0x7fffffffULL ) \ - f("0x80000000", BAD, 0x80000000, 0x80000000LL, 0x80000000ULL ) \ - f("0xfffffffe", BAD, max_juint-1, 0xfffffffeLL, 0xfffffffeULL ) \ - f("0xffffffff", BAD, max_juint, 0xffffffffLL, 0xffffffffULL ) \ - f("0x100000000", BAD, BAD, 0x100000000LL, 0x100000000ULL ) \ - f("-0x7fffffff", min_jint+1, BAD, -0x7fffffffLL, BAD ) \ - f("-0x80000000", min_jint, BAD, -0x80000000LL, BAD ) \ - f("-0x80000001", BAD, BAD, -0x80000001LL, BAD ) \ + f("0x80000000", BAD_INT, 0x80000000, 0x80000000LL, 0x80000000ULL ) \ + f("0xfffffffe", BAD_INT, max_juint-1, 0xfffffffeLL, 0xfffffffeULL ) \ + f("0xffffffff", BAD_INT, max_juint, 0xffffffffLL, 0xffffffffULL ) \ + f("0x100000000", BAD_INT, BAD_INT, 0x100000000LL, 0x100000000ULL ) \ + f("-0x7fffffff", min_jint+1, BAD_INT, -0x7fffffffLL, BAD_INT ) \ + f("-0x80000000", min_jint, BAD_INT, -0x80000000LL, BAD_INT ) \ + f("-0x80000001", BAD_INT, BAD_INT, -0x80000001LL, BAD_INT ) \ \ - f("0x7ffffffffffffffe", BAD, BAD, max_jlong-1, 0x7ffffffffffffffeULL ) \ - f("0x7fffffffffffffff", BAD, BAD, max_jlong, 0x7fffffffffffffffULL ) \ - f("0x8000000000000000", BAD, BAD, BAD, 0x8000000000000000ULL ) \ - f("0xfffffffffffffffe", BAD, BAD, BAD, max_julong-1 ) \ - f("0xffffffffffffffff", BAD, BAD, BAD, max_julong ) \ - f("0x10000000000000000", BAD, BAD, BAD, BAD ) \ - f("-0x7fffffffffffffff", BAD, BAD, min_jlong+1, BAD ) \ - f("-0x8000000000000000", BAD, BAD, min_jlong, BAD ) \ - f("-0x8000000000000001", BAD, BAD, BAD, BAD ) \ + f("0x7ffffffffffffffe", BAD_INT, BAD_INT, max_jlong-1, 0x7ffffffffffffffeULL ) \ + f("0x7fffffffffffffff", BAD_INT, BAD_INT, max_jlong, 0x7fffffffffffffffULL ) \ + f("0x8000000000000000", BAD_INT, BAD_INT, BAD_INT, 0x8000000000000000ULL ) \ + f("0xfffffffffffffffe", BAD_INT, BAD_INT, BAD_INT, max_julong-1 ) \ + f("0xffffffffffffffff", BAD_INT, BAD_INT, BAD_INT, max_julong ) \ + f("0x10000000000000000", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ + f("-0x7fffffffffffffff", BAD_INT, BAD_INT, min_jlong+1, BAD_INT ) \ + f("-0x8000000000000000", BAD_INT, BAD_INT, min_jlong, BAD_INT ) \ + f("-0x8000000000000001", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ \ /* edge cases for suffix: K */ \ f("0x1ffffek", 0x1ffffe * k, 0x1ffffeU * k,0x1ffffeLL * k, 0x1ffffeULL * k ) \ f("0x1fffffk", 0x1fffff * k, 0x1fffffU * k,0x1fffffLL * k, 0x1fffffULL * k ) \ - f("0x200000k", BAD, 0x200000U * k,0x200000LL * k, 0x200000ULL * k ) \ - f("0x3ffffek", BAD, 0x3ffffeU * k,0x3ffffeLL * k, 0x3ffffeULL * k ) \ - f("0x3fffffk", BAD, 0x3fffffU * k,0x3fffffLL * k, 0x3fffffULL * k ) \ - f("0x400000k", BAD, BAD, 0x400000LL * k, 0x400000ULL * k ) \ - f("-0x1fffffk", -0x1fffff * k, BAD, -0x1fffffLL * k, BAD ) \ - f("-0x200000k", -0x200000 * k, BAD, -0x200000LL * k, BAD ) \ - f("-0x200001k", BAD, BAD, -0x200001LL * k, BAD ) \ + f("0x200000k", BAD_INT, 0x200000U * k,0x200000LL * k, 0x200000ULL * k ) \ + f("0x3ffffek", BAD_INT, 0x3ffffeU * k,0x3ffffeLL * k, 0x3ffffeULL * k ) \ + f("0x3fffffk", BAD_INT, 0x3fffffU * k,0x3fffffLL * k, 0x3fffffULL * k ) \ + f("0x400000k", BAD_INT, BAD_INT, 0x400000LL * k, 0x400000ULL * k ) \ + f("-0x1fffffk", -0x1fffff * k, BAD_INT, -0x1fffffLL * k, BAD_INT ) \ + f("-0x200000k", -0x200000 * k, BAD_INT, -0x200000LL * k, BAD_INT ) \ + f("-0x200001k", BAD_INT, BAD_INT, -0x200001LL * k, BAD_INT ) \ \ - f("0x1ffffffffffffek", BAD, BAD, 0x1ffffffffffffeLL * k, 0x1ffffffffffffeULL * k ) \ - f("0x1fffffffffffffk", BAD, BAD, 0x1fffffffffffffLL * k, 0x1fffffffffffffULL * k ) \ - f("0x20000000000000k", BAD, BAD, BAD, 0x20000000000000ULL * k ) \ - f("0x3ffffffffffffek", BAD, BAD, BAD, 0x3ffffffffffffeULL * k ) \ - f("0x3fffffffffffffk", BAD, BAD, BAD, 0x3fffffffffffffULL * k ) \ - f("0x40000000000000k", BAD, BAD, BAD, BAD ) \ - f("-0x1fffffffffffffk", BAD, BAD, -0x1fffffffffffffLL * k, BAD ) \ - f("-0x20000000000000k", BAD, BAD, -0x20000000000000LL * k, BAD ) \ - f("-0x20000000000001k", BAD, BAD, BAD, BAD ) \ + f("0x1ffffffffffffek", BAD_INT, BAD_INT, 0x1ffffffffffffeLL * k, 0x1ffffffffffffeULL * k ) \ + f("0x1fffffffffffffk", BAD_INT, BAD_INT, 0x1fffffffffffffLL * k, 0x1fffffffffffffULL * k ) \ + f("0x20000000000000k", BAD_INT, BAD_INT, BAD_INT, 0x20000000000000ULL * k ) \ + f("0x3ffffffffffffek", BAD_INT, BAD_INT, BAD_INT, 0x3ffffffffffffeULL * k ) \ + f("0x3fffffffffffffk", BAD_INT, BAD_INT, BAD_INT, 0x3fffffffffffffULL * k ) \ + f("0x40000000000000k", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ + f("-0x1fffffffffffffk", BAD_INT, BAD_INT, -0x1fffffffffffffLL * k, BAD_INT ) \ + f("-0x20000000000000k", BAD_INT, BAD_INT, -0x20000000000000LL * k, BAD_INT ) \ + f("-0x20000000000001k", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ \ /* edge cases for suffix: M */ \ f("0x7fem", 0x7fe * m, 0x7feU * m, 0x7feLL * m, 0x7feULL * m ) \ f("0x7ffm", 0x7ff * m, 0x7ffU * m, 0x7ffLL * m, 0x7ffULL * m ) \ - f("0x800m", BAD, 0x800U * m, 0x800LL * m, 0x800ULL * m ) \ - f("0xffem", BAD, 0xffeU * m, 0xffeLL * m, 0xffeULL * m ) \ - f("0xfffm", BAD, 0xfffU * m, 0xfffLL * m, 0xfffULL * m ) \ - f("0x1000m", BAD, BAD, 0x1000LL * m, 0x1000ULL * m ) \ - f("-0x7ffm", -0x7ff * m, BAD, -0x7ffLL * m, BAD ) \ - f("-0x800m", -0x800 * m, BAD, -0x800LL * m, BAD ) \ - f("-0x801m", BAD, BAD, -0x801LL * m, BAD ) \ + f("0x800m", BAD_INT, 0x800U * m, 0x800LL * m, 0x800ULL * m ) \ + f("0xffem", BAD_INT, 0xffeU * m, 0xffeLL * m, 0xffeULL * m ) \ + f("0xfffm", BAD_INT, 0xfffU * m, 0xfffLL * m, 0xfffULL * m ) \ + f("0x1000m", BAD_INT, BAD_INT, 0x1000LL * m, 0x1000ULL * m ) \ + f("-0x7ffm", -0x7ff * m, BAD_INT, -0x7ffLL * m, BAD_INT ) \ + f("-0x800m", -0x800 * m, BAD_INT, -0x800LL * m, BAD_INT ) \ + f("-0x801m", BAD_INT, BAD_INT, -0x801LL * m, BAD_INT ) \ \ - f("0x7fffffffffem", BAD, BAD, 0x7fffffffffeLL * m, 0x7fffffffffeULL * m ) \ - f("0x7ffffffffffm", BAD, BAD, 0x7ffffffffffLL * m, 0x7ffffffffffULL * m ) \ - f("0x80000000000m", BAD, BAD, BAD, 0x80000000000ULL * m ) \ - f("0xffffffffffem", BAD, BAD, BAD, 0xffffffffffeULL * m ) \ - f("0xfffffffffffm", BAD, BAD, BAD, 0xfffffffffffULL * m ) \ - f("0x100000000000m", BAD, BAD, BAD, BAD ) \ - f("-0x7ffffffffffm", BAD, BAD, -0x7ffffffffffLL * m, BAD ) \ - f("-0x80000000000m", BAD, BAD, -0x80000000000LL * m, BAD ) \ - f("-0x80000000001m", BAD, BAD, BAD, BAD ) \ + f("0x7fffffffffem", BAD_INT, BAD_INT, 0x7fffffffffeLL * m, 0x7fffffffffeULL * m ) \ + f("0x7ffffffffffm", BAD_INT, BAD_INT, 0x7ffffffffffLL * m, 0x7ffffffffffULL * m ) \ + f("0x80000000000m", BAD_INT, BAD_INT, BAD_INT, 0x80000000000ULL * m ) \ + f("0xffffffffffem", BAD_INT, BAD_INT, BAD_INT, 0xffffffffffeULL * m ) \ + f("0xfffffffffffm", BAD_INT, BAD_INT, BAD_INT, 0xfffffffffffULL * m ) \ + f("0x100000000000m", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ + f("-0x7ffffffffffm", BAD_INT, BAD_INT, -0x7ffffffffffLL * m, BAD_INT ) \ + f("-0x80000000000m", BAD_INT, BAD_INT, -0x80000000000LL * m, BAD_INT ) \ + f("-0x80000000001m", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ \ /* edge cases for suffix: G */ \ f("0x0g", 0x0 * g, 0x0U * g, 0x0LL * g, 0x0ULL * g ) \ f("0x1g", 0x1 * g, 0x1U * g, 0x1LL * g, 0x1ULL * g ) \ - f("0x2g", BAD, 0x2U * g, 0x2LL * g, 0x2ULL * g ) \ - f("0x3g", BAD, 0x3U * g, 0x3LL * g, 0x3ULL * g ) \ - f("0x4g", BAD, BAD, 0x4LL * g, 0x4ULL * g ) \ - f("-0x1g", -0x1 * g, BAD, -0x1LL * g, BAD ) \ - f("-0x2g", -0x2 * g, BAD, -0x2LL * g, BAD ) \ - f("-0x3g", BAD, BAD, -0x3LL * g, BAD ) \ + f("0x2g", BAD_INT, 0x2U * g, 0x2LL * g, 0x2ULL * g ) \ + f("0x3g", BAD_INT, 0x3U * g, 0x3LL * g, 0x3ULL * g ) \ + f("0x4g", BAD_INT, BAD_INT, 0x4LL * g, 0x4ULL * g ) \ + f("-0x1g", -0x1 * g, BAD_INT, -0x1LL * g, BAD_INT ) \ + f("-0x2g", -0x2 * g, BAD_INT, -0x2LL * g, BAD_INT ) \ + f("-0x3g", BAD_INT, BAD_INT, -0x3LL * g, BAD_INT ) \ \ - f("0x1fffffffeg", BAD, BAD, 0x1fffffffeLL * g, 0x1fffffffeULL * g ) \ - f("0x1ffffffffg", BAD, BAD, 0x1ffffffffLL * g, 0x1ffffffffULL * g ) \ - f("0x200000000g", BAD, BAD, BAD, 0x200000000ULL * g ) \ - f("0x3fffffffeg", BAD, BAD, BAD, 0x3fffffffeULL * g ) \ - f("0x3ffffffffg", BAD, BAD, BAD, 0x3ffffffffULL * g ) \ - f("0x400000000g", BAD, BAD, BAD, BAD ) \ - f("-0x1ffffffffg", BAD, BAD, -0x1ffffffffLL * g, BAD ) \ - f("-0x200000000g", BAD, BAD, -0x200000000LL * g, BAD ) \ - f("-0x200000001g", BAD, BAD, BAD, BAD ) \ + f("0x1fffffffeg", BAD_INT, BAD_INT, 0x1fffffffeLL * g, 0x1fffffffeULL * g ) \ + f("0x1ffffffffg", BAD_INT, BAD_INT, 0x1ffffffffLL * g, 0x1ffffffffULL * g ) \ + f("0x200000000g", BAD_INT, BAD_INT, BAD_INT, 0x200000000ULL * g ) \ + f("0x3fffffffeg", BAD_INT, BAD_INT, BAD_INT, 0x3fffffffeULL * g ) \ + f("0x3ffffffffg", BAD_INT, BAD_INT, BAD_INT, 0x3ffffffffULL * g ) \ + f("0x400000000g", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ + f("-0x1ffffffffg", BAD_INT, BAD_INT, -0x1ffffffffLL * g, BAD_INT ) \ + f("-0x200000000g", BAD_INT, BAD_INT, -0x200000000LL * g, BAD_INT ) \ + f("-0x200000001g", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ \ /* edge cases for suffix: T */ \ - f("0x7ffffet", BAD, BAD, 0x7ffffeLL * t, 0x7ffffeULL * t ) \ - f("0x7ffffft", BAD, BAD, 0x7fffffLL * t, 0x7fffffULL * t ) \ - f("0x800000t", BAD, BAD, BAD, 0x800000ULL * t ) \ - f("0xfffffet", BAD, BAD, BAD, 0xfffffeULL * t ) \ - f("0xfffffft", BAD, BAD, BAD, 0xffffffULL * t ) \ - f("0x1000000t", BAD, BAD, BAD, BAD ) \ - f("-0x7ffffft", BAD, BAD, -0x7fffffLL * t, BAD ) \ - f("-0x800000t", BAD, BAD, -0x800000LL * t, BAD ) \ - f("-0x800001t", BAD, BAD, BAD, BAD ) + f("0x7ffffet", BAD_INT, BAD_INT, 0x7ffffeLL * t, 0x7ffffeULL * t ) \ + f("0x7ffffft", BAD_INT, BAD_INT, 0x7fffffLL * t, 0x7fffffULL * t ) \ + f("0x800000t", BAD_INT, BAD_INT, BAD_INT, 0x800000ULL * t ) \ + f("0xfffffet", BAD_INT, BAD_INT, BAD_INT, 0xfffffeULL * t ) \ + f("0xfffffft", BAD_INT, BAD_INT, BAD_INT, 0xffffffULL * t ) \ + f("0x1000000t", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) \ + f("-0x7ffffft", BAD_INT, BAD_INT, -0x7fffffLL * t, BAD_INT ) \ + f("-0x800000t", BAD_INT, BAD_INT, -0x800000LL * t, BAD_INT ) \ + f("-0x800001t", BAD_INT, BAD_INT, BAD_INT, BAD_INT ) #define INTEGER_TEST_i32(s, i32, u32, i64, u64) NumericArgument(s, i32), #define INTEGER_TEST_u32(s, i32, u32, i64, u64) NumericArgument(s, u32), -- GitLab From c587b29bc9ca7e6d3879fda7df099b7411624f19 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Sat, 26 Mar 2022 13:32:10 +0000 Subject: [PATCH 179/237] 8283720: ProblemList java/time/test/java/time/TestZoneOffset.java Reviewed-by: alanb --- test/jdk/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 25858d1cb71..0626a952784 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -759,6 +759,8 @@ javax/swing/JTree/4908142/bug4908142.java 8278348 macosx-all # jdk_time +java/time/test/java/time/TestZoneOffset.java 8283716 generic-all + ############################################################################ -- GitLab From b0daf70a251ba0ca04ca757b98cffd5607a154d4 Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sat, 26 Mar 2022 21:46:22 +0000 Subject: [PATCH 180/237] 8263134: HotSpot Style Guide should disallow inheriting constructors Reviewed-by: dholmes, dcubed, kvn --- doc/hotspot-style.html | 5 +++++ doc/hotspot-style.md | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index c93b941c988..3c0332e4b49 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -51,6 +51,7 @@

    • <atomic>
    • Uniform Initialization
    • Local Function Objects
    • +
    • Inheriting constructors
    • Additional Permitted Features
    • Excluded Features
    • Undecided Features
    • @@ -405,6 +406,10 @@ while ( test_foo(args...) ) { // No, excess spaces around control
    • Make () more optional for lambdas (p1102r2)
    +

    Inheriting constructors

    +

    Do not use inheriting constructors (n2540).

    +

    C++11 provides simple syntax allowing a class to inherit the constructors of a base class. Unfortunately there are a number of problems with the original specification, and C++17 contains significant revisions (p0136r1 opens with a list of 8 Core Issues). Since HotSpot doesn't support use of C++17, use of inherited constructors could run into those problems. Such uses might also change behavior in a future HotSpot update to use C++17 or later, potentially in subtle ways that could lead to hard to diagnose problems. Because of this, HotSpot code must not use inherited constructors.

    +

    Note that gcc7 provides the -fnew-inheriting-ctors option to use the p0136r1 semantics. This is enabled by default when using C++17 or later. It is also enabled by default for fabi-version=11 (introduced by gcc7) or higher when using C++11/14, as the change is considered a Defect Report that applies to those versions. Earlier versions of gcc don't have that option, and other supported compilers may not have anything similar.

    Additional Permitted Features

    • constexpr (n2235) (n3652)

    • diff --git a/doc/hotspot-style.md b/doc/hotspot-style.md index 89d9684672d..f8825cbd07b 100644 --- a/doc/hotspot-style.md +++ b/doc/hotspot-style.md @@ -985,6 +985,30 @@ References from C++23 [p1102r2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1102r2.html +### Inheriting constructors + +Do not use _inheriting constructors_ +([n2540](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm)). + +C++11 provides simple syntax allowing a class to inherit the constructors of a +base class. Unfortunately there are a number of problems with the original +specification, and C++17 contains significant revisions ([p0136r1] opens with +a list of 8 Core Issues). Since HotSpot doesn't support use of C++17, use of +inherited constructors could run into those problems. Such uses might also +change behavior in a future HotSpot update to use C++17 or later, potentially +in subtle ways that could lead to hard to diagnose problems. Because of this, +HotSpot code must not use inherited constructors. + +Note that gcc7 provides the `-fnew-inheriting-ctors` option to use the +[p0136r1] semantics. This is enabled by default when using C++17 or later. +It is also enabled by default for `fabi-version=11` (introduced by gcc7) or +higher when using C++11/14, as the change is considered a Defect Report that +applies to those versions. Earlier versions of gcc don't have that option, +and other supported compilers may not have anything similar. + +[p0136r1]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0136r1.html + "p0136r1" + ### Additional Permitted Features * `constexpr` -- GitLab From c2c0cb2a4372d78658326461562363de9a1a194f Mon Sep 17 00:00:00 2001 From: Kim Barrett Date: Sat, 26 Mar 2022 21:55:33 +0000 Subject: [PATCH 181/237] 8282668: HotSpot Style Guide should permit unrestricted unions Reviewed-by: dholmes, dcubed, tschatzl, kvn --- doc/hotspot-style.html | 1 + doc/hotspot-style.md | 3 +++ 2 files changed, 4 insertions(+) diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index 3c0332e4b49..f0dfad09eb8 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -428,6 +428,7 @@ while ( test_foo(args...) ) { // No, excess spaces around control

      final virtual specifiers for classes and virtual functions (n2928), (n3206), (n3272)

    • override virtual specifiers for virtual functions (n2928), (n3206), (n3272)

    • Range-based for loops (n2930) (range-for)

    • +
    • Unrestricted Unions (n2544)

    Excluded Features